package beast.core.parameter; import java.util.ArrayList; import java.util.List; import beast.core.BEASTObject; import beast.core.CalculationNode; import beast.core.Description; import beast.core.Function; import beast.core.Input; import beast.core.Input.Validate; import beast.core.StateNode; @Description("Summarizes a set of valuables so that for example a rate matrix can be " + "specified that uses a parameter in various places in the matrix.") public class CompoundValuable extends CalculationNode implements Function { final public Input<List<BEASTObject>> m_values = new Input<>("var", "reference to a valuable", new ArrayList<>(), Validate.REQUIRED, Function.class); boolean m_bRecompute = true; /** * contains values of the inputs * */ double[] m_fValues; @Override public void initAndValidate() { // determine dimension int dimension = 0; for (BEASTObject beastObject : m_values.get()) { if (!(beastObject instanceof Function)) { throw new IllegalArgumentException("Input does not implement Valuable"); } dimension += ((Function) beastObject).getDimension(); } m_fValues = new double[dimension]; } /** * Valuable implementation follows * */ @Override public int getDimension() { return m_fValues.length; } @Override public double getArrayValue() { if (m_bRecompute) { recompute(); } return m_fValues[0]; } @Override public double getArrayValue(int dim) { if (m_bRecompute) { recompute(); } return m_fValues[dim]; } /** * collect values of the compounds into an array * */ private void recompute() { int k = 0; for (BEASTObject beastObject : m_values.get()) { Function valuable = (Function) beastObject; if (beastObject instanceof StateNode) { valuable = ((StateNode) beastObject).getCurrent(); } int dimension = valuable.getDimension(); for (int i = 0; i < dimension; i++) { m_fValues[k++] = valuable.getArrayValue(i); } } m_bRecompute = false; } /** * CalculationNode methods * */ @Override public void store() { m_bRecompute = true; super.store(); } @Override public void restore() { m_bRecompute = true; super.restore(); } @Override public boolean requiresRecalculation() { m_bRecompute = true; return true; } }