Minsky
MathDAG::SystemOfEquations Class Reference

#include <equations.h>

Collaboration diagram for MathDAG::SystemOfEquations:
Collaboration graph

Public Member Functions

 SystemOfEquations (const Minsky &, const Group &g)
 construct the system of equations More...
 
 SystemOfEquations (const Minsky &m)
 
ostream & latex (ostream &) const
 render as a LaTeX eqnarray Use LaTeX brqn environment to wrap long lines More...
 
ostream & latexWrapped (ostream &) const
 
ostream & matlab (ostream &) const
 render as MatLab code create equations suitable for Runge-Kutta solver More...
 
void populateEvalOpVector (EvalOpVector &equations, std::vector< Integral > &integrals)
 
void updatePortVariableValue (EvalOpVector &equations)
 
template<class Expr >
NodePtr derivative (const Expr &expr)
 symbolically differentiate expr More...
 
VariableDAGPtr getNodeFromVar (const VariableBase &v)
 
VariableDAGPtr getNodeFromValueId (const std::string &v)
 
VariableDAGPtr getNodeFromIntVar (const std::string &valueId)
 
ostringstream getDefFromIntVar (const VariableBase &v)
 
void renderEquations (ecolab::cairo::Surface &, double height) const
 render equations into a cairo context More...
 
template<>
NodePtr chainRule (const Expr &x, const Expr &deriv)
 
template<>
NodePtr derivative (const VariableDAG &expr)
 
template<>
NodePtr derivative (const ConstantDAG &)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::constant > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::add > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::subtract > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::multiply > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::divide > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::log > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::pow > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::lt > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::le > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::eq > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::and_ > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::or_ > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::not_ > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::min > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::max > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::time > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::euler > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::pi > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::zero > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::one > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::inf > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::percent > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::copy > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::integrate > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::differentiate > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::data > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::ravel > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::sqrt > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::exp > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::ln > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::sin > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::cos > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::tan > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::asin > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::acos > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::atan > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::sinh > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::cosh > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::tanh > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::abs > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::floor > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::frac > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::Gamma > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::polygamma > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::fact > &expr)
 
template<>
NodePtr derivative (const OperationDAG< OperationType::userFunction > &expr)
 

Public Attributes

NodePtr zero {new ConstantDAG("0")}
 useful constants to share More...
 
NodePtr one {new ConstantDAG("1")}
 

Private Member Functions

NodePtr makeDAG (const string &valueId, const string &name, VariableType::Type type)
 create a variable DAG. returns cached value if previously called More...
 
NodePtr makeDAG (VariableBase &v)
 
NodePtr makeDAG (const OperationBase &op)
 create an operation DAG. returns cached value if previously called More...
 
NodePtr makeDAG (const SwitchIcon &op)
 
NodePtr makeDAG (const Lock &op)
 
NodePtr getNodeFromWire (const Wire &wire)
 returns cached subexpression node representing what feeds the wire, creating a new one if necessary More...
 
void processGodleyTable (map< string, GodleyColumnDAG > &godleyVariables, const GodleyIcon &)
 
template<class Expr >
NodePtr chainRule (const Expr &x, const Expr &deriv)
 applies the chain rule to expression x More...
 

Private Attributes

SubexpressionCache expressionCache
 
vector< VariableDAG * > variables
 
vector< VariableDAG * > integrationVariables
 
set< string > processedColumns
 
vector< pair< VariableDAGPtr, string > > derivInputs
 
const Minskyminsky
 
std::set< std::string > varNames
 used to rename ambiguous variables in different scopes More...
 
std::set< std::string > processingDerivative
 keep track of derivatives of variables, to trap definition loops More...
 
std::map< std::string, std::string > userDefinedFunctions
 table of user defined functions and their definitions More...
 

Detailed Description

Definition at line 358 of file equations.h.

Constructor & Destructor Documentation

◆ SystemOfEquations() [1/2]

MathDAG::SystemOfEquations::SystemOfEquations ( const Minsky m,
const Group g 
)

construct the system of equations

Definition at line 460 of file equations.cc.

References minsky::Minsky::canvas, derivInputs, expressionCache, MathDAG::SubexpressionCache::getIntegralInput(), getNodeFromWire(), minsky::GroupItems::groups, TCLcmd::trap::init, MathDAG::SubexpressionCache::insertAnonymous(), MathDAG::SubexpressionCache::insertIntegralInput(), integrationVariables, MathDAG::VariableDAG::intOp, minsky::Canvas::itemIndicator, minsky::GroupItems::items, makeDAG(), minsky::minsky(), minsky::Minsky::model, MathDAG::VariableDAG::name, one, processGodleyTable(), MathDAG::VariableDAG::rhs, MathDAG::SubexpressionCache::size(), minsky::VariableType::stock, minsky::VariableType::typeName(), minsky::uqName(), userDefinedFunctions, variables, minsky::Minsky::variableValues, and zero.

