package dr.evomodel.arg.operators; import dr.evomodel.arg.ARGModel; import dr.evomodelxml.tree.TreeModelParser; import dr.inference.model.CompoundParameter; import dr.inference.operators.OperatorFailedException; import dr.inference.operators.SimpleMCMCOperator; import dr.math.MathUtils; import java.util.logging.Logger; public class ARGReassortmentOperator extends SimpleMCMCOperator { public static final String ADD_PROBABILITY = "addProbability"; public static final String ARG_REASSORTMENT_OPERATOR = "argReassortmentOperator"; public static final String INTERNAL_NODES = "internalNodes"; public static final String INTERNAL_AND_ROOT = "internalNodesPlusRoot"; public static final String NODE_RATES = TreeModelParser.NODE_RATES; public static final String CHOOSE_BRANCHES_FIRST = "chooseBranchesFirst"; public static final double LOG_TWO = Math.log(2.0); private double singlePartitionProbability = 0.0; private double probBelowRoot = 0.9; private double size = 0.0; //Used to choose add step private boolean branchesFirst; private ARGModel arg; private CompoundParameter internalNodeParameters; private CompoundParameter internalAndRootNodeParameters; private CompoundParameter nodeRates; public ARGReassortmentOperator(ARGModel arg, int weight, boolean branchesFirst, double singlePartProb, double addProbability, CompoundParameter internalNodeParameters, CompoundParameter internalAndRootNodeParameters, CompoundParameter nodeRates) { this.arg = arg; this.internalNodeParameters = internalNodeParameters; this.internalAndRootNodeParameters = internalAndRootNodeParameters; this.nodeRates = nodeRates; this.branchesFirst = branchesFirst; this.singlePartitionProbability = singlePartProb; setWeight(weight); this.size = addProbability; //Transformed for computation reasons probBelowRoot = -Math.log(1 - Math.sqrt(probBelowRoot)); } public double doOperation() throws OperatorFailedException { double logHastings = 0; try { if (MathUtils.nextDouble() < 1.0 / (1 + Math.exp(-size))) logHastings = addOperation() - size; else logHastings = removeOperation() + size; } catch (NoReassortmentEventException nree) { return Double.NEGATIVE_INFINITY; } catch (OperatorFailedException ofe) { Logger.getLogger("dr.evomodel.operators").fine(ofe.getMessage()); } return logHastings; } private double addOperation() throws OperatorFailedException { if (branchesFirst) return addOperationBranchesFirst(); return addOperationHeightsFirst(); } private double addOperationBranchesFirst() throws OperatorFailedException { double logHastings = 0; double treeHeight = arg.getNodeHeight(arg.getRoot()); double newBifurcationHeight = Double.POSITIVE_INFINITY; double newReassortmentHeight = Double.POSITIVE_INFINITY; double theta = probBelowRoot / treeHeight; while (newBifurcationHeight > treeHeight && newReassortmentHeight > treeHeight) { newBifurcationHeight = MathUtils.nextExponential(theta); newReassortmentHeight = MathUtils.nextExponential(theta); } logHastings += theta * (newBifurcationHeight + newReassortmentHeight) - LOG_TWO - 2.0 * Math.log(theta) + Math.log(1 - Math.exp(-2.0 * treeHeight * theta)); if (newBifurcationHeight < newReassortmentHeight) { double temp = newBifurcationHeight; newBifurcationHeight = newReassortmentHeight; newReassortmentHeight = temp; } return 0; } private double addOperationHeightsFirst() throws OperatorFailedException { return 0; } private double removeOperation() throws OperatorFailedException { return 0; } public String getOperatorName() { return ARG_REASSORTMENT_OPERATOR; } public String getPerformanceSuggestion() { return "Try changing the add probability probability"; } private class NoReassortmentEventException extends OperatorFailedException { private static final long serialVersionUID = 1L; public NoReassortmentEventException() { super(""); } } }