aGrUM  0.15.0
formula_inl.h
Go to the documentation of this file.
1 
24 
25 namespace gum {
26 
27  // ==========================================================================
28  // === Class FormulaPart ===
29  // ==========================================================================
30 
31 
32  INLINE
34  switch (character) {
35  case '+':
36  case '-':
37  case '*':
38  case '/': {
39  return true;
40  }
41 
42  case '_': {
43  return false;
44  }
45  case '^': {
46  return false;
47  }
48 
49  default: {
50  GUM_ERROR(OperationNotAllowed, "A - not an operator");
51  }
52  }
53  }
54 
55  INLINE
57  switch (character) {
58  case '_': {
59  return false;
60  }
61  default: {
62  return !isLeftAssociative();
63  }
64  }
65  }
66 
67  INLINE
69  switch (character) {
70  case '+':
71  case '-': {
72  return 2;
73  }
74 
75  case '*':
76  case '/': {
77  return 3;
78  }
79 
80  case '^': {
81  return 4;
82  }
83 
84  case '_': {
85  return 5;
86  }
87 
88  default: {
89  GUM_ERROR(OperationNotAllowed, "B - not an operator");
90  }
91  }
92  }
93 
94  INLINE
95  size_t FormulaPart::argc() const {
96  switch (type) {
97  case OPERATOR: {
98  return __operator_argc();
99  }
100 
101  case FUNCTION: {
102  return __function_argc();
103  }
104 
105  default: {
106  GUM_ERROR(OperationNotAllowed, "expecting a function or an operator");
107  }
108  }
109  }
110 
111  INLINE
113  switch (character) {
114  case '_': {
115  return (size_t)1;
116  }
117  case '+':
118  case '-':
119  case '*':
120  case '/':
121  case '^': {
122  return (size_t)2;
123  }
124 
125  default: {
126  GUM_ERROR(OperationNotAllowed, "C - not an operator");
127  }
128  }
129  }
130 
131  INLINE
133  switch (function) {
134  case FormulaPart::token_function::exp: {
135  return 1;
136  }
137  case FormulaPart::token_function::log: {
138  return 1;
139  }
140  case FormulaPart::token_function::ln: {
141  return 1;
142  }
143  case FormulaPart::token_function::pow: {
144  return 2;
145  }
146  case FormulaPart::token_function::sqrt: {
147  return 1;
148  }
149  // case FormulaPart::token_function::nil: { return "nil"; }
150  default: {
151  GUM_ERROR(OperationNotAllowed, "unknown function");
152  }
153  }
154  }
155 
157  INLINE
158  double
159  FormulaPart::__operator_eval(const std::vector< FormulaPart >& args) const {
160  switch (character) {
161  case '+': {
162  return args[1].number + args[0].number;
163  }
164 
165  case '-': {
166  return args[1].number - args[0].number;
167  }
168 
169  case '*': {
170  return args[1].number * args[0].number;
171  }
172 
173  case '/': {
174  return args[1].number / args[0].number;
175  }
176 
177  case '^': {
178  return std::pow(args[1].number, args[0].number);
179  }
180 
181  case '_': {
182  return 0 - args[0].number;
183  }
184 
185  default: {
186  GUM_ERROR(OperationNotAllowed, "D - not an operator");
187  }
188  }
189  }
190 
192  INLINE
193  double
194  FormulaPart::__function_eval(const std::vector< FormulaPart >& args) const {
195  switch (function) {
196  case FormulaPart::token_function::exp: {
197  return std::exp(args[0].number);
198  }
199  case FormulaPart::token_function::log: {
200  return std::log(args[0].number);
201  }
202  case FormulaPart::token_function::ln: {
203  return std::log2(args[0].number);
204  }
205  case FormulaPart::token_function::pow: {
206  return std::pow(args[1].number, args[0].number);
207  }
208  case FormulaPart::token_function::sqrt: {
209  return std::sqrt(args[0].number);
210  }
211  // case FormulaPart::token_function::nil: { return "nil"; }
212  default: {
213  GUM_ERROR(OperationNotAllowed, "unknown function");
214  }
215  }
216  }
217 
219  INLINE
220  FormulaPart FormulaPart::eval(const std::vector< FormulaPart >& args) const {
221  switch (type) {
222  case OPERATOR: {
223  return FormulaPart(token_type::NUMBER, __operator_eval(args));
224  }
225 
226  case FUNCTION: {
227  return FormulaPart(token_type::NUMBER, __function_eval(args));
228  }
229 
230  default: {
231  GUM_ERROR(OperationNotAllowed, "cannot evaluate expression");
232  }
233  }
234  }
235 
236  // ==========================================================================
237  // === Class Formula ===
238  // ==========================================================================
239 
240 
241  INLINE
242  const std::string& Formula::formula() const { return __formula; }
243 
244  INLINE
245  std::string& Formula::formula() { return __formula; }
246 
247  INLINE
248  void Formula::__push_number(const double& v) {
249  FormulaPart t(FormulaPart::token_type::NUMBER, v);
250  __push_output(t);
251  }
252 
253  INLINE
255  if (__stack.empty()
256  || __stack.top().type != FormulaPart::token_type::OPERATOR) {
257  return false;
258  }
259 
260  if (o.isLeftAssociative() && o.precedence() <= __stack.top().precedence()) {
261  return true;
262  }
263 
264  if (o.isRightAssociative() && o.precedence() < __stack.top().precedence()) {
265  return true;
266  }
267 
268  return false;
269  }
270 
271  INLINE
273  if (__isUnaryOperator(o)) {
274  __push_unaryOperator(o);
275 
276  } else {
277  FormulaPart t(FormulaPart::token_type::OPERATOR, o);
278  __push_operator(t);
279  }
280  }
281 
282  INLINE
284  switch (__last_token.type) {
285  case FormulaPart::token_type::OPERATOR:
286  case FormulaPart::token_type::NIL:
287  case FormulaPart::token_type::ARG_SEP: {
288  return o == '-';
289  }
290 
291  case FormulaPart::token_type::PARENTHESIS: {
292  return (o == '-') && (__last_token.character == '(');
293  }
294 
295  default: {
296  return false;
297  }
298  }
299  }
300 
301  INLINE
303  // Only unary operator is the negative sign -
304  FormulaPart t(FormulaPart::token_type::OPERATOR, '_');
305  __push_operator(t);
306  }
307 
308  INLINE
310  while (__popOperator(t)) {
311  __push_output(__stack.top());
312  __stack.pop();
313  }
314 
315  __push_stack(t);
316  }
317 
318  INLINE
320  FormulaPart t(FormulaPart::token_type::PARENTHESIS, '(');
321  __push_stack(t);
322  }
323 
324  INLINE
326  while ((!__stack.empty()) && (__stack.top().character != '(')) {
327  __push_output(__stack.top());
328  __stack.pop();
329  }
330 
331  if (__stack.empty()) {
332  GUM_ERROR(OperationNotAllowed, "expecting '('");
333 
334  } else if (__stack.top().character != '(') {
335  GUM_ERROR(OperationNotAllowed, "expecting '('");
336  }
337 
338  __stack.pop();
339 
340  if ((!__stack.empty())
341  && __stack.top().type == FormulaPart::token_type::FUNCTION) {
342  __push_output(__stack.top());
343  __stack.pop();
344  }
345  __last_token = FormulaPart(FormulaPart::token_type::PARENTHESIS, ')');
346  }
347 
348  INLINE
350  while (!__stack.empty()) {
351  if (__stack.top().character == '(') {
352  GUM_ERROR(OperationNotAllowed, "expecting ')'");
353  }
354 
355  __push_output(__stack.top());
356  __stack.pop();
357  }
358  }
359 
360  INLINE
361  void
363  std::stack< FormulaPart >& stack) const {
364  std::vector< FormulaPart > args;
365 
366  if (stack.size() < item.argc()) {
367  GUM_ERROR(OperationNotAllowed, "not enought inputs ");
368  }
369 
370  while (item.argc() > args.size()) {
371  args.push_back(stack.top());
372  stack.pop();
373  }
374 
375  stack.push(item.eval(args));
376  }
377 
378  INLINE
380  __output.push_back(t);
381  __last_token = t;
382  }
383 
384  INLINE
386  __stack.push(t);
387  __last_token = t;
388  }
389 
390  INLINE
391  void Formula::__push_function(const std::string& func) {
392  if (func == "exp") {
393  FormulaPart t(FormulaPart::token_type::FUNCTION,
394  FormulaPart::token_function::exp);
395  __push_stack(t);
396 
397  } else if (func == "log") {
398  FormulaPart t(FormulaPart::token_type::FUNCTION,
399  FormulaPart::token_function::log);
400  __push_stack(t);
401 
402  } else if (func == "ln") {
403  FormulaPart t(FormulaPart::token_type::FUNCTION,
404  FormulaPart::token_function::ln);
405  __push_stack(t);
406 
407  } else if (func == "pow") {
408  FormulaPart t(FormulaPart::token_type::FUNCTION,
409  FormulaPart::token_function::pow);
410  __push_stack(t);
411 
412  } else if (func == "sqrt") {
413  FormulaPart t(FormulaPart::token_type::FUNCTION,
414  FormulaPart::token_function::sqrt);
415  __push_stack(t);
416 
417  } else {
418  GUM_ERROR(OperationNotAllowed, "unknown function");
419  }
420  }
421 
422  INLINE
424  while ((!__stack.empty()) && (__stack.top().character != '(')) {
425  __push_output(__stack.top());
426  __stack.pop();
427  }
428 
429  if (__stack.empty() || __stack.top().character != '(') {
430  GUM_ERROR(OperationNotAllowed, "expecting a '('");
431  }
432 
433  __last_token = FormulaPart(FormulaPart::token_type::ARG_SEP, ',');
434  }
435 
436  INLINE
438 
439  INLINE
441  return __variables;
442  }
443 
444  INLINE
445  void Formula::__push_variable(const std::string& var) {
446  if (__variables.exists(var)) {
447  __push_number(__variables[var]);
448 
449  } else {
450  GUM_ERROR(OperationNotAllowed, "unknonw variable");
451  }
452  }
453 
454  INLINE
455  void Formula::__push_identifier(const std::string& ident) {
456  try {
457  __push_function(ident);
458 
459  } catch (OperationNotAllowed&) {
460  try {
461  __push_variable(ident);
462 
463  } catch (OperationNotAllowed&) {
464  GUM_ERROR(OperationNotAllowed, "unknown identifier");
465  }
466  }
467  }
468 
469  // ========================================================================
470  // @name Arithmetic Operators
471  // ========================================================================
472 
473  INLINE
475  return Formula(std::to_string(-1 * a.result()));
476  }
477 
478  INLINE
479  Formula operator+(const Formula& a, const Formula& b) {
480  return Formula(std::to_string(a.result() + b.result()));
481  }
482 
483  INLINE
484  Formula operator-(const Formula& a, const Formula& b) {
485  return Formula(std::to_string(a.result() - b.result()));
486  }
487 
488  INLINE
489  Formula operator*(const Formula& a, const Formula& b) {
490  return Formula(std::to_string(a.result() * b.result()));
491  }
492 
493  INLINE
494  Formula operator/(const Formula& a, const Formula& b) {
495  return Formula(std::to_string(a.result() / b.result()));
496  }
497 
498  INLINE
499  std::string to_string(const Formula& f) { return std::to_string(f.result()); }
500 
501  INLINE
502  std::ostream& operator<<(std::ostream& os, const Formula& f) {
503  os << f.result();
504  return os;
505  }
506 
507 } // namespace gum
const std::string & formula() const
Returns the formula.
Definition: formula_inl.h:242
double result() const
Returns the result of this gum::Formula.
Definition: formula.cpp:301
void __push_function(const std::string &func)
Push a function in the formula.
Definition: formula_inl.h:391
size_t __function_argc() const
Returns the number of arguments expected by the function stored in this gum::FormulaPart.
Definition: formula_inl.h:132
bool __isUnaryOperator(char o)
Returns true if o is an unary operator.
Definition: formula_inl.h:283
size_t argc() const
Returns the number of argument of the function stored in this gum::FormulaPart.
Definition: formula_inl.h:95
void __push_rightParenthesis()
Push a right parenthesis in the formula.
Definition: formula_inl.h:325
bool __popOperator(FormulaPart o)
Pop the operator in the inner formula&#39;s stack.
Definition: formula_inl.h:254
void __reduceOperatorOrFunction(FormulaPart item, std::stack< FormulaPart > &stack) const
Evaluate an operator or function and push its result.
Definition: formula_inl.h:362
bool isRightAssociative() const
Returns true if this gum::FormulaPart is right associative.
Definition: formula_inl.h:56
Formula operator+(const Formula &a, const Formula &b)
Definition: formula_inl.h:479
Evaluates a string as a algebraic formula.
Definition: formula.h:274
FormulaPart eval(const std::vector< FormulaPart > &args) const
Returns the evaluation of the vector of gum::FormulaPart as arguments of the value stored in this gum...
Definition: formula_inl.h:220
void __finalize()
Finalize the formula and prepare it for evaluation.
Definition: formula_inl.h:349
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
double __operator_eval(const std::vector< FormulaPart > &args) const
Returns the evaluation of the vector of gum::FormulaPart as arguments of the value stored in this gum...
Definition: formula_inl.h:159
Represents part of a formula.
Definition: formula.h:60
size_t __operator_argc() const
Returns the number of arguments expected by the operator stored in this gum::FormulaPart.
Definition: formula_inl.h:112
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Definition: agrum.h:25
void __push_number(const double &v)
Push a number in the formula.
Definition: formula_inl.h:248
void __push_identifier(const std::string &ident)
Use this if you don&#39;t know if ident is a function or a variable.
Definition: formula_inl.h:455
std::ostream & operator<<(std::ostream &output, const BayesNet< GUM_SCALAR > &bn)
Prints map&#39;s DAG in output using the Graphviz-dot format.
Definition: BayesNet_tpl.h:586
Formula operator/(const Formula &a, const Formula &b)
Definition: formula_inl.h:494
std::string to_string(const Formula &f)
Definition: formula_inl.h:499
void __push_variable(const std::string &var)
Push a variable in the formula.
Definition: formula_inl.h:445
Formula operator*(const Formula &a, const Formula &b)
Definition: formula_inl.h:489
token_type type
The token_type stored by this gum::FormulaPart.
Definition: formula.h:69
double __function_eval(const std::vector< FormulaPart > &args) const
Returns the evaluation of the vector of gum::FormulaPart as arguments of the value stored in this gum...
Definition: formula_inl.h:194
ListConstIterator< Val >::difference_type operator-(const ListConstIterator< Val > &iter1, const ListConstIterator< Val > &iter2)
For STL compliance, a distance operator.
Definition: list_tpl.h:349
FormulaPart()
Class constructor.
Definition: formula.cpp:86
void __push_stack(FormulaPart t)
Push the gum::FormulaPart in the stack.
Definition: formula_inl.h:385
bool isLeftAssociative() const
Returns true if this gum::FormulaPart is left associative.
Definition: formula_inl.h:33
void __push_comma()
Push a comma in the formula.
Definition: formula_inl.h:423
int precedence() const
Returns the precedence priority of the value stored in this gum::FormulaPart.
Definition: formula_inl.h:68
void __push_operator(char o)
Push an operator in the formula.
Definition: formula_inl.h:272
void __push_output(FormulaPart t)
Push the gum::FormulaPart in the output vector.
Definition: formula_inl.h:379
double number
The value stored by this gum::FormulaPart.
Definition: formula.h:78
HashTable< std::string, double > & variables()
Returns the variables used by this gum::Formula.
Definition: formula_inl.h:437
void __push_unaryOperator(char o)
Push an unary operator.
Definition: formula_inl.h:302
char character
The value stored by this gum::FormulaPart.
Definition: formula.h:79
void __push_leftParenthesis()
Push a left parenthesis in the formula.
Definition: formula_inl.h:319
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55