/**
   * override this for proposals,
   *
   * @return log of Hastings Ratio, or Double.NEGATIVE_INFINITY if proposal should not be accepted *
   */
  @Override
  public double proposal() {
    testing = isTestInput.get();
    speciesTreeNodes = speciesTree.getNodesAsArray();
    nLeafNodes = speciesTree.getLeafNodeCount();
    nInternalNodes = speciesTree.getInternalNodeCount();
    nSpeciesNodes = speciesTree.getNodeCount();

    boolean isNarrow = isNarrowInput.get();
    double logHastingsRatio = 0.0;
    if (isNarrow) {
      // only proceed to rearrange gene trees if the species tree can be changed
      // doesn't execute if testing
      if (!testing && !pickNarrow()) return Double.NEGATIVE_INFINITY;

      int validGP = 0;
      for (int i = nLeafNodes; i < nSpeciesNodes; ++i) {
        validGP += isg(speciesTree.getNode(i));
      }

      final int c2 = sisg(yNode) + sisg(cNode);

      fillNodes(); // fills in movedNodes and graftNodes
      pruneAndRegraft(yNode, cNode, bNode);

      final int validGPafter = validGP - c2 + sisg(yNode) + sisg(cNode);

      logHastingsRatio += Math.log(validGP) - Math.log(validGPafter);
    } else {
      // only proceed to rearrange gene trees if the species tree can be changed
      // doesn't execute if testing
      if (!testing && !pickWide()) return Double.NEGATIVE_INFINITY;

      fillNodes(); // fills in movedNodes and graftNodes
      pruneAndRegraft(yNode, cNode, bNode);
    }

    for (final Tree geneTree : geneTreeInput.get())
      geneTree.startEditing(null); // hack to stop beast.core.State.Trie memory leak

    for (int i = 0; i < czBranchCount; i++) {
      final List<SortedMap<Node, Node>> perBranchMovedNodes = movedNodes.get(i);
      final SetMultimap<Integer, Node> perBranchGraftNodes = graftNodes.get(i);
      final double logForward = rearrangeGeneTrees(perBranchMovedNodes, perBranchGraftNodes, true);
      assert logForward != Double.NEGATIVE_INFINITY;
      if (logForward == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY;
      else logHastingsRatio += logForward;
    }

    // compute reverse move (Hastings ratio denominator)
    final Node bNodeTmp = bNode;
    final Node cNodeTmp = cNode;

    bNode = cNodeTmp;
    cNode = bNodeTmp;

    fillNodes(); // fills in movedNodes and graftNodes for reverse move

    for (int i = 0; i < czBranchCount; i++) {
      final List<SortedMap<Node, Node>> perBranchMovedNodes = movedNodes.get(i);
      final SetMultimap<Integer, Node> perBranchGraftNodes = graftNodes.get(i);
      final double logReverse = rearrangeGeneTrees(perBranchMovedNodes, perBranchGraftNodes, false);
      assert logReverse != Double.NEGATIVE_INFINITY;
      if (logReverse == Double.NEGATIVE_INFINITY) return Double.NEGATIVE_INFINITY;
      else logHastingsRatio -= logReverse;
    }

    return logHastingsRatio;
  }