Buildup code ideas

namespace sim
{

Accumulator protocol:

One of the traitional pitfalls in simulation is “aliasing”, whereby all parts of the world do not update at the exact same rate, depending on their order of evaluation and update. Where many parameters are interdependent in a system, say a, b and c, their values at time [t+1] should be based on values at time [t].

Example:

  a[t+1] = f( a[t] ); 
  b[t+1] = g( b[t] ); 
  c[t+1] = h( a[t], b[t] );
  But by this common error we'd have, instead,
  a[t+1] = f( a[t] ); 
  b[t+1] = g( b[t] ); 
  c[t+1] = h( a[t+1], b[t+1] ); //ERROR

To prevent this error, yet hide the implementation details of having to keep copies of the old values of a and b above, the class “accumulator” has overloaded +=, -= and other assignment operators used in numerical integration, that do not affect the value of the parameter when it is read. Accumulations are performed onto a hidden temporary and only when the function call operator is called, the value returned is updated to reflect the value accumulated in the temporary.

Example:

  typedef sim::accumulator<double> dfoo;
  dfoo a(dfoo(0.7)), b, c;
  ..................
  while(1)
  {
    ...............
    //During read/update phase, read current values, +=/-= do not change current value returned, temporary is updated.
    ...............
    //cout << a; //prints 0.7 (on first pass, of course)
    a += 0.1;
    //cout << a; //prints 0.7 (again, no apparent change)
    b -= 0.1;
    c += ( 0.1 * a - 0.1 * b );
    ...............
    //After all updates are done, tick them all
    ...............
    a();
    //cout << a; //prints 0.8 (now shows change)
    b();
    c();
    ...............
  };

Implementation follows...

template <class T>
class accumulator
{
    T  temp_;
    mutable T curr_;
public:
    typedef accumulator<T> aT;
    explicit accumulator(T val=0.0) : temp_(val), curr_(val) {}
    //default copy ctor and dtor ok.
    aT& operator=(aT const & other)
    {
        temp_ = other.temp_;
        curr_ = other.curr_;
        return *this;
    }
    virtual void print() = 0;
 
    //read/hidden-update phase of protocol functions:
    operator      T()  const  { return curr_; }
    void operator+=( T val )  { temp_ += val; }
    void operator-=( T val )  { temp_ -= val; }
    void operator++()         { temp_ += T(1); }
    void operator--()         { temp_ -= T(1); }
    void operator++(int)      { temp_ += T(1); } //same as preincrement
    void operator--(int)      { temp_ -= T(1); } //same as predecrement
    void operator*=(double x) { temp_ = T( double(temp_) * x ); }
    void operator/=(double x) { temp_ = T( double(temp_) / x ); } //no div/0 check!
    void operator= ( T val )  { temp_ = val; } //use carefully
 
    //unhide updates, our "tick"-phase function:
    void operator()()  const  { curr_ = temp_; } //const because curr_ is mutable
};

Similar to accumulator, class boolean’s return value is unaffected by assignment operators until the function operator is called.

class boolean
{
    bool  temp_;
    mutable bool curr_;
public:
    explicit boolean(bool val=false) : temp_(val), curr_(val) {}
    //default copy ctor and dtor ok.
    boolean& operator=(boolean const & other)
    {
        temp_ = other.temp_;
        curr_ = other.curr_;
        return *this;
    }
    virtual void print() = 0;
 
    //read/hidden-update phase of protocol functions:
    operator    bool()    const   { return !!curr_; }
    void operator||=( bool val )  { if(  val ) temp_ =  true; }
    void operator&&=( bool val )  { if( !val ) temp_ = false; }
    void operator=  ( bool val )  { temp_  = val!=0; } //use carefully
 
    //unhide updates, our "tick"-phase function:
    void  operator()()    const   { curr_ = temp_; } //const because curr_ is mutable
};
template <typename T>
T chk( T Min, T Max, T val )
{
    T result = val;
    assert( val >= Min );
    assert( val <= Max );
    if( val < Min ) result = Min;
    if( val > Max ) result = Max;
    return result;
}
template <float Min, float Max>
class sim_real : accumulator<float>
{
    void chk(){ *this = sim::chk( Min, Max, float(*this) );
public:
    sim_real(sim_real const & other) : accumulator(other) { chk(); }
    void operator=(sim_real const & other){ accumulator = accumulator(other); chk(); }
};
namespace params
{
  typedef sim_real<0.0f,999999999999.9f> population;
  typedef sim_real<-1.0f,+1.0f> happiness;
  typedef sim_real<-0.5,1.9f> productivity;
};
}; //end namespace sim
 
wcu/priv3/plot/partd/code.txt · Last modified: 2007/02/19 10:33 by chuck_starchaser