460  : minsky(m)
461  {
464  zero->result=m.variableValues.find("constant:zero")->second;
465  one->result=m.variableValues.find("constant:one")->second;
466 
467  // store stock & integral variables for later reordering
468  map<string, VariableDAG*> integVarMap;
469 
470  vector<pair<VariableDAGPtr,Wire*>> integralInputs;
471  // list of stock vars whose input expression has not yet been calculated when the derivative operator is called.
472 
473  // search through operations looking for integrals
474  group.recursiveDo
475  (&Group::items,
476  [&](const Items&, Items::const_iterator it){
477  if (auto v=(*it)->variableCast())
478  {
479  // check variable is not multiply defined
480  if (v->inputWired() && v!=minsky.definingVar(v->valueId()).get())
481  {
482  minsky.displayErrorItem(*v);
483  throw runtime_error("Multiply defined");
484  }
485  // check that variable's type matches it's variableValue's type (see ticket #1087)
486  if (auto vv=v->vValue())
487  if (vv->type() != v->type())
488  {
489  minsky.displayErrorItem(*v);
490  throw error("type %s of variable %s doesn't match it's value's type %s",VariableType::typeName(v->type()).c_str(), v->name().c_str(), VariableType::typeName(vv->type()).c_str());
491  }
492  }
493  else if (IntOp* i=dynamic_cast<IntOp*>(it->get()))
494  {
495  if (const VariablePtr iv=i->intVar)
496  {
497  // .get() OK here because object lifetime controlled by
498  // expressionCache
499  VariableDAG* v=integVarMap[iv->valueId()]=
500  dynamic_cast<VariableDAG*>(makeDAG(*iv).get());
501  v->intOp=i;
502  if (!i->ports(1).lock()->wires().empty())
503  {
504  // with integrals, we need to create a distinct variable to
505  // prevent infinite recursion of order() in the case of graph cycles
506  const VariableDAGPtr input(new IntegralInputVariableDAG);
507  input->name=iv->name();
508  variables.push_back(input.get());
509  // manage object's lifetime with expressionCache
510  expressionCache.insertIntegralInput(iv->valueId(), input);
511  try
512  {input->rhs=getNodeFromWire(*(i->ports(1).lock()->wires()[0]));}
513  catch (...)
514  {
515  // try again later
516  integralInputs.emplace_back(input,i->ports(1).lock()->wires()[0]);
517  // clear error indicator
519  }
520  }
521 
522  if (!i->ports(2).lock()->wires().empty())
523  {
524  // second port can be attached to a variable,
525  // which supplies an init string
526  NodePtr init;
527  try
528  {
529  init=getNodeFromWire(*(i->ports(2).lock()->wires()[0]));
530  }
531  catch (...) {}
532  if (auto v=dynamic_cast<VariableDAG*>(init.get()))
533  iv->init(uqName(v->name));
534  else if (auto c=dynamic_cast<ConstantDAG*>(init.get()))
535  {
536  // slightly convoluted to prevent sliderSet from overriding c->value
537  iv->init(c->value);
538  if (auto vv=iv->vValue()) vv->adjustSliderBounds();
539  }
540  else
541  throw error("only constants, parameters and variables can be connected to the initial value port");
542  }
543 
544  }
545  }
546  else if (auto fn=dynamic_cast<UserFunction*>(it->get()))
547  {
548  userDefinedFunctions.emplace(fn->description(), fn->expression);
549  }
550  return false;
551  });
552 
553  // add groups to the userDefinedFunctions table
554  group.recursiveDo
555  (&Group::groups,
556  [&](const Groups&, Groups::const_iterator it){
557  if (!(*it)->name().empty())
558  try
559  {
560  userDefinedFunctions.emplace((*it)->name()+(*it)->arguments(), (*it)->formula());
561  }
562  catch (const std::exception&)
563  {/* if we can't generate a function definition, too bad, too sad. */}
564  return false;
565  });
566 
567  // add input variables for all stock variables to the expression cache
568  group.recursiveDo
569  (&Group::items,
570  [&](const Items&, Items::const_iterator it){
571  if (auto i=dynamic_cast<Variable<VariableType::stock>*>(it->get()))
572  if (!expressionCache.getIntegralInput(i->valueId()))
573  {
574  const VariableDAGPtr input(new IntegralInputVariableDAG);
575  input->name=i->name();
576  variables.push_back(input.get());
577  // manage object's lifetime with expressionCache
579  }
580  return false;
581  });
582 
583  // wire up integral inputs, now that all integrals are defined, so that derivative works. See #511
584  for (auto& i: integralInputs)
585  i.first->rhs=getNodeFromWire(*i.second);
586 
587  // process the Godley tables
588  derivInputs.clear();
589  map<string, GodleyColumnDAG> godleyVars;
590  group.recursiveDo
591  (&Group::items,
592  [&](const Items&, Items::const_iterator i)
593  {
594  if (auto g=dynamic_cast<GodleyIcon*>(i->get()))
595  processGodleyTable(godleyVars, *g);
596  return false;
597  });
598 
599  for (auto& g: godleyVars)
600  {
601  integVarMap[g.first]=dynamic_cast<VariableDAG*>
602  (makeDAG(g.first,
603  g.second.name, VariableValue::stock).get());
604  if (auto integralInput=expressionCache.getIntegralInput(g.first))
605  integralInput->rhs=expressionCache.insertAnonymous(make_shared<GodleyColumnDAG>(g.second));
606  }
607 
608  // fix up broken derivative computations, now that all stock vars
609  // are defined. See ticket #1087
610  for (auto& i: derivInputs)
611  if (auto ii=expressionCache.getIntegralInput(i.second))
612  {
613  if (ii->rhs)
614  {
615  i.first->rhs=ii->rhs;
616  continue;
617  }
618  }
619  else
620  throw runtime_error("Unable to differentiate "+i.second);
621 
622 // // check that all integral input variables now have a rhs defined,
623 // // so that derivatives can be processed correctly
624 // group.recursiveDo
625 // (&Group::items,
626 // [&](const Items&, Items::const_iterator i)
627 // {
628 // if (auto g=dynamic_cast<GodleyIcon*>(i->get()))
629 // for (auto& v: g->flowVars())
630 // if (auto vv=minsky.definingVar(v->valueId()))
631 // {
632 // auto vd=makeDAG(*vv);
633 // static_cast<VariableDAG*>(vd.get())->rhs=getNodeFromWire(*vv->ports[1]->wires()[0]);
634 // }
635 // return false;
636 // });
637 
638 
639 
640  for (auto& v: integVarMap)
641  integrationVariables.push_back(v.second);
642 
643  if (&group==m.model.get())
644  {
645  for (auto& v: m.variableValues)
646  if (v.second->isFlowVar())
647  if (auto vv=dynamic_cast<VariableDAG*>
648  (makeDAG(v.first, v.second->name, v.second->type()).get()))
649  variables.push_back(vv);
650 
651  // sort variables into their order of definition
652  sort(variables.begin(), variables.end(),
653  VariableDefOrder(expressionCache.size()));
654  }
655  else
656  {
657  // now start with the variables, and work our way back to how they
658  // are defined
659  const VariableDefOrder variableDefOrder(expressionCache.size()+m.variableValues.size());
660  set<VariableDAG*,VariableDefOrder> variableSet(variableDefOrder);
661  group.recursiveDo
662  (&Group::items,
663  [&](const Items&, Items::const_iterator it){
664  if (auto v=(*it)->variableCast())
665  if (auto vv=v->vValue())
666  if (auto dag=dynamic_cast<VariableDAG*>
667  (makeDAG(v->valueId(), vv->name, vv->type()).get()))
668  variableSet.insert(dag);
669  return false;
670  });
671  // TODO - if we can pass VariableDefOrder to the definition of variableSet, we don't need to resort...
672  variables.insert(variables.end(), variableSet.begin(), variableSet.end());
673  }
674  }
std::string name() const override
Definition: group.h:241
Definition: input.py:1
const Minsky & minsky
Definition: equations.h:367
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
VariableValues variableValues
Definition: minsky.h:200
std::size_t size() const
Definition: equations.h:340
SubexpressionCache expressionCache
Definition: equations.h:360
std::string uqName(const std::string &name)
extract unqualified portion of name
Definition: valueId.cc:135
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
NodePtr zero
useful constants to share
Definition: equations.h:418
struct TCLcmd::trap::init_t init
ItemPtr itemIndicator
for drawing error indicator on the canvas
Definition: canvas.h:120
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
std::vector< ItemPtr > Items
Definition: item.h:366
void processGodleyTable(map< string, GodleyColumnDAG > &godleyVariables, const GodleyIcon &)
Definition: equations.cc:1074
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
Canvas canvas
Definition: minsky.h:256
std::vector< GroupPtr > Groups
Definition: group.h:54
static std::string typeName(int t)
Definition: variableType.cc:30
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
Groups groups
Definition: group.h:79
NodePtr insertAnonymous(NodePtr x)
Definition: equations.h:351
void insertIntegralInput(const string &name, const VariableDAGPtr &n)
Definition: equations.h:329
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
GroupPtr model
Definition: minsky.h:255
vector< VariableDAG * > variables
Definition: equations.h:362
Definition: group.tcl:84
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
Minsky & minsky()
global minsky object
Definition: minskyTCL.cc:51
Here is the call graph for this function:

◆ SystemOfEquations() [2/2]

MathDAG::SystemOfEquations::SystemOfEquations ( const Minsky m)

Definition at line 457 of file equations.cc.

457 : SystemOfEquations(m,*m.model) {}
SystemOfEquations(const Minsky &, const Group &g)
construct the system of equations
Definition: equations.cc:460
GroupPtr model
Definition: minsky.h:255

Member Function Documentation

◆ chainRule() [1/2]

template<>
NodePtr MathDAG::SystemOfEquations::chainRule ( const Expr x,
const Expr deriv 
)

Definition at line 68 of file derivative.cc.

69  {
70  const NodePtr dx=x->derivative(*this);
71  // perform some constant optimisation
72  if (dx==zero)
73  return zero;
74  if (dx==one)
75  return deriv;
76  return dx * deriv;
77  }
NodePtr zero
useful constants to share
Definition: equations.h:418
std::shared_ptr< Node > NodePtr
Definition: equations.h:131

◆ chainRule() [2/2]

template<class Expr >
NodePtr MathDAG::SystemOfEquations::chainRule ( const Expr x,
const Expr deriv 
)
private

applies the chain rule to expression x

◆ derivative() [1/49]

NodePtr MathDAG::SystemOfEquations::derivative ( const VariableDAG expr)

Definition at line 80 of file derivative.cc.

References MathDAG::Node::derivative(), MathDAG::differentiateName(), minsky::VariableType::integral, MathDAG::VariableDAG::name, MathDAG::VariableDAG::rhs, minsky::VariableType::stock, minsky::VariableType::tempFlow, MathDAG::VariableDAG::type, and MathDAG::VariableDAG::valueId.

81  {
82  const string name=differentiateName(expr.name);
83  // ensure variable value exists, even if only temporary
84  const VariablePtr tmp(VariableType::tempFlow, name);
85  VariableDAGPtr r(dynamic_pointer_cast<VariableDAG>(makeDAG(tmp->valueId(),tmp->name(),tmp->type())));
86  if (expr.rhs)
87  {
88  if (processingDerivative.contains(expr.name))
89  throw error("definition loop detected in processing derivative of %s",expr.name.c_str());
90  processingDerivative.insert(expr.name);
91  r->rhs=expr.rhs->derivative(*this);
92  processingDerivative.erase(expr.name);
93  }
94  else if (expr.type==VariableType::integral || expr.type==VariableType::stock)
95  {
96  auto ii=expressionCache.getIntegralInput(expr.valueId);
97  if (!ii)
98  throw error("integral input %s not defined",expr.valueId.c_str());
99  if (ii->rhs)
100  r->rhs=ii->rhs; // elide input variable, in case this is a temporary
101  else
102  derivInputs.emplace_back(r, expr.valueId);
103  }
104  else
105  {
106  r->rhs=zero;
107  return zero;
108  }
109  assert(expressionCache.reverseLookup(*r));
110  return r;
111  }
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
std::set< std::string > processingDerivative
keep track of derivatives of variables, to trap definition loops
Definition: equations.h:391
string differentiateName(const string &x)
creates a new name to represent the derivative of a variable
Definition: derivative.cc:39
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
vector< pair< VariableDAGPtr, string > > derivInputs
Definition: equations.h:365
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342
Here is the call graph for this function:

