diff --git a/src/main/java/beastlabs/prevalence/PrevalenceList.java b/src/main/java/beastlabs/prevalence/PrevalenceList.java index 163324d..90c537b 100644 --- a/src/main/java/beastlabs/prevalence/PrevalenceList.java +++ b/src/main/java/beastlabs/prevalence/PrevalenceList.java @@ -294,20 +294,35 @@ public void fromXML(Node node) { @Override /** scale only those items associated with a node and leave the rest **/ - public int scale(double fScale) { + public double scale(double fScale) { Set nodes = m_nodeIDtoItemMap.keySet(); for (Integer nNodeID : nodes) { int iTime = indexOfNode(nNodeID); - Item item = m_items.get(iTime); + Item item = m_items.get(iTime); move(iTime, item.m_fTime * fScale); } - return nodes.size(); + return nodes.size() * Math.log(fScale); + } + + /** + * Read this list's position on its dilation axis: sum of times across all + * items associated with a node. Each such time is multiplied by the scale + * factor in {@link #scale(double)}, so the sum is exactly {@code s}-equivariant. + */ + @Override + public double getScalableValue() { + double sum = 0.0; + for (Integer nNodeID : m_nodeIDtoItemMap.keySet()) { + int iTime = indexOfNode(nNodeID); + sum += m_items.get(iTime).m_fTime; + } + return sum; } @Override public void scaleOne(int i, double scale) { int iTime = indexOfNode(i); - Item item = m_items.get(iTime); + Item item = m_items.get(iTime); move(iTime, item.m_fTime * scale); } diff --git a/src/main/java/beastlabs/prevalence/TreeScaleOperator.java b/src/main/java/beastlabs/prevalence/TreeScaleOperator.java index b13abfc..8a2e381 100644 --- a/src/main/java/beastlabs/prevalence/TreeScaleOperator.java +++ b/src/main/java/beastlabs/prevalence/TreeScaleOperator.java @@ -59,16 +59,18 @@ public double proposal() { double d = Randomizer.nextDouble(); double scale = (m_fScaleFactor + (d * ((1.0 / m_fScaleFactor) - m_fScaleFactor))); - Tree tree = m_tree.get(); + Tree tree = m_tree.get(); // scale the beast.tree - int nInternalNodes = tree.scale(scale); + // tree.scale returns the log Jacobian (dof * log(scale)); + // operator adds the -2*log(scale) kernel-symmetry correction. + final double treeLogJacobian = tree.scale(scale); PrevalenceList list = m_list.get(); - // scale only internal nodes in the list - // nNodesScaled is the number of nodes that have been scaled - int nNodesScaled = list.scale(scale); + // scale only internal nodes in the list (return discarded — + // see TODO below; list's contribution to HR is not currently included) + list.scale(scale); // TODO: check the HastingsRatio, since the prevalence list is assumed to be unchanged here - return Math.log(scale) * (nInternalNodes - 2); + return treeLogJacobian - 2 * Math.log(scale); } catch (Exception e) { return Double.NEGATIVE_INFINITY; }