/**
   * Disconnect edge <node,node.getParent()> by joining node's sister directly to node's grandmother
   * and adding all colour changes previously on <node.getParent(),node.getParent().getParent()> to
   * the new branch.
   *
   * @param node
   */
  public void disconnectBranch(Node node) {

    // Check argument validity:
    Node parent = node.getParent();
    if (node.isRoot() || parent.isRoot())
      throw new IllegalArgumentException("Illegal argument to " + "disconnectBranch().");

    Node sister = getOtherChild(parent, node);

    // Add colour changes originally attached to parent to those attached
    // to node's sister:
    for (int idx = 0; idx < ((MultiTypeNode) parent).getChangeCount(); idx++) {
      int colour = ((MultiTypeNode) parent).getChangeType(idx);
      double time = ((MultiTypeNode) parent).getChangeTime(idx);
      ((MultiTypeNode) sister).addChange(colour, time);
    }

    // Implement topology change.
    replace(parent.getParent(), parent, sister);

    // Clear colour changes from parent:
    ((MultiTypeNode) parent).clearChanges();

    // Ensure BEAST knows to update affected likelihoods:
    parent.makeDirty(Tree.IS_FILTHY);
    sister.makeDirty(Tree.IS_FILTHY);
    node.makeDirty(Tree.IS_FILTHY);
  }
  /**
   * Disconnect node from root, discarding all colouring on <node,root> and <node's sister,root>.
   *
   * @param node
   */
  public void disconnectBranchFromRoot(Node node) {

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

    // Implement topology change:
    Node parent = node.getParent();
    Node sister = getOtherChild(parent, node);
    sister.setParent(null);
    parent.getChildren().remove(sister);

    // Clear colour changes on new root:
    ((MultiTypeNode) sister).clearChanges();

    // Ensure BEAST knows to update affected likelihoods:
    parent.makeDirty(Tree.IS_FILTHY);
    sister.makeDirty(Tree.IS_FILTHY);
    node.makeDirty(Tree.IS_FILTHY);
  }
  /**
   * 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);
  }