aGrUM  0.20.2
a C++ library for (probabilistic) graphical models
formula_inl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright 2005-2020 Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 #include <agrum/tools/core/math/formula.h>
23 
24 namespace gum {
25 
26  // ==========================================================================
27  // === Class FormulaPart ===
28  // ==========================================================================
29 
30 
31  INLINE
33  switch (character) {
34  case '+':
35  case '-':
36  case '*':
37  case '/': {
38  return true;
39  }
40 
41  case '_': {
42  return false;
43  }
44  case '^': {
45  return false;
46  }
47 
48  default: {
49  GUM_ERROR(OperationNotAllowed, "A - not an operator");
50  }
51  }
52  }
53 
54  INLINE
56  switch (character) {
57  case '_': {
58  return false;
59  }
60  default: {
61  return !isLeftAssociative();
62  }
63  }
64  }
65 
66  INLINE
67  int FormulaPart::precedence() const {
68  switch (character) {
69  case '+':
70  case '-': {
71  return 2;
72  }
73 
74  case '*':
75  case '/': {
76  return 3;
77  }
78 
79  case '^': {
80  return 4;
81  }
82 
83  case '_': {
84  return 5;
85  }
86 
87  default: {
88  GUM_ERROR(OperationNotAllowed, "B - not an operator");
89  }
90  }
91  }
92 
93  INLINE
94  size_t FormulaPart::argc() const {
95  switch (type) {
96  case OPERATOR: {
97  return operator_argc__();
98  }
99 
100  case FUNCTION: {
101  return function_argc__();
102  }
103 
104  default: {
105  GUM_ERROR(OperationNotAllowed, "expecting a function or an operator");
106  }
107  }
108  }
109 
110  INLINE
112  switch (character) {
113  case '_': {
114  return (size_t)1;
115  }
116  case '+':
117  case '-':
118  case '*':
119  case '/':
120  case '^': {
121  return (size_t)2;
122  }
123 
124  default: {
125  GUM_ERROR(OperationNotAllowed, "C - not an operator");
126  }
127  }
128  }
129 
130  INLINE
132  switch (function) {
133  case FormulaPart::token_function::exp: {
134  return 1;
135  }
136  case FormulaPart::token_function::log: {
137  return 1;
138  }
139  case FormulaPart::token_function::ln: {
140  return 1;
141  }
142  case FormulaPart::token_function::pow: {
143  return 2;
144  }
146  return 1;
147  }
148  // case FormulaPart::token_function::nil: { return "nil"; }
149  default: {
150  GUM_ERROR(OperationNotAllowed, "unknown function");
151  }
152  }
153  }
154 
155  /// Args are backwards !
156  INLINE
157  double
159  switch (character) {
160  case '+': {
161  return args[1].number + args[0].number;
162  }
163 
164  case '-': {
165  return args[1].number - args[0].number;
166  }
167 
168  case '*': {
169  return args[1].number * args[0].number;
170  }
171 
172  case '/': {
173  return args[1].number / args[0].number;
174  }
175 
176  case '^': {
177  return std::pow(args[1].number, args[0].number);
178  }
179 
180  case '_': {
181  return 0 - args[0].number;
182  }
183 
184  default: {
185  GUM_ERROR(OperationNotAllowed, "D - not an operator");
186  }
187  }
188  }
189 
190  /// Args are backwards !
191  INLINE
192  double
194  switch (function) {
195  case FormulaPart::token_function::exp: {
196  return std::exp(args[0].number);
197  }
198  case FormulaPart::token_function::log: {
199  return std::log(args[0].number);
200  }
201  case FormulaPart::token_function::ln: {
202  return std::log2(args[0].number);
203  }
204  case FormulaPart::token_function::pow: {
205  return std::pow(args[1].number, args[0].number);
206  }
208  return std::sqrt(args[0].number);
209  }
210  // case FormulaPart::token_function::nil: { return "nil"; }
211  default: {
212  GUM_ERROR(OperationNotAllowed, "unknown function");
213  }
214  }
215  }
216 
217  /// Args are backwards !
218  INLINE
220  switch (type) {
221  case OPERATOR: {
223  }
224 
225  case FUNCTION: {
227  }
228 
229  default: {
230  GUM_ERROR(OperationNotAllowed, "cannot evaluate expression");
231  }
232  }
233  }
234 
235  // ==========================================================================
236  // === Class Formula ===
237  // ==========================================================================
238 
239 
240  INLINE
241  const std::string& Formula::formula() const { return formula__; }
242 
243  INLINE
244  std::string& Formula::formula() { return formula__; }
245 
246  INLINE
247  void Formula::push_number__(const double& v) {
249  push_output__(t);
250  }
251 
252  INLINE
254  if (stack__.empty()
256  return false;
257  }
258 
259  if (o.isLeftAssociative() && o.precedence() <= stack__.top().precedence()) {
260  return true;
261  }
262 
264  return true;
265  }
266 
267  return false;
268  }
269 
270  INLINE
271  void Formula::push_operator__(char o) {
272  if (isUnaryOperator__(o)) {
274 
275  } else {
278  }
279  }
280 
281  INLINE
283  switch (last_token__.type) {
285  case FormulaPart::token_type::NIL:
286  case FormulaPart::token_type::ARG_SEP: {
287  return o == '-';
288  }
289 
291  return (o == '-') && (last_token__.character == '(');
292  }
293 
294  default: {
295  return false;
296  }
297  }
298  }
299 
300  INLINE
302  // Only unary operator is the negative sign -
305  }
306 
307  INLINE
309  while (popOperator__(t)) {
311  stack__.pop();
312  }
313 
314  push_stack__(t);
315  }
316 
317  INLINE
320  push_stack__(t);
321  }
322 
323  INLINE
325  while ((!stack__.empty()) && (stack__.top().character != '(')) {
327  stack__.pop();
328  }
329 
330  if (stack__.empty()) {
331  GUM_ERROR(OperationNotAllowed, "expecting '('");
332 
333  } else if (stack__.top().character != '(') {
334  GUM_ERROR(OperationNotAllowed, "expecting '('");
335  }
336 
337  stack__.pop();
338 
339  if ((!stack__.empty())
342  stack__.pop();
343  }
345  }
346 
347  INLINE
348  void Formula::finalize__() {
349  while (!stack__.empty()) {
350  if (stack__.top().character == '(') {
351  GUM_ERROR(OperationNotAllowed, "expecting ')'");
352  }
353 
355  stack__.pop();
356  }
357  }
358 
359  INLINE
360  void
362  std::stack< FormulaPart >& stack) const {
364 
365  if (stack.size() < item.argc()) {
366  GUM_ERROR(OperationNotAllowed, "not enought inputs ");
367  }
368 
369  while (item.argc() > args.size()) {
370  args.push_back(stack.top());
371  stack.pop();
372  }
373 
374  stack.push(item.eval(args));
375  }
376 
377  INLINE
380  last_token__ = t;
381  }
382 
383  INLINE
385  stack__.push(t);
386  last_token__ = t;
387  }
388 
389  INLINE
391  if (func == "exp") {
394  push_stack__(t);
395 
396  } else if (func == "log") {
399  push_stack__(t);
400 
401  } else if (func == "ln") {
404  push_stack__(t);
405 
406  } else if (func == "pow") {
409  push_stack__(t);
410 
411  } else if (func == "sqrt") {
414  push_stack__(t);
415 
416  } else {
417  GUM_ERROR(OperationNotAllowed, "unknown function");
418  }
419  }
420 
421  INLINE
423  while ((!stack__.empty()) && (stack__.top().character != '(')) {
425  stack__.pop();
426  }
427 
428  if (stack__.empty() || stack__.top().character != '(') {
429  GUM_ERROR(OperationNotAllowed, "expecting a '('");
430  }
431 
433  }
434 
435  INLINE
436  HashTable< std::string, double >& Formula::variables() { return variables__; }
437 
438  INLINE
439  const HashTable< std::string, double >& Formula::variables() const {
440  return variables__;
441  }
442 
443  INLINE
445  if (variables__.exists(var)) {
447 
448  } else {
449  GUM_ERROR(OperationNotAllowed, "unknonw variable");
450  }
451  }
452 
453  INLINE
455  try {
457 
458  } catch (OperationNotAllowed&) {
459  try {
461 
462  } catch (OperationNotAllowed&) {
463  GUM_ERROR(OperationNotAllowed, "unknown identifier");
464  }
465  }
466  }
467 
468  // ========================================================================
469  // @name Arithmetic Operators
470  // ========================================================================
471 
472  INLINE
474  return Formula(std::to_string(-1 * a.result()));
475  }
476 
477  INLINE
478  Formula operator+(const Formula& a, const Formula& b) {
479  return Formula(std::to_string(a.result() + b.result()));
480  }
481 
482  INLINE
483  Formula operator-(const Formula& a, const Formula& b) {
484  return Formula(std::to_string(a.result() - b.result()));
485  }
486 
487  INLINE
488  Formula operator*(const Formula& a, const Formula& b) {
489  return Formula(std::to_string(a.result() * b.result()));
490  }
491 
492  INLINE
493  Formula operator/(const Formula& a, const Formula& b) {
494  return Formula(std::to_string(a.result() / b.result()));
495  }
496 
497  INLINE
498  std::string to_string(const Formula& f) { return std::to_string(f.result()); }
499 
500  INLINE
502  os << f.result();
503  return os;
504  }
505 
506 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:669