private Node insert(Node root, String data, int pos) { if (pos == data.length()) { return root; } if (root == null) { root = new Node(); root.data = data.charAt(pos); root.eq = insert(root.eq, data, pos + 1); if (pos == (data.length() - 1)) { root.isLeaf = true; } } else { if (root.data == data.charAt(pos)) { root.eq = insert(root.eq, data, pos + 1); if (pos == (data.length() - 1)) { root.isLeaf = true; } } else if (root.data < data.charAt(pos)) { root.right = insert(root.right, data, pos); } else { root.left = insert(root.left, data, pos); } } return root; }
public void print(String prefix) { if (isLeaf()) { int bestLabelIndex = getGainRatio().getBaseLabelDistribution().getBestIndex(); int numMajorityLabel = (int) (getGainRatio().getBaseLabelDistribution().value(bestLabelIndex) * getSize()); System.out.println( "root:" + getGainRatio().getBaseLabelDistribution().getBestLabel() + " " + numMajorityLabel + "/" + getSize()); } else { String featName = m_dataDict.lookupObject(getGainRatio().getMaxValuedIndex()).toString(); double threshold = getGainRatio().getMaxValuedThreshold(); System.out.print(prefix + "\"" + featName + "\" <= " + threshold + ":"); if (m_leftChild.isLeaf()) { int bestLabelIndex = m_leftChild.getGainRatio().getBaseLabelDistribution().getBestIndex(); int numMajorityLabel = (int) (m_leftChild.getGainRatio().getBaseLabelDistribution().value(bestLabelIndex) * m_leftChild.getSize()); System.out.println( m_leftChild.getGainRatio().getBaseLabelDistribution().getBestLabel() + " " + numMajorityLabel + "/" + m_leftChild.getSize()); } else { System.out.println(); m_leftChild.print(prefix + "| "); } System.out.print(prefix + "\"" + featName + "\" > " + threshold + ":"); if (m_rightChild.isLeaf()) { int bestLabelIndex = m_rightChild.getGainRatio().getBaseLabelDistribution().getBestIndex(); int numMajorityLabel = (int) (m_rightChild.getGainRatio().getBaseLabelDistribution().value(bestLabelIndex) * m_rightChild.getSize()); System.out.println( m_rightChild.getGainRatio().getBaseLabelDistribution().getBestLabel() + " " + numMajorityLabel + "/" + m_rightChild.getSize()); } else { System.out.println(); m_rightChild.print(prefix + "| "); } } }
public static void printPaths(Node node, ArrayList<Integer> path) { if (node == null) { return; } ArrayList<Integer> newPath = (ArrayList<Integer>) path.clone(); newPath.add(Integer.valueOf(node.data)); if (node.isLeaf()) { printPath(newPath); return; } printPaths(node.left, newPath); printPaths(node.right, newPath); /* The following alternate approach won't work * because we'll append a node to the same list every time, * even when we move back up the tree and start on a new branch. * * path.add(Integer.valueOf(node.data)); if (node.isLeaf()) { printPath(path); return; } printPaths(node.left , path); printPaths(node.right, path); */ }
private void recursiveGetNodes( Node node, Shape shape, int detailLevel, boolean inclParents, Collection<Node> result) { if (node.isLeaf()) { // cell is within shape result.add(node); return; } final Collection<Node> subCells = node.getSubCells(shape); if (node.getLevel() == detailLevel - 1) { if (subCells.size() < node.getSubCellsSize()) { if (inclParents) result.add(node); for (Node subCell : subCells) { subCell.setLeaf(); } result.addAll(subCells); } else { // a bottom level (i.e. detail level) optimization where all boxes intersect, so use // parent cell. node.setLeaf(); result.add(node); } } else { if (inclParents) { result.add(node); } for (Node subCell : subCells) { recursiveGetNodes(subCell, shape, detailLevel, inclParents, result); // tail call } } }
MultiTypeNode copyFromFlatNode(Node node) { MultiTypeNode mNode = new MultiTypeNode(); mNode.height = node.height; mNode.parent = node.parent; mNode.nTypeChanges = 0; mNode.changeTimes.addAll(new ArrayList<Double>()); mNode.changeTypes.addAll(new ArrayList<Integer>()); mNode.nodeType = 0; mNode.labelNr = node.labelNr; if (node.isLeaf()) { int type = (int) node.getMetaData("location"); if (type != 0) { mNode.setNodeType(type); mNode.addChange( 0, (node.getHeight() + (node.getParent().getHeight() - node.getHeight()) * Randomizer.nextDouble())); } } else { mNode.addChild(copyFromFlatNode(node.getLeft())); mNode.addChild(copyFromFlatNode(node.getRight())); } return mNode; }
/** * Iteratively traverses a tree from the specified node in a post-order fashion, performing * computations at each node. * * @param node The node the traversal starts from. * @param pv The population vector to use for node computations. */ public void iterativeTraverse(Node root, PopulationVector pv) { Stack<Node> s = new Stack<Node>(); s.push(root); Node prev = null; while (!s.empty()) { Node curr = s.peek(); if (prev == null || prev.leftChild() == curr || prev.rightChild() == curr) { if (curr.leftChild() != null) s.push(curr.leftChild()); else if (curr.rightChild() != null) s.push(curr.rightChild()); // If traversing up tree from left, traverse to right child if available. } else if (curr.leftChild() == prev && curr.rightChild() != null) { s.push(curr.rightChild()); } // Otherwise traversing up tree from right, compute g arrays and pop. else { if (curr.isLeaf()) { initLeafNode(curr, pv); } else { computeSubnetNode(curr, pv); } s.pop(); } prev = curr; } }
/** * Performs modifications, and reassigns certain properties on the tree in place. The input is * assumed to be a properly "crunched" tree. This is mainly to aid creating the "mini-tree" for * the data selection in the RDF mapping. <br> * The only properties that are recalculated are the weights and the selectors. */ public void recrunch(Node node) { if (!node.isLeaf()) { for (Node child : node.getChildren()) { recrunch(child); } computeWeightAndSelector(node); } }
// make a lookup table from symbols and their encodings private void buildCode(String[] code, Node n, String path) { // If n isn't a leaf, we need to go deeper if (!n.isLeaf()) { buildCode(code, n.left, path + '0'); buildCode(code, n.right, path + '1'); } else // if it's a leaf, we fill the case in the code table that correspond to this letter with // the equivalent code that represent it { code[n.c] = path; } }
public int predict(Message msg) { Node current = root; while (!current.isLeaf()) { // if not null must have two children if (msg.contains(current.getWord())) { current = current.getLeft(); } else { current = current.getRight(); } } return current.getClassification(); }
/** Will add the trailing leaf byte for leaves. This isn't particularly efficient. */ public static List<String> nodesToTokenStrings(Collection<Node> nodes) { List<String> tokens = new ArrayList<String>((nodes.size())); for (Node node : nodes) { final String token = node.getTokenString(); if (node.isLeaf()) { tokens.add(token + (char) Node.LEAF_BYTE); } else { tokens.add(token); } } return tokens; }
/** * Recursively searches the tree for all intersecting entries. Immediately calls execute() on the * passed IntProcedure when a matching entry is found. * * <p>[x] TODO rewrite this to be non-recursive? Make sure it doesn't slow it down. */ private void intersects(Rectangle r, IntProcedure v, Node n) { for (int i = 0; i < n.entryCount; i++) { if (r.intersects(n.entries[i])) { if (n.isLeaf()) { v.execute(n.ids[i]); } else { Node childNode = getNode(n.ids[i]); intersects(r, v, childNode); } } } }
private void intersects(float x1, float y1, float x2, float y2, IntProcedure v, Node n) { for (int i = 0; i < n.entryCount; i++) { if (intersects(x1, y1, x2, y2, n.entries[i])) { if (n.isLeaf()) { v.execute(n.ids[i]); } else { Node childNode = getNode(n.ids[i]); intersects(x1, y1, x2, y2, v, childNode); } } } }
private void writeCode(Node n) throws IOException { if (n.isLeaf()) { output.write(1); System.out.print(1); output.write((int) n.c); System.out.print((int) n.c); } else { output.write(0); System.out.print(0); writeCode(n.left); writeCode(n.right); } }
/** @see com.infomatiq.jsi.SpatialIndex#contains(Rectangle, IntProcedure) */ public void contains(Rectangle r, IntProcedure v) { // find all rectangles in the tree that are contained by the passed // rectangle // written to be non-recursive (should model other searches on this?) parents.clear(); parents.push(rootNodeId); parentsEntry.clear(); parentsEntry.push(-1); // TODO: possible shortcut here - could test for intersection with the // MBR of the root node. If no intersection, return immediately. while (parents.size() > 0) { Node n = getNode(parents.peek()); int startIndex = parentsEntry.peek() + 1; if (!n.isLeaf()) { // go through every entry in the index node to check // if it intersects the passed rectangle. If so, it // could contain entries that are contained. boolean intersects = false; for (int i = startIndex; i < n.entryCount; i++) { if (r.intersects(n.entries[i])) { parents.push(n.ids[i]); parentsEntry.pop(); parentsEntry.push(i); // this becomes the start index // when the child has been // searched parentsEntry.push(-1); intersects = true; break; // ie go to next iteration of while() } } if (intersects) { continue; } } else { // go through every entry in the leaf to check if // it is contained by the passed rectangle for (int i = 0; i < n.entryCount; i++) { if (r.contains(n.entries[i])) { v.execute(n.ids[i]); } } } parents.pop(); parentsEntry.pop(); } }
/** * Recursively traverses a tree from the specified node in a post-order fashion, performing * computations at each node. * * @param node The node the traversal starts from. * @param pv The population vector to use for node computations. */ public void recursiveTraverse(Node node, PopulationVector pv) { if (node.leftChild() != null) { recursiveTraverse(node.leftChild(), pv); } if (node.rightChild() != null) { recursiveTraverse(node.rightChild(), pv); } if (node.isLeaf()) { initLeafNode(node, pv); } else { computeSubnetNode(node, pv); } }
/** * get clade for internal node * * @param idGroup order of labels * @param internalNode Node * @param boolean[] clade */ public static void getClade(IdGroup idGroup, Node internalNode, boolean[] clade) { if (internalNode.isLeaf() || internalNode.isRoot()) { throw new IllegalArgumentException("Only internal nodes (and no root) nodes allowed"); } // make sure clade is reset for (int i = 0; i < clade.length; i++) { clade[i] = false; } // mark all leafs downstream of the node // AJD removed loop, as doesn't appear to be necessary SplitUtils.markNode(idGroup, internalNode, clade); }
/** * Assign a category to an item. This is the implementation of algorithm 4.1 on page 53 of the * book. * * @param item The Item which has to be classified by the algorithm. * @return A String describing the name of category to which the item belongs. */ public String assignCategory(Item item) { Node current; // 1) start at the root node current = root; // 2) repeat while the current node is not a leaf while (!current.isLeaf()) { // a) follow the arc corresponding to the item's // value of the current node split attribute // b) the node reached becomes the current node current = current.follow(item.getFeatureValue(current.getLabel())); } // 3) the label of the leaf node is the class of the item return current.getLabel(); }
private void addTreeItem(JSONObject jsonObject, int index) { Node node = new Node( jsonObject.get("id").isString().stringValue(), jsonObject.get("leaf").isBoolean().booleanValue(), jsonObject.get("text").isString().stringValue()); if (node.getText() != null) { TreeItem item = new TreeItem(); item.setText(node.getText()); item.setUserObject(node); if (!node.isLeaf()) item.addItem(""); // Temporarily add an item so we can expand this node treeItem.addItem(item); } }
static void markNode(IdGroup idGroup, Node node, boolean[] split) { if (node.isLeaf()) { String name = node.getIdentifier().getName(); int index = idGroup.whichIdNumber(name); if (index < 0) { throw new IllegalArgumentException("INCOMPATIBLE IDENTIFIER (" + name + ")"); } split[index] = true; } else { for (int i = 0; i < node.getChildCount(); i++) { markNode(idGroup, node.getChild(i), split); } } }
private void print(Stack<Node> stack, Node n) { if (n.isLeaf()) { assert n.value != null; for (Node node : stack) { System.out.print(node.key + "->"); } System.out.print(n.value); System.out.println(); return; } for (Map.Entry<Character, Node> e : n.children.entrySet()) { stack.push(e.getValue()); print(stack, e.getValue()); stack.pop(); } }
/** * Recursively searches the tree for the nearest entry. Other queries call execute() on an * IntProcedure when a matching entry is found; however nearest() must store the entry Ids as it * searches the tree, in case a nearer entry is found. Uses the member variable nearestIds to * store the nearest entry IDs. * * <p>[x] TODO rewrite this to be non-recursive? */ private float nearest(Point p, Node n, float nearestDistance) { for (int i = 0; i < n.entryCount; i++) { float tempDistance = n.entries[i].distance(p); if (n.isLeaf()) { // for leaves, the distance is an actual nearest distance if (tempDistance < nearestDistance) { nearestDistance = tempDistance; nearestIds.clear(); } if (tempDistance <= nearestDistance) { nearestIds.add(n.ids[i]); } } else { // for index nodes, only go into them if they potentially could have // a rectangle nearer than actualNearest if (tempDistance <= nearestDistance) { // search the child node nearestDistance = nearest(p, getNode(n.ids[i]), nearestDistance); } } } return nearestDistance; }
private Node makeCrunchNode(Node topologicalNode) { // copy the intrinsic properties: id, weights, relationship, and selectors will be set Node node = new Node(topologicalNode); // assign the id from the name hash node.setId(computeId(node)); if (!topologicalNode.isLeaf()) { List<Node> newChildren = new ArrayList<Node>(); List<Node> children = topologicalNode.getChildren(); for (Node child : children) { // depth-first traversal Node newChild = makeCrunchNode(child); // set the child-parent relationship newChildren.add(newChild); newChild.setParent(node); } node.setChildren(newChildren); // weights and selector should be set after all lower nodes are crunched computeWeightAndSelector(node); } return node; }
/** * Remove the node if possible or set its count to 0 if it has children and it needs to be kept * around */ private Node tryRemove(Node node) { if (node == null) { return null; } if (node.weightedCount >= ZERO_WEIGHT_THRESHOLD) { --nonZeroNodeCount; } weightedCount -= node.weightedCount; Node result = null; if (node.isLeaf()) { --totalNodeCount; } else if (node.hasSingleChild()) { result = node.getSingleChild(); --totalNodeCount; } else { node.weightedCount = 0; result = node; } return result; }
/** * get split for branch associated with internal node * * @param idGroup order of labels * @param internalNode Node * @param boolean[] split */ public static void getSplit(IdGroup idGroup, Node internalNode, boolean[] split) { if (internalNode.isLeaf() || internalNode.isRoot()) { throw new IllegalArgumentException("Only internal nodes (and no root) nodes allowed"); } // make sure split is reset for (int i = 0; i < split.length; i++) { split[i] = false; } // mark all leafs downstream of the node for (int i = 0; i < internalNode.getChildCount(); i++) { markNode(idGroup, internalNode, split); } // standardize split (i.e. first index is alway true) if (split[0] == false) { for (int i = 0; i < split.length; i++) { if (split[i] == false) split[i] = true; else split[i] = false; } } }
/** * Removes an element from the tree. * * @param val The value. */ public void remove(int val) { Node k = findNode(root, val); if (k == null) throw new IllegalArgumentException( "Cannot remove " + val + " because such a node does not exist."); Node kParent = k.parent; System.out.printf("Removing value: %d%n", val); // Delete node that is a leaf. if (k.isLeaf()) { System.out.println(" -> Corresponding node is a leaf : Performing cutoff."); if (k == root) root = null; else k.parent.removeSon(k); // Delete node that us a single son. } else if (k.isSingleSon()) { System.out.println( " -> Corresponding node has only one son. Connecting node's son and parent."); if (k == root) k.onlySon().setRoot(); else k.parent.replace(k, k.onlySon()); // Delete inner node. } else { // Check if it is more efficient to exchange node by another left or right side node // If uncertain, choose right side (and thus bigger element) for finding a replacement. boolean replaceByLeft = k.left != null && (k.right == null || k.left.height > k.right.height); Node s; if (replaceByLeft) s = findNextSmallerNode(k); else s = findNextBiggerNode(k); System.out.printf( " -> Correspondig node has two sons. Removing next %s element from tree first" + " before proceeding. Removing: %d%n", replaceByLeft ? "bigger" : "smaller", s.value); // Remove node first that is to be used as a replacement. remove(s.value); System.out.printf(" -> %d is removed. Proceeding with replacing %d%n", s.value, k.value); // Set new node in place of the removed node. if (k == root) s.setRoot(); else k.parent.replace(k, s); // Fix father - son relationships. s.setLeft(k.left); s.setRight(k.right); s.update(); } if (kParent != null) up(kParent); }
public void outputToJSON(String filePath, int numTopWords, double boundaryFactor) { System.out.println("Writing down the model..."); JSONObject featureCollection = new JSONObject(); featureCollection.put("type", "FeatureCollection"); JSONArray features = new JSONArray(); Queue<Node> nodeQueue = new LinkedList<>(); nodeQueue.offer(root); while (!nodeQueue.isEmpty()) { Node currentNode = nodeQueue.poll(); JSONObject feature = new JSONObject(); feature.put("type", "Feature"); feature.put("id", currentNode.hashCode()); JSONObject properties = new JSONObject(); properties.put("level", currentNode.level + 1); properties.put("num_documents", currentNode.numCustomers); if (currentNode.parent != null) { properties.put("parent", currentNode.parent.hashCode()); } if (!currentNode.isLeaf()) { JSONArray children = new JSONArray(); for (Node child : currentNode.children) { children.put(child.hashCode()); } properties.put("children", children); } JSONArray center = new JSONArray(); double longitude = currentNode.location.longitude; center.put(longitude); double latitude = currentNode.location.latitude; center.put(latitude); properties.put("center", center); JSONArray deviation = new JSONArray(); double longitudeDeviation = Math.sqrt(currentNode.location.longitudeVariance); deviation.put(longitudeDeviation); double latitudeDeviation = Math.sqrt(currentNode.location.latitudeVariance); deviation.put(latitudeDeviation); properties.put("deviation", deviation); JSONArray topWords = new JSONArray(); PriorityQueue<Map.Entry<Integer, Integer>> wordMinHeap = new PriorityQueue<>( numTopWords, new Comparator<Map.Entry<Integer, Integer>>() { @Override public int compare(Map.Entry<Integer, Integer> o1, Map.Entry<Integer, Integer> o2) { return o1.getValue() - o2.getValue(); } }); for (Map.Entry<Integer, Integer> entry : currentNode.wordCounts.entrySet()) { if (wordMinHeap.size() < numTopWords) { wordMinHeap.offer(entry); } else { if (entry.getValue() > wordMinHeap.peek().getValue()) { wordMinHeap.poll(); wordMinHeap.offer(entry); } } } while (!wordMinHeap.isEmpty()) { topWords.put(this.id2Word.get(wordMinHeap.poll().getKey())); } properties.put("top_words", topWords); feature.put("properties", properties); JSONObject geometry = new JSONObject(); geometry.put("type", "Polygon"); JSONArray coordinates = new JSONArray(); JSONArray boundary = new JSONArray(); double east = longitude + boundaryFactor * longitudeDeviation; double west = longitude - boundaryFactor * longitudeDeviation; double north = latitude + boundaryFactor * latitudeDeviation; double south = latitude - boundaryFactor * latitudeDeviation; boundary.put(new JSONArray(new double[] {west, north})); boundary.put(new JSONArray(new double[] {east, north})); boundary.put(new JSONArray(new double[] {east, south})); boundary.put(new JSONArray(new double[] {west, south})); boundary.put(new JSONArray(new double[] {west, north})); coordinates.put(boundary); geometry.put("coordinates", coordinates); feature.put("geometry", geometry); features.put(feature); for (Node child : currentNode.children) { nodeQueue.offer(child); } } featureCollection.put("features", features); try { PrintWriter writer = new PrintWriter(filePath); featureCollection.write(writer); writer.close(); } catch (FileNotFoundException e) { System.err.println("Model JSON cannot be created."); } }
/** @see com.infomatiq.jsi.SpatialIndex#delete(Rectangle, int) */ public boolean delete(Rectangle r, int id) { // FindLeaf algorithm inlined here. Note the "official" algorithm // searches all overlapping entries. This seems inefficient to me, // as an entry is only worth searching if it contains (NOT overlaps) // the rectangle we are searching for. // // Also the algorithm has been changed so that it is not recursive. // FL1 [Search subtrees] If root is not a leaf, check each entry // to determine if it contains r. For each entry found, invoke // findLeaf on the node pointed to by the entry, until r is found or // all entries have been checked. parents.clear(); parents.push(rootNodeId); parentsEntry.clear(); parentsEntry.push(-1); Node n = null; int foundIndex = -1; // index of entry to be deleted in leaf while (foundIndex == -1 && parents.size() > 0) { n = getNode(parents.peek()); int startIndex = parentsEntry.peek() + 1; if (!n.isLeaf()) { deleteLog.debug("searching node " + n.nodeId + ", from index " + startIndex); boolean contains = false; for (int i = startIndex; i < n.entryCount; i++) { if (n.entries[i].contains(r)) { parents.push(n.ids[i]); parentsEntry.pop(); parentsEntry.push(i); // this becomes the start index when the child has been searched parentsEntry.push(-1); contains = true; break; // ie go to next iteration of while() } } if (contains) { continue; } } else { foundIndex = n.findEntry(r, id); } parents.pop(); parentsEntry.pop(); } // while not found if (foundIndex != -1) { n.deleteEntry(foundIndex, minNodeEntries); condenseTree(n); size--; } // shrink the tree if possible (i.e. if root node has exactly one entry,and that // entry is not a leaf node, delete the root (it's entry becomes the new root) Node root = getNode(rootNodeId); while (root.entryCount == 1 && treeHeight > 1) { root.entryCount = 0; rootNodeId = root.ids[0]; treeHeight--; root = getNode(rootNodeId); } return (foundIndex != -1); }