bpp-core3  3.0.0
ComputationTree.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 #include <algorithm>
6 
7 #include "BinaryOperator.h"
8 #include "ComputationTree.h"
9 #include "ConstantOperator.h"
10 #include "FunctionOperator.h"
11 #include "MathOperator.h"
12 #include "NegativeOperator.h"
13 
14 using namespace std;
15 using namespace bpp;
16 
17 ComputationTree::ComputationTree(const std::string& formula, const std::map<std::string, std::shared_ptr<FunctionInterface>>& functionNames) :
19 {
20  getGraph();
21 
22  std::string str2 = formula;
23 
24  str2.erase(std::remove_if(str2.begin(),
25  str2.end(),
26  [](char x){
27  return std::isspace(x);
28  }),
29  str2.end());
30  string form2 = TextTools::removeWhiteSpaces(formula);
31 
32  setRoot(readFormula_(str2, functionNames));
33 }
34 
35 std::shared_ptr<Operator> ComputationTree::readFormula_(const std::string& formula, const std::map<std::string, std::shared_ptr<FunctionInterface>>& functionNames)
36 {
37  unsigned int level = 0;
38  // inside parentheses check
39  // case + or -
40  // most right '+' or '-' (but not inside '()') search and split
41 
42  for (size_t i = formula.size(); i > 0; --i)
43  {
44  char c = formula[i - 1];
45 
46  if (c == ')')
47  {
48  ++level;
49  continue;
50  }
51 
52  if (c == '(')
53  {
54  --level;
55  continue;
56  }
57 
58  if (level > 0)
59  continue;
60 
61  if ((c == '+' || c == '-') && !(i == 1 || formula[i - 2] == '*' || formula[i - 2] == '/'
62  || formula[i - 2] == '+' || formula[i - 2] == '-' || formula[i - 2] == '('))
63  {
64  std::shared_ptr<Operator> left = readFormula_(formula.substr(0, i - 1), functionNames);
65  std::shared_ptr<Operator> right = readFormula_(formula.substr(i), functionNames);
66 
67  shared_ptr<Operator> here(new BinaryOperator(c, left, right));
68 
69  createNode(here);
70 
71  setFather(left, here);
72  setFather(right, here);
73 
74  return here;
75  }
76  }
77 
78  // case * or /
79  // most right '*' or '/' (but not inside '()') search and split
80  for (size_t i = formula.size(); i > 0; --i)
81  {
82  char c = formula[i - 1];
83 
84  if (c == ')')
85  {
86  ++level;
87  continue;
88  }
89 
90  if (c == '(')
91  {
92  --level;
93  continue;
94  }
95 
96  if (level > 0)
97  continue;
98 
99  if (c == '*' || c == '/')
100  {
101  std::shared_ptr<Operator> left = readFormula_(formula.substr(0, i - 1), functionNames);
102  std::shared_ptr<Operator> right = readFormula_(formula.substr(i), functionNames);
103 
104  shared_ptr<Operator> here(new BinaryOperator(c, left, right));
105 
106  createNode(here);
107 
108  setFather(left, here);
109  setFather(right, here);
110 
111  return here;
112  }
113  }
114 
115 
116  if (formula[0] == '(')
117  return readFormula_(formula.substr(1, formula.size() - 2), functionNames);
118 
119  else
120  // case value
121  {
122  shared_ptr<Operator> here;
123  try
124  {
125  double v = TextTools::toDouble(formula);
126  here = shared_ptr<Operator>(new ConstantOperator(v));
127  }
128  catch (Exception& e)
129  {
130  if (formula[0] == '-')
131  {
132  std::shared_ptr<Operator> son = readFormula_(formula.substr(1), functionNames);
133  here = shared_ptr<Operator>(new NegativeOperator(son));
134  }
135  else
136  {
137  auto it = functionNames.find(formula);
138 
139  if (it != functionNames.end())
140  {
141  if (dynamic_pointer_cast<const SecondOrderDerivable>(it->second))
142  here = shared_ptr<Operator>(new FunctionOperator<SecondOrderDerivable>(*dynamic_pointer_cast<SecondOrderDerivable>(it->second), formula));
143  else if (dynamic_pointer_cast<const FirstOrderDerivable>(it->second))
144  here = shared_ptr<Operator>(new FunctionOperator<FirstOrderDerivable>(*dynamic_pointer_cast<FirstOrderDerivable>(it->second), formula));
145  else
146  here = shared_ptr<Operator>(new FunctionOperator<FunctionInterface>(*it->second, formula));
147  }
148  else
149  {
150  size_t posp = formula.find("(");
151  if (posp == string::npos)
152  throw Exception("ComputationTree::readFormula_ : unknown formula : " + formula);
153 
154  std::shared_ptr<Operator> son = readFormula_(formula.substr(posp), functionNames);
155  string fonc = formula.substr(0, posp);
156 
157  if (fonc == "exp")
158  here = shared_ptr<Operator>(new MathOperator(&exp, "exp", son));
159  else if (fonc == "log")
160  here = shared_ptr<Operator>(new MathOperator(&log, "log", son));
161  else
162  throw Exception("ComputationTree::readFormula_ : unknown formula : " + formula);
163  }
164  }
165  }
166 
167  this->getGraph();
168  createNode(here);
169  return here;
170  } return NULL;
171  // never
172 }
173 
175 {
176  std::unique_ptr<NodeIterator> it = allNodesIterator();
177 
178  for ( ; it->end(); it->next())
179  {
180  const BinaryOperator* op = dynamic_cast<const BinaryOperator*>((**it).get());
181  if (op && op->getSymbol() != '+' && op->getSymbol() != '-')
182  return false;
183  }
184  return true;
185 }
186 
187 
188 std::string ComputationTree::output() const
189 {
190  std::string op = getRoot()->output();
191  while (op.size() > 1 && op[0] == '(' && op[op.size() - 1] == ')')
192  {
193  op = op.substr(1, op.size() - 2);
194  }
195  return op;
196 }
Implements a double operator (ie leaf in the computation tree) where value comes from a function...
double toDouble(const std::string &s, char dec, char scientificNotation)
Convert from string to double.
Definition: TextTools.cpp:217
std::string output() const
STL namespace.
Binary arithmetic operator for numerical computation.
std::string removeWhiteSpaces(const std::string &s)
Remove all white spaces characters in a string.
Definition: TextTools.cpp:57
const std::shared_ptr< TreeGraphImpl > getGraph() const
Implements a unary operator that applies a math (described in cmath) operator.
Definition: MathOperator.h:20
void setRoot(const Nref newRoot)
set the root (but no checking, to be used at first construction)
std::shared_ptr< Operator > readFormula_(const std::string &formula, const std::map< std::string, std::shared_ptr< FunctionInterface >> &functionNames)
std::unique_ptr< typename AssociationGraphObserver< N, E >::NodeIterator > allNodesIterator()
Exception base class. Overload exception constructor (to control the exceptions mechanism). Destructor is already virtual (from std::exception)
Definition: Exceptions.h:20
void setFather(const std::shared_ptr< N > nodeObject, const std::shared_ptr< N > fatherNodeObject, const std::shared_ptr< E > edgeObject=0)
char getSymbol() const
Constant (ie leaf) operator.
Negative value for an operator.
Interface of operator for numerical computation.
Definition: Operator.h:19