Example #1
0
  public String toGraphviz() {
    StringBuilder builder = new StringBuilder();

    builder.append("digraph QuantileDigest {\n").append("\tgraph [ordering=\"out\"];");

    final List<Node> nodes = new ArrayList<>();
    postOrderTraversal(
        root,
        new Callback() {
          @Override
          public boolean process(Node node) {
            nodes.add(node);
            return true;
          }
        });

    Multimap<Integer, Node> nodesByLevel =
        Multimaps.index(
            nodes,
            new Function<Node, Integer>() {
              @Override
              public Integer apply(Node input) {
                return input.level;
              }
            });

    for (Map.Entry<Integer, Collection<Node>> entry : nodesByLevel.asMap().entrySet()) {
      builder.append("\tsubgraph level_" + entry.getKey() + " {\n").append("\t\trank = same;\n");

      for (Node node : entry.getValue()) {
        builder.append(
            String.format(
                "\t\t%s [label=\"[%s..%s]@%s\\n%s\", shape=rect, style=filled,color=%s];\n",
                idFor(node),
                node.getLowerBound(),
                node.getUpperBound(),
                node.level,
                node.weightedCount,
                node.weightedCount > 0 ? "salmon2" : "white"));
      }

      builder.append("\t}\n");
    }

    for (Node node : nodes) {
      if (node.left != null) {
        builder.append(format("\t%s -> %s;\n", idFor(node), idFor(node.left)));
      }
      if (node.right != null) {
        builder.append(format("\t%s -> %s;\n", idFor(node), idFor(node.right)));
      }
    }

    builder.append("}\n");

    return builder.toString();
  }
Example #2
0
 private void setChild(Node parent, long branch, Node child) {
   if (parent == null) {
     root = child;
   } else if (branch == 0) {
     parent.left = child;
   } else {
     parent.right = child;
   }
 }
Example #3
0
  private Node copyRecursive(Node node) {
    Node result = null;

    if (node != null) {
      result = createNode(node.bits, node.level, node.weightedCount);
      result.left = copyRecursive(node.left);
      result.right = copyRecursive(node.right);
    }

    return result;
  }
Example #4
0
  public static QuantileDigest deserialize(DataInput input) {
    try {
      double maxError = input.readDouble();
      double alpha = input.readDouble();

      QuantileDigest result = new QuantileDigest(maxError, alpha);

      result.landmarkInSeconds = input.readLong();
      result.min = input.readLong();
      result.max = input.readLong();
      result.totalNodeCount = input.readInt();

      Deque<Node> stack = new ArrayDeque<>();
      for (int i = 0; i < result.totalNodeCount; i++) {
        int flags = input.readByte();

        Node node = deserializeNode(input);

        if ((flags & Flags.HAS_RIGHT) != 0) {
          node.right = stack.pop();
        }

        if ((flags & Flags.HAS_LEFT) != 0) {
          node.left = stack.pop();
        }

        stack.push(node);
        result.weightedCount += node.weightedCount;
        if (node.weightedCount >= ZERO_WEIGHT_THRESHOLD) {
          result.nonZeroNodeCount++;
        }
      }

      if (!stack.isEmpty()) {
        Preconditions.checkArgument(
            stack.size() == 1, "Tree is corrupted. Expected a single root node");
        result.root = stack.pop();
      }

      return result;
    } catch (IOException e) {
      throw Throwables.propagate(e);
    }
  }
Example #5
0
  private void insert(long bits, double weight) {
    long lastBranch = 0;
    Node parent = null;
    Node current = root;

    while (true) {
      if (current == null) {
        setChild(parent, lastBranch, createLeaf(bits, weight));
        return;
      } else if (!inSameSubtree(bits, current.bits, current.level)) {
        // if bits and node.bits are not in the same branch given node's level,
        // insert a parent above them at the point at which branches diverge
        setChild(parent, lastBranch, makeSiblings(current, createLeaf(bits, weight)));
        return;
      } else if (current.level == 0 && current.bits == bits) {
        // found the node

        double oldWeight = current.weightedCount;

        current.weightedCount += weight;

        if (current.weightedCount >= ZERO_WEIGHT_THRESHOLD && oldWeight < ZERO_WEIGHT_THRESHOLD) {
          ++nonZeroNodeCount;
        }

        weightedCount += weight;

        return;
      }

      // we're on the correct branch of the tree and we haven't reached a leaf, so keep going down
      long branch = bits & current.getBranchMask();

      parent = current;
      lastBranch = branch;

      if (branch == 0) {
        current = current.left;
      } else {
        current = current.right;
      }
    }
  }
Example #6
0
  /**
   * 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;
  }
Example #7
0
  private Node makeSiblings(Node node, Node sibling) {
    int parentLevel = MAX_BITS - Long.numberOfLeadingZeros(node.bits ^ sibling.bits);

    Node parent = createNode(node.bits, parentLevel, 0);

    // the branch is given by the bit at the level one below parent
    long branch = sibling.bits & parent.getBranchMask();
    if (branch == 0) {
      parent.left = sibling;
      parent.right = node;
    } else {
      parent.left = node;
      parent.right = sibling;
    }

    return parent;
  }
Example #8
0
  private Node merge(Node node, Node other) {
    if (node == null) {
      return copyRecursive(other);
    } else if (other == null) {
      return node;
    } else if (!inSameSubtree(node.bits, other.bits, Math.max(node.level, other.level))) {
      return makeSiblings(node, copyRecursive(other));
    } else if (node.level > other.level) {
      long branch = other.bits & node.getBranchMask();

      if (branch == 0) {
        node.left = merge(node.left, other);
      } else {
        node.right = merge(node.right, other);
      }
      return node;
    } else if (node.level < other.level) {
      Node result = createNode(other.bits, other.level, other.weightedCount);

      long branch = node.bits & other.getBranchMask();
      if (branch == 0) {
        result.left = merge(node, other.left);
        result.right = copyRecursive(other.right);
      } else {
        result.left = copyRecursive(other.left);
        result.right = merge(node, other.right);
      }

      return result;
    }

    // else, they must be at the same level and on the same path, so just bump the counts
    double oldWeight = node.weightedCount;

    weightedCount += other.weightedCount;
    node.weightedCount = node.weightedCount + other.weightedCount;
    node.left = merge(node.left, other.left);
    node.right = merge(node.right, other.right);

    if (oldWeight < ZERO_WEIGHT_THRESHOLD && node.weightedCount >= ZERO_WEIGHT_THRESHOLD) {
      nonZeroNodeCount++;
    }

    return node;
  }