Skip to content

Commit

Permalink
Refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
rambaut committed Jan 28, 2025
1 parent 204e952 commit 928c4e6
Show file tree
Hide file tree
Showing 7 changed files with 277 additions and 855 deletions.
25 changes: 7 additions & 18 deletions src/dr/app/tools/treeannotator/BiClade.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ public BiClade(int index, Taxon taxon) {
credibility = 1.0;
size = 1;

key = index;
key = new CladeKey(index);

this.taxon = taxon;
}

public BiClade(Object key, int size) {
public BiClade(CladeKey key, int size) {
this.index = -1;
count = 0;
credibility = 1.0;
Expand Down Expand Up @@ -160,24 +160,13 @@ public Set<Pair<BiClade, BiClade>> getSubClades() {
}

@Override
public Object getKey() {
public CladeKey getKey() {
return key;
}

public static Object makeKey(Object key1, Object key2) {
BitSet bits = new BitSet();
if (key1 instanceof Integer) {
bits.set((Integer) key1);
} else {
assert key1 instanceof BitSet;
bits.or((BitSet) key1);
}
if (key2 instanceof Integer) {
bits.set((Integer) key2);
} else {
assert key2 instanceof BitSet;
bits.or((BitSet) key2);
}
public static CladeKey makeKey(CladeKey key1, CladeKey key2) {
CladeKey bits = new CladeKey();
bits.or(key1, key2);
return bits;
}

Expand All @@ -204,7 +193,7 @@ public String toString() {
final int size;
final int index;

final Object key;
final CladeKey key;

private final Taxon taxon;

Expand Down
2 changes: 1 addition & 1 deletion src/dr/app/tools/treeannotator/Clade.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public interface Clade {

Clade getBestRight();

Object getKey();
CladeKey getKey();

void addAttributeValues(Object[] values);

Expand Down
240 changes: 240 additions & 0 deletions src/dr/app/tools/treeannotator/CladeKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
/*
* Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/

package dr.app.tools.treeannotator;

import java.io.*;
import java.util.Arrays;

/**
* This class implements a vector of bits that grows as needed. Each
* component of the bit set has a {@code boolean} value. The
* bits of a {@code BitSet} are indexed by nonnegative integers.
* Individual indexed bits can be examined, set, or cleared. One
* {@code BitSet} may be used to modify the contents of another
* {@code BitSet} through logical AND, logical inclusive OR, and
* logical exclusive OR operations.
*
* <p>By default, all bits in the set initially have the value
* {@code false}.
*
* <p>Every bit set has a current size, which is the number of bits
* of space currently in use by the bit set. Note that the size is
* related to the implementation of a bit set, so it may change with
* implementation. The length of a bit set relates to logical length
* of a bit set and is defined independently of implementation.
*
* <p>Unless otherwise noted, passing a null parameter to any of the
* methods in a {@code BitSet} will result in a
* {@code NullPointerException}.
*
* <p>A {@code BitSet} is not safe for multithreaded use without
* external synchronization.
*
* @author Arthur van Hoff
* @author Michael McCloskey
* @author Martin Buchholz
* @since 1.0
*/
public class CladeKey {
/*
* BitSets are packed into arrays of "words." Currently a word is
* a long, which consists of 64 bits, requiring 6 address bits.
* The choice of word size is determined purely by performance concerns.
*/
private static final int ADDRESS_BITS_PER_WORD = 6;
private static final int BITS_PER_WORD = 1 << ADDRESS_BITS_PER_WORD;
/* Used to shift left or right for a partial word mask */
private static final long WORD_MASK = 0xffffffffffffffffL;

/**
* The internal field corresponding to the serialField "bits".
*/
private long[] words;

/**
* The number of words in the logical size of this BitSet.
*/
private transient int wordsInUse = 0;

/**
* Given a bit index, return word index containing it.
*/
private static int wordIndex(int bitIndex) {
return bitIndex >> ADDRESS_BITS_PER_WORD;
}

/**
* Creates a new bit set. All bits are initially {@code false}.
*/
public CladeKey() {
words = new long[wordIndex(CladeKey.BITS_PER_WORD -1) + 1];
}

public CladeKey(int bitIndex) {
words = new long[wordIndex(CladeKey.BITS_PER_WORD -1) + 1];
set(bitIndex);
}

public long[] toLongArray() {
return Arrays.copyOf(words, wordsInUse);
}


public void clear() {
while (wordsInUse > 0)
words[--wordsInUse] = 0;
}

public boolean get(int bitIndex) {
int wordIndex = wordIndex(bitIndex);
return (wordIndex < wordsInUse)
&& ((words[wordIndex] & (1L << bitIndex)) != 0);
}

public void set(int bitIndex) {
int wordIndex = wordIndex(bitIndex);
int wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
if (words.length < wordsRequired) {
// Allocate larger of doubled size or required size
int request = Math.max(2 * words.length, wordsRequired);
words = Arrays.copyOf(words, request);
}
wordsInUse = wordsRequired;
}

words[wordIndex] |= (1L << bitIndex); // Restores invariants
}

public void set(CladeKey set) {
words = Arrays.copyOf(set.words, set.wordsInUse);
wordsInUse = set.wordsInUse;
}


public boolean isEmpty() {
return wordsInUse == 0;
}

public int cardinality() {
int sum = 0;
for (int i = 0; i < wordsInUse; i++)
sum += Long.bitCount(words[i]);
return sum;
}

public void or(CladeKey key1, CladeKey key2) {

if (key1.wordsInUse >= key2.wordsInUse) {
wordsInUse = key1.wordsInUse;
words = Arrays.copyOf(key1.words, wordsInUse);
for (int i = 0; i < wordsInUse; i++) {
words[i] |= key2.words[i];
}
} else {
wordsInUse = key2.wordsInUse;
words = Arrays.copyOf(key2.words, wordsInUse);
for (int i = 0; i < wordsInUse; i++) {
words[i] |= key1.words[i];
}
}
}


/**
* Returns the hash code value for this bit set. The hash code depends
* only on which bits are set within this {@code BitSet}.
*
* <p>The hash code is defined to be the result of the following
* calculation:
* <pre> {@code
* public int hashCode() {
* long h = 1234;
* long[] words = toLongArray();
* for (int i = words.length; --i >= 0; )
* h ^= words[i] * (i + 1);
* return (int)((h >> 32) ^ h);
* }}</pre>
* Note that the hash code changes if the set of bits is altered.
*
* @return the hash code value for this bit set
*/
public int hashCode() {
long h = 1234;
for (int i = wordsInUse; --i >= 0; )
h ^= words[i] * (i + 1);

return (int)((h >> 32) ^ h);
}


public boolean equals(Object obj) {
if (!(obj instanceof CladeKey set))
return false;
if (this == obj)
return true;

if (wordsInUse != set.wordsInUse)
return false;

// Check words in use by both BitSets
for (int i = 0; i < wordsInUse; i++)
if (words[i] != set.words[i])
return false;

return true;
}

/**
* Returns the index of the first bit that is set to {@code true}
* that occurs on or after the specified starting index and up to and
* including the specified word index
* If no such bit exists then {@code -1} is returned.
*
* @param fromIndex the index to start checking from (inclusive)
* @param toWordIndex the last word index to check (inclusive)
* @return the index of the next set bit, or {@code -1} if there
* is no such bit
*/
private int nextSetBit(int fromIndex, int toWordIndex) {
int u = wordIndex(fromIndex);
// Check if out of bounds
if (u > toWordIndex)
return -1;

long word = words[u] & (WORD_MASK << fromIndex);

while (true) {
if (word != 0)
return (u * BITS_PER_WORD) + Long.numberOfTrailingZeros(word);
// Check if out of bounds
if (++u > toWordIndex)
return -1;
word = words[u];
}
}

}
31 changes: 16 additions & 15 deletions src/dr/app/tools/treeannotator/CladeSystem.java
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ private void addTipClades(Tree tree) {
if (taxonNumberMap != null) {
index = taxonNumberMap.get(taxon);
}
Clade clade = new BiClade(index, taxon);
tipClades.put(index, clade);
BiClade clade = new BiClade(index, taxon);
tipClades.put(clade.key, clade);
}
}

Expand Down Expand Up @@ -153,7 +153,7 @@ private Clade addClades(Tree tree, NodeRef node) {
* see if a clade exists otherwise create it
*/
private Clade getOrAddClade(Clade child1, Clade child2) {
Object key = BiClade.makeKey(child1.getKey(), child2.getKey());
CladeKey key = BiClade.makeKey(child1.getKey(), child2.getKey());
BiClade clade = (BiClade) cladeMap.get(key);
if (clade == null) {
if (keepSubClades) {
Expand Down Expand Up @@ -184,20 +184,21 @@ public void traverseTree(Tree tree, CladeAction action) {
traverseTree(tree, tree.getRoot(), action);
}

private Object traverseTree(Tree tree, NodeRef node, CladeAction action) {
private CladeKey traverseTree(Tree tree, NodeRef node, CladeAction action) {

Object key;
CladeKey key;

if (tree.isExternal(node)) {
key = node.getNumber();
if (taxonNumberMap != null) {
key = taxonNumberMap.get(tree.getNodeTaxon(node));
}
// key = node.getNumber();
// if (taxonNumberMap != null) {
int index = taxonNumberMap.get(tree.getNodeTaxon(node));
key = new CladeKey(index);
// }
} else {
assert tree.getChildCount(node) == 2;

Object key1 = traverseTree(tree, tree.getChild(node, 0), action);
Object key2 = traverseTree(tree, tree.getChild(node, 1), action);
CladeKey key1 = traverseTree(tree, tree.getChild(node, 0), action);
CladeKey key2 = traverseTree(tree, tree.getChild(node, 1), action);

key = BiClade.makeKey(key1, key2);
}
Expand Down Expand Up @@ -401,11 +402,11 @@ public int getCommonCladeCount(CladeSystem referenceCladeSystem) {
return count;
}

public Map<Object, Clade> getTipClades() {
public Map<CladeKey, Clade> getTipClades() {
return tipClades;
}

public Map<Object, Clade> getCladeMap() {
public Map<CladeKey, Clade> getCladeMap() {
return cladeMap;
}

Expand All @@ -419,8 +420,8 @@ public TaxonList getTaxonList() {
private TaxonList taxonList = null;
private final Map<Taxon, Integer> taxonNumberMap = new HashMap<>();

private final Map<Object, Clade> tipClades = new HashMap<>();
private final Map<Object, Clade> cladeMap = new HashMap<>();
private final Map<CladeKey, Clade> tipClades = new HashMap<>();
private final Map<CladeKey, Clade> cladeMap = new HashMap<>();

Clade rootClade;

Expand Down
Loading

0 comments on commit 928c4e6

Please sign in to comment.