aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
formula_inl.h
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by 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 FormulaPart::_operator_eval_(const std::vector< FormulaPart >& args) const {
158  switch (character) {
159  case '+': {
160  return args[1].number + args[0].number;
161  }
162 
163  case '-': {
164  return args[1].number - args[0].number;
165  }
166 
167  case '*': {
168  return args[1].number * args[0].number;
169  }
170 
171  case '/': {
172  return args[1].number / args[0].number;
173  }
174 
175  case '^': {
176  return std::pow(args[1].number, args[0].number);
177  }
178 
179  case '_': {
180  return 0 - args[0].number;
181  }
182 
183  default: {
184  GUM_ERROR(OperationNotAllowed, "D - not an operator")
185  }
186  }
187  }
188 
189  /// Args are backwards !
190  INLINE
191  double FormulaPart::_function_eval_(const std::vector< FormulaPart >& args) const {
192  switch (function) {
193  case FormulaPart::token_function::exp: {
194  return std::exp(args[0].number);
195  }
196  case FormulaPart::token_function::log: {
197  return std::log(args[0].number);
198  }
199  case FormulaPart::token_function::ln: {
200  return std::log2(args[0].number);
201  }
202  case FormulaPart::token_function::pow: {
203  return std::pow(args[1].number, args[0].number);
204  }
206  return std::sqrt(args[0].number);
207  }
208  // case FormulaPart::token_function::nil: { return "nil"; }
209  default: {
210  GUM_ERROR(OperationNotAllowed, "unknown function")
211  }
212  }
213  }
214 
215  /// Args are backwards !
216  INLINE
218  switch (type) {
219  case OPERATOR: {
221  }
222 
223  case FUNCTION: {
225  }
226 
227  default: {
228  GUM_ERROR(OperationNotAllowed, "cannot evaluate expression")
229  }
230  }
231  }
232 
233  // ==========================================================================
234  // === Class Formula ===
235  // ==========================================================================
236 
237 
238  INLINE
239  const std::string& Formula::formula() const { return _formula_; }
240 
241  INLINE
242  std::string& Formula::formula() { return _formula_; }
243 
244  INLINE
245  void Formula::_push_number_(const double& v) {
247  _push_output_(t);
248  }
249 
250  INLINE
253  return false;
254  }
255 
256  if (o.isLeftAssociative() && o.precedence() <= _stack_.top().precedence()) { return true; }
257 
258  if (o.isRightAssociative() && o.precedence() < _stack_.top().precedence()) { return true; }
259 
260  return false;
261  }
262 
263  INLINE
264  void Formula::_push_operator_(char o) {
265  if (_isUnaryOperator_(o)) {
267 
268  } else {
271  }
272  }
273 
274  INLINE
276  switch (_last_token_.type) {
278  case FormulaPart::token_type::NIL:
279  case FormulaPart::token_type::ARG_SEP: {
280  return o == '-';
281  }
282 
284  return (o == '-') && (_last_token_.character == '(');
285  }
286 
287  default: {
288  return false;
289  }
290  }
291  }
292 
293  INLINE
295  // Only unary operator is the negative sign -
298  }
299 
300  INLINE
302  while (_popOperator_(t)) {
304  _stack_.pop();
305  }
306 
307  _push_stack_(t);
308  }
309 
310  INLINE
313  _push_stack_(t);
314  }
315 
316  INLINE
318  while ((!_stack_.empty()) && (_stack_.top().character != '(')) {
320  _stack_.pop();
321  }
322 
323  if (_stack_.empty()) {
324  GUM_ERROR(OperationNotAllowed, "expecting '('")
325 
326  } else if (_stack_.top().character != '(') {
327  GUM_ERROR(OperationNotAllowed, "expecting '('")
328  }
329 
330  _stack_.pop();
331 
334  _stack_.pop();
335  }
337  }
338 
339  INLINE
340  void Formula::_finalize_() {
341  while (!_stack_.empty()) {
342  if (_stack_.top().character == '(') { GUM_ERROR(OperationNotAllowed, "expecting ')'") }
343 
345  _stack_.pop();
346  }
347  }
348 
349  INLINE
351  std::stack< FormulaPart >& stack) const {
353 
354  if (stack.size() < item.argc()) { GUM_ERROR(OperationNotAllowed, "not enought inputs ") }
355 
356  while (item.argc() > args.size()) {
357  args.push_back(stack.top());
358  stack.pop();
359  }
360 
361  stack.push(item.eval(args));
362  }
363 
364  INLINE
367  _last_token_ = t;
368  }
369 
370  INLINE
372  _stack_.push(t);
373  _last_token_ = t;
374  }
375 
376  INLINE
378  if (func == "exp") {
380  _push_stack_(t);
381 
382  } else if (func == "log") {
384  _push_stack_(t);
385 
386  } else if (func == "ln") {
388  _push_stack_(t);
389 
390  } else if (func == "pow") {
392  _push_stack_(t);
393 
394  } else if (func == "sqrt") {
396  _push_stack_(t);
397 
398  } else {
399  GUM_ERROR(OperationNotAllowed, "unknown function")
400  }
401  }
402 
403  INLINE
405  while ((!_stack_.empty()) && (_stack_.top().character != '(')) {
407  _stack_.pop();
408  }
409 
410  if (_stack_.empty() || _stack_.top().character != '(') {
411  GUM_ERROR(OperationNotAllowed, "expecting a '('")
412  }
413 
415  }
416 
417  INLINE
418  HashTable< std::string, double >& Formula::variables() { return _variables_; }
419 
420  INLINE
421  const HashTable< std::string, double >& Formula::variables() const { return _variables_; }
422 
423  INLINE
425  if (_variables_.exists(var)) {
427 
428  } else {
429  GUM_ERROR(OperationNotAllowed, "unknonw variable")
430  }
431  }
432 
433  INLINE
435  try {
437 
438  } catch (OperationNotAllowed&) {
439  try {
441 
442  } catch (OperationNotAllowed&) { GUM_ERROR(OperationNotAllowed, "unknown identifier") }
443  }
444  }
445 
446  // ========================================================================
447  // @name Arithmetic Operators
448  // ========================================================================
449 
450  INLINE
451  Formula operator-(const Formula& a) { return Formula(std::to_string(-1 * a.result())); }
452 
453  INLINE
454  Formula operator+(const Formula& a, const Formula& b) {
455  return Formula(std::to_string(a.result() + b.result()));
456  }
457 
458  INLINE
459  Formula operator-(const Formula& a, const Formula& b) {
460  return Formula(std::to_string(a.result() - b.result()));
461  }
462 
463  INLINE
464  Formula operator*(const Formula& a, const Formula& b) {
465  return Formula(std::to_string(a.result() * b.result()));
466  }
467 
468  INLINE
469  Formula operator/(const Formula& a, const Formula& b) {
470  return Formula(std::to_string(a.result() / b.result()));
471  }
472 
473  INLINE
474  std::string to_string(const Formula& f) { return std::to_string(f.result()); }
475 
476  INLINE
478  os << f.result();
479  return os;
480  }
481 
482 } // namespace gum
INLINE void emplace(Args &&... args)
Definition: set_tpl.h:643