public String toString() {
   int ngt = piosb.numberOfGeneTrees();
   String nl = System.getProperty("line.separator");
   String s = nl + pioTreeAsText() + nl;
   for (int g = 0; g < ngt; g++) {
     s += "Gene tree " + g + nl;
     s += piosb.genetreeAsText(g) + nl;
   }
   s += nl;
   return s;
 }
 private void recordSubtreeLineageCounts(PopsIONode node) {
   if (node.lft < 0) {
     int spIndex = piosb.speciesId2index(node.getTaxon().getId());
     node.nlineages = piosb.nLineages(spIndex);
   } else {
     node.nlineages = 0;
     recordSubtreeLineageCounts(pionodes[node.lft]);
     node.nlineages += pionodes[node.lft].nlineages - pionodes[node.lft].coalheights.size();
     recordSubtreeLineageCounts(pionodes[node.rgt]);
     node.nlineages += pionodes[node.rgt].nlineages - pionodes[node.rgt].coalheights.size();
   }
 }
  public PopsIOSpeciesTreeModel(
      PopsIOSpeciesBindings piosb, Parameter popPriorScale, PriorComponent[] priorComponents) {
    super(PopsIOSpeciesTreeModelParser.PIO_SPECIES_TREE);
    this.piosb = piosb;

    this.popPriorScale = popPriorScale;
    addVariable(popPriorScale);
    popPriorScale.addBounds(new Parameter.DefaultBounds(Double.POSITIVE_INFINITY, 0.0, 1));

    this.priorComponents = priorComponents;

    PopsIOSpeciesBindings.SpInfo[] species = piosb.getSpecies();
    int nTaxa = species.length;
    int nNodes = 2 * nTaxa - 1;
    pionodes = new PopsIONode[nNodes];
    for (int n = 0; n < nNodes; n++) {
      pionodes[n] = new PopsIONode(n);
    }
    ArrayList<Integer> tojoin = new ArrayList<Integer>(nTaxa);
    for (int n = 0; n < nTaxa; n++) {
      pionodes[n].setTaxon(species[n].name);
      pionodes[n].setHeight(0.0);
      pionodes[n].setUnion(piosb.tipUnionFromTaxon(pionodes[n].getTaxon()));
      tojoin.add(n);
    }
    double rate = 1.0;
    double treeheight = 0.0;
    for (int i = 0; i < nTaxa - 1; i++) {
      int numtojoin = tojoin.size();
      int j = MathUtils.nextInt(numtojoin);
      Integer child0 = tojoin.get(j);
      tojoin.remove(j);
      int k = MathUtils.nextInt(numtojoin - 1);
      Integer child1 = tojoin.get(k);
      tojoin.remove(k);
      pionodes[nTaxa + i].addChildren(pionodes[child0], pionodes[child1]);
      pionodes[nTaxa + i].setHeight(treeheight + randomnodeheight(numtojoin * rate));
      treeheight = pionodes[nTaxa + i].getHeight();
      tojoin.add(nTaxa + i);
    }
    rootn = pionodes.length - 1;

    double scale = 0.99 * piosb.initialMinGeneNodeHeight() / pionodes[rootn].height;
    scaleAllHeights(scale);
    pionodes[rootn].fillinUnionsInSubtree(piosb.getSpecies().length);

    stree = makeSimpleTree();

    Logger.getLogger("dr.evomodel.speciation.popsio")
        .info(
            "\tConstructing a PopsIO Species Tree Model, please cite:\n"
                + Citable.Utils.getCitationString(this));
  }
 private void accumSubtreeCoalCountsIntensities(PopsIONode node) {
   if (node.lft >= 0) {
     accumSubtreeCoalCountsIntensities(pionodes[node.lft]);
     accumSubtreeCoalCountsIntensities(pionodes[node.rgt]);
   }
   int k = node.coalheights.size();
   node.coalcount += k;
   double[] t = new double[k + 2];
   t[0] = node.height;
   for (int i = 0; i < k; i++) {
     t[i + 1] = node.coalheights.get(i);
   }
   t[k + 1] = (node.anc < 0) ? piosb.maxGeneTreeHeight() : pionodes[node.anc].height;
   int n = node.nlineages;
   for (int i = 0; i <= k; i++) {
     node.coalintensity += (t[i + 1] - t[i]) * 0.5 * (n - i) * (n - i - 1);
   }
 }
 public void fixupAfterNodeSlide() {
   pionodes[rootn].fillinUnionsInSubtree(piosb.getSpecies().length);
   stree = makeSimpleTree();
 }