Source code for p4.node
import p4.func
from p4.var import var
import sys
import p4.pf as pf
class NodeBranchPart(object):
def __init__(self):
self.rMatrixNum = -1
self.gdasrvNum = -1
#self.bigP = None
class NodeBranch(object):
def __init__(self):
self.len = 0.1
# self.textDrawSymbol = '-' # See var.modelSymbols for some
# alternative symbols
self.rawSplitKey = None # Odd or even
self.splitKey = None # Only even
#self.name = None
# self.uName = None # under-name
# self.color = None # US spelling.
# self.support = None # A float, so that it can preserve all its significant
# digits, yet can be formatted flexibly for output.
# self.biRootCount = None # For cons trees, where the input trees are
# bi-Rooted, ie have bifurcating roots. This
# is the number of compatible input trees that
# were rooted on this branch.
self.parts = [] # NodeBranchPart() objects
self.lenChanged = False
class NodePart(object):
def __init__(self):
#self.pats = None
#self.nPats = 0
self.compNum = -1
#self.cl = None
#self.cl2 = None
[docs]class Node(object):
"""A Node is a vertex in a Tree. All but the root have a branch.
A Node has pointers to its parent, leftChild, and sibling, any of which may be None.
"""
# def __del__(self, freeNode=pf.p4_freeNode, dp_freeNode=pf.dp_freeNode,
# mysys=sys):
def __del__(self, freeNode=pf.p4_freeNode, mysys=sys):
# def __del__(self, freeNode=pf.p4_freeNode, dp_freeNode=pf.dp_freeNode):
# def __del__(self, freeNode=pf.p4_freeNode):
# if self.nodeNum == 0:
#mysys.stdout.write('Node.__del__() deleting node %i\n' % self.nodeNum)
# mysys.stdout.flush()
# Generally, cNodes are deleted before the cTree is freed. freeNode
# requires the cTree!
if self.cNode:
mysys.stdout.write('Node.__del__() node %i (%s) has a cNode (%s). How?!?\n' % (
self.nodeNum, self, self.cNode))
if self.doDataPart:
dp_freeNode(self.cNode)
else:
freeNode(self.cNode)
self.cNode = None
def __init__(self):
self.name = None
self.nodeNum = -1
self.parent = None
self.leftChild = None
self.sibling = None
self.isLeaf = 0
self.cNode = None # Pointer to a c-struct
# Zero-based seq numbering of course, so -1 means no sequence.
self.seqNum = -1
self.br = NodeBranch()
# self.rootCount = None # For cons trees, where the input trees do not
# have bifurcating roots. This is the number of
# compatible input trees that were rooted on this node.
self.parts = [] # NodePart objects
self.doDataPart = 0
self.flag = 0
[docs] def wipe(self):
"""Set the pointers parent, leftChild, and sibling to None"""
self.parent = None
self.leftChild = None
self.sibling = None
[docs] def rightmostChild(self):
"""Find and return the rightmostChild of self.
If self has no children, return None.
"""
n = self.leftChild
if not n:
return None
while n.sibling:
n = n.sibling
return n
[docs] def leftSibling(self):
"""Find and return the sibling on the left.
A node has a pointer to its sibling, but that is the sibling
on the right. It is a bit awkward to find the sibling on the
left, as you need to go via the parent and the leftChild of
the parent.
If there is no parent, return None. If there is no
leftSibling, return None.
"""
if not self.parent:
# print 'leftSibling(%i). No parent. returning None.' %
# self.nodeNum
return None
lsib = self.parent.leftChild
if lsib == self:
# print 'leftSibling(%i). self is self.parent.leftChild.
# returning None.' % self.nodeNum
return None
while lsib:
if lsib.sibling == self:
# print 'leftSibling(%i): returning node %i' % (self.nodeNum,
# lsib.nodeNum)
return lsib
lsib = lsib.sibling
# These next 3 were suggestions from Rick Ree. Thanks, Rick!
# Then I added a couple more. Note that all of these use
# recursion, and so could bump into the recursion limit, and might
# fail on large trees. However, I tried iterPreOrder() on a
# random tree of 10,000 taxa, and it was fine.
# You can temporarily set a different recursion limit with the sys module.
# oldlimit = sys.getrecursionlimit()
# sys.setrecursionlimit(newLimit)
# See also Tree.iterNodesNoRoot()
[docs] def iterChildren(self):
n = self.leftChild
while n:
yield n
n = n.sibling
[docs] def iterPostOrder(self):
for c in self.iterChildren():
for n in c.iterPostOrder():
yield n
yield self
[docs] def iterPreOrder(self):
yield self
for c in self.iterChildren():
for n in c.iterPreOrder():
yield n
[docs] def iterLeaves(self):
for n in self.iterPreOrder():
if n.isLeaf:
yield n
[docs] def iterInternals(self):
for n in self.iterPreOrder():
if not n.isLeaf:
yield n
[docs] def iterDown(self, showDown=False):
"""Iterates over all the nodes below self (including self)
Starts by returning self. And then iterates over all nodes below self.
It does so by a combination of Node.iterPreOrder() and
Node.iterDown() (ie recursively). Now sometimes we want to
know if the nodes that are returned come from iterDown()
(strictly) or not (ie from iterPreOrder()). If that bit of
info is needed, then you can turn on the arg ``showDown``.
(The following is probably bad Python practice!) When that is done, whenever
iterDown() is called the first node that is returned will have
the attribute ``down`` set to True. But after it is returned,
that ``down`` attribute is zapped (to try to keep the bloat
down ...). So you need to test ``if hasattr(yourNode,
'down'):`` before you actually use it.
"""
if showDown:
self.down = True
yield self
if showDown:
del(self.down)
if self.parent:
for c in self.parent.iterChildren():
if c == self:
for n in c.parent.iterDown(showDown):
yield n
else:
for n in c.iterPreOrder():
yield n
# ###############################
[docs] def getNChildren(self):
"""Returns the number of children that the node has."""
if not self.leftChild:
return 0
c = self.leftChild
counter = 0
while c:
c = c.sibling
counter += 1
return counter
[docs] def isAncestorOf(self, otherNode):
"""Asks whether self is an an ancestor of otherNode."""
n = otherNode
while 1:
n = n.parent
if not n:
return False
elif n == self:
return True
def _ladderize(self, biggerGroupsOnBottom):
"""This is only used by Tree.ladderize()."""
# print '====Node %i' % self.nodeNum
if not self.leftChild:
pass
else:
nLeaves = []
children = []
ch = self.leftChild
while ch:
nL = len([n2 for n2 in ch.iterLeaves()])
nLeaves.append(nL)
ch.nLeaves = nL
children.append(ch)
ch = ch.sibling
# print ' nLeaves = %s' % nLeaves
allOnes = True
for ch in children:
if ch.nLeaves > 1:
allOnes = False
break
if not allOnes:
children = p4.func.sortListOfObjectsOnAttribute(
children, 'nLeaves')
if not biggerGroupsOnBottom:
children.reverse()
# print '\n Children\n ------------'
# for ch in children:
# print ' node=%i, nLeaves=%i' % (ch.nodeNum, ch.nLeaves)
self.leftChild = children[0]
theLeftChild = self.leftChild
theLeftChild.sibling = None
for ch in children[1:]:
theLeftChild.sibling = ch
theLeftChild = ch
theLeftChild.sibling = None
for ch in children:
del(ch.nLeaves)
for ch in self.iterChildren():
ch._ladderize(biggerGroupsOnBottom)