@Test
  public void testOperator2() throws Exception {

    Tree tree;
    int taxaSize = 3;

    // make a caterpillar
    Node left = new ZeroBranchSANode();
    left.setNr(0);
    left.setHeight(0.0);
    for (int i = 1; i < taxaSize; i++) {
      Node right = new ZeroBranchSANode();
      right.setNr(i);
      right.setHeight(i);
      Node parent = new ZeroBranchSANode();
      parent.setNr(taxaSize + i - 1);
      parent.setHeight(i);
      left.setParent(parent);
      parent.setLeft(left);
      right.setParent(parent);
      parent.setRight(right);
      left = parent;
    }
    left.setHeight(left.getRight().getHeight() + 2);
    tree = new Tree(left);

    System.out.println("Tree was = " + tree.getRoot().toShortNewick(false));

    TreeDimensionJump operator = new TreeDimensionJump();
    operator.initByName("tree", tree);
    double logHastingsRatio = operator.proposal();

    System.out.println("Proposed tree = " + tree.getRoot().toShortNewick(false));
    System.out.println("Log Hastings ratio = " + logHastingsRatio);
  }
  /**
   * Creates a new branch between node and a new node at time destTime between destBranchBase and
   * its parent. Colour changes are divided between the two new branches created by the split.
   *
   * @param node
   * @param destBranchBase
   * @param destTime
   */
  public void connectBranch(Node node, Node destBranchBase, double destTime) {

    // Check argument validity:
    if (node.isRoot() || destBranchBase.isRoot())
      throw new IllegalArgumentException("Illegal argument to " + "connectBranch().");

    // Obtain existing parent of node and set new time:
    Node parent = node.getParent();
    parent.setHeight(destTime);

    MultiTypeNode mtParent = (MultiTypeNode) parent;
    MultiTypeNode mtDestBranchBase = (MultiTypeNode) destBranchBase;

    // Determine where the split comes in the list of colour changes
    // attached to destBranchBase:
    int split;
    for (split = 0; split < mtDestBranchBase.getChangeCount(); split++)
      if (mtDestBranchBase.getChangeTime(split) > destTime) break;

    // Divide colour changes between new branches:
    mtParent.clearChanges();
    for (int idx = split; idx < mtDestBranchBase.getChangeCount(); idx++)
      mtParent.addChange(mtDestBranchBase.getChangeType(idx), mtDestBranchBase.getChangeTime(idx));

    mtDestBranchBase.truncateChanges(split);

    // Set colour at split:
    mtParent.setNodeType(mtDestBranchBase.getFinalType());

    // Implement topology changes:
    replace(destBranchBase.getParent(), destBranchBase, parent);
    destBranchBase.setParent(parent);

    if (parent.getLeft() == node) parent.setRight(destBranchBase);
    else if (parent.getRight() == node) parent.setLeft(destBranchBase);

    // Ensure BEAST knows to update affected likelihoods:
    node.makeDirty(Tree.IS_FILTHY);
    parent.makeDirty(Tree.IS_FILTHY);
    destBranchBase.makeDirty(Tree.IS_FILTHY);
  }
  /**
   * Set up node's parent as the new root with a height of destTime, with oldRoot as node's new
   * sister.
   *
   * @param node
   * @param oldRoot
   * @param destTime
   */
  public void connectBranchToRoot(Node node, Node oldRoot, double destTime) {

    // Check argument validity:
    if (node.isRoot() || !oldRoot.isRoot())
      throw new IllegalArgumentException("Illegal argument " + "to connectBranchToRoot().");

    // Obtain existing parent of node and set new time:
    Node newRoot = node.getParent();
    newRoot.setHeight(destTime);

    // Implement topology changes:

    newRoot.setParent(null);

    if (newRoot.getLeft() == node) newRoot.setRight(oldRoot);
    else if (newRoot.getRight() == node) newRoot.setLeft(oldRoot);

    oldRoot.setParent(newRoot);

    // Ensure BEAST knows to recalculate affected likelihood:
    newRoot.makeDirty(Tree.IS_FILTHY);
    oldRoot.makeDirty(Tree.IS_FILTHY);
    node.makeDirty(Tree.IS_FILTHY);
  }