Comments (6)
I should add that copy-on-write has some advantages too. First, it makes shared-memory parallelism really easy because threads won't trip over each other by making concurrent model changes. Second, it could also be implemented using a base class to maintain a conditional dependency structure on model parameters, so the code footprint might not be large. Third, copy time is likely to be small relative to peeling (but what about other models that don't involve peeling?). Computers have gotten pretty good at allocating&freeing memory chunks since I set out on my coding journey many moons ago.
from sts.
FWIW, Bio++ has some bits to deal with the event listener approach:
It still suffers the graph traversal problem you mention...
On Fri, Dec 14, 2012 at 6:01 AM, Aaron Darling [email protected]:
I should add that copy-on-write has some advantages too. First, it makes
shared-memory parallelism really easy because threads won't trip over each
other by making concurrent model changes. Second, it could also be
implemented using a base class to maintain a conditional dependency
structure on model parameters, so the code footprint might not be large.
Third, copy time is likely to be small relative to peeling (but what about
other models that don't involve peeling?). Computers have gotten pretty
good at allocating&freeing memory chunks since I set out on my coding
journey many moons ago.—
Reply to this email directly or view it on GitHubhttps://github.com//issues/66#issuecomment-11377085.
from sts.
i didn't see that, thanks! it actually looks workable and might save us from reinventing the wheel. the graph traversal seems unavoidable to me in any of the three situations i outlined above, it's more a question of how burdensome the traversal is.
i started to sketch out what an implementation of copy-on-dependency write would look like in code. It's a funky twist on the usual C++ clone(). Here's an example I came up with for a node class:
void node::dependency_clone(std::unordered_map< Parameter*, Parameter* >& invalid_to_new_map) {
// do a straight up copy
newnode = new node(this);
// if a child of this node is also invalid get the address of the new copy
// this little incantation could be made generic or put in the base class
if(invalid_to_new_map.count(c1) > 0){
if(invalid_to_new_map[c1] == NULL) c1->dependency_clone(invalid_to_new_map);
newnode.c1 = invalid_to_new_map[c1];
}
if(invalid_to_new_map.count(c2) > 0){
if(invalid_to_new_map[c2] == NULL) c2->dependency_clone(invalid_to_new_map);
newnode.c2 = invalid_to_new_map[c2];
}
// this could also go in the base class
invalid_to_new_map[this] = newnode;
}
we would probably want to use shared_ptr and/or weak_ptr instead of new but I didn't work that out for this sketch... This function would be outlined in a base class of all model parameters, something like:
class Parameter
{
public:
Parameter* dependency_clone(Parameter* p) = 0;
void register_dependent(Parameter* p);
private:
// a list of parameters that have conditional dependencies on this parameter in the model
vector< std::weak_ptr<Parameter> > dependents;
};
As with clone()
we would need dependency_clone()
to be defined in each derived class.
EDIT: there were a few problems with the above code...
from sts.
Here we go:
void Node::dependency_clone(std::unordered_map< Parameter*, Parameter* >& invalid_to_new_map) {
// do a straight up copy, this copies the current children pointers
newnode = new node(this);
// copy new children only if necessary
depcopy(invalid_to_new_map, child1, newnode.child1);
depcopy(invalid_to_new_map, child2, newnode.child2);
// add the new parameter to the map
invalid_to_new_map[this] = new_p;
}
// clone a dependency tree
void Parameter::dependency_clone() {
std::unordered_map< Parameter*, Parameter* > invalid_to_new_map;
dependency_pre_clone(invalid_to_new_map)
for( auto d : dependents ){
if(!invalid_to_new_map[d]){
d->dependency_clone(invalid_to_new_map);
}
}
}
// does a depth-first traversal to discover all affected model components.
void Parameter::dependency_pre_clone(std::unordered_map< Parameter*, Parameter* >& invalid_to_new_map) {
for( auto d : dependents ){
invalid_to_new_map[d] = NULL;
d->dependency_pre_clone(invalid_to_new_map);
}
}
// create a clone of a parameter if it is a dependent and only if it hasn't already been cloned
void Parameter::depcopy(std::unordered_map< Parameter*, Parameter* >& invalid_to_new_map, Parameter* current, Parameter*& new_p)
{
if(invalid_to_new_map.count(current) > 0){
if(!invalid_to_new_map[current]){
current->dependency_clone(invalid_to_new_map);
}
new_p = invalid_to_new_map[c1];
}
}
Derived parameter classes, e.g. Node will only need to implement the dependency_clone(invalid_to_new_map) function. We might actually break this up into two parts, one which does the clone and something like "depcopy_parts" which makes the two calls to depcopy(). This would make further subclassing of parameters possible.
from sts.
I'm not sure I totally follow - would invalid_to_new_map
be from the previous value of a parameter to the new value? Which is then filled in with all of the dependent parameters? Sorry to be slow.
from sts.
yes, invalid_to_new_map
would hold a mapping of previous parameter pointers (invalidated by a change) to new pointers.
We could also create a hybrid of the versioning and EventListener approaches wherein each parameter has an integer version that gets bumped whenever it's notified of a change in a paramter it depends on.
from sts.
Related Issues (20)
- Verify log likelihoods of trees sampled from sts HOT 4
- post-processing tool
- particles with incomplete trees HOT 1
- least-squares fitting of JC likelihood function HOT 1
- make terminology consistent
- simulations to help understand how good the "natural extension" is HOT 6
- check out performance of SMC on mixture distributions HOT 6
- inference ll != test ll HOT 3
- propose nodes to merge non-uniformly HOT 19
- A general system to store particle metadata HOT 11
- MCMC move diagnostics/logging HOT 1
- Read model / rate distribution parameters from posterior
- Use lcfit for attachment branch length proposals? HOT 2
- Online: cache likelihoods
- BEAGLE has moved to version 2, whereas we are using hmsbeagle-1. HOT 1
- Propose attachment uniformly over tree length, rather than uniformly over edges HOT 1
- Track induced split frequencies
- consider using a two-parameter lcfit? HOT 1
- License HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from sts.