package beast.core; /** * A CalculationNode is a BEAST Object that perform calculations based on the State. * CalculationNodes differ from StateNodes in that they * 1. Calculate something * 2. can not be changed by Operators. * * Calculations are functions, StateNodes are variables. * * @author Andrew Rambaut */ @Description("BEASTObject that performs calculations based on the State.") public abstract class CalculationNode extends BEASTObject { //================================================================= // The API of CalculationNode. These 3 functions (store/restore/requireCalculation) // can be overridden to increase efficiency by caching internal calculations. // General default implementations are provided. //================================================================= /** * Store internal calculations. Called before a calculation node * is asked to perform any calculations, but after some part of the * state has changed through a operator proposal. * <p/> * This is not meant to be used to calculate anything, just store * intermediate results of calculations. Input values should not * be accessed because some StateNodes may have been changed. */ protected void store() { isDirty = false; } /** * Check whether internal calculations need to be updated * <p/> * This is called after a proposal of a new state. * A CalculationNode that needs a custom implementation should * override requiresRecalculation() */ final void checkDirtiness() { isDirty = requiresRecalculation(); } /** * @return whether the API for the particular BEASTObject returns different * answers than before the operation was applied. * <p/> * This method is called before the CalculationNode do their calculations. * Called in order of the partial order defined by Input-BEASTObject relations. * Called only on those CalculationNodes potentially affected by a * StateNode change. * <p/> * Default implementation return 'true', since requiresRecalculation is * called for a node only if one of its arguments has changed. */ protected boolean requiresRecalculation() { return true; // * <p/> // * Default implementation inspects all input beastObjects // * and checks if there is any dirt anywhere. // * Derived classes can provide a more efficient implementation // * by checking which part of any input StateNode or BEASTObject has changed. // * <p/> // * Note this default implementation is relative expensive since it uses // * introspection, so overrides should be preferred. // * After the operation has changed the state.state // this is a prototypical implementation of requiresRecalculation() // try { // for (BEASTObject beastObject : listActivePlugins()) { // if (beastObject instanceof StateNode && ((StateNode)beastObject).somethingIsDirty()) { // return true; // } // // if (beastObject instanceof CalculationNode && ((CalculationNode)beastObject).isDirtyCalculation()) { // return true; // } // } // } catch (IllegalAccessException e) { // e.printStackTrace(); // } // // return false; } /** * Restore internal calculations * <p/> * This is called when a proposal is rejected */ protected void restore() { isDirty = false; } /** * Accept internal state and mark internal calculations as current * <p/> * This is called when a proposal is accepted */ protected void accept() { isDirty = false; } /** * @return true if the node became dirty - that is needs to recalculate due to * changes in the inputs. * <p/> * CalcalationNodes typically know whether an input is a CalculationNode or StateNode * and also know whether the input is Validate.REQUIRED, hence cannot be null. * Further, for CalculationNodes, a shadow parameter can be kept so that a * call to Input.get() can be saved. * Made public to squeeze out a few cycles and save a few seconds in * calculation time by calling this directly instead of calling isDirty() * on the associated input. */ final public boolean isDirtyCalculation() { return isDirty; } /** * flag to indicate whether this node will be updating its calculations */ private boolean isDirty = false; } // class CalculationNode