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));
  }
  public WeightedMixtureModel(
      List<AbstractModelLikelihood> likelihoodList, Parameter mixtureWeights) {
    super(MIXTURE_MODEL);
    this.likelihoodList = likelihoodList;
    this.mixtureWeights = mixtureWeights;
    for (AbstractModelLikelihood model : likelihoodList) {
      addModel(model);
    }
    addVariable(mixtureWeights);

    StringBuilder sb = new StringBuilder();
    sb.append("Constructing a finite mixture model\n");
    sb.append("\tComponents:\n");
    for (AbstractModelLikelihood model : likelihoodList) {
      sb.append("\t\t\t").append(model.getId()).append("\n");
    }
    sb.append("\tMixing parameter: ").append(mixtureWeights.getId()).append("\n");
    sb.append("\tPlease cite:\n");
    sb.append(Citable.Utils.getCitationString((this)));

    Logger.getLogger("dr.inference.model").info(sb.toString());
  }
  public static Transform[] parseListOfTransforms(XMLObject xo, int maxDim)
      throws XMLParseException {
    Transform[] transforms = null;

    boolean anyTransforms = false;
    for (int i = 0; i < xo.getChildCount(); ++i) {
      if (xo.getChild(i) instanceof Transform.ParsedTransform) {
        Transform.ParsedTransform t = (Transform.ParsedTransform) xo.getChild(i);
        if (transforms == null) {
          transforms = Transform.Util.getListOfNoTransforms(maxDim);
        }

        t.end = Math.max(t.end, maxDim);
        if (t.start < 0 || t.end < 0 || t.start > t.end) {
          throw new XMLParseException("Invalid bounds for transform in " + xo.getId());
        }
        for (int j = t.start; j < t.end; j += t.every) {
          transforms[j] = t.transform;
          anyTransforms = true;
        }
      }
    }
    if (anyTransforms) {
      StringBuilder sb =
          new StringBuilder("Using distributional transforms in " + xo.getId() + "\n");
      for (int i = 0; i < transforms.length; ++i) {
        if (transforms[i] != Transform.NONE) {
          sb.append("\t")
              .append(transforms[i].getTransformName())
              .append(" on index ")
              .append(i + 1)
              .append("\n");
        }
      }
      sb.append("Please cite:\n").append(Citable.Utils.getCitationString(Transform.LOG));
      Logger.getLogger("dr.utils.Transform").info(sb.toString());
    }
    return transforms;
  }