aGrUM  0.14.2
formula.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Pierre-Henri WUILLEMIN et Christophe GONZALES *
3  * {prenom.nom}_at_lip6.fr *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
22 
23 // Keep this here because of cyclic dependencies
24 #include <agrum/core/math/cocoR/Parser.h>
25 #include <agrum/core/math/cocoR/Scanner.h>
26 
27 namespace gum {
28 
29  // ==========================================================================
30  // === Class FormulaPart ===
31  // ==========================================================================
32 
33  // Helper function for debuging
34  void print_stack(std::stack< FormulaPart > s) {
35  std::cout << std::endl;
36  std::list< FormulaPart > l;
37  while (!s.empty()) {
38  l.push_front(s.top());
39  s.pop();
40  }
41 
42  std::cout << "Stack: ";
43  for (const auto& elt : l) {
44  std::cout << elt.str() << " ";
45  }
46  std::cout << std::endl;
47  }
48 
49  // Helper function for debuging
50  void print_output(std::vector< FormulaPart > v) {
51  std::cout << "Output: ";
52  for (const auto& elt : v) {
53  std::cout << elt.str() << " ";
54  }
55  std::cout << std::endl;
56  }
57 
59  switch (func) {
60  case FormulaPart::token_function::exp: {
61  return "exp";
62  }
63  case FormulaPart::token_function::log: {
64  return "log";
65  }
66  case FormulaPart::token_function::ln: {
67  return "ln";
68  }
69  case FormulaPart::token_function::pow: {
70  return "pow";
71  }
72  case FormulaPart::token_function::sqrt: {
73  return "sqrt";
74  }
75  case FormulaPart::token_function::nil: {
76  return "nil";
77  }
78  default: { GUM_ERROR(OperationNotAllowed, "unknown function"); }
79  }
80  }
81 
83  type(token_type::NIL), number(NAN), character('\0'), function(nil) {
84  GUM_CONSTRUCTOR(FormulaPart);
85  }
86 
88  type(t), number(n), character('\0'), function(nil) {
89  GUM_CONSTRUCTOR(FormulaPart);
90  }
91 
93  type(t), number(NAN), character(c), function(nil) {
94  GUM_CONSTRUCTOR(FormulaPart);
95  }
96 
98  type(t), number(NAN), character('\0'), function(func) {
99  GUM_CONSTRUCTOR(FormulaPart);
100  }
101 
103  type(source.type), number(source.number), character(source.character),
104  function(source.function) {
105  GUM_CONS_CPY(FormulaPart);
106  }
107 
109  type(std::move(source.type)), number(std::move(source.number)),
110  character(std::move(source.character)),
111  function(std::move(source.function)) {
112  GUM_CONS_MOV(FormulaPart);
113  }
114 
115  FormulaPart::~FormulaPart() { GUM_DESTRUCTOR(FormulaPart); }
116 
118  if (this == &source) { return *this; }
119 
120  type = source.type;
121  number = source.number;
122  character = source.character;
123  function = source.function;
124 
125  return *this;
126  }
127 
129  if (this == &source) { return *this; }
130 
131  type = std::move(source.type);
132  number = std::move(source.number);
133  character = std::move(source.character);
134  function = std::move(source.function);
135 
136  return *this;
137  }
138 
139  std::string FormulaPart::str() const {
140  std::ostringstream s;
141  switch (type) {
142  case token_type::NUMBER: {
143  s << number;
144  break;
145  }
146 
147  case token_type::PARENTHESIS:
148  case token_type::OPERATOR: {
149  if (character == '\0') {
150  s << "\\0";
151  } else {
152  s << character;
153  }
154  break;
155  }
156 
157  case token_type::FUNCTION: {
158  s << func2str(function);
159  break;
160  }
161 
162  default: { GUM_ERROR(OperationNotAllowed, "unknown type"); }
163  }
164  return s.str();
165  }
166 
167  // ==========================================================================
168  // === Class Formula ===
169  // ==========================================================================
170 
172  auto c_str = (unsigned char*)__formula.c_str();
173  auto scanner = new gum::formula::Scanner(c_str, (int)__formula.size());
174  __scanner = std::unique_ptr< gum::formula::Scanner >(scanner);
175 
176  auto parser = new gum::formula::Parser(scanner);
177  __parser = std::unique_ptr< gum::formula::Parser >(parser);
178  __parser->formula(this);
179  }
180 
181  Formula::Formula(short s) :
182  __formula(std::to_string(s)), __last_token(FormulaPart()) {
183  GUM_CONSTRUCTOR(Formula);
184  __initialise();
185  }
186 
187  Formula::Formula(unsigned short us) :
189  GUM_CONSTRUCTOR(Formula);
190  __initialise();
191  }
192 
195  GUM_CONSTRUCTOR(Formula);
196  __initialise();
197  }
198 
199  Formula::Formula(unsigned int ui) :
201  GUM_CONSTRUCTOR(Formula);
202  __initialise();
203  }
204 
207  GUM_CONSTRUCTOR(Formula);
208  __initialise();
209  }
210 
211  Formula::Formula(unsigned long ul) :
213  GUM_CONSTRUCTOR(Formula);
214  __initialise();
215  }
216 
217  Formula::Formula(long long l) :
219  GUM_CONSTRUCTOR(Formula);
220  __initialise();
221  }
222 
223  Formula::Formula(unsigned long long ul) :
225  GUM_CONSTRUCTOR(Formula);
226  __initialise();
227  }
228 
229  Formula::Formula(float f) :
231  GUM_CONSTRUCTOR(Formula);
232  __initialise();
233  }
234 
235  Formula::Formula(double d) :
237  GUM_CONSTRUCTOR(Formula);
238  __initialise();
239  }
240 
241  Formula::Formula(const std::string& f) :
243  GUM_CONSTRUCTOR(Formula);
244 
245  __initialise();
246  }
247 
248  Formula::Formula(const Formula& source) :
249  __formula(source.__formula), __last_token(source.__last_token),
250  __output(source.__output), __stack(source.__stack) {
251  GUM_CONS_CPY(Formula);
252 
253  __initialise();
254  }
255 
257  __formula(std::move(source.__formula)),
258  __scanner(std::move(source.__scanner)), __parser(std::move(source.__parser)),
259  __last_token(std::move(source.__last_token)),
260  __output(std::move(source.__output)), __stack(std::move(source.__stack)) {
261  GUM_CONS_CPY(Formula);
262 
263  __parser->formula(this);
264  }
265 
266  Formula::~Formula() { GUM_DESTRUCTOR(Formula); }
267 
269  if (this == &source) { return *this; }
270 
271  __formula = source.__formula;
272  __last_token = source.__last_token;
273  __output = source.__output;
274  __stack = source.__stack;
275 
276  __initialise();
277 
278  return *this;
279  }
280 
282  if (this == &source) { return *this; }
283 
284  __formula = std::move(source.__formula);
285  __scanner = std::move(source.__scanner);
286  __parser = std::move(source.__parser);
287  __parser->formula(this);
288  __last_token = std::move(source.__last_token);
289  __output = std::move(source.__output);
290  __stack = std::move(source.__stack);
291 
292  return *this;
293  }
294 
295  double Formula::result() const {
296  __parser->Parse();
297 
298  std::stack< FormulaPart > stack;
299  if (__output.empty()) { GUM_ERROR(OperationNotAllowed, "no output found"); }
300 
301  for (auto item : __output) {
302  switch (item.type) {
303  case FormulaPart::token_type::NUMBER: {
304  stack.push(item);
305  break;
306  }
307 
308  case FormulaPart::token_type::OPERATOR:
309  case FormulaPart::token_type::FUNCTION: {
310  __reduceOperatorOrFunction(item, stack);
311  break;
312  }
313 
314  default: {
316  "expecting numbers, operators or functions");
317  }
318  }
319  }
320 
321  if (stack.size() != 1) {
322  GUM_ERROR(OperationNotAllowed, "too many inputs");
323 
324  } else if (stack.top().type != FormulaPart::token_type::NUMBER) {
325  GUM_ERROR(OperationNotAllowed, "too many inputs");
326  }
327  return stack.top().number;
328  }
329 
330 } // namespace gum
331 
332 #ifdef GUM_NO_INLINE
334 #endif // GUM_NO_INLINE
double result() const
Returns the result of this gum::Formula.
Definition: formula.cpp:295
std::string __formula
The formula to evaluate.
Definition: formula.h:439
token_function function
The value stored by this gum::FormulaPart.
Definition: formula.h:77
void __reduceOperatorOrFunction(FormulaPart item, std::stack< FormulaPart > &stack) const
Evaluate an operator or function and push its result.
Definition: formula_inl.h:342
token_type
The tokens constituting a formula.
Definition: formula.h:60
Evaluates a string as a algebraic formula.
Definition: formula.h:271
STL namespace.
std::unique_ptr< gum::formula::Parser > __parser
The parser used by the formula.
Definition: formula.h:445
token_function
The functions allowed in a formula.
Definition: formula.h:63
FormulaPart __last_token
The last token added to the formula.
Definition: formula.h:448
Headers files for the gum::FormulaPart and gum::Formula classes.
Represents part of a formula.
Definition: formula.h:57
~Formula()
Class destructor.
Definition: formula.cpp:266
gum is the global namespace for all aGrUM entities
Definition: agrum.h:25
std::string func2str(FormulaPart::token_function func)
Definition: formula.cpp:58
Formula & operator=(const Formula &source)
Copy operator.
Definition: formula.cpp:268
std::string to_string(const Formula &f)
Definition: formula_inl.h:479
token_type type
The token_type stored by this gum::FormulaPart.
Definition: formula.h:66
std::stack< FormulaPart > __stack
A stack used during evaluation.
Definition: formula.h:454
Formula(short s)
Constructor.
Definition: formula.cpp:181
FormulaPart()
Class constructor.
Definition: formula.cpp:82
void print_stack(std::stack< FormulaPart > s)
Definition: formula.cpp:34
~FormulaPart()
Class destuctor.
Definition: formula.cpp:115
FormulaPart & operator=(const FormulaPart &source)
Definition: formula.cpp:117
void __initialise()
Initialise the formula scanner and parser.
Definition: formula.cpp:171
void print_output(std::vector< FormulaPart > v)
Definition: formula.cpp:50
std::vector< FormulaPart > __output
The output stack, will contain one value after evaluation.
Definition: formula.h:451
double number
The value stored by this gum::FormulaPart.
Definition: formula.h:75
std::unique_ptr< gum::formula::Scanner > __scanner
The scanner used by the formula.
Definition: formula.h:442
char character
The value stored by this gum::FormulaPart.
Definition: formula.h:76
std::string str() const
Returns a string representation of this gum::FormulaPart value.
Definition: formula.cpp:139
#define GUM_ERROR(type, msg)
Definition: exceptions.h:52