Minsky
equations.h
Go to the documentation of this file.
1 /*
2  @copyright Steve Keen 2012
3  @author Russell Standish
4  This file is part of Minsky.
5 
6  Minsky is free software: you can redistribute it and/or modify it
7  under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Minsky is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Minsky. If not, see <http://www.gnu.org/licenses/>.
18 */
19 /*
20  Structures for building a mathematical representation of the Minsky
21  model as a directed acyclic graph (DAG)
22 */
23 
24 #ifndef EQUATIONS_H
25 #define EQUATIONS_H
26 
27 #include "evalOp.h"
28 #include "godleyIcon.h"
29 #include "switchIcon.h"
30 #include "lock.h"
31 
32 #include "operation.h"
33 #include <cairo_base.h>
34 #include <classdesc.h>
35 #include <ostream>
36 #include <vector>
37 #include <map>
38 #include <string>
39 #include <cstddef>
40 #include "integral.h"
41 
42 namespace minsky
43 {
44  class Minsky;
46  void doOneEvent(bool idleTasksOnly);
47 }
48 
49 namespace MathDAG
50 {
51  using namespace std;
52  using classdesc::shared_ptr;
53  using namespace minsky;
54  class SystemOfEquations;
55 
56  struct Node;
58  struct LaTeXManip
59  {
60  const Node& node;
61  LaTeXManip(const Node& node): node(node) {}
62  };
63 
64  struct MatlabManip
65  {
66  const Node& node;
67  MatlabManip(const Node& node): node(node) {}
68  };
69 
71  string latex(double);
72  // string latex(const TensorVal&);
74  string latexInit(const string&);
77  string mathrm(const string& nm);
78 
79  // string matlab(const TensorVal&);
81  string matlabInit(const string&);
82 
83  struct Node
84  {
85  virtual ~Node() {}
86 
89  virtual int BODMASlevel() const=0;
91  virtual ostream& latex(ostream&) const=0;
92  std::string latexStr() const {ostringstream o; latex(o); return o.str();}
94  virtual ostream& matlab(ostream&) const=0;
95  std::string matlabStr() const {ostringstream o; matlab(o); return o.str();}
101  virtual void render(ecolab::cairo::Surface& surf) const=0;
102 
108  virtual VariableValuePtr addEvalOps(EvalOpVector&, const VariableValuePtr& result={})=0;
111  virtual int order(unsigned maxOrder) const=0;
114  virtual bool tensorEval(std::set<const Node*>& visited) const=0;
116  bool tensorEval() {std::set<const Node*> visited; return tensorEval(visited);}
117  mutable int cachedOrder=-1;
119  LaTeXManip latex() const {return LaTeXManip(*this);}
120  MatlabManip matlab() const {return MatlabManip(*this);}
121 
123  // Done as a virtual function to ensure that all Node types get a
124  // definition, however, the actual work is delegated back to
125  // SystemOfEquations via a templated method.
126  virtual std::shared_ptr<Node> derivative(SystemOfEquations&) const=0;
129  };
130 
131  typedef std::shared_ptr<Node> NodePtr;
133  struct WeakNodePtr
134  {
136  Node& operator*() {return *payload;}
137  const Node& operator*() const {return *payload;}
138  Node* operator->() {return payload;}
139  const Node* operator->() const {return payload;}
141  {payload=x.get(); return *this;}
143  {payload=x; return *this;}
144  WeakNodePtr(): payload(nullptr) {}
145  template <class T>
146  WeakNodePtr(const std::shared_ptr<T>& x): payload(x.get()) {}
147  operator bool() const {return payload!=nullptr;}
148  };
149 
150  inline ostream& operator<<(ostream& o, LaTeXManip m)
151  {return m.node.latex(o);}
152  inline ostream& operator<<(ostream& o, MatlabManip m)
153  {return m.node.matlab(o);}
154 
155  // the presence of the result member in the base class means a ConstantDAG cannot be declared static
156  struct ConstantDAG: public Node
157  {
158  string value;
159  ConstantDAG(const string& value="0"): value(value.length()? value: "0") {}
160  ConstantDAG(double value): value(str(value)) {}
161  int BODMASlevel() const override {return 0;}
162  int order(unsigned maxOrder) const override {return 0;}
163  bool tensorEval(std::set<const Node*>&) const override {return false;}
164  ostream& latex(ostream& o) const override {return o<<value;}
165  ostream& matlab(ostream& o) const override {return o<<value;}
166  void render(ecolab::cairo::Surface& surf) const override;
167  VariableValuePtr addEvalOps(EvalOpVector&, const VariableValuePtr&) override;
168  NodePtr derivative(SystemOfEquations&) const override;
169  };
170 
171  class VariableDAG: public Node, public VariableType
172  {
173  public:
174  string valueId;
175  Type type=undefined;
176  string name;
177  string init="0";
179  IntOp* intOp=0;
180  VariableDAG() {}
182  VariableDAG(const string& valueId, const string& name, Type type):
183  valueId(valueId), type(type), name(name) {}
184  int BODMASlevel() const override {return 0;}
185  int order(unsigned maxOrder) const override {
186  if (rhs) {
187  if (cachedOrder>=0) return cachedOrder;
188  if (maxOrder==0) throw error("maximum order recursion reached");
189  return cachedOrder=rhs->order(maxOrder-1)+1;
190  }
191  else
192  return 0;
193  }
194  bool tensorEval(std::set<const Node*>&) const override;
195  using Node::tensorEval;
196  using Node::latex;
197  using Node::matlab;
198  using Node::addEvalOps;
199  ostream& latex(ostream&) const override;
200  ostream& matlab(ostream&) const override;
201  VariableValuePtr addEvalOps(EvalOpVector&, const VariableValuePtr& v={}) override;
202  void render(ecolab::cairo::Surface& surf) const override;
203  NodePtr derivative(SystemOfEquations&) const override;
205  bool addTensorOp(EvalOpVector& ev);
206  };
207 
208  typedef shared_ptr<VariableDAG> VariableDAGPtr;
209 
213  {
214  VariableValuePtr addEvalOps(EvalOpVector&,const VariableValuePtr&) override;
215  };
216 
217  struct OperationDAGBase: public Node, public OperationType
218  {
219  vector<vector<WeakNodePtr> > arguments;
220  string name;
221  string init="0";
223  OperationDAGBase(const string& name=""):
224  name(name) {}
225  virtual Type type() const=0;
227  static OperationDAGBase* create(Type type, const string& name="");
228  int order(unsigned maxOrder) const override;
229  bool tensorEval(std::set<const Node*>&) const override;
230  using Node::tensorEval;
231  VariableValuePtr addEvalOps(EvalOpVector&, const VariableValuePtr&) override;
232  void checkArg(unsigned i, unsigned j) const;
233  };
234 
235  template <OperationType::Type T>
237  {
238  Type type() const override {return T;}
239  OperationDAG(const string& name=""): OperationDAGBase(name)
240  {arguments.resize(OperationTypeInfo::numArguments<T>());}
241  int BODMASlevel() const override {
242  switch (type())
243  {
246  case OperationType::and_:
247  return 1;
249  case OperationType::add:
250  case OperationType::or_:
251  return 2;
252  case OperationType::constant: // varies, depending on what's in it
253  if (name.find_first_of("+-")!=string::npos)
254  return 2;
255  else
256  return 1;
257  default:
258  return 0;
259  }
260  }
261  ostream& latex(ostream&) const override;
262  ostream& matlab(ostream& o) const override;
263  void render(ecolab::cairo::Surface& surf) const override;
264  using Node::latex;
265  using Node::matlab;
266  NodePtr derivative(SystemOfEquations&) const override;
267  };
268 
270  struct GodleyColumnDAG: public OperationDAG<OperationType::subtract>
271  {
272  std::string name; //unqualified name of stock variable
273  int order(unsigned maxOrder) const override {return 0;} // Godley columns define integration vars
274  };
275 
276  struct LockDAG: public Node
277  {
278  const Lock& lock;
280  LockDAG(const Lock& lock): lock(lock) {}
281  int BODMASlevel() const override {return 0;}
282  ostream& latex(ostream& o) const override {return o<<"locked";}
283  ostream& matlab(ostream& o) const override {return o<<"";}
284  void render(ecolab::cairo::Surface& surf) const override;
285  VariableValuePtr addEvalOps(EvalOpVector&, const VariableValuePtr& result={}) override;
286  int order(unsigned maxOrder) const override {return rhs? rhs->order(maxOrder-1)+1:0;}
287  bool tensorEval(std::set<const Node*>&) const override {return true;}
288  std::shared_ptr<Node> derivative(SystemOfEquations&) const override
289  {lock.throw_error("derivative not defined for locked objects");}
290  };
291 
293  {
294  std::map<std::string, NodePtr > cache;
295  std::map<std::string, VariableDAGPtr> integrationInputs;
296  std::map<const Node*, NodePtr> reverseLookupCache;
297  public:
298  std::string key(const OperationBase& x) const {
299  return "op:"+std::to_string(std::size_t(x.ports(0).lock().get()));
300  }
301  std::string key(const VariableBase& x) const {
302  return "var:"+x.valueId();
303  }
304  std::string key(const SwitchIcon& x) const {
305  return "switch:"+std::to_string(std::size_t(x.ports(0).lock().get()));
306  }
307  std::string key(const Lock& x) const {
308  return "lock:"+std::to_string(std::size_t(x.ports(0).lock().get()));
309  }
311  std::string key(const string& x) const {
312  return "var:"+x;
313  }
314  template <class T>
315  bool exists(const T& x) {return cache.count(key(x));}
316  template <class T>
317  NodePtr operator[](const T& x) const {
318  auto r=cache.find(key(x));
319  if (r!=cache.end())
320  return r->second;
321  else
322  return NodePtr();
323  }
324  template <class T>
325  const NodePtr& insert(const T& x, const NodePtr& n) {
326  reverseLookupCache[n.get()]=n;
327  return cache.insert(make_pair(key(x),n)).first->second;
328  }
329  void insertIntegralInput(const string& name, const VariableDAGPtr& n) {
330  integrationInputs.insert(make_pair("input:"+name,n));
331  reverseLookupCache[n.get()]=n;
332  }
333  VariableDAGPtr getIntegralInput(const string& name) const {
334  auto r=integrationInputs.find("input:"+name);
335  if (r!=integrationInputs.end())
336  return r->second;
337  else
338  return VariableDAGPtr();
339  }
340  std::size_t size() const {return cache.size()+integrationInputs.size();}
342  NodePtr reverseLookup(const Node& x) const {
343  auto it=reverseLookupCache.find(&x);
344  if (it==reverseLookupCache.end())
345  return NodePtr();
346  else
347  return it->second;
348  }
349  // inserts x anonymously
350  //NodePtr insertAnonymous(const NodePtr& x) {
352  assert(x);
353  return reverseLookupCache.insert(make_pair(x.get(), x)).first->second;
354  }
355  };
356 
357 
359  {
361  // these are weak references
362  vector<VariableDAG*> variables;
363  vector<VariableDAG*> integrationVariables;
364  set<string> processedColumns; // to avoid double counting shared columns
365  vector<pair<VariableDAGPtr,string>> derivInputs; //handle recursively defined stock vars and derivatives
366 
367  const Minsky& minsky;
368 
370  NodePtr makeDAG(const string& valueId, const string& name, VariableType::Type type);
372  {v.ensureValueExists(v.vValue().get(),v.name()); return makeDAG(v.valueId(),uqName(v.name()),v.type());}
374  NodePtr makeDAG(const OperationBase& op);
375  NodePtr makeDAG(const SwitchIcon& op);
376  NodePtr makeDAG(const Lock& op);
377 
380  NodePtr getNodeFromWire(const Wire& wire);
381 
382  void processGodleyTable
383  (map<string, GodleyColumnDAG>& godleyVariables, const GodleyIcon&);
384 
386  template <class Expr> NodePtr chainRule(const Expr& x, const Expr& deriv);
387 
389  std::set<std::string> varNames;
391  std::set<std::string> processingDerivative;
393  std::map<std::string, std::string> userDefinedFunctions;
394  public:
396  SystemOfEquations(const Minsky&, const Group&g);
397  SystemOfEquations(const Minsky& m);
398  ostream& latex(ostream&) const;
399  ostream& latexWrapped(ostream&) const;
401  ostream& matlab(ostream&) const;
402  void populateEvalOpVector
407  (EvalOpVector& equations, std::vector<Integral>& integrals);
408 
409  // ensure all variables have their output port's variable value up
410  // to date and add evalOps for plots and sheets
411  void updatePortVariableValue(EvalOpVector& equations);
412 
413 
415  template <class Expr> NodePtr derivative(const Expr& expr);
416 
418  NodePtr zero{new ConstantDAG("0")}, one{new ConstantDAG("1")};
419 
420  VariableDAGPtr getNodeFromVar(const VariableBase& v);
421  VariableDAGPtr getNodeFromValueId(const std::string& v)
422  {return dynamic_pointer_cast<VariableDAG>(expressionCache[v]);}
424  {return expressionCache.getIntegralInput(valueId);}
425  ostringstream getDefFromIntVar(const VariableBase& v);
426 
428  void renderEquations(ecolab::cairo::Surface&, double height) const;
429  };
430 
432  std::string differentiateName(const std::string& x);
433 
434  template <> NodePtr SystemOfEquations::derivative(const ConstantDAG&);
435  template <> NodePtr SystemOfEquations::derivative(const VariableDAG&);
436 
437  template <OperationType::Type T>
439  {return se.derivative(*this);}
440 
441 }
442 
443 
444 #endif
virtual VariableValuePtr addEvalOps(EvalOpVector &, const VariableValuePtr &result={})=0
adds EvalOps to an EvalOpVector representing this node.
bool addTensorOp(const shared_ptr< VariableValue > &result, OperationDAGBase &nodeOp, EvalOpVector &ev)
Definition: equations.cc:88
LockDAG(const Lock &lock)
Definition: equations.h:280
bool exists(const T &x)
Definition: equations.h:315
Type type() const override
Definition: equations.h:238
bool tensorEval()
returns true if the evaluation of this involves tensor processing
Definition: equations.h:116
LaTeXManip latex() const
used within io streaming
Definition: equations.h:119
void doOneEvent(bool idletasksOnly)
checks if any GUI events are waiting, and proces an event if so
Definition: tclmain.cc:161
bool tensorEval(std::set< const Node *> &) const override
returns true if the evaluation of this involves tensor processing
Definition: equations.h:163
ostream & matlab(ostream &o) const override
writes a matlab representation of this DAG to the stream
Definition: equations.h:283
const Node & node
Definition: equations.h:66
ostream & latex(ostream &o) const override
writes LaTeX representation of this DAG to the stream
Definition: equations.h:282
const Minsky & minsky
Definition: equations.h:367
int BODMASlevel() const override
algebraic heirarchy level, used for working out whether brackets are necessary.
Definition: equations.h:184
const Node & operator*() const
Definition: equations.h:137
OperationDAG(const string &name="")
Definition: equations.h:239
std::string key(const OperationBase &x) const
Definition: equations.h:298
const NodePtr & insert(const T &x, const NodePtr &n)
Definition: equations.h:325
std::set< std::string > processingDerivative
keep track of derivatives of variables, to trap definition loops
Definition: equations.h:391
VariableDAG(const string &valueId, const string &name, Type type)
Definition: equations.h:182
string differentiateName(const string &x)
creates a new name to represent the derivative of a variable
Definition: derivative.cc:39
int order(unsigned maxOrder) const override
returns evaluation order in sequence of variable defintions
Definition: equations.h:286
std::size_t size() const
Definition: equations.h:340
STL namespace.
SubexpressionCache expressionCache
Definition: equations.h:360
std::shared_ptr< Item > ItemPtr
Definition: item.h:57
VariableValuePtr result
reference to where this node&#39;s value is stored
Definition: equations.h:128
std::string matlabStr() const
Definition: equations.h:95
std::string uqName(const std::string &name)
extract unqualified portion of name
Definition: valueId.cc:135
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
WeakNodePtr(const std::shared_ptr< T > &x)
Definition: equations.h:146
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
int BODMASlevel() const override
algebraic heirarchy level, used for working out whether brackets are necessary.
Definition: equations.h:281
a shared_ptr that default constructs a default target, and is always valid
virtual Type type() const =0
string latexInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_latex.cc:73
VariableDAGPtr getNodeFromIntVar(const std::string &valueId)
Definition: equations.h:423
bool tensorEval(std::set< const Node *> &) const override
returns true if the evaluation of this involves tensor processing
Definition: equations.h:287
virtual ~Node()
Definition: equations.h:85
std::map< const Node *, NodePtr > reverseLookupCache
Definition: equations.h:296
virtual int order(unsigned maxOrder) const =0
returns evaluation order in sequence of variable defintions
struct TCLcmd::trap::init_t init
std::string latexStr() const
Definition: equations.h:92
std::shared_ptr< Node > derivative(SystemOfEquations &) const override
support for the derivative operator.
Definition: equations.h:288
int order(unsigned maxOrder) const override
returns evaluation order in sequence of variable defintions
Definition: equations.h:162
OperationDAGBase(const string &name="")
Definition: equations.h:223
const Node & node
Definition: equations.h:60
ConstantDAG(const string &value="0")
Definition: equations.h:159
std::string key(const Lock &x) const
Definition: equations.h:307
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
int order(unsigned maxOrder) const override
returns evaluation order in sequence of variable defintions
Definition: equations.h:273
string matlabInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_matlab.cc:45
virtual std::string valueId() const
string used to link to the VariableValue associated with this
Definition: variable.cc:186
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
MatlabManip matlab() const
Definition: equations.h:120
int BODMASlevel() const override
algebraic heirarchy level, used for working out whether brackets are necessary.
Definition: equations.h:241
NodePtr derivative(const Expr &expr)
symbolically differentiate expr
void ensureValueExists(VariableValue *vv, const std::string &name) const
ensure an associated variableValue exists
Definition: variable.cc:262
LaTeXManip(const Node &node)
Definition: equations.h:61
std::string str(T x)
utility function to create a string representation of a numeric type
Definition: str.h:33
std::map< std::string, NodePtr > cache
Definition: equations.h:294
void throw_error(const std::string &) const
mark item on canvas, then throw
Definition: item.cc:86
ostream & matlab(ostream &o) const override
writes a matlab representation of this DAG to the stream
Definition: equations.h:165
WeakNodePtr & operator=(const NodePtr &x)
Definition: equations.h:140
std::string key(const SwitchIcon &x) const
Definition: equations.h:304
weak reference into subexpression cache
Definition: equations.h:133
ostream & operator<<(ostream &o, LaTeXManip m)
Definition: equations.h:150
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
NodePtr makeDAG(VariableBase &v)
Definition: equations.h:371
represents the input of an integration operation - differs from Variable DAG in that it doesn&#39;t refer...
Definition: equations.h:212
int order(unsigned maxOrder) const override
returns evaluation order in sequence of variable defintions
Definition: equations.h:185
virtual std::string name() const
variable displayed name
Definition: variable.cc:201
MatlabManip(const Node &node)
Definition: equations.h:67
VariableDAGPtr getNodeFromValueId(const std::string &v)
Definition: equations.h:421
const Node * operator->() const
Definition: equations.h:139
NodePtr insertAnonymous(NodePtr x)
Definition: equations.h:351
ConstantDAG(double value)
Definition: equations.h:160
void insertIntegralInput(const string &name, const VariableDAGPtr &n)
Definition: equations.h:329
std::string key(const VariableBase &x) const
Definition: equations.h:301
vector< vector< WeakNodePtr > > arguments
Definition: equations.h:219
int BODMASlevel() const override
algebraic heirarchy level, used for working out whether brackets are necessary.
Definition: equations.h:161
std::set< std::string > varNames
used to rename ambiguous variables in different scopes
Definition: equations.h:389
represents a Godley column
Definition: equations.h:270
virtual ostream & matlab(ostream &) const =0
writes a matlab representation of this DAG to the stream
vector< pair< VariableDAGPtr, string > > derivInputs
Definition: equations.h:365
std::map< std::string, std::string > userDefinedFunctions
table of user defined functions and their definitions
Definition: equations.h:393
vector< VariableDAG * > variables
Definition: equations.h:362
string latex(double)
convert double to a LaTeX string representing that value
Definition: node_latex.cc:28
virtual std::weak_ptr< Port > ports(std::size_t i) const
callback to be run when item deleted from group
Definition: item.h:180
const Lock & lock
Definition: equations.h:278
WeakNodePtr & operator=(Node *x)
Definition: equations.h:142
string to_string(CONST84 char *x)
Definition: minskyTCLObj.h:33
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
string mathrm(const string &nm)
wraps in if nm has more than one letter - and also takes into account LaTeX subscript/superscripts ...
Definition: node_latex.cc:41
NodePtr derivative(SystemOfEquations &) const override
support for the derivative operator.
Definition: equations.h:438
std::string key(const string &x) const
strings refer to variable names
Definition: equations.h:311
std::shared_ptr< VariableValue > vValue() const
variableValue associated with this. nullptr if not associated with a variableValue ...
Definition: variable.cc:161
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342
WeakNodePtr rhs
Definition: equations.h:279
a manipulator to make iostream expressions easy
Definition: equations.h:58
NodePtr operator[](const T &x) const
Definition: equations.h:317
set< string > processedColumns
Definition: equations.h:364
WeakNodePtr rhs
Definition: equations.h:178
std::map< std::string, VariableDAGPtr > integrationInputs
Definition: equations.h:295
virtual ostream & latex(ostream &) const =0
writes LaTeX representation of this DAG to the stream
ostream & latex(ostream &o) const override
writes LaTeX representation of this DAG to the stream
Definition: equations.h:164