aGrUM  0.18.1
a C++ library for (probabilistic) graphical models
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
size_t argc() const
Returns the number of argument of the function stored in this gum::FormulaPart.
Definition: formula_inl.h:95
bool isRightAssociative() const
Returns true if this gum::FormulaPart is right associative.
Definition: formula_inl.h:56
void push_output__(FormulaPart t)
Push the gum::FormulaPart in the output vector.
Definition: formula_inl.h:379
void push_leftParenthesis__()
Push a left parenthesis in the formula.
Definition: formula_inl.h:319
Formula operator+(const Formula &a, const Formula &b)
Definition: formula_inl.h:479
Evaluates a string as a algebraic formula.
Definition: formula.h:274
void push_rightParenthesis__()
Push a right parenthesis in the formula.
Definition: formula_inl.h:325
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
size_t operator_argc__() const
Returns the number of arguments expected by the operator stored in this gum::FormulaPart.
Definition: formula_inl.h:112
void push_unaryOperator__(char o)
Push an unary operator.
Definition: formula_inl.h:302
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
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
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Represents part of a formula.
Definition: formula.h:60
Copyright 2005-2020 Pierre-Henri WUILLEMIN() & Christophe GONZALES() info_at_agrum_dot_org.
Definition: agrum.h:25
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
void reduceOperatorOrFunction__(FormulaPart item, std::stack< FormulaPart > &stack) const
Evaluate an operator or function and push its result.
Definition: formula_inl.h:362
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:631
Formula operator/(const Formula &a, const Formula &b)
Definition: formula_inl.h:494
void push_variable__(const std::string &var)
Push a variable in the formula.
Definition: formula_inl.h:445
std::string to_string(const Formula &f)
Definition: formula_inl.h:499
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
ListConstIterator< Val >::difference_type operator-(const ListConstIterator< Val > &iter1, const ListConstIterator< Val > &iter2)
For STL compliance, a distance operator.
Definition: list_tpl.h:349
void push_stack__(FormulaPart t)
Push the gum::FormulaPart in the stack.
Definition: formula_inl.h:385
void finalize__()
Finalize the formula and prepare it for evaluation.
Definition: formula_inl.h:349
FormulaPart()
Class constructor.
Definition: formula.cpp:86
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
void push_function__(const std::string &func)
Push a function in the formula.
Definition: formula_inl.h:391
void push_operator__(char o)
Push an operator in the formula.
Definition: formula_inl.h:272
int precedence() const
Returns the precedence priority of the value stored in this gum::FormulaPart.
Definition: formula_inl.h:68
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
bool isUnaryOperator__(char o)
Returns true if o is an unary operator.
Definition: formula_inl.h:283
void push_number__(const double &v)
Push a number in the formula.
Definition: formula_inl.h:248
size_t function_argc__() const
Returns the number of arguments expected by the function stored in this gum::FormulaPart.
Definition: formula_inl.h:132
char character
The value stored by this gum::FormulaPart.
Definition: formula.h:79
#define GUM_ERROR(type, msg)
Definition: exceptions.h:55
bool popOperator__(FormulaPart o)
Pop the operator in the inner formula&#39;s stack.
Definition: formula_inl.h:254