public MulTreeNodeSlide(
      MulSpeciesTreeModel tree,
      MulSpeciesBindings species /*, boolean outgroupOnly*/,
      double weight) {
    this.multree = tree;
    this.species = species;
    //    this.outgroupOnly = outgroupOnly;

    preOrderIndexBefore = new int[tree.getNodeCount()];
    Arrays.fill(preOrderIndexBefore, -1);

    preOrderIndexAfter = new int[tree.getNodeCount()];
    Arrays.fill(preOrderIndexAfter, -1);

    setWeight(weight);
  }
 public String getOperatorName() {
   return TreeNodeSlideParser.TREE_NODE_REHEIGHT
       + "("
       + multree.getId()
       + ","
       + species.getId()
       + ")";
 }
  private static NodeRef mauReconstructSub(
      MulSpeciesTreeModel tree, int from, int to, NodeRef[] order, boolean[] wasSwaped) {
    if (from == to) {
      return order[2 * from];
    }

    int rootIndex = -1;
    {
      double h = -1;

      for (int i = from; i < to; ++i) {
        final double v = tree.getNodeHeight(order[2 * i + 1]);
        if (h < v) {
          h = v;
          rootIndex = i;
        }
      }
    }

    final NodeRef root = order[2 * rootIndex + 1];

    final NodeRef lchild = tree.getChild(root, 0);
    final NodeRef rchild = tree.getChild(root, 1);

    NodeRef lTargetChild = mauReconstructSub(tree, from, rootIndex, order, wasSwaped);
    NodeRef rTargetChild = mauReconstructSub(tree, rootIndex + 1, to, order, wasSwaped);

    if (wasSwaped[rootIndex]) {
      NodeRef z = lTargetChild;
      lTargetChild = rTargetChild;
      rTargetChild = z;
    }

    if (lchild != lTargetChild) {
      tree.replaceChild(root, lchild, lTargetChild);
    }

    if (rchild != rTargetChild) {
      tree.replaceChild(root, rchild, rTargetChild);
    }

    return root;
  }
  public void operateOneNode(final double factor) throws OperatorFailedException {

    //            #print "operate: tree", ut.treerep(t)
    //   if( verbose)  System.out.println("  Mau at start: " + tree.getSimpleTree());

    final int count = multree.getExternalNodeCount();
    assert count == species.nSpSeqs();

    NodeRef[] order = new NodeRef[2 * count - 1];
    boolean[] swapped = new boolean[count - 1];
    mauCanonical(multree, order, swapped);

    // internal node to change
    // count-1 - number of internal nodes
    int which = MathUtils.nextInt(count - 1);

    FixedBitSet left = new FixedBitSet(count);
    FixedBitSet right = new FixedBitSet(count);

    for (int k = 0; k < 2 * which + 1; k += 2) {
      left.set(multree.speciesIndex(order[k]));
    }

    for (int k = 2 * (which + 1); k < 2 * count; k += 2) {
      right.set(multree.speciesIndex(order[k]));
    }

    double newHeight;

    if (factor > 0) {
      newHeight = multree.getNodeHeight(order[2 * which + 1]) * factor;
    } else {
      final double limit = species.speciationUpperBound(left, right);
      newHeight = MathUtils.nextDouble() * limit;
    }

    multree.beginTreeEdit();

    multree.setPreorderIndices(preOrderIndexBefore);

    final NodeRef node = order[2 * which + 1];

    multree.setNodeHeight(node, newHeight);

    mauReconstruct(multree, order, swapped);

    // restore pre-order of pops -
    {
      multree.setPreorderIndices(preOrderIndexAfter);

      double[] splitPopValues = null;

      for (int k = 0; k < preOrderIndexBefore.length; ++k) {
        final int b = preOrderIndexBefore[k];
        if (b >= 0) {
          final int a = preOrderIndexAfter[k];
          if (a != b) {
            // if( verbose)  System.out.println("pops: " + a + " <- " + b);

            final Parameter p1 = multree.sppSplitPopulations;
            if (splitPopValues == null) {
              splitPopValues = p1.getParameterValues();
            }

            if (multree.constPopulation()) {
              p1.setParameterValue(count + a, splitPopValues[count + b]);
            } else {
              for (int i = 0; i < 2; ++i) {
                p1.setParameterValue(count + 2 * a + i, splitPopValues[count + 2 * b + i]);
              }
            }
          }
        }
      }
    }

    multree.endTreeEdit();
  }
 private static void mauReconstruct(MulSpeciesTreeModel tree, NodeRef[] order, boolean[] swapped) {
   final NodeRef root = mauReconstructSub(tree, 0, swapped.length, order, swapped);
   if (tree.getRoot() != root) {
     tree.setRoot(root);
   }
 }