Spaces:
No application file
No application file
File size: 5,745 Bytes
b7731cd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# Copyright 2005-2008 by Frank Kauff & Cymon J. Cox. All rights reserved.
#
# This file is part of the Biopython distribution and governed by your
# choice of the "Biopython License Agreement" or the "BSD 3-Clause License".
# Please see the LICENSE file that should have been included as part of this
# package.
"""Linked list functionality for use in Bio.Nexus.
Provides functionality of a linked list.
Each node has one (or none) predecessor, and an arbitrary number of successors.
Nodes can store arbitrary data in a NodeData class.
Subclassed by Nexus.Trees to store phylogenetic trees.
Bug reports to Frank Kauff ([email protected])
"""
class ChainException(Exception):
"""Provision for the management of Chain exceptions."""
pass
class NodeException(Exception):
"""Provision for the management of Node exceptions."""
pass
class Chain:
"""Stores a list of nodes that are linked together."""
def __init__(self):
"""Initialize a node chain."""
self.chain = {}
self.id = -1
def _get_id(self):
"""Get a new id for a node in the chain (PRIVATE)."""
self.id += 1
return self.id
def all_ids(self):
"""Return a list of all node ids."""
return list(self.chain.keys())
def add(self, node, prev=None):
"""Attach node to another."""
if prev is not None and prev not in self.chain:
raise ChainException("Unknown predecessor: " + str(prev))
else:
id = self._get_id()
node.set_id(id)
node.set_prev(prev)
if prev is not None:
self.chain[prev].add_succ(id)
self.chain[id] = node
return id
def collapse(self, id):
"""Delete node from chain and relinks successors to predecessor."""
if id not in self.chain:
raise ChainException("Unknown ID: " + str(id))
prev_id = self.chain[id].get_prev()
self.chain[prev_id].remove_succ(id)
succ_ids = self.chain[id].get_succ()
for i in succ_ids:
self.chain[i].set_prev(prev_id)
self.chain[prev_id].add_succ(succ_ids)
node = self.chain[id]
self.kill(id)
return node
def kill(self, id):
"""Kill a node from chain without caring to what it is connected."""
if id not in self.chain:
raise ChainException("Unknown ID: " + str(id))
else:
del self.chain[id]
def unlink(self, id):
"""Disconnect node from his predecessor."""
if id not in self.chain:
raise ChainException("Unknown ID: " + str(id))
else:
prev_id = self.chain[id].prev
if prev_id is not None:
self.chain[prev_id].succ.pop(self.chain[prev_id].succ.index(id))
self.chain[id].prev = None
return prev_id
def link(self, parent, child):
"""Connect son to parent."""
if child not in self.chain:
raise ChainException("Unknown ID: " + str(child))
elif parent not in self.chain:
raise ChainException("Unknown ID: " + str(parent))
else:
self.unlink(child)
self.chain[parent].succ.append(child)
self.chain[child].set_prev(parent)
def is_parent_of(self, parent, grandchild):
"""Check if grandchild is a subnode of parent."""
if grandchild == parent or grandchild in self.chain[parent].get_succ():
return True
else:
for sn in self.chain[parent].get_succ():
if self.is_parent_of(sn, grandchild):
return True
else:
return False
def trace(self, start, finish):
"""Return a list of all node_ids between two nodes (excluding start, including end)."""
if start not in self.chain or finish not in self.chain:
raise NodeException("Unknown node.")
if not self.is_parent_of(start, finish) or start == finish:
return []
for sn in self.chain[start].get_succ():
if self.is_parent_of(sn, finish):
return [sn] + self.trace(sn, finish)
class Node:
"""A single node."""
def __init__(self, data=None):
"""Represent a node with one predecessor and multiple successors."""
self.id = None
self.data = data
self.prev = None
self.succ = []
def set_id(self, id):
"""Set the id of a node, if not set yet."""
if self.id is not None:
raise NodeException("Node id cannot be changed.")
self.id = id
def get_id(self):
"""Return the node's id."""
return self.id
def get_succ(self):
"""Return a list of the node's successors."""
return self.succ
def get_prev(self):
"""Return the id of the node's predecessor."""
return self.prev
def add_succ(self, id):
"""Add a node id to the node's successors."""
if isinstance(id, type([])):
self.succ.extend(id)
else:
self.succ.append(id)
def remove_succ(self, id):
"""Remove a node id from the node's successors."""
self.succ.remove(id)
def set_succ(self, new_succ):
"""Set the node's successors."""
if not isinstance(new_succ, type([])):
raise NodeException("Node successor must be of list type.")
self.succ = new_succ
def set_prev(self, id):
"""Set the node's predecessor."""
self.prev = id
def get_data(self):
"""Return a node's data."""
return self.data
def set_data(self, data):
"""Set a node's data."""
self.data = data
|