/**
  * Set the key for each leaf from root, in order from 0 to N - 1 for N leaves in the tree
  *
  * @param root
  */
 @Requires("root == this.root")
 private void assignKeys(final StratNode<K> root) {
   int key = 0;
   for (final StratNode<K> node : root) {
     if (node.isLeaf()) node.setKey(key++);
   }
 }
 private void assignStratifierValuesByKey(
     final StratNode<K> node, final LinkedList<Object> states) {
   if (node.isLeaf()) { // we're here!
     if (states.isEmpty())
       throw new ReviewedGATKException("Found a leaf node with an empty state values vector");
     stratifierValuesByKey.set(
         node.getKey(), Collections.unmodifiableList(new ArrayList<Object>(states)));
   } else {
     for (Map.Entry<Object, StratNode<K>> entry : node.getSubnodes().entrySet()) {
       final LinkedList<Object> newStates = new LinkedList<Object>(states);
       newStates.addLast(entry.getKey());
       assignStratifierValuesByKey(entry.getValue(), newStates);
     }
   }
 }
  /**
   * Create a new StratificationManager with nodes to store data for all combinations of the ordered
   * list of strats
   *
   * @param strats ordered list of stratifications to representation
   */
  @Requires("!strats.isEmpty()")
  public StratificationManager(final List<K> strats) {
    this.stratifiers = new ArrayList<K>(strats);

    // construct and store the full tree of strats
    this.root = buildStratificationTree(new LinkedList<K>(strats));
    // assign the linear key ordering to the leafs
    assignKeys(root);

    // cache the size, and check for a bad state
    this.size = root.size();
    if (this.size == 0) throw new ReviewedGATKException("Size == 0 in StratificationManager");

    // prepare the assocated data vectors mapping from key -> data
    this.valuesByKey = new ArrayList<V>(size());
    this.stratifierValuesByKey = new ArrayList<List<Object>>(size());
    this.keyStrings = new ArrayList<String>(size());
    for (int i = 0; i < size(); i++) {
      this.valuesByKey.add(null);
      this.stratifierValuesByKey.add(null);
      this.keyStrings.add(null);
    }

    assignStratifierValuesByKey(root);
  }
 @Requires("allStates != null")
 @Ensures("result != null")
 public Set<Integer> getKeys(final List<List<Object>> allStates) {
   final HashSet<Integer> keys = new HashSet<Integer>();
   root.find(allStates, 0, keys);
   return keys;
 }
 @Requires("states != null")
 @Ensures("result >= -1")
 public int getKey(final List<Object> states) {
   return root.find(states, 0);
 }