◆ derivative() [2/49]

NodePtr MathDAG::SystemOfEquations::derivative ( const ConstantDAG )

Definition at line 114 of file derivative.cc.

115  {
116  return zero;
117  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [3/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::constant > &  expr)

Definition at line 121 of file derivative.cc.

122  {
123  return zero;
124  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [4/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::add > &  expr)

Definition at line 128 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

129  {
130  CachedOp<OperationType::add> r(expressionCache);
131  r->arguments.resize(expr.arguments.size());
132  for (size_t i=0; i<expr.arguments.size(); ++i)
133  for (WeakNodePtr n: expr.arguments[i])
134  {
135  assert(expressionCache.reverseLookup(*n));
136  r->arguments[i].push_back(n->derivative(*this));
137  assert(expressionCache.reverseLookup(*r->arguments[i].back()));
138  }
139  assert(expressionCache.reverseLookup(*r));
140  return r;
141  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342

◆ derivative() [5/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::subtract > &  expr)

Definition at line 145 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

146  {
147  CachedOp<OperationType::subtract> r(expressionCache);
148  r->arguments.resize(expr.arguments.size());
149  for (size_t i=0; i<expr.arguments.size(); ++i)
150  for (WeakNodePtr n: expr.arguments[i])
151  r->arguments[i].push_back(n->derivative(*this));
152  assert(expressionCache.reverseLookup(*r));
153  return r;
154  }
SubexpressionCache expressionCache
Definition: equations.h:360
vector< vector< WeakNodePtr > > arguments
Definition: equations.h:219
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342

◆ derivative() [6/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::multiply > &  expr)

Definition at line 158 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

159  {
160  // unfold arguments into a single list
161  vector<WeakNodePtr> args;
162  for (size_t i=0; i<expr.arguments.size(); ++i)
163  for (const WeakNodePtr n: expr.arguments[i])
164  args.push_back(n);
165 
166  // remember multiplies are n-ary, not binary. eg
167  // (uvw)' = u'(vw)+v'(uw)+w'(uv)
168 
169  CachedOp<OperationType::add> r(expressionCache);
170  assert(!r->arguments.empty());
171 
172  for (size_t i=0; i<args.size(); ++i)
173  {
174  const CachedOp<OperationType::multiply> p(expressionCache);
175  r->arguments[0].push_back(p);
176  assert(!p->arguments.empty());
177  for (size_t j=0; j<args.size(); ++j)
178  if (j!=i)
179  p->arguments[0].push_back(args[j]);
180  p->arguments[0].push_back(args[i]->derivative(*this));
181  assert(expressionCache.reverseLookup(*p->arguments[0].back()));
182  }
183 
184  assert(expressionCache.reverseLookup(*r));
185  return r;
186  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr derivative(const Expr &expr)
symbolically differentiate expr
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342

◆ derivative() [7/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::divide > &  expr)

Definition at line 190 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

191  {
192  // remember divides are n-ary, not binary. So convert each
193  // argument list into a product expression, and then perform the
194  // standard binary quotient rule. u=numerator, v=denominator
195  // d(u/v) = (vdu-udv)/v^2
196 
197  const CachedOp<OperationType::multiply> u1(expressionCache), v1(expressionCache);
198 
199  assert(expr.arguments.size()==2);
200  assert(!u1->arguments.empty() && !v1->arguments.empty());
201 
202  // check all arguments are cached
203 #ifndef NDEBUG
204  for (auto av: expr.arguments)
205  for (auto a: av)
206  assert(a && expressionCache.reverseLookup(*a));
207 #endif
208 
209  u1->arguments[0]=expr.arguments[0];
210  v1->arguments[0]=expr.arguments[1];
211 
212  const Expr u(expressionCache,u1), v(expressionCache,v1);
213  const Expr du(expressionCache, u->derivative(*this)), dv(expressionCache, v->derivative(*this));
214 
215  NodePtr r = (v*du-u*dv)/(v*v);
216  assert(expressionCache.reverseLookup(*r));
217  return r;
218  }
SubexpressionCache expressionCache
Definition: equations.h:360
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342

◆ derivative() [8/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::log > &  expr)

Definition at line 221 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::log().

222  {
223  // log_b(x) = ln(x)/ln(b)
224  assert(expr.arguments.size()==2);
225  if (expr.arguments[0].empty())
226  return zero;
227  const Expr x(expressionCache, expressionCache.reverseLookup(*expr.arguments[0][0]));
228  if (expr.arguments[1].empty())
229  return x->derivative(*this)/x;
230  const Expr b(expressionCache, expressionCache.reverseLookup(*expr.arguments[1][0]));
231  return (log(x)/log(b))->derivative(*this);
232  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418
NodePtr derivative(const Expr &expr)
symbolically differentiate expr
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342
Expr log(const Expr &x)
Definition: expr.h:120
Here is the call graph for this function:

◆ derivative() [9/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::pow > &  expr)

Definition at line 237 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, MathDAG::exp(), and MathDAG::log().

238  {
239  // x^y = exp(y*ln(x))
240  assert(expr.arguments.size()==2);
241  if (expr.arguments[0].empty())
242  return zero;
243  if (expr.arguments[1].empty())
244  {
245  const Expr x(expressionCache, expr.arguments[0][0]);
246  const Expr dx(expressionCache, x->derivative(*this));
247  return dx * x;
248  }
249  const Expr x(expressionCache, expr.arguments[0][0]);
250  const Expr y(expressionCache, expr.arguments[1][0]);
251  return exp(y * log(x))->derivative(*this);
252  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418
Expr exp(const Expr &x)
Definition: expr.h:126
Expr log(const Expr &x)
Definition: expr.h:120
Here is the call graph for this function:

◆ derivative() [10/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::lt > &  expr)

Definition at line 256 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

257  {
258  if (expr.arguments[0].empty())
259  return zero;
260  throw error("lt is not differentiable");
261  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [11/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::le > &  expr)

Definition at line 265 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

266  {
267  if (expr.arguments[0].empty())
268  return zero;
269  throw error("le is not differentiable");
270  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [12/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::eq > &  expr)

Definition at line 274 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

275  {
276  if (expr.arguments[0].empty())
277  return zero;
278  throw error("eq is not differentiable");
279  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [13/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::and_ > &  expr)

Definition at line 283 of file derivative.cc.

284  {
285  return zero;
286  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [14/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::or_ > &  expr)

Definition at line 290 of file derivative.cc.

291  {
292  return zero;
293  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [15/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::not_ > &  expr)

Definition at line 297 of file derivative.cc.

298  {
299  return zero;
300  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [16/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::min > &  expr)

Definition at line 306 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

307  {
308  assert(expr.arguments.size()==2);
309  auto tmp=make_shared<OperationDAG<OperationType::min>>(expr);
310  // combine all arguments
311  tmp->arguments[1].clear();
312  for (auto i: expr.arguments[1])
313  tmp->arguments[0].push_back(i);
314 
315  switch (tmp->arguments[0].size())
316  {
317  case 0:
318  return zero;
319  case 1:
320  return tmp->arguments[0][0]->derivative(*this);
321  default:
322  {
323  const Expr x(expressionCache,tmp->arguments[0].back());
324  tmp->arguments[0].pop_back();
325  const Expr y(expressionCache,NodePtr(tmp));
326  return (x<=y)*x->derivative(*this) +
327  (1-(x<=y))*y->derivative(*this);
328  }
329  };
330  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418
std::shared_ptr< Node > NodePtr
Definition: equations.h:131

◆ derivative() [17/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::max > &  expr)

Definition at line 336 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

337  {
338  assert(expr.arguments.size()==2);
339  auto tmp=make_shared<OperationDAG<OperationType::max>>(expr);
340  // combine all arguments
341  tmp->arguments[1].clear();
342  for (auto i: expr.arguments[1])
343  tmp->arguments[0].push_back(i);
344 
345  switch (tmp->arguments[0].size())
346  {
347  case 0:
348  return zero;
349  case 1:
350  return tmp->arguments[0][0]->derivative(*this);
351  default:
352  {
353  const Expr x(expressionCache,tmp->arguments[0].back());
354  tmp->arguments[0].pop_back();
355  const Expr y(expressionCache,NodePtr(tmp));
356  return (x<=y)*y->derivative(*this) +
357  (1-(x<=y))*x->derivative(*this);
358  }
359  };
360  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418
std::shared_ptr< Node > NodePtr
Definition: equations.h:131

◆ derivative() [18/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::time > &  expr)

Definition at line 364 of file derivative.cc.

365  {
366  return one;
367  }

◆ derivative() [19/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::euler > &  expr)

Definition at line 371 of file derivative.cc.

372  {
373  return zero;
374  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [20/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::pi > &  expr)

Definition at line 378 of file derivative.cc.

379  {
380  return zero;
381  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [21/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::zero > &  expr)

Definition at line 385 of file derivative.cc.

386  {
387  return zero;
388  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [22/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::one > &  expr)

Definition at line 392 of file derivative.cc.

393  {
394  return zero;
395  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [23/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::inf > &  expr)

Definition at line 399 of file derivative.cc.

400  {
401  return zero;
402  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [24/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::percent > &  expr)

Definition at line 406 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

407  {
408  if (expr.arguments[0].empty())
409  return zero;
410  const Expr x(expressionCache, expr.arguments[0][0]);
411  return (100*x)->derivative(*this);
412  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [25/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::copy > &  expr)

Definition at line 416 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

417  {
418  if (!expr.arguments[0].empty() && expr.arguments[0][0])
419  return expr.arguments[0][0]->derivative(*this);
420  return zero;
421  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [26/49]

template<class Expr >
NodePtr MathDAG::SystemOfEquations::derivative ( const Expr expr)

symbolically differentiate expr

◆ derivative() [27/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::integrate > &  expr)

Definition at line 425 of file derivative.cc.

426  {
427  throw error("shouldn't be executed");
428  }

◆ derivative() [28/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::differentiate > &  expr)

Definition at line 432 of file derivative.cc.

433  {
434  throw error("shouldn't be executed");
435  }

◆ derivative() [29/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::data > &  expr)

Definition at line 439 of file derivative.cc.

440  {
441  throw error("cannot differentiate an empirical curve");
442  }

◆ derivative() [30/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::ravel > &  expr)

Definition at line 446 of file derivative.cc.

447  {
448  throw error("cannot differentiate an empirical curve");
449  }

◆ derivative() [31/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::sqrt > &  expr)

Definition at line 453 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::sqrt().

454  {
455  if (expr.arguments[0].empty())
456  return zero;
457  const Expr x(expressionCache, expr.arguments[0][0]);
458  return chainRule(x, 0.5/sqrt(x));
459  }
Expr sqrt(const Expr &x)
Definition: expr.h:154
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [32/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::exp > &  expr)

Definition at line 463 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::exp().

464  {
465  if (expr.arguments[0].empty())
466  return zero;
467  const Expr x(expressionCache, expr.arguments[0][0]);
468  const Expr expx(expressionCache, expressionCache.reverseLookup(expr));
469  return chainRule(x, exp(x));
470  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Expr exp(const Expr &x)
Definition: expr.h:126
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342
Here is the call graph for this function:

◆ derivative() [33/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::ln > &  expr)

Definition at line 474 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

475  {
476  if (expr.arguments[0].empty())
477  return zero;
478  const Expr x(expressionCache, expr.arguments[0][0]);
479  return chainRule(x, 1/x);
480  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [34/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::sin > &  expr)

Definition at line 484 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::cos().

485  {
486  if (expr.arguments[0].empty())
487  return zero;
488  const Expr x(expressionCache, expr.arguments[0][0]);
489  return chainRule(x,cos(x));
490  }
Expr cos(const Expr &x)
Definition: expr.h:137
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [35/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::cos > &  expr)

Definition at line 494 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::sin().

495  {
496  if (expr.arguments[0].empty())
497  return zero;
498  const Expr x(expressionCache, expr.arguments[0][0]);
499  return chainRule(x,-1*sin(x));
500  }
Expr sin(const Expr &x)
Definition: expr.h:131
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [36/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::tan > &  expr)

Definition at line 505 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::cos().

506  {
507  if (expr.arguments[0].empty())
508  return zero;
509  const Expr x(expressionCache, expr.arguments[0][0]);
510  const Expr secx=1/cos(x);
511  return chainRule(x,secx * secx);
512  }
Expr cos(const Expr &x)
Definition: expr.h:137
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [37/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::asin > &  expr)

Definition at line 516 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::sqrt().

517  {
518  if (expr.arguments[0].empty())
519  return zero;
520  const Expr x(expressionCache, expr.arguments[0][0]);
521  return chainRule(x, 1/sqrt(1-x*x));
522  }
Expr sqrt(const Expr &x)
Definition: expr.h:154
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [38/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::acos > &  expr)

Definition at line 526 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::sqrt().

527  {
528  if (expr.arguments[0].empty())
529  return zero;
530  const Expr x(expressionCache, expr.arguments[0][0]);
531  return chainRule(x, -1/sqrt(1-x*x));
532  }
Expr sqrt(const Expr &x)
Definition: expr.h:154
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [39/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::atan > &  expr)

Definition at line 536 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

537  {
538  if (expr.arguments[0].empty())
539  return zero;
540  const Expr x(expressionCache, expr.arguments[0][0]);
541  return chainRule(x, 1/(1+x*x));
542  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [40/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::sinh > &  expr)

Definition at line 546 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::cosh().

547  {
548  if (expr.arguments[0].empty())
549  return zero;
550  const Expr x(expressionCache, expr.arguments[0][0]);
551  return chainRule(x, cosh(x));
552  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Expr cosh(const Expr &x)
Definition: expr.h:148
Here is the call graph for this function:

◆ derivative() [41/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::cosh > &  expr)

Definition at line 556 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::sinh().

557  {
558  if (expr.arguments[0].empty())
559  return zero;
560  const Expr x(expressionCache, expr.arguments[0][0]);
561  return chainRule(x, sinh(x));
562  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Expr sinh(const Expr &x)
Definition: expr.h:142
Here is the call graph for this function:

◆ derivative() [42/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::tanh > &  expr)

Definition at line 566 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::cosh().

567  {
568  if (expr.arguments[0].empty())
569  return zero;
570  const Expr x(expressionCache, expr.arguments[0][0]);
571  const Expr sech=1/cosh(x);
572  return chainRule(x, sech*sech);
573  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Expr cosh(const Expr &x)
Definition: expr.h:148
Here is the call graph for this function:

◆ derivative() [43/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::abs > &  expr)

Definition at line 577 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

578  {
579  if (expr.arguments[0].empty())
580  return zero;
581  const Expr x(expressionCache, expr.arguments[0][0]);
582  return chainRule(x, (one-2*(x<=zero)));
583  }
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [44/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::floor > &  expr)

Definition at line 587 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

588  {
589  if (expr.arguments[0].empty())
590  return zero;
591  // should really be δ(x-⌊x⌋)
592  throw error("floor is not differentiable");
593  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [45/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::frac > &  expr)

Definition at line 597 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments.

598  {
599  if (expr.arguments[0].empty())
600  return zero;
601  throw error("frac is not differentiable");
602  }
NodePtr zero
useful constants to share
Definition: equations.h:418

◆ derivative() [46/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::Gamma > &  expr)

Definition at line 606 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, MathDAG::Gamma(), and MathDAG::polygamma().

607  {
608  if (expr.arguments[0].empty())
609  return zero;
610  const Expr x(expressionCache, expr.arguments[0][0]);
611  return chainRule(x,polygamma(x,Expr(expressionCache,zero))*Gamma(x));
612  }
Expr polygamma(const Expr &x, const Expr &y)
Definition: expr.h:166
Expr Gamma(const Expr &x)
Definition: expr.h:160
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [47/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::polygamma > &  expr)

Definition at line 616 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, and MathDAG::polygamma().

617  {
618  assert(expr.arguments.size()==2);
619  if (expr.arguments[0].empty())
620  return zero;
621  const Expr x(expressionCache, expressionCache.reverseLookup(*expr.arguments[0][0]));
622  if (expr.arguments[1].empty())
623  return chainRule(x,polygamma(x,Expr(expressionCache, one)));
624  return chainRule(x,polygamma(x,1+Expr(expressionCache, expr.arguments[1][0])));
625  }
Expr polygamma(const Expr &x, const Expr &y)
Definition: expr.h:166
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
NodePtr reverseLookup(const Node &x) const
returns NodePtr corresponding to object , if it exists in cache, nullptr otherwise ...
Definition: equations.h:342
Here is the call graph for this function:

◆ derivative() [48/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::fact > &  expr)

Definition at line 629 of file derivative.cc.

References MathDAG::OperationDAGBase::arguments, MathDAG::Gamma(), and MathDAG::polygamma().

630  {
631  if (expr.arguments[0].empty())
632  return zero;
633  const Expr x(expressionCache, expr.arguments[0][0]);
634  return chainRule(x,polygamma(1+x,Expr(expressionCache,zero))*Gamma(1+x));
635  }
Expr polygamma(const Expr &x, const Expr &y)
Definition: expr.h:166
Expr Gamma(const Expr &x)
Definition: expr.h:160
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr chainRule(const Expr &x, const Expr &deriv)
applies the chain rule to expression x
NodePtr zero
useful constants to share
Definition: equations.h:418
Here is the call graph for this function:

◆ derivative() [49/49]

template<>
NodePtr MathDAG::SystemOfEquations::derivative ( const OperationDAG< OperationType::userFunction > &  expr)

Definition at line 639 of file derivative.cc.

640  {throw error("Derivatives of user defined functions not implemented");}

◆ getDefFromIntVar()

ostringstream MathDAG::SystemOfEquations::getDefFromIntVar ( const VariableBase v)

Definition at line 891 of file equations.cc.

References expressionCache, MathDAG::SubexpressionCache::getIntegralInput(), and minsky::VariableBase::valueId().

Referenced by minsky::VariableBase::definition().

892  {
893  ostringstream o;
894 
896  if (input && input->rhs) input->rhs->latex(o);
897 
898  return o;
899  }
Definition: input.py:1
SubexpressionCache expressionCache
Definition: equations.h:360
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
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNodeFromIntVar()

VariableDAGPtr MathDAG::SystemOfEquations::getNodeFromIntVar ( const std::string &  valueId)
inline

Definition at line 423 of file equations.h.

References MathDAG::SubexpressionCache::getIntegralInput(), and minsky::valueId().

Referenced by minsky::VariableValue::summary().

SubexpressionCache expressionCache
Definition: equations.h:360
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNodeFromValueId()

VariableDAGPtr MathDAG::SystemOfEquations::getNodeFromValueId ( const std::string &  v)
inline

Definition at line 421 of file equations.h.

Referenced by minsky::VariableValue::summary().

422  {return dynamic_pointer_cast<VariableDAG>(expressionCache[v]);}
SubexpressionCache expressionCache
Definition: equations.h:360
Here is the caller graph for this function:

◆ getNodeFromVar()

VariableDAGPtr MathDAG::SystemOfEquations::getNodeFromVar ( const VariableBase v)

Definition at line 882 of file equations.cc.

References MathDAG::SubexpressionCache::exists(), expressionCache, makeDAG(), and minsky::VariableType::undefined.

Referenced by minsky::Group::arguments(), minsky::VariableBase::definition(), and minsky::Group::formula().

883  {
884  NodePtr r;
885  if (expressionCache.exists(v))
886  return dynamic_pointer_cast<VariableDAG>(expressionCache[v]);
887  if (v.type()!=VariableBase::undefined) r=makeDAG(const_cast<VariableBase&>(v));
888  return dynamic_pointer_cast<VariableDAG>(r);
889  }
bool exists(const T &x)
Definition: equations.h:315
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
SubexpressionCache expressionCache
Definition: equations.h:360
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
Here is the call graph for this function:
Here is the caller graph for this function:

◆ getNodeFromWire()

NodePtr MathDAG::SystemOfEquations::getNodeFromWire ( const Wire wire)
private

returns cached subexpression node representing what feeds the wire, creating a new one if necessary

Definition at line 846 of file equations.cc.

References MathDAG::SubexpressionCache::exists(), expressionCache, makeDAG(), minsky::VariableType::undefined, and minsky::wire.

Referenced by makeDAG(), SystemOfEquations(), and updatePortVariableValue().

847  {
848  if (auto p=wire.from())
849  {
850  auto& item=p->item();
851  if (auto o=item.operationCast())
852  {
853  if (expressionCache.exists(*o))
854  return expressionCache[*o];
855  // we're wired to an operation
856  return makeDAG(*o);
857  }
858  if (auto v=item.variableCast())
859  {
860  if (expressionCache.exists(*v))
861  return expressionCache[*v];
862  if (v && v->type()!=VariableBase::undefined)
863  // we're wired to a variable
864  return makeDAG(*v);
865  }
866  else if (auto s=dynamic_cast<SwitchIcon*>(&item))
867  {
868  if (expressionCache.exists(*s))
869  return expressionCache[*s];
870  return makeDAG(*s);
871  }
872  else if (auto l=dynamic_cast<Lock*>(&item))
873  {
874  if (expressionCache.exists(*l))
875  return expressionCache[*l];
876  return makeDAG(*l);
877  }
878  }
879  return {};
880  }
bool exists(const T &x)
Definition: equations.h:315
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
SubexpressionCache expressionCache
Definition: equations.h:360
Here is the call graph for this function:
Here is the caller graph for this function:

◆ latex()

ostream & MathDAG::SystemOfEquations::latex ( ostream &  o) const

render as a LaTeX eqnarray Use LaTeX brqn environment to wrap long lines

Definition at line 902 of file equations.cc.

References minsky::VariableType::constant, expressionCache, MathDAG::SubexpressionCache::getIntegralInput(), integrationVariables, MathDAG::latexInit(), MathDAG::mathrm(), minsky::VariableType::tempFlow, userDefinedFunctions, and variables.

Referenced by minsky::Minsky::latex().

903  {
904  o << "\\begin{eqnarray*}\n";
905  // output user defined functions
906  for (auto& i: userDefinedFunctions)
907  o<<i.first<<"(x,y)&=&"<<i.second<<"\\\\\n";
908  for (const VariableDAG* i: variables)
909  {
910  if (dynamic_cast<const IntegralInputVariableDAG*>(i) ||
911  !i || i->type==VariableType::constant || i->type==VariableType::tempFlow) continue;
912  o << i->latex() << "&=&";
913  if (i->rhs)
914  i->rhs->latex(o);
915  else
916  o<<latexInit(i->init);
917  o << "\\\\\n";
918  }
919 
920  for (const VariableDAG* i: integrationVariables)
921  {
922  o << mathrm(i->name)<<"(0)&=&"<<latexInit(i->init)<<"\\\\\n";
923  o << "\\frac{ d " << mathrm(i->name) <<
924  "}{dt} &=&";
926  if (input && input->rhs)
927  input->rhs->latex(o);
928  o << "\\\\\n";
929  }
930  return o << "\\end{eqnarray*}\n";
931  }
Definition: input.py:1
SubexpressionCache expressionCache
Definition: equations.h:360
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
string latexInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_latex.cc:73
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
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
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ latexWrapped()

ostream & MathDAG::SystemOfEquations::latexWrapped ( ostream &  o) const

Definition at line 933 of file equations.cc.

References minsky::VariableType::constant, expressionCache, MathDAG::SubexpressionCache::getIntegralInput(), integrationVariables, MathDAG::latexInit(), MathDAG::mathrm(), minsky::VariableType::tempFlow, and variables.

Referenced by minsky::Minsky::latex().

934  {
935  o << "\\begin{dgroup*}\n";
936  for (const VariableDAG* i: variables)
937  {
938  if (dynamic_cast<const IntegralInputVariableDAG*>(i)) continue;
939  if (!i || i->type==VariableType::constant || i->type==VariableType::tempFlow) continue;
940  o<<"\\begin{dmath*}\n";
941  o << i->latex() << "=";
942  if (i->rhs)
943  i->rhs->latex(o);
944  else
945  o<<latexInit(i->init);
946  o << "\n\\end{dmath*}\n";
947  }
948 
949  for (const VariableDAG* i: integrationVariables)
950  {
951  o<<"\\begin{dmath*}\n";
952  o << mathrm(i->name)<<"(0)="<<latexInit(i->init)<<"\n\\end{dmath*}\n";
953  o << "\\begin{dmath*}\n\\frac{ d " << mathrm(i->name) <<
954  "}{dt} =";
956  if (input && input->rhs)
957  input->rhs->latex(o);
958  o << "\\end{dmath*}\n";
959  }
960  return o << "\\end{dgroup*}\n";
961  }
Definition: input.py:1
SubexpressionCache expressionCache
Definition: equations.h:360
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
string latexInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_latex.cc:73
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
vector< VariableDAG * > variables
Definition: equations.h:362
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ makeDAG() [1/5]

NodePtr MathDAG::SystemOfEquations::makeDAG ( const string &  valueId,
const string &  name,
VariableType::Type  type 
)
private

create a variable DAG. returns cached value if previously called

Definition at line 676 of file equations.cc.

References minsky::VariableType::constant, MathDAG::SubexpressionCache::exists(), expressionCache, getNodeFromWire(), MathDAG::SubexpressionCache::insert(), minsky::VariableType::integral, minsky::isValueId(), minsky::to_string(), minsky::valueId(), and varNames.

Referenced by getNodeFromVar(), getNodeFromWire(), makeDAG(), and SystemOfEquations().

677  {
679  return expressionCache[valueId];
680 
681  if (!isValueId(valueId)||!minsky.variableValues.contains(valueId))
682  throw runtime_error("Invalid valueId: "+valueId);
683  auto vv=minsky.variableValues[valueId];
684 
685  if (type==VariableType::constant)
686  {
687  NodePtr r(new ConstantDAG(vv->init()));
688  r->result=vv;
690  return r;
691  }
692 
693  // ensure name is unique
694  string nm=name;
695  for (unsigned i=0; varNames.contains(nm); ++i)
696  nm=name+"_"+to_string(i);
697  varNames.insert(nm);
698 
699  shared_ptr<VariableDAG> r(new VariableDAG(valueId, nm, type));
701  r->init=vv->init();
702  if (auto v=minsky.definingVar(valueId))
703  if (v->type()!=VariableType::integral && v->numPorts()>1 && !v->ports(1).lock()->wires().empty())
704  r->rhs=getNodeFromWire(*v->ports(1).lock()->wires()[0]);
705  return r;
706  }
bool exists(const T &x)
Definition: equations.h:315
const NodePtr & insert(const T &x, const NodePtr &n)
Definition: equations.h:325
SubexpressionCache expressionCache
Definition: equations.h:360
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
bool isValueId(const string &name)
check that name is a valid valueId (useful for assertions)
Definition: valueId.cc:33
std::set< std::string > varNames
used to rename ambiguous variables in different scopes
Definition: equations.h:389
string to_string(CONST84 char *x)
Definition: minskyTCLObj.h:33
Here is the call graph for this function:
Here is the caller graph for this function:

◆ makeDAG() [2/5]

NodePtr MathDAG::SystemOfEquations::makeDAG ( VariableBase v)
inlineprivate

Definition at line 371 of file equations.h.

References minsky::VariableBase::ensureValueExists(), minsky::VariableBase::name(), minsky::VariableBase::type(), minsky::uqName(), minsky::VariableBase::valueId(), and minsky::VariableBase::vValue().

372  {v.ensureValueExists(v.vValue().get(),v.name()); return makeDAG(v.valueId(),uqName(v.name()),v.type());}
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
std::string uqName(const std::string &name)
extract unqualified portion of name
Definition: valueId.cc:135
virtual Type type() const =0
virtual std::string valueId() const
string used to link to the VariableValue associated with this
Definition: variable.cc:186
void ensureValueExists(VariableValue *vv, const std::string &name) const
ensure an associated variableValue exists
Definition: variable.cc:262
virtual std::string name() const
variable displayed name
Definition: variable.cc:201
std::shared_ptr< VariableValue > vValue() const
variableValue associated with this. nullptr if not associated with a variableValue ...
Definition: variable.cc:161
Here is the call graph for this function:

◆ makeDAG() [3/5]

NodePtr MathDAG::SystemOfEquations::makeDAG ( const OperationBase op)
private

create an operation DAG. returns cached value if previously called

Definition at line 708 of file equations.cc.

References MathDAG::OperationDAGBase::create(), minsky::OperationType::differentiate, minsky::Minsky::displayErrorItem(), MathDAG::SubexpressionCache::exists(), expressionCache, getNodeFromWire(), MathDAG::SubexpressionCache::insert(), makeDAG(), minsky::minsky(), minsky::op, and minsky::valueId().

709  {
711  return dynamic_pointer_cast<OperationDAGBase>(expressionCache[op]);
712 
713  if (op.type()==OperationType::differentiate)
714  {
715  assert(op.portsSize()==2);
716  NodePtr expr;
717  if (op.ports(1).lock()->wires().empty() || !(expr=getNodeFromWire(*op.ports(1).lock()->wires()[0])))
718  op.throw_error("derivative not wired");
719  try
720  {
721  return expressionCache.insert
722  (op, expr->derivative(*this));
723  }
724  catch (...)
725  {
727  throw;
728  }
729  }
730  else
731  {
732  shared_ptr<OperationDAGBase> r(OperationDAGBase::create(op.type()));
734  r->state=minsky.model->findItem(op);
735  assert(r->state);
736 
737  r->arguments.resize(op.numPorts()-1);
738  for (size_t i=1; i<op.portsSize(); ++i)
739  if (auto p=op.ports(i).lock())
740  for (auto w: p->wires())
741  r->arguments[i-1].push_back(getNodeFromWire(*w));
742  if (auto uf=dynamic_cast<const UserFunction*>(&op))
743  {
744  // add external variable references as additional "arguments" in order to determine the correct evaluation order
745  r->arguments.emplace_back();
746  for (auto& i: uf->symbolNames())
747  {
748  auto vv=minsky.variableValues.find(valueId(op.group.lock(), i));
749  if (vv!=minsky.variableValues.end())
750  {
751  r->arguments.back().emplace_back(makeDAG(vv->first,vv->second->name,vv->second->type()));
752  }
753  }
754  }
755  return r;
756  }
757  }
bool exists(const T &x)
Definition: equations.h:315
void displayErrorItem(const Item &op) const
indicate operation item has error, if visible, otherwise contining group
Definition: minsky.cc:1230
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
const NodePtr & insert(const T &x, const NodePtr &n)
Definition: equations.h:325
SubexpressionCache expressionCache
Definition: equations.h:360
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
Minsky & minsky()
global minsky object
Definition: minskyTCL.cc:51
static OperationDAGBase * create(Type type, const string &name="")
factory method
Definition: equations.cc:176
Here is the call graph for this function:

◆ makeDAG() [4/5]

NodePtr MathDAG::SystemOfEquations::makeDAG ( const SwitchIcon op)
private

Definition at line 759 of file equations.cc.

References expressionCache, getNodeFromWire(), and MathDAG::SubexpressionCache::insert().

760  {
761  // grab list of input wires
762  vector<Wire*> wires;
763  for (unsigned i=1; i<sw.portsSize(); ++i)
764  {
765  auto& w=sw.ports(i).lock()->wires();
766  if (w.empty())
767  {
768  minsky.displayErrorItem(sw);
769  throw error("input port not wired");
770  }
771  // shouldn't be more than 1 wire, ignore extraneous wires is present
772  assert(w.size()==1);
773  wires.push_back(w[0]);
774  }
775 
776  assert(wires.size()==sw.numCases()+1);
777  const Expr input(expressionCache, getNodeFromWire(*wires[0]));
778 
779  auto r=make_shared<OperationDAG<OperationType::add>>();
780  r->state=minsky.model->findItem(sw);
781  assert(r->state);
782  expressionCache.insert(sw, r);
783  r->arguments[0].resize(sw.numCases());
784 
785  // implemented as a sum of step functions
786  r->arguments[0][0]=getNodeFromWire(*wires[1])*(input<1);
787  for (unsigned i=1; i<sw.numCases()-1; ++i)
788  r->arguments[0][i]=getNodeFromWire
789  (*wires[i+1])*((input<i+1) - (input<i));
790  r->arguments[0][sw.numCases()-1]=getNodeFromWire
791  (*wires[sw.numCases()])*(1-(input<sw.numCases()-1));
792  return r;
793  };
Definition: input.py:1
const NodePtr & insert(const T &x, const NodePtr &n)
Definition: equations.h:325
SubexpressionCache expressionCache
Definition: equations.h:360
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
Here is the call graph for this function:

◆ makeDAG() [5/5]

NodePtr MathDAG::SystemOfEquations::makeDAG ( const Lock op)
private

Definition at line 828 of file equations.cc.

References expressionCache, getNodeFromWire(), MathDAG::SubexpressionCache::insert(), minsky::Lock::locked(), minsky::Item::ports(), and minsky::Lock::ravelInput().

829  {
830  auto r=make_shared<LockDAG>(l);
831  expressionCache.insert(l,r);
832  auto ravel=l.ravelInput();
833  if (ravel && l.locked())
834  {
835  if (auto p=ravel->ports(1).lock())
836  if (!p->wires().empty())
837  r->rhs=getNodeFromWire(*p->wires()[0]);
838  }
839  else
840  if (auto p=l.ports(1).lock())
841  if (!p->wires().empty())
842  r->rhs=getNodeFromWire(*p->wires()[0]);
843  return r;
844  }
const NodePtr & insert(const T &x, const NodePtr &n)
Definition: equations.h:325
SubexpressionCache expressionCache
Definition: equations.h:360
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
Here is the call graph for this function:

◆ matlab()

ostream & MathDAG::SystemOfEquations::matlab ( ostream &  o) const

render as MatLab code create equations suitable for Runge-Kutta solver

Parameters
vectorof equations to be constructed
vectorof integrals to be constructed
portValMap- map of flowVar ids assigned with an output port

Definition at line 963 of file equations.cc.

References minsky::VariableType::constant, expressionCache, MathDAG::SubexpressionCache::getIntegralInput(), integrationVariables, MathDAG::matlabInit(), userDefinedFunctions, and variables.

Referenced by minsky::Minsky::matlab().

964  {
965  // output user defined functions
966  for (auto& i: userDefinedFunctions)
967  {
968  o<<"function f="<<i.first<<"\n";
969  o<<"f="<<i.second<<"\nendfunction;\n\n";
970  }
971  o<<"function f=f(x,t)\n";
972  // define names for the components of x for reference
973  int j=1;
974  for (const VariableDAG* i: integrationVariables)
975  o<<i->matlab()<<"=x("<<j++<<");\n";
976 
977  for (const VariableDAG* i: variables)
978  {
979  if (dynamic_cast<const IntegralInputVariableDAG*>(i) ||
980  !i || i->type==VariableType::constant) continue;
981  o << i->matlab() << "=";
982  if (i->rhs)
983  o << i->rhs->matlab();
984  else
985  o << matlabInit(i->init);
986  o<<";\n";
987  }
988 
989  j=1;
990  for (const VariableDAG* i: integrationVariables)
991  {
992  o << "f("<<j++<<")=";
994  if (input && input->rhs)
995  input->rhs->matlab(o);
996  else
997  o<<0;
998  o<<";\n";
999  }
1000  o<<"endfunction;\n\n";
1001 
1002  // now write out the initial conditions
1003  j=1;
1004  for (const VariableDAG* i: integrationVariables)
1005  o << "x0("<<j++<<")="<<matlabInit(i->init)<<";\n";
1006 
1007  return o;
1008  }
Definition: input.py:1
SubexpressionCache expressionCache
Definition: equations.h:360
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
string matlabInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_matlab.cc:45
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
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
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
Here is the call graph for this function:
Here is the caller graph for this function:

◆ populateEvalOpVector()

void MathDAG::SystemOfEquations::populateEvalOpVector ( EvalOpVector equations,
std::vector< Integral > &  integrals 
)

Definition at line 1011 of file equations.cc.

References minsky::isValueId().

Referenced by minsky::Minsky::constructEquations(), and minsky::Group::operator()().

1012  {
1013  equations.clear();
1014  integrals.clear();
1015 
1016  for (VariableDAG* i: variables)
1017  {
1018  i->addEvalOps(equations,i->result);
1019  assert(minsky.variableValues.validEntries());
1020  }
1021 
1022  for (const VariableDAG* i: integrationVariables)
1023  {
1024  const string vid=i->valueId;
1025  integrals.push_back(Integral());
1026  assert(isValueId(vid));
1027  assert(minsky.variableValues.count(vid));
1028  integrals.back().stock=minsky.variableValues[vid];
1029  integrals.back().operation=dynamic_cast<IntOp*>(i->intOp);
1031  if (iInput && iInput->rhs)
1032  integrals.back().setInput(iInput->rhs->addEvalOps(equations));
1033  }
1034  assert(minsky.variableValues.validEntries());
1035  }
An integral is an additional stock variable, that integrates its flow variable.
Definition: integral.h:28
SubexpressionCache expressionCache
Definition: equations.h:360
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
bool isValueId(const string &name)
check that name is a valid valueId (useful for assertions)
Definition: valueId.cc:33
vector< VariableDAG * > variables
Definition: equations.h:362
shared_ptr< VariableDAG > VariableDAGPtr
Definition: equations.h:208
Here is the call graph for this function:
Here is the caller graph for this function:

◆ processGodleyTable()

void MathDAG::SystemOfEquations::processGodleyTable ( map< string, GodleyColumnDAG > &  godleyVariables,
const GodleyIcon gi 
)
private

Definition at line 1074 of file equations.cc.

References MathDAG::OperationDAGBase::arguments, minsky::VariableType::flow, MathDAG::GodleyColumnDAG::name, minsky::GodleyIcon::table, minsky::trimWS(), minsky::uqName(), and minsky::valueId().

Referenced by SystemOfEquations().

1075  {
1076  auto& godley=gi.table;
1077  for (size_t c=1; c<godley.cols(); ++c)
1078  {
1079  string colName=trimWS(godley.cell(0,c));
1080  if (uqName(colName).empty())
1081  continue; // ignore empty Godley columns
1082  // resolve scope
1083  colName=valueId(gi.group.lock(), colName);
1084  if (processedColumns.contains(colName)) continue; //skip shared columns
1085  processedColumns.insert(colName);
1086  GodleyColumnDAG& gd=godleyVariables[colName];
1087  gd.name=trimWS(godley.cell(0,c));
1088  gd.arguments.resize(2);
1089  const vector<WeakNodePtr>& arguments=gd.arguments[0];
1090  for (size_t r=1; r<godley.rows(); ++r)
1091  {
1092  if (godley.initialConditionRow(r)) continue;
1093  const FlowCoef fc(godley.cell(r,c));
1094  if (fc.name.empty()) continue;
1095 
1096  const VariablePtr v(VariableType::flow, fc.name);
1097  v->group=gi.group;
1098 
1099  if (abs(fc.coef)==1)
1100  gd.arguments[fc.coef<0? 1: 0].push_back(WeakNodePtr(makeDAG(*v)));
1101  else
1102  {
1103  OperationDAG<OperationType::multiply>* term=
1104  new OperationDAG<OperationType::multiply>;
1105  gd.arguments[fc.coef<0? 1: 0].push_back
1107 
1108  term->arguments.resize(2);
1109  term->arguments[0].push_back
1110  (expressionCache.insertAnonymous(NodePtr(new ConstantDAG(abs(fc.coef)))));
1111  term->arguments[1].push_back(WeakNodePtr(makeDAG(*v)));
1112  }
1113  }
1114  }
1115  }
NodePtr makeDAG(const string &valueId, const string &name, VariableType::Type type)
create a variable DAG. returns cached value if previously called
Definition: equations.cc:676
void resize(const LassoBox &) override
resize this item on the canvas
Definition: godleyIcon.cc:177
SubexpressionCache expressionCache
Definition: equations.h:360
std::string uqName(const std::string &name)
extract unqualified portion of name
Definition: valueId.cc:135
string valueId(const string &name)
construct a valueId from fully qualified name @ name should not be canonicalised
Definition: valueId.cc:75
GodleyTable table
table data. Must be declared before editor
Definition: godleyIcon.h:80
std::string trimWS(const std::string &s)
Definition: str.h:49
represents a numerical coefficient times a variable (a "flow")
Definition: flowCoef.h:27
std::shared_ptr< Node > NodePtr
Definition: equations.h:131
NodePtr insertAnonymous(NodePtr x)
Definition: equations.h:351
set< string > processedColumns
Definition: equations.h:364
Here is the call graph for this function:
Here is the caller graph for this function:

◆ renderEquations()

void MathDAG::SystemOfEquations::renderEquations ( ecolab::cairo::Surface &  ,
double  height 
) const

render equations into a cairo context

Definition at line 141 of file equationDisplayRender.cc.

References MathDAG::latexInit(), minsky::latexToPango(), MathDAG::mathrm(), MathDAG::anonymous_namespace{equationDisplayRender.cc}::print(), and MathDAG::anonymous_namespace{equationDisplayRender.cc}::variableRender().

Referenced by minsky::EquationDisplay::redraw().

142  {
143  double x, y; // starting position of current line
144  cairo_get_current_point(dest.cairo(),&x,&y);
145  const double origin=-y;
146  Pango den(dest.cairo());
147  den.setMarkup("dt");
148 
149  const double fontHeight=30;
150  const int baseEqn=origin/fontHeight;
151  int eqnNo=0;
152 
153  for (const VariableDAG* i: variables)
154  {
155  if (dynamic_cast<const IntegralInputVariableDAG*>(i)) continue;
156  if (!i || i->type==VariableType::constant) continue;
157  if (eqnNo++ < baseEqn) continue;
158  RecordingSurface line;
159  variableRender(line,*i);
160  cairo_move_to(dest.cairo(), x, y-line.top());
161  variableRender(dest,*i);
162  y+=line.height()+4;
163  cairo_move_to(dest.cairo(), x, y);
164  if (y>height) return;
165  }
166 
167  for (const VariableDAG* i: integrationVariables)
168  {
169  if (eqnNo++ < baseEqn) continue;
170  // initial conditions
171  cairo_move_to(dest.cairo(), x, y); // needed to define a current point on the equations tab. for ticket 1256
172  y+=print(dest.cairo(), latexToPango(mathrm(i->name))+"(0) = "+
173  latexToPango(latexInit(i->init)),Anchor::nw);
174 
175  // differential equation
176  Pango num(dest.cairo());
177  num.setMarkup("d"+latexToPango(mathrm(i->name)));
178  double lineSpacing=num.height()+den.height()+2;
179 
181  if (input && input->rhs)
182  { // adjust linespacing to allow enough height for RHS
183  RecordingSurface rhs;
184  input->rhs->render(rhs);
185  lineSpacing = max(rhs.height(), lineSpacing);
186  }
187 
188  // vertical location of the = sign
189  const double eqY=y+max(num.height(), 0.5*lineSpacing);
190 
191  cairo_move_to(dest.cairo(), x, eqY-num.height());
192  num.show();
193  cairo_move_to(dest.cairo(), x, eqY);
194  const double solidusLength = max(num.width(),den.width());
195  cairo_rel_line_to(dest.cairo(), solidusLength, 0);
196  cairo_stroke(dest.cairo());
197  cairo_move_to(dest.cairo(), x+solidusLength, eqY);
198  // display RHS here
199  if (input && input->rhs)
200  {
201  print(dest.cairo()," = ", Anchor::w);
202  input->rhs->render(dest);
203  }
204  else
205  print(dest.cairo()," = 0", Anchor::w);
206  cairo_move_to(dest.cairo(), x+0.5*(num.width()-den.width()), eqY);
207  den.show();
208  cairo_move_to(dest.cairo(), x, y+=lineSpacing);// move to next line
209 
210  if (y>height) return;
211  }
212  }
void variableRender(Surface &surf, const VariableDAG &v)
std::string latexToPango(const char *s)
Definition: latexMarkup.h:30
Definition: input.py:1
SubexpressionCache expressionCache
Definition: equations.h:360
vector< VariableDAG * > integrationVariables
Definition: equations.h:363
string latexInit(const string &)
convert an initialisation string into a matlab expression
Definition: node_latex.cc:73
VariableDAGPtr getIntegralInput(const string &name) const
Definition: equations.h:333
double print(cairo_t *cairo, const string &text, Anchor anchor)
vector< VariableDAG * > variables
Definition: equations.h:362
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
Here is the call graph for this function:
Here is the caller graph for this function:

◆ updatePortVariableValue()

void MathDAG::SystemOfEquations::updatePortVariableValue ( EvalOpVector equations)

Definition at line 1037 of file equations.cc.

References getNodeFromWire(), minsky::GroupItems::items, and minsky::VariableType::undefined.

Referenced by minsky::Minsky::constructEquations().

1038  {
1039  // ensure all variables have their output port's variable value up to date
1040  minsky.model->recursiveDo
1041  (&Group::items,
1042  [&](Items&, Items::iterator i)
1043  {
1044  if (auto v=(*i)->variableCast())
1045  {
1046  if (v->type()==VariableType::undefined)
1047  throw error("variable %s has undefined type",v->name().c_str());
1048  assert(minsky.variableValues.count(v->valueId()));
1049  if (v->portsSize()>0)
1050  v->ports(0).lock()->setVariableValue(minsky.variableValues[v->valueId()]);
1051  }
1052  else if (auto pw=(*i)->plotWidgetCast())
1053  for (size_t port=0; port<pw->portsSize(); ++port)
1054  for (auto w: pw->ports(port).lock()->wires())
1055  // ensure plot inputs are evaluated
1056  w->from()->setVariableValue(getNodeFromWire(*w)->addEvalOps(equations));
1057  else if (auto s=dynamic_cast<Sheet*>(i->get()))
1058  {
1059  for (auto w: s->ports(0).lock()->wires())
1060  // ensure sheet inputs are evaluated
1061  w->from()->setVariableValue(getNodeFromWire(*w)->addEvalOps(equations));
1062  s->computeValue();
1063  }
1064  else if (auto r=dynamic_cast<Ravel*>(i->get()))
1065  for (auto w: r->ports(1).lock()->wires())
1066  // ensure sheet inputs are evaluated
1067  w->from()->setVariableValue(getNodeFromWire(*w)->addEvalOps(equations));
1068 
1069  return false;
1070  });
1071  }
Creation and access to the minskyTCL_obj object, which has code to record whenever Minsky&#39;s state cha...
Definition: constMap.h:22
std::vector< ItemPtr > Items
Definition: item.h:366
NodePtr getNodeFromWire(const Wire &wire)
returns cached subexpression node representing what feeds the wire, creating a new one if necessary ...
Definition: equations.cc:846
Here is the call graph for this function:
Here is the caller graph for this function:

Member Data Documentation

◆ derivInputs

vector<pair<VariableDAGPtr,string> > MathDAG::SystemOfEquations::derivInputs
private

Definition at line 365 of file equations.h.

Referenced by SystemOfEquations().

◆ expressionCache

SubexpressionCache MathDAG::SystemOfEquations::expressionCache
private

◆ integrationVariables

vector<VariableDAG*> MathDAG::SystemOfEquations::integrationVariables
private

Definition at line 363 of file equations.h.

Referenced by latex(), latexWrapped(), matlab(), and SystemOfEquations().

◆ minsky

const Minsky& MathDAG::SystemOfEquations::minsky
private

Definition at line 367 of file equations.h.

◆ one

NodePtr MathDAG::SystemOfEquations::one {new ConstantDAG("1")}

Definition at line 418 of file equations.h.

Referenced by SystemOfEquations().

◆ processedColumns

set<string> MathDAG::SystemOfEquations::processedColumns
private

Definition at line 364 of file equations.h.

◆ processingDerivative

std::set<std::string> MathDAG::SystemOfEquations::processingDerivative
private

keep track of derivatives of variables, to trap definition loops

Definition at line 391 of file equations.h.

◆ userDefinedFunctions

std::map<std::string, std::string> MathDAG::SystemOfEquations::userDefinedFunctions
private

table of user defined functions and their definitions

Definition at line 393 of file equations.h.

Referenced by latex(), matlab(), and SystemOfEquations().

◆ variables

vector<VariableDAG*> MathDAG::SystemOfEquations::variables
private

Definition at line 362 of file equations.h.

Referenced by latex(), latexWrapped(), matlab(), and SystemOfEquations().

◆ varNames

std::set<std::string> MathDAG::SystemOfEquations::varNames
private

used to rename ambiguous variables in different scopes

Definition at line 389 of file equations.h.

Referenced by makeDAG().

◆ zero

NodePtr MathDAG::SystemOfEquations::zero {new ConstantDAG("0")}

useful constants to share

Definition at line 418 of file equations.h.

Referenced by SystemOfEquations().


The documentation for this class was generated from the following files: