GithubHelp home page GithubHelp logo

Comments (6)

koadman avatar koadman commented on July 28, 2024

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.

cmccoy avatar cmccoy commented on July 28, 2024

FWIW, Bio++ has some bits to deal with the event listener approach:

http://biopp.univ-montp2.fr/Documents/ClassDocumentation/bpp-core/html/classbpp_1_1Parameter.html#abfdb45447531f2ded0047e5526762eee

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.

koadman avatar koadman commented on July 28, 2024

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.

koadman avatar koadman commented on July 28, 2024

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.

cmccoy avatar cmccoy commented on July 28, 2024

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.

koadman avatar koadman commented on July 28, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.