@Override public DeepTree<N, E> snoc(final Node<N, E> lst) { if (right.length < MAX_DIGIT) { final Node<N, E>[] newRight = slice(right, 0, right.length + 1); newRight[right.length] = lst; return new DeepTree<>(left, leftSize, middle, newRight, size + lst.size()); } final int rl = right.length, m = NODE_SIZE; final Node<N, E>[] sub = slice(right, 0, m), newRight = slice(right, m, rl + 1); newRight[rl - m] = lst; final FingerTree<Node<N, E>, E> mid = middle.snoc(new InnerNode<>(sub)); return new DeepTree<>(left, leftSize, mid, newRight, size + lst.size()); }
public void union(Node x, Node y) { Node a = find(x); Node b = find(y); if (a != b) { if (a.size > b.size) { b.up = a; a.size += b.size; b.size = 0; } else { a.up = b; b.size += a.size; a.size = 0; } } }
@Override public FingerTree<N, E> replaceLast(final Node<N, E> last) { final int lst = right.length - 1; final Node<N, E>[] newRight = right.clone(); newRight[lst] = last; return new DeepTree<>(left, leftSize, middle, newRight, size + last.size() - right[lst].size()); }
@Override public FingerTree<N, E> replaceHead(final Node<N, E> head) { final long sizeDiff = head.size() - left[0].size(); final Node<N, E>[] newLeft = left.clone(); newLeft[0] = head; return new DeepTree<>(newLeft, leftSize + sizeDiff, middle, right, size + sizeDiff); }
/** * Creates a tree slice from a digit. * * @param <N> node type * @param <E> element type * @param nodes the digit * @param from element offset * @param len number of elements * @param buffer buffer to insert the node slice into * @param inBuffer initial number of nodes in the buffer * @return the slice */ private static <N, E> int splitDigit( final Node<N, E>[] nodes, final long from, final long len, final NodeLike<N, E>[] buffer, final int inBuffer) { if (len <= 0) return inBuffer; // find the first sub-node containing used elements int firstPos = 0; long firstOff = from; Node<N, E> first = nodes[0]; long firstSize = first.size(); while (firstOff >= firstSize) { firstOff -= firstSize; first = nodes[++firstPos]; firstSize = first.size(); } // firstOff < firstSize final long inFirst = firstSize - firstOff; if (inFirst >= len) { // everything in first sub-node final NodeLike<N, E> part = len == firstSize ? first : first.slice(firstOff, len); return part.append(buffer, inBuffer); } final NodeLike<N, E> firstSlice = firstOff == 0 ? first : first.slice(firstOff, inFirst); int numMerged = firstSlice.append(buffer, inBuffer); int pos = firstPos; long remaining = len - inFirst; while (remaining > 0) { final Node<N, E> curr = nodes[++pos]; final long currSize = curr.size(); final NodeLike<N, E> slice = remaining >= currSize ? curr : curr.slice(0, remaining); numMerged = slice.append(buffer, numMerged); remaining -= currSize; } return numMerged; }
public void mergeFrom(Node right) { assert (right.size() == capacity / 2) || (size == capacity / 2) : "Should have exactly half capacity nodes"; Leaf leaf = (Leaf) right; shallowCopy(leaf, 0, this, size, leaf.size()); next = leaf.next(); size += leaf.size(); }
@Test public void test1() { Random random = new Random(228); Node root = EmptyNode.instance; for (int i = 0; i < 10; i++) { root = root.merge(new NotEmptyNode(i, random.nextInt())); System.out.println(root.size()); } Node.SplitResult split = root.split(5); }
private Node<K, V> put(K key, V val, Node<K, V> node) { if (node == null) return new Node<K, V>(key, val, 1); int cmp = key.compareTo(node.key); if (cmp == 0) { node.value = val; } else if (cmp < 0) { node.left = put(key, val, node.left); } else if (cmp > 0) { node.right = put(key, val, node.right); } node.size = size(node.left) + size(node.right) + 1; return node; }
@Override public DeepTree<N, E> cons(final Node<N, E> fst) { final long sz = fst.size(); if (left.length < MAX_DIGIT) { final Node<N, E>[] newLeft = slice(left, -1, left.length); newLeft[0] = fst; return new DeepTree<>(newLeft, leftSize + sz, middle, right, size + sz); } final int ll = left.length, m = ll - NODE_SIZE; final Node<N, E>[] newLeft = slice(left, -1, m), sub = slice(left, m, ll); newLeft[0] = fst; final FingerTree<Node<N, E>, E> mid = middle.cons(new InnerNode<>(sub)); return get(newLeft, mid, right, size + sz); }
long ans() { if (_ans != -3) return _ans; if (children.size() == 0) { if (this == EMPTY_LEAF) return 0; return i; } long digits = 0; long ret = 0; for (int i = children.size() - 1; i >= 0; i--) { Node node = children.get(i); ret = (ret + (node.ans() * modPow(digits)) % MOD) % MOD; digits += node.size(); digits %= MOD - 1; } _ans = ret; return ret; }
// Given a binary tree, find the largest Binary Search Tree (BST), // where largest means BST with largest number of nodes in it. // The largest BST may or may not include all of its descendants. public static LargestBST largestBSTSubtree1(Node node) { if (node == null) return null; if (node.left == null && node.right == null) { return new LargestBST(node, node.size(), node.value, node.value); } LargestBST leftNode = largestBSTSubtree1(node.left); LargestBST rightNode = largestBSTSubtree1(node.right); if (leftNode != null && rightNode != null) { if ((node.value > leftNode.max && node.left == leftNode.node) && (node.value < rightNode.min && node.right == rightNode.node)) { LargestBST bst = new LargestBST( node, leftNode.maxNode + rightNode.maxNode + 1, leftNode.min, rightNode.max); return bst; } else if (node.value > leftNode.max && node.left == leftNode.node) { return new LargestBST(node, leftNode.maxNode + 1, leftNode.min, node.value); } else if (node.value < rightNode.min && node.right == rightNode.node) { return new LargestBST(node, rightNode.maxNode + 1, node.value, rightNode.max); } else { return (leftNode.maxNode > rightNode.maxNode) ? leftNode : rightNode; } } else if (leftNode != null) { if (node.value > leftNode.max && node.left == leftNode.node) { return new LargestBST(node, leftNode.maxNode + 1, leftNode.min, node.value); } else { return leftNode; } } else if (rightNode != null) { if (node.value < rightNode.min && node.right == rightNode.node) { return new LargestBST(node, rightNode.maxNode + 1, node.value, rightNode.max); } else { return rightNode; } } return null; }
@Override public TreeSlice<N, E> remove(final long pos) { if (pos < leftSize) return new TreeSlice<>(removeLeft(pos)); final long rightStart = leftSize + middle.size(); if (pos >= rightStart) return new TreeSlice<>(removeRight(pos - rightStart)); final TreeSlice<Node<N, E>, E> slice = middle.remove(pos - leftSize); if (slice.isTree()) { // no underflow final FingerTree<Node<N, E>, E> newMiddle = slice.getTree(); return slice.setTree(new DeepTree<>(left, leftSize, newMiddle, right, size - 1)); } // middle tree had an underflow, one sub-node left final Node<N, E> node = (Node<N, E>) ((PartialInnerNode<N, E>) slice.getPartial()).sub; // try to extend the smaller digit if (left.length < right.length) { // merge into left digit final Node<N, E>[] newLeft = slice(left, 0, left.length + 1); newLeft[left.length] = node; return slice.setTree(get(newLeft, leftSize + node.size(), right, size - 1)); } if (right.length < MAX_DIGIT) { // merge into right digit final Node<N, E>[] newRight = slice(right, -1, right.length); newRight[0] = node; return slice.setTree(get(left, leftSize, newRight, size - 1)); } // redistribute the nodes final int n = 2 * MAX_DIGIT + 1, ll = (n - NODE_SIZE) / 2; @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = slice(left, 0, ll), ch = new Node[NODE_SIZE]; final int inL = left.length - ll, inR = NODE_SIZE - inL - 1; System.arraycopy(left, ll, ch, 0, inL); ch[inL] = node; System.arraycopy(right, 0, ch, inL + 1, inR); final Node<N, E>[] newRight = slice(right, inR, MAX_DIGIT); final Node<Node<N, E>, E> newMid = new InnerNode<>(ch); return slice.setTree(get(newLeft, new SingletonTree<>(newMid), newRight, size - 1)); }
/** * Deletes an element from the given digit containing at least two nodes. * * @param <N> node type * @param <E> element type * @param arr array of nodes * @param pos deletion position * @return new digit */ private static <N, E> Node<N, E>[] remove(final Node<N, E>[] arr, final long pos) { int i = 0; long off = pos; Node<N, E> node; while (true) { node = arr[i]; final long nodeSize = node.size(); if (off < nodeSize) break; off -= nodeSize; i++; } final int n = arr.length; final NodeLike<N, E>[] res = arr[i].remove(i == 0 ? null : arr[i - 1], i == n - 1 ? null : arr[i + 1], off); final Node<N, E> l = (Node<N, E>) res[0], m = (Node<N, E>) res[1], r = (Node<N, E>) res[2]; if (m != null) { // same number of nodes final Node<N, E>[] out = arr.clone(); if (i > 0) out[i - 1] = l; out[i] = m; if (i < n - 1) out[i + 1] = r; return out; } // the node was merged @SuppressWarnings("unchecked") final Node<N, E>[] out = new Node[n - 1]; if (i > 0) { // nodes to the left System.arraycopy(arr, 0, out, 0, i - 1); out[i - 1] = l; } if (i < n - 1) { // nodes to the right out[i] = r; System.arraycopy(arr, i + 2, out, i + 1, n - i - 2); } return out; }
/** * Returns the number of character sequences with non-zero counts, including the empty (zero * length) character sequence. * * @return Number of character sequences with non-zero counts. */ public long uniqueSequenceCount() { return mRootNode.size(); }
/** @param args */ public static void main(final String[] args) throws Exception { final BufferedReader br = new BufferedReader( new InputStreamReader( (new GZIPInputStream( new FileInputStream( new File( new File(System.getProperty("user.dir")), "testdata/mobo1.txt.gz")))))); final List<Instance> instances = Lists.newLinkedList(); int count = 0; while (true) { count++; final String line = br.readLine(); if (line == null) { break; } final JSONObject jo = (JSONObject) JSONValue.parse(line); final HashMapAttributes a = new HashMapAttributes(); a.putAll((JSONObject) jo.get("attributes")); Instance instance = new Instance(a, (String) jo.get("output")); instances.add(instance); } final List<Instance> train = instances.subList(0, instances.size() / 2); final List<Instance> test = instances.subList(instances.size() / 2 + 1, instances.size() - 1); System.out.println("Read " + instances.size() + " instances"); System.out.println("Testing scorers with single decision node"); for (final Scorer scorer : Sets.newHashSet(new Scorer1())) { final TreeBuilder tb = new TreeBuilder(scorer); final long startTime = System.currentTimeMillis(); final Node tree = tb.buildPredictiveModel(train).node; System.out.println( scorer.getClass().getSimpleName() + " build time " + (System.currentTimeMillis() - startTime) + ", size: " + tree.size() + " mean depth: " + tree.meanDepth()); int correctlyClassified = 0; for (Instance testInstance : test) { String result = (String) tree.getLeaf(testInstance.getAttributes()).getBestClassification(); if (result.equals(testInstance.getClassification())) { correctlyClassified++; } } System.out.println(", accuracy: " + (double) correctlyClassified / test.size()); System.out.println("Testing random forest"); for (int i = 2; i <= 20; i++) { RandomForestBuilder rfBuilder = new RandomForestBuilder(new TreeBuilder()); RandomForest randomForest = rfBuilder.buildPredictiveModel(train); correctlyClassified = 0; for (Instance testInstance : test) { Serializable result = randomForest.getClassificationByMaxProb(testInstance.getAttributes()); if (result.equals(testInstance.getClassification())) { correctlyClassified++; } } System.out.println( "accuracy with " + i + " trees: " + (double) correctlyClassified / test.size()); // ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new // File("baggedTree.ser"))); // out.writeObject(baggedTree); } } }
/** * Remove an element from the left digit. * * @param pos position inside the left digit * @return resulting tree */ private FingerTree<N, E> removeLeft(final long pos) { if (left.length > 1) { // left digit cannot underflow, just delete the element return new DeepTree<>(remove(left, pos), leftSize - 1, middle, right, size - 1); } // singleton digit might underflow final Node<N, E> node = left[0]; if (!middle.isEmpty()) { // next node for balancing is in middle tree final InnerNode<N, E> head = (InnerNode<N, E>) middle.head(); final Node<N, E> first = head.getSub(0); final NodeLike<N, E>[] rem = node.remove(null, first, pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirst = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged final Node<N, E>[] newLeft = head.children.clone(); newLeft[0] = newFirst; return get(newLeft, middle.tail(), right, size - 1); } @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirst != first) { // nodes were balanced final FingerTree<Node<N, E>, E> newMid = middle.replaceHead(head.replaceFirst(newFirst)); return new DeepTree<>(newLeft, newNode.size(), newMid, right, size - 1); } // no changes to this tree's structure return new DeepTree<>(newLeft, newNode.size(), middle, right, size - 1); } // potentially balance with right digit final NodeLike<N, E>[] rem = node.remove(null, right[0], pos); final Node<N, E> newNode = (Node<N, E>) rem[1], newFirstRight = (Node<N, E>) rem[2]; if (newNode == null) { // nodes were merged if (right.length == 1) return new SingletonTree<>(newFirstRight); final int mid = right.length / 2; final Node<N, E>[] newLeft = slice(right, 0, mid); newLeft[0] = newFirstRight; return get(newLeft, middle, slice(right, mid, right.length), size - 1); } // structure does not change @SuppressWarnings("unchecked") final Node<N, E>[] newLeft = new Node[] {newNode}; if (newFirstRight == right[0]) { // right digit stays the same return new DeepTree<>(newLeft, newLeft[0].size(), middle, right, size - 1); } // adapt the right digit final Node<N, E>[] newRight = right.clone(); newRight[0] = newFirstRight; return new DeepTree<>(newLeft, newNode.size(), middle, newRight, size - 1); }