COPASI API  4.16.103
CEvaluationTree.cpp
Go to the documentation of this file.
1 // Copyright (C) 2010 - 2015 by Pedro Mendes, Virginia Tech Intellectual
2 // Properties, Inc., University of Heidelberg, and The University
3 // of Manchester.
4 // All rights reserved.
5 
6 // Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
7 // Properties, Inc., EML Research, gGmbH, University of Heidelberg,
8 // and The University of Manchester.
9 // All rights reserved.
10 
11 // Copyright (C) 2005 - 2007 by Pedro Mendes, Virginia Tech Intellectual
12 // Properties, Inc. and EML Research, gGmbH.
13 // All rights reserved.
14 
15 #include "copasi.h"
16 
17 #include <sstream>
18 #include <vector>
19 #include <algorithm>
20 
21 #include "CEvaluationNode.h"
22 #include "CEvaluationTree.h"
23 #include "CFunction.h"
24 #include "CExpression.h"
25 #include "CEvaluationLexer.h"
26 #include "CFunctionDB.h"
27 
28 #include "report/CKeyFactory.h"
30 #include "sbml/math/ASTNode.h"
31 #include "utilities/CCopasiTree.h"
35 #include "math/CMathObject.h"
36 
37 const std::string CEvaluationTree::TypeName[] =
38 {
39  "userdefined",
40  "predefined",
41  "predefined",
42  "userdefined",
43  "userdefined",
44  "userdefined",
45  "internal",
46  ""
47 };
48 
49 const char* CEvaluationTree::XMLType[] =
50 {
51  "Function",
52  "MassAction",
53  "PreDefined",
54  "UserDefined",
55  "Expression",
56  "Boolean",
57  "MathExpression",
58  NULL
59 };
60 
63 {
64  CEvaluationTree * pNew = NULL;
65 
66  switch (type)
67  {
68  case Function:
69  pNew = new CFunction();
70  break;
71 
72  case MassAction:
73  pNew = new CMassAction();
74  break;
75 
76  case PreDefined:
77  pNew = new CKinFunction();
78  pNew->setType(PreDefined);
79  break;
80 
81  case UserDefined:
82  pNew = new CKinFunction();
83  break;
84 
85  case Expression:
86  pNew = new CExpression();
87  break;
88 
89  default:
90  fatalError();
91  break;
92  }
93 
94  return pNew;
95 }
96 
99 {
100  CEvaluationTree * pNew = NULL;
101 
102  switch (src.getType())
103  {
104  case Function:
105  pNew = new CFunction(*static_cast<const CFunction *>(&src));
106  break;
107 
108  case MassAction:
109  pNew = new CMassAction(*static_cast<const CMassAction *>(&src));
110  break;
111 
112  case PreDefined:
113  case UserDefined:
114  pNew = new CKinFunction(*static_cast<const CKinFunction *>(&src));
115  break;
116 
117  case Expression:
118  pNew = new CExpression(*static_cast<const CExpression *>(&src));
119  break;
120 
121  default:
122  fatalError();
123  break;
124  }
125 
126  return pNew;
127 }
128 
129 CEvaluationTree::CEvaluationTree(const std::string & name,
130  const CCopasiContainer * pParent,
131  const CEvaluationTree::Type & type):
132  CCopasiContainer(name, pParent, "Function"),
133  mType(type),
134  mInfix(),
135  mUsable(false),
136  mErrorPosition(std::string::npos),
137  mpNodeList(NULL),
138  mpRoot(NULL),
139  mValue(std::numeric_limits<C_FLOAT64>::quiet_NaN()),
140  mCalculationSequence()
141 {
142  initObjects();
143  setInfix("");
144 }
145 
147  const CCopasiContainer * pParent):
148  CCopasiContainer(src, pParent),
149  mType(src.mType),
150  mInfix(),
151  mUsable(false),
152  mErrorPosition(std::string::npos),
153  mpNodeList(NULL),
154  mpRoot(NULL),
155  mValue(src.mValue),
156  mCalculationSequence()
157 {
158  initObjects();
159  setInfix(src.mInfix);
160 }
161 
163 {
165 }
166 
168 {return mType;}
169 
171 {
172  mType = type;
173 }
174 
175 bool CEvaluationTree::setInfix(const std::string & infix)
176 {
177  if (infix == mInfix &&
178  infix != "") return true;
179 
180  // We assume until proven otherwise that the tree is not usable
181  mUsable = false;
182 
183  mInfix = infix;
184 
185  return parse();
186 }
187 
188 const std::string & CEvaluationTree::getInfix() const
189 {return mInfix;}
190 
192 {
193  return (mInfix == rhs.mInfix && mType == rhs.mType);
194 }
195 
196 std::string::size_type CEvaluationTree::getErrorPosition() const
197 {return mErrorPosition;}
198 
199 const std::vector< CEvaluationNode * > & CEvaluationTree::getNodeList() const
200 {
201  if (!mpNodeList)
202  const_cast<CEvaluationTree *>(this)->mpNodeList = new std::vector< CEvaluationNode * >();
203 
204  return *mpNodeList;
205 }
206 
207 size_t CEvaluationTree::getVariableIndex(const std::string & /*name*/) const
208 {return C_INVALID_INDEX;}
209 
210 const C_FLOAT64 & CEvaluationTree::getVariableValue(const size_t & /*index*/) const
211 {
212  static C_FLOAT64 Value = std::numeric_limits<C_FLOAT64>::quiet_NaN();
213  return Value;
214 }
215 
217 {
218  bool success = true;
219 
220  // clean up
222  mpNodeList = NULL;
223  mpRoot = NULL;
224 
225  if (mType == MassAction) return true;
226 
227  if (mInfix == "")
228  {
229  mpNodeList = new std::vector< CEvaluationNode * >;
230  mpRoot = new CEvaluationNode();
231  mpNodeList->push_back(mpRoot);
232  return true;
233  }
234 
235  // parse the description into a linked node tree
236  std::istringstream buffer(mInfix);
237  CEvaluationLexer Parser(&buffer);
238 
239  success = (Parser.yyparse() == 0);
240 
241  mpNodeList = Parser.getNodeList();
242  mpRoot = Parser.getRootNode();
243 
244  // clean up if parsing failed
245  if (!success)
246  {
247  mErrorPosition = Parser.getErrorPosition();
248 
250  mpNodeList = NULL;
251  mpRoot = NULL;
252  }
253 
254  if (success && hasCircularDependency())
255  {
256  success = false;
258  }
259 
260  return success;
261 }
262 
264 {return compileNodes();}
265 
267 {return mUsable;}
268 
270 {
271  if (mpRoot != NULL)
272  return mpRoot->isBoolean();
273 
274  return false;
275 }
276 
278 {
280 
281  while (itNode.next() != itNode.end())
282  {
283  switch (CEvaluationNode::type(itNode->getType()))
284  {
288  break;
289 
290  default:
291  mCalculationSequence.push_back(*itNode);
292  break;
293  }
294  }
295 }
296 
298 {
300  mCalculationSequence.clear();
301 
302  if (mInfix == "")
303  return mUsable = true;
304 
305  if (mpNodeList == NULL)
306  return mUsable = false;
307 
308  // The compile order must be child first.
310  CEvaluationNode *pErrorNode = NULL;
311  mUsable = true;
312 
313  while (itNode.next() != itNode.end())
314  {
315  if (*itNode != NULL)
316  {
317  if (!itNode->compile(this))
318  {
319  if (mUsable)
320  {
321  mUsable = false;
322  pErrorNode = *itNode;
323  }
324  }
325  }
326  }
327 
328  std::vector< CEvaluationNode * >::iterator it;
329  std::vector< CEvaluationNode * >::iterator end = mpNodeList->end();
330 
331  if (!mUsable)
332  {
333  // Find the error node in the node list
334  for (it = mpNodeList->begin(); it != end; ++it)
335  {
336  if (*it == pErrorNode)
337  {
338  end = it + 1;
339  break;
340  }
341  }
342 
343  mErrorPosition = 0;
344 
345  for (it = mpNodeList->begin(); it != end; ++it)
346  mErrorPosition += (*it)->getData().length();
347 
348  mErrorPosition -= (*--it)->getData().length();
350  }
351  else
352  {
353  const CObjectInterface * pObject;
354 
355  for (it = mpNodeList->begin(); it != end; ++it)
356  switch ((*it)->getType() & 0xFF000000)
357  {
359  {
360  if (mType == Expression &&
361  (pObject = static_cast< CEvaluationNodeObject *>(*it)->getObjectInterfacePtr()) != NULL)
362  {
363  const CCopasiObject * pDataObject = dynamic_cast< const CCopasiObject * >(pObject);
364 
365  if (pDataObject == NULL)
366  {
367  const CMathObject * pMathObject = dynamic_cast< const CMathObject * >(pObject);
368 
369  if (pMathObject != NULL)
370  {
371  pDataObject = pMathObject->getDataObject();
372  }
373  }
374 
375  addDirectDependency(pDataObject);
376  }
377  }
378  break;
379 
381  addDirectDependency(static_cast< CEvaluationNodeCall *>(*it)->getCalledTree());
382  break;
383 
384  default:
385  break;
386  }
387 
389  }
390 
391  return mUsable;
392 }
393 
395 {
396  try
397  {
398  if (mpRoot != NULL)
399  {
400  std::vector< CEvaluationNode * >::iterator it = mCalculationSequence.begin();
401  std::vector< CEvaluationNode * >::iterator end = mCalculationSequence.end();
402 
403  for (; it != end; ++it)
404  {
405  (*it)->calculate();
406  }
407 
408  mValue = mpRoot->getValue();
409  }
410  else
411  {
412  mValue = std::numeric_limits< C_FLOAT64 >::quiet_NaN();
413  }
414  }
415 
416  catch (...)
417  {
418  mValue = std::numeric_limits<C_FLOAT64>::quiet_NaN();
419  }
420 }
421 
423 {
424  if (pRootNode == NULL) return false;
425 
426  assert(pRootNode->getParent() == NULL);
427 
428  if (mpNodeList != NULL)
430 
431  mpRoot = pRootNode;
432 
433  mpNodeList = new std::vector< CEvaluationNode * >();
434 
435  return this->updateTree();
436 }
437 
439 {
440  if (mpRoot == NULL)
441  {
443  mpNodeList = NULL;
444 
445  return false;
446  }
447 
448  if (mpNodeList == NULL)
449  {
450  mpNodeList = new std::vector< CEvaluationNode * >;
451  }
452 
453  // Clear the list but preserve the tree
454  mpNodeList->clear();
455 
458 
459  for (; it != end; ++it)
460  mpNodeList->push_back(&*it);
461 
462  mInfix = mpRoot->buildInfix();
463 
464  return true;
465 }
466 
467 bool CEvaluationTree::setTree(const ASTNode& pRootNode)
468 {
469  return this->setRoot(CEvaluationTree::fromAST(&pRootNode));
470 }
471 
472 CEvaluationNode * CEvaluationTree::fromAST(const ASTNode * pASTNode)
473 {
474  if (pASTNode == NULL) return NULL;
475 
477  CEvaluationNode* pResultNode = NULL;
478 
479  while (itNode.next() != itNode.end())
480  {
481  if (*itNode != NULL)
482  {
484 
485  switch (itNode->getType())
486  {
487  case AST_LAMBDA:
488  // this nodetype will never be handled directly
489  break;
490 
491  case AST_PLUS:
492  case AST_MINUS:
493  case AST_TIMES:
494  case AST_DIVIDE:
495  case AST_POWER:
496  case AST_FUNCTION_POWER:
497  // create a CEvaluationNodeOperator
498  pResultNode = CEvaluationNodeOperator::fromAST(*itNode, itNode.context());
499  break;
500 
501  case AST_INTEGER:
502  case AST_REAL:
503  case AST_REAL_E:
504  case AST_RATIONAL:
505  // create a CEvaluationNodeNumber
506  pResultNode = CEvaluationNodeNumber::fromAST(*itNode, itNode.context());
507  break;
508 
509  case AST_NAME:
510  case AST_NAME_TIME:
511 #if LIBSBML_VERSION >= 40100
512  case AST_NAME_AVOGADRO:
513 #endif // LIBSBML_VERSION >= 40100
514  // create a CEvaluationNodeObject
515  pResultNode = CEvaluationNodeObject::fromAST(*itNode, itNode.context());
516  break;
517 
518  case AST_CONSTANT_E:
519  case AST_CONSTANT_PI:
520  case AST_CONSTANT_FALSE:
521  case AST_CONSTANT_TRUE:
522  // create a CEvaluationNodeConstant
523  pResultNode = CEvaluationNodeConstant::fromAST(*itNode, itNode.context());
524  break;
525 
526  case AST_FUNCTION:
527  // create a function call node
528  pResultNode = CEvaluationNodeCall::fromAST(*itNode, itNode.context());
529  break;
530 
531  case AST_FUNCTION_DELAY:
532  // create a function call node
533  pResultNode = CEvaluationNodeDelay::fromAST(*itNode, itNode.context());
534  break;
535 
536  case AST_FUNCTION_ABS:
537  case AST_FUNCTION_ARCCOS:
538  case AST_FUNCTION_ARCCOSH:
539  case AST_FUNCTION_ARCCOT:
540  case AST_FUNCTION_ARCCOTH:
541  case AST_FUNCTION_ARCCSC:
542  case AST_FUNCTION_ARCCSCH:
543  case AST_FUNCTION_ARCSEC:
544  case AST_FUNCTION_ARCSECH:
545  case AST_FUNCTION_ARCSIN:
546  case AST_FUNCTION_ARCSINH:
547  case AST_FUNCTION_ARCTAN:
548  case AST_FUNCTION_ARCTANH:
549  case AST_FUNCTION_CEILING:
550  case AST_FUNCTION_COS:
551  case AST_FUNCTION_COSH:
552  case AST_FUNCTION_COT:
553  case AST_FUNCTION_COTH:
554  case AST_FUNCTION_CSC:
555  case AST_FUNCTION_CSCH:
556  case AST_FUNCTION_EXP:
557  case AST_FUNCTION_FACTORIAL:
558  case AST_FUNCTION_FLOOR:
559  case AST_FUNCTION_LN:
560  case AST_FUNCTION_LOG:
561  case AST_FUNCTION_ROOT:
562  case AST_FUNCTION_SEC:
563  case AST_FUNCTION_SECH:
564  case AST_FUNCTION_SIN:
565  case AST_FUNCTION_SINH:
566  case AST_FUNCTION_TAN:
567  case AST_FUNCTION_TANH:
568  case AST_LOGICAL_NOT:
569  pResultNode = CEvaluationNodeFunction::fromAST(*itNode, itNode.context());
570  break;
571 
572  case AST_LOGICAL_AND:
573  case AST_LOGICAL_OR:
574  case AST_LOGICAL_XOR:
575  case AST_RELATIONAL_EQ:
576  case AST_RELATIONAL_GEQ:
577  case AST_RELATIONAL_GT:
578  case AST_RELATIONAL_LEQ:
579  case AST_RELATIONAL_LT:
580  case AST_RELATIONAL_NEQ:
581  pResultNode = CEvaluationNodeLogical::fromAST(*itNode, itNode.context());
582  break;
583 
584  case AST_FUNCTION_PIECEWISE:
585  pResultNode = CEvaluationNodeChoice::fromAST(*itNode, itNode.context());
586  break;
587 
588  case AST_UNKNOWN:
589  // create an unknown element error
591 
592  break;
593  }
594 
595  if (itNode.parentContextPtr() != NULL)
596  {
597  itNode.parentContextPtr()->push_back(pResultNode);
598  }
599  }
600  }
601 
602  return pResultNode;
603 }
604 
606 {
607  return this->mpRoot;
608 }
609 
611 {
612  return this->mpRoot;
613 }
614 
616 {
617  std::set< const CCopasiObject * > Self;
618  Self.insert(this);
619 
620  CCopasiObject * pObject =
622 
623  pObject->setDirectDependencies(Self);
624 }
625 
627 {
629 
630  Deleted.insert(this);
631  Deleted.insert(static_cast< const CCopasiObject * >(getObject(CCopasiObjectName("Reference=Value"))));
632 
633  return Deleted;
634 }
635 
636 ASTNode* CEvaluationTree::toAST(const CCopasiDataModel* pDataModel) const
637 {
638  return this->mpRoot->toAST(pDataModel);
639 }
640 
642 {
643  std::set< std::string > List;
644 
645  return calls(List);
646 }
647 
648 bool CEvaluationTree::dependsOnTree(const std::string & name) const
649 {
650  if (!mpNodeList) return false;
651 
652  std::vector< CEvaluationNode * >::const_iterator it = mpNodeList->begin();
653  std::vector< CEvaluationNode * >::const_iterator end = mpNodeList->end();
654 
655  for (; it != end; ++it)
656  if (((*it)->getType() & 0xFF000000) == CEvaluationNode::CALL &&
657  (*it)->getData() == name)
658  return true;
659 
660  return false;
661 }
662 
663 bool CEvaluationTree::calls(std::set< std::string > & list) const
664 {
665  if (!mpNodeList) return false;
666 
667  std::pair<std::set< std::string >::iterator, bool> Result = list.insert(getObjectName());
668 
669  if (!Result.second) return true;
670 
671  bool Calls = false;
672  std::vector< CEvaluationNode * >::iterator it;
673  std::vector< CEvaluationNode * >::iterator end = mpNodeList->end();
674 
675  for (it = mpNodeList->begin(); it != end; ++it)
676  if (((*it)->getType() & 0xFF000000) == CEvaluationNode::CALL &&
677  dynamic_cast<CEvaluationNodeCall *>(*it)->calls(list))
678  {
679  Calls = true;
680  break;
681  }
682 
683  list.erase(Result.first);
684 
685  return Calls;
686 }
687 
689 {
690  if (mpNodeList == NULL)
691  return false;
692 
693  std::vector< CEvaluationNode * >::iterator it = mpNodeList->begin();
694  std::vector< CEvaluationNode * >::iterator end = mpNodeList->end();
695 
696  for (; it != end; ++it)
697  {
698  switch ((int)(*it)->getType())
699  {
704  // We found a discontinuity.
705  return true;
706  break;
707 
710 
711  // If the called tree has a discontinuity so do we.
712  if (static_cast< CEvaluationNodeCall * >(*it)->getCalledTree()->hasDiscontinuity())
713  {
714  return true;
715  }
716 
717  break;
718  }
719  }
720 
721  return false;
722 }
Header file of class CExpression.
void setType(const CEvaluationTree::Type &type)
virtual bool setRoot(CEvaluationNode *pRootNode)
virtual ASTNode * toAST(const CCopasiDataModel *pDataModel) const
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
void clearDirectDependencies()
virtual ~CEvaluationTree()
#define MCMathML
#define MCFunction
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
std::vector< CEvaluationNode * > * mpNodeList
const std::string & getObjectName() const
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
virtual size_t getVariableIndex(const std::string &name) const
const C_FLOAT64 & getValue() const
bool hasDiscontinuity() const
#define fatalError()
const Type & getType() const
void setDirectDependencies(const DataObjectSet &directDependencies)
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
std::string buildInfix() const
const CEvaluationTree::Type & getType() const
virtual ASTNode * toAST(const CCopasiDataModel *pDataModel) const
#define C_INVALID_INDEX
Definition: copasi.h:222
std::string mInfix
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
const CNodeIteratorMode::State & next()
static const std::string TypeName[]
std::vector< CEvaluationNode * > mCalculationSequence
static CEvaluationNode * fromAST(const ASTNode *pASTNode)
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
virtual const C_FLOAT64 & getVariableValue(const size_t &index) const
void buildCalculationSequence()
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
static Type type(const Type &type)
void addDirectDependency(const CCopasiObject *pObject)
std::string::size_type getErrorPosition() const
struct MESSAGES Message
bool dependsOnTree(const std::string &name) const
static CEvaluationTree * copy(const CEvaluationTree &src)
bool operator==(const CEvaluationTree &rhs) const
Context * parentContextPtr()
CCopasiObject::DataObjectSet getDeletedObjects() const
bool isUsable() const
bool setTree(const ASTNode &pRootNode)
CEvaluationNode * getRootNode()
#define C_FLOAT64
Definition: copasi.h:92
virtual bool isBoolean() const
CCopasiNode< Data > * getParent()
Definition: CCopasiNode.h:139
virtual bool compile(const CEvaluationTree *pTree)
virtual bool compile()
The class for handling a chemical kinetic function.
Definition: CFunction.h:29
std::string::size_type mErrorPosition
static const char * XMLType[]
static void freeNodeList(std::vector< CEvaluationNode * > *pNodeList)
virtual const CObjectInterface * getObject(const CCopasiObjectName &cn) const
CNodeIteratorMode::State end() const
bool calls(std::set< std::string > &list) const
static CEvaluationNode * fromAST(const ASTNode *pASTNode, const std::vector< CEvaluationNode * > &children)
std::set< const CCopasiObject * > DataObjectSet
const std::vector< CEvaluationNode * > & getNodeList() const
CEvaluationTree(const std::string &name="NoName", const CCopasiContainer *pParent=NULL, const Type &type=Function)
CCopasiObject * addObjectReference(const std::string &name, CType &reference, const unsigned C_INT32 &flag=0)
bool isBoolean() const
bool hasCircularDependency() const
CEvaluationNode * getRoot()
const std::string & getInfix() const
virtual bool setInfix(const std::string &infix)
CEvaluationNode * mpRoot
const CCopasiObject * getDataObject() const
std::vector< CEvaluationNode * > * getNodeList()
CEvaluationTree::Type mType
static CEvaluationTree * create(CEvaluationTree::Type type)