3
// (c) 1999-2001 PAL Development Core Team
5
// This package may be distributed under the
6
// terms of the Lesser GNU General Public License (LGPL)
14
import java.util.Hashtable;
15
import java.util.Enumeration;
19
* data structure for a node (includes branch) in a binary/non-binary
20
* rooted/unrooted tree
22
* @version $Id: SimpleNode.java,v 1.27 2003/10/19 02:35:26 matt Exp $
24
* @author Korbinian Strimmer
25
* @author Alexei Drummond
27
public class SimpleNode implements AttributeNode {
32
/** number of node as displayed */
35
/** sequences associated with node */
36
private byte[] sequence;
38
/** length of branch to parent node */
39
private double length;
41
/** standard error of length of branch to parent node */
42
private double lengthSE;
44
/** height of this node */
45
private double height;
47
/** identifier of node/associated branch */
48
private Identifier identifier;
50
/** the attributes associated with this node. */
51
private Hashtable attributes = null;
60
// Serialization Stuff
63
static final long serialVersionUID=3472432765038556717L;
65
//serialver -classpath ./classes pal.tree.SimpleNode
67
/** I like doing things my self! */
68
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
69
out.writeByte(3); //Version number
70
out.writeObject(parent);
72
out.writeObject(sequence);
73
out.writeDouble(length);
74
out.writeDouble(lengthSE);
75
out.writeDouble(height);
76
out.writeObject(identifier);
77
out.writeObject(child);
78
out.writeObject(attributes);
81
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
82
byte version = in.readByte();
85
parent = (Node)in.readObject();
86
number = in.readInt();
87
sequence = (byte[])in.readObject();
88
Object partial = (double[][][])in.readObject();
89
length = in.readDouble();
90
lengthSE = in.readDouble();
91
height = in.readDouble();
93
identifier = (Identifier)in.readObject();
94
child = (Node[])in.readObject();
98
//attributes are transient
100
parent = (Node)in.readObject();
101
number = in.readInt();
102
sequence = (byte[])in.readObject();
103
length = in.readDouble();
104
lengthSE = in.readDouble();
105
height = in.readDouble();
106
identifier = (Identifier)in.readObject();
107
child = (Node[])in.readObject();
111
//attributes are not transient!
113
parent = (Node)in.readObject();
114
number = in.readInt();
115
sequence = (byte[])in.readObject();
116
length = in.readDouble();
117
lengthSE = in.readDouble();
118
height = in.readDouble();
119
identifier = (Identifier)in.readObject();
120
child = (Node[])in.readObject();
121
attributes = (Hashtable)in.readObject();
126
// the following constructors should eventually become
127
// "friendly" to prevent anyone calling them directly.
128
// Instead, the NodeFactory should be used!
130
/** constructor default node */
138
identifier = Identifier.ANONYMOUS;
144
public SimpleNode(String name, double branchLength) {
146
identifier = new Identifier(name);
147
length = branchLength;
153
* @param branchLength
154
* @throws IllegalArgumentException if only one child!
156
protected SimpleNode(Node[] children, double branchLength) {
158
this.child = children;
159
if(children.length==1) {
160
throw new IllegalArgumentException("Must have more than one child!");
162
for(int i = 0 ; i < child.length ; i++) {
163
child[i].setParent(this);
165
this.length = branchLength;
167
protected SimpleNode(Node[] children) {
168
this(children, BranchLimits.MINARC);
171
/** constructor used to clone a node and all children */
172
public SimpleNode(Node n)
186
identifier = Identifier.ANONYMOUS;
192
public SimpleNode(Node n, boolean keepIds) {
194
for (int i = 0; i < n.getChildCount(); i++) {
195
addChild(new SimpleNode(n.getChild(i), keepIds));
199
public SimpleNode(Node n, LabelMapping lm) {
201
for (int i = 0; i < n.getChildCount(); i++) {
202
addChild(new SimpleNode(n.getChild(i), lm));
206
protected void init(Node n) {
210
* Initialized node instance variables based on given Node.
211
* children are ignored.
213
protected void init(Node n, boolean keepId) {
217
* Initialized node instance variables based on given Node.
218
* children are ignored.
219
* @param lm - may be null
221
protected void init(Node n, boolean keepId, LabelMapping lm) {
223
length = n.getBranchLength();
224
lengthSE = n.getBranchLengthSE();
225
height = n.getNodeHeight();
228
identifier = lm.getLabelIdentifier(n.getIdentifier());
230
identifier = n.getIdentifier();
232
} else { identifier = Identifier.ANONYMOUS; }
234
number = n.getNumber();
235
sequence = n.getSequence();
237
if (n instanceof AttributeNode) {
238
AttributeNode attNode = (AttributeNode)n;
239
Enumeration e = attNode.getAttributeNames();
240
while ((e != null) && e.hasMoreElements()) {
241
String name = (String)e.nextElement();
242
setAttribute(name, attNode.getAttribute(name));
250
* Returns the parent node of this node.
252
public final Node getParent() {
256
/** Set the parent node of this node. */
257
public void setParent(Node node)
265
public final void removeParent() {
270
* Returns the sequence at this node, in the form of a String.
272
public String getSequenceString() {
273
return new String(sequence);
277
* Returns the sequence at this node, in the form of an array of bytes.
279
public byte[] getSequence() {
284
* Sets the sequence at this node, in the form of an array of bytes.
286
public void setSequence(byte[] s) {
291
* Get the length of the branch attaching this node to its parent.
293
public final double getBranchLength() {
298
* Set the length of the branch attaching this node to its parent.
300
public final void setBranchLength(double value) {
305
* Get the length SE of the branch attaching this node to its parent.
307
public final double getBranchLengthSE() {
312
* Set the length SE of the branch attaching this node to its parent.
314
public final void setBranchLengthSE(double value) {
320
* Get the height of this node relative to the most recent node.
322
public final double getNodeHeight() {
327
* Set the height of this node relative to the most recent node.
328
* @note corrects children branch lengths
330
public final void setNodeHeight(double value) {
337
for(int i = 0 ; i<child.length ; i++) {
338
child[i].setBranchLength(height-child[i].getNodeHeight());
343
* Set the height of this node relative to the most recent node.
344
* @param adjustChildBranchLengths if true
346
public final void setNodeHeight(double value,boolean adjustChildBranchLengths) {
352
if(adjustChildBranchLengths &&child!=null) {
353
for(int i = 0 ; i<child.length ; i++) {
354
child[i].setBranchLength(height-child[i].getNodeHeight());
360
* Returns the identifier for this node.
362
public final Identifier getIdentifier() {
367
* Set identifier for this node.
369
public final void setIdentifier(Identifier id) {
374
public void setNumber(int n) {
378
public int getNumber() {
385
* @param n number of child
389
public Node getChild(int n)
398
* @node node new child node
400
public void setChild(int n, Node node)
403
child[n].setParent(this);
407
* check whether this node is an internal node
409
* @return result (true or false)
411
public boolean hasChildren()
417
* check whether this node is an external node
419
* @return result (true or false)
421
public boolean isLeaf() {
422
return (getChildCount() == 0);
426
* check whether this node is a root node
428
* @return result (true or false)
430
public boolean isRoot()
446
* @param n new child node
448
public void addChild(Node n)
450
insertChild(n, getChildCount());
454
* add new child node (insertion at a specific position)
456
* @param n new child node
457
+ @param pos position
459
public void insertChild(Node n, int pos)
461
int numChildren = getChildCount();
463
Node[] newChild = new Node[numChildren + 1];
465
for (int i = 0; i < pos; i++)
467
newChild[i] = child[i];
470
for (int i = pos; i < numChildren; i++)
472
newChild[i+1] = child[i];
484
* @param n number of child to be removed
486
public Node removeChild(int n)
488
int numChildren = getChildCount();
490
if (n >= numChildren)
492
throw new IllegalArgumentException("Nonexistent child");
494
Node[] newChild = new Node[numChildren-1];
496
for (int i = 0; i < n; i++)
498
newChild[i] = child[i];
501
for (int i = n; i < numChildren-1; i++)
503
newChild[i] = child[i+1];
506
Node removed = child[n];
508
//remove parent link from removed child!
509
removed.setParent(null);
517
* determines the height of this node and its descendants
518
* from branch lengths, assuming contemporaneous tips.
520
public void lengths2HeightsContemp()
522
double largestHeight = 0.0;
526
for (int i = 0; i < getChildCount(); i++)
528
NodeUtils.lengths2Heights(getChild(i));
531
getChild(i).getNodeHeight() + getChild(i).getBranchLength();
533
if (newHeight > largestHeight)
535
largestHeight = newHeight;
540
setNodeHeight(largestHeight);
544
* Sets a named attribute to the given value.
545
* @param name the name of the attribute
546
* @param value the value to set the attribute
548
public final void setAttribute(String name, Object value) {
549
if (attributes == null) attributes = new Hashtable();
550
attributes.put(name, value);
554
* @return the attribute with the given name or null if it doesn't exist.
555
* @param name the name of the attribute.
557
public final Object getAttribute(String name) {
558
if (attributes == null) return null;
559
return attributes.get(name);
563
* @return an enumeration of the attributes that this node has or null if the
564
* node has no attributes.
566
public final Enumeration getAttributeNames() {
567
if (attributes == null) return null;
568
return attributes.keys();
572
* Returns the number of children this node has.
574
public final int getChildCount() {
575
if (child == null) return 0;
579
public String toString() {
580
StringWriter sw = new StringWriter();
581
NodeUtils.printNH(new PrintWriter(sw), this, true, false, 0, false);
582
return sw.toString();