I am ending up with various score states which have to be updated in the right order. Currently this requires that the user add them to the model in the right order and non-obvious things happen if this is not the case. I think adding an iteration counter to the update call would make this simpler (and the change could be implemented without changing individual score states much).
Model maintains a counter which is incremented each time evaluate is called. It then calls ScoreState::update(int) for each score state passing the counter. This update is a method in the ScoreState base class which simply compares the passed counter to the stored counter and calls the existing update method if the counters are different. ScoreStates which depend on other score states can simply call update on their dependencies with the counter. Each ScoreState is updated exactly once and, unless there are circular dependencies, everything is updated before it is used. The same thing can be used for after_evaluate, although there is currently no need. With slightly more logic we could catch circular dependencies too.
Comments?
Daniel Russel wrote: > I am ending up with various score states which have to be updated in > the right order. Currently this requires that the user add them to the > model in the right order and non-obvious things happen if this is not > the case. I think adding an iteration counter to the update call > would make this simpler (and the change could be implemented without > changing individual score states much). > > Model maintains a counter which is incremented each time evaluate is > called. It then calls ScoreState::update(int) for each score state > passing the counter. This update is a method in the ScoreState base > class which simply compares the passed counter to the stored counter > and calls the existing update method if the counters are different. > ScoreStates which depend on other score states can simply call update > on their dependencies with the counter. Each ScoreState is updated > exactly once and, unless there are circular dependencies, everything > is updated before it is used. The same thing can be used for > after_evaluate, although there is currently no need. With slightly > more logic we could catch circular dependencies too.
I don't really follow what you're proposing. Which 'evaluate' method are you talking about? And what is the 'stored counter'? Are you proposing that ScoreStates contain a container of their own dependencies? Perhaps an example would be instructive.
Here is an example of a state which would benefit from ordering: Keren asked about GravityCenters which contain other GravityCenters, e.g. given particles P1 through P4, we could create two new particles P5 and P6 which are gravity centers of P1,P2 and P3,P4 respectively, i.e P5=G(P1,P2) and P6=G(P3,P4). The two GravityCenterScoreStates set the xyz coordinates of P5 and P6 from their 'child' particles *before* evaluating the score function, and map the derivatives on P5 and P6 back onto the child particles *after* evaluation. The problem now is if we add a new GravityCenter P7=G(P5,P6). In order for this to work properly the before-update has to happen after that for P5 and P6, but the after-update has to happen before P5 and P6. So ordering could help here, but would need to happen in reverse order for update() and after_evaluate(). (The alternative is to prohibit gravity centers from containing other gravity centers, in which case we would simply define P7=G(P1,P2,P3,P4).)
Ben
Model has a counter, initially set to 0.
When Model::evaluate is called, it calls update on each ScoreState is has a pointer to, passing the counter value to the ScoreState.
When a ScoreState::update is called, it checks its stored value for the counter. If the counter value is one it has not seen yet, then it performs an update and stores the counter value.
Model increments the counter.
Now, if a ScoreState has dependencies, it simply stores a pointer to its dependencies. When its update is called, it calls update on each of its dependencies then updates itself. Since the counter is passed, each ScoreState is only updated once per call to Model::evaluate, not matter how many ScoreStates depend on it.
In the GravityCenter case, the GC would have a list of child particles and child CGs (and a list of parent GCs). On update, it would call the update method on each of its child GCs and then update itself. The after_evaluate method would call after_evaluate on each of its parents, and then propagate its own derivatives.
Clear?
On May 8, 2008, at 12:54 PM, Ben Webb wrote:
> Daniel Russel wrote: >> I am ending up with various score states which have to be updated in >> the right order. Currently this requires that the user add them to >> the >> model in the right order and non-obvious things happen if this is not >> the case. I think adding an iteration counter to the update call >> would make this simpler (and the change could be implemented without >> changing individual score states much). >> >> Model maintains a counter which is incremented each time evaluate is >> called. It then calls ScoreState::update(int) for each score state >> passing the counter. This update is a method in the ScoreState base >> class which simply compares the passed counter to the stored counter >> and calls the existing update method if the counters are different. >> ScoreStates which depend on other score states can simply call update >> on their dependencies with the counter. Each ScoreState is updated >> exactly once and, unless there are circular dependencies, everything >> is updated before it is used. The same thing can be used for >> after_evaluate, although there is currently no need. With slightly >> more logic we could catch circular dependencies too. > > I don't really follow what you're proposing. Which 'evaluate' method > are > you talking about? And what is the 'stored counter'? Are you proposing > that ScoreStates contain a container of their own dependencies? > Perhaps > an example would be instructive. > > Here is an example of a state which would benefit from ordering: Keren > asked about GravityCenters which contain other GravityCenters, e.g. > given particles P1 through P4, we could create two new particles P5 > and > P6 which are gravity centers of P1,P2 and P3,P4 respectively, i.e > P5=G(P1,P2) and P6=G(P3,P4). The two GravityCenterScoreStates set the > xyz coordinates of P5 and P6 from their 'child' particles *before* > evaluating the score function, and map the derivatives on P5 and P6 > back > onto the child particles *after* evaluation. The problem now is if we > add a new GravityCenter P7=G(P5,P6). In order for this to work > properly > the before-update has to happen after that for P5 and P6, but the > after-update has to happen before P5 and P6. So ordering could help > here, but would need to happen in reverse order for update() and > after_evaluate(). (The alternative is to prohibit gravity centers from > containing other gravity centers, in which case we would simply define > P7=G(P1,P2,P3,P4).) > > Ben > -- > ben@salilab.org http://salilab.org/~ben/ > "It is a capital mistake to theorize before one has data." > - Sir Arthur Conan Doyle > _______________________________________________ > IMP-dev mailing list > IMP-dev@salilab.org > https://salilab.org/mailman/listinfo/imp-dev
Daniel Russel wrote: > Model has a counter, initially set to 0. > > When Model::evaluate is called, it calls update on each ScoreState is > has a pointer to, passing the counter value to the ScoreState. > > When a ScoreState::update is called, it checks its stored value for > the counter. If the counter value is one it has not seen yet, then it > performs an update and stores the counter value. > > Model increments the counter.
OK, makes sense to me, and seems like a reasonable improvement.
Ben
participants (2)
-
Ben Webb
-
Daniel Russel