aGrUM 2.3.2
a C++ library for (probabilistic) graphical models
formula_inl.h
Go to the documentation of this file.
1/****************************************************************************
2 * This file is part of the aGrUM/pyAgrum library. *
3 * *
4 * Copyright (c) 2005-2025 by *
5 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
6 * - Christophe GONZALES(_at_AMU) *
7 * *
8 * The aGrUM/pyAgrum library is free software; you can redistribute it *
9 * and/or modify it under the terms of either : *
10 * *
11 * - the GNU Lesser General Public License as published by *
12 * the Free Software Foundation, either version 3 of the License, *
13 * or (at your option) any later version, *
14 * - the MIT license (MIT), *
15 * - or both in dual license, as here. *
16 * *
17 * (see https://agrum.gitlab.io/articles/dual-licenses-lgplv3mit.html) *
18 * *
19 * This aGrUM/pyAgrum library is distributed in the hope that it will be *
20 * useful, but WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
21 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES MERCHANTABILITY or FITNESS *
22 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
25 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
26 * OTHER DEALINGS IN THE SOFTWARE. *
27 * *
28 * See LICENCES for more details. *
29 * *
30 * SPDX-FileCopyrightText: Copyright 2005-2025 *
31 * - Pierre-Henri WUILLEMIN(_at_LIP6) *
32 * - Christophe GONZALES(_at_AMU) *
33 * SPDX-License-Identifier: LGPL-3.0-or-later OR MIT *
34 * *
35 * Contact : info_at_agrum_dot_org *
36 * homepage : http://agrum.gitlab.io *
37 * gitlab : https://gitlab.com/agrumery/agrum *
38 * *
39 ****************************************************************************/
40#pragma once
41
42
44
45namespace gum {
46
47 // ==========================================================================
48 // === Class FormulaPart ===
49 // ==========================================================================
50
51
52 INLINE
54 switch (character) {
55 case '+' :
56 case '-' :
57 case '*' :
58 case '/' : {
59 return true;
60 }
61
62 case '_' : {
63 return false;
64 }
65 case '^' : {
66 return false;
67 }
68
69 default : {
70 GUM_ERROR(OperationNotAllowed, "A - not an operator")
71 }
72 }
73 }
74
75 INLINE
77 switch (character) {
78 case '_' : {
79 return false;
80 }
81 default : {
82 return !isLeftAssociative();
83 }
84 }
85 }
86
87 INLINE
89 switch (character) {
90 case '+' :
91 case '-' : {
92 return 2;
93 }
94
95 case '*' :
96 case '/' : {
97 return 3;
98 }
99
100 case '^' : {
101 return 4;
102 }
103
104 case '_' : {
105 return 5;
106 }
107
108 default : {
109 GUM_ERROR(OperationNotAllowed, "B - not an operator")
110 }
111 }
112 }
113
114 INLINE
115 size_t FormulaPart::argc() const {
116 switch (type) {
117 case OPERATOR : {
118 return _operator_argc_();
119 }
120
121 case FUNCTION : {
122 return _function_argc_();
123 }
124
125 default : {
126 GUM_ERROR(OperationNotAllowed, "expecting a function or an operator")
127 }
128 }
129 }
130
131 INLINE
133 switch (character) {
134 case '_' : {
135 return (size_t)1;
136 }
137 case '+' :
138 case '-' :
139 case '*' :
140 case '/' :
141 case '^' : {
142 return (size_t)2;
143 }
144
145 default : {
146 GUM_ERROR(OperationNotAllowed, "C - not an operator")
147 }
148 }
149 }
150
151 INLINE
153 switch (function) {
155 return 1;
156 }
158 return 1;
159 }
161 return 1;
162 }
164 return 2;
165 }
167 return 1;
168 }
169 // case FormulaPart::token_function::nil: { return "nil"; }
170 default : {
171 GUM_ERROR(OperationNotAllowed, "unknown function")
172 }
173 }
174 }
175
177 INLINE
178 double FormulaPart::_operator_eval_(const std::vector< FormulaPart >& args) const {
179 switch (character) {
180 case '+' : {
181 return args[1].number + args[0].number;
182 }
183
184 case '-' : {
185 return args[1].number - args[0].number;
186 }
187
188 case '*' : {
189 return args[1].number * args[0].number;
190 }
191
192 case '/' : {
193 return args[1].number / args[0].number;
194 }
195
196 case '^' : {
197 return std::pow(args[1].number, args[0].number);
198 }
199
200 case '_' : {
201 return 0 - args[0].number;
202 }
203
204 default : {
205 GUM_ERROR(OperationNotAllowed, "D - not an operator")
206 }
207 }
208 }
209
211 INLINE
212 double FormulaPart::_function_eval_(const std::vector< FormulaPart >& args) const {
213 switch (function) {
215 return std::exp(args[0].number);
216 }
218 return std::log(args[0].number);
219 }
221 return std::log2(args[0].number);
222 }
224 return std::pow(args[1].number, args[0].number);
225 }
227 return std::sqrt(args[0].number);
228 }
229 // case FormulaPart::token_function::nil: { return "nil"; }
230 default : {
231 GUM_ERROR(OperationNotAllowed, "unknown function")
232 }
233 }
234 }
235
237 INLINE
238 FormulaPart FormulaPart::eval(const std::vector< FormulaPart >& args) const {
239 switch (type) {
240 case OPERATOR : {
242 }
243
244 case FUNCTION : {
246 }
247
248 default : {
249 GUM_ERROR(OperationNotAllowed, "cannot evaluate expression")
250 }
251 }
252 }
253
254 // ==========================================================================
255 // === Class Formula ===
256 // ==========================================================================
257
258
259 INLINE
260 const std::string& Formula::formula() const { return _formula_; }
261
262 INLINE
263 std::string& Formula::formula() { return _formula_; }
264
265 INLINE
266 void Formula::_push_number_(const double& v) {
268 _push_output_(t);
269 }
270
271 INLINE
273 if (_stack_.empty() || _stack_.top().type != FormulaPart::token_type::OPERATOR) {
274 return false;
275 }
276
277 if (o.isLeftAssociative() && o.precedence() <= _stack_.top().precedence()) { return true; }
278
279 if (o.isRightAssociative() && o.precedence() < _stack_.top().precedence()) { return true; }
280
281 return false;
282 }
283
284 INLINE
286 if (_isUnaryOperator_(o)) {
288
289 } else {
292 }
293 }
294
295 INLINE
297 switch (_last_token_.type) {
301 return o == '-';
302 }
303
305 return (o == '-') && (_last_token_.character == '(');
306 }
307
308 default : {
309 return false;
310 }
311 }
312 }
313
314 INLINE
316 // Only unary operator is the negative sign -
319 }
320
321 INLINE
323 while (_popOperator_(t)) {
324 _push_output_(_stack_.top());
325 _stack_.pop();
326 }
327
328 _push_stack_(t);
329 }
330
331 INLINE
336
337 INLINE
339 while ((!_stack_.empty()) && (_stack_.top().character != '(')) {
340 _push_output_(_stack_.top());
341 _stack_.pop();
342 }
343
344 if (_stack_.empty()) {
345 GUM_ERROR(OperationNotAllowed, "expecting '('")
346
347 } else if (_stack_.top().character != '(') {
348 GUM_ERROR(OperationNotAllowed, "expecting '('")
349 }
350
351 _stack_.pop();
352
353 if ((!_stack_.empty()) && _stack_.top().type == FormulaPart::token_type::FUNCTION) {
354 _push_output_(_stack_.top());
355 _stack_.pop();
356 }
358 }
359
360 INLINE
362 while (!_stack_.empty()) {
363 if (_stack_.top().character == '(') { GUM_ERROR(OperationNotAllowed, "expecting ')'") }
364
365 _push_output_(_stack_.top());
366 _stack_.pop();
367 }
368 }
369
370 INLINE
372 std::stack< FormulaPart >& stack) const {
373 std::vector< FormulaPart > args;
374
375 if (stack.size() < item.argc()) { GUM_ERROR(OperationNotAllowed, "not enought inputs ") }
376
377 while (item.argc() > args.size()) {
378 args.push_back(stack.top());
379 stack.pop();
380 }
381
382 stack.push(item.eval(args));
383 }
384
385 INLINE
387 _output_.push_back(t);
388 _last_token_ = t;
389 }
390
391 INLINE
393 _stack_.push(t);
394 _last_token_ = t;
395 }
396
397 INLINE
398 void Formula::_push_function_(const std::string& func) {
399 if (func == "exp") {
401 _push_stack_(t);
402
403 } else if (func == "log") {
405 _push_stack_(t);
406
407 } else if (func == "ln") {
409 _push_stack_(t);
410
411 } else if (func == "pow") {
413 _push_stack_(t);
414
415 } else if (func == "sqrt") {
417 _push_stack_(t);
418
419 } else {
420 GUM_ERROR(OperationNotAllowed, "unknown function")
421 }
422 }
423
424 INLINE
426 while ((!_stack_.empty()) && (_stack_.top().character != '(')) {
427 _push_output_(_stack_.top());
428 _stack_.pop();
429 }
430
431 if (_stack_.empty() || _stack_.top().character != '(') {
432 GUM_ERROR(OperationNotAllowed, "expecting a '('")
433 }
434
436 }
437
438 INLINE
440
441 INLINE
443
444 INLINE
445 void Formula::_push_variable_(const std::string& var) {
446 if (_variables_.exists(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 const&) {
460 try {
461 _push_variable_(ident);
462
463 } catch (OperationNotAllowed const&) { GUM_ERROR(OperationNotAllowed, "unknown identifier") }
464 }
465 }
466
467 // ========================================================================
468 // @name Arithmetic Operators
469 // ========================================================================
470
471 INLINE
472 Formula operator-(const Formula& a) { return Formula(std::to_string(-1 * a.result())); }
473
474 INLINE
475 Formula operator+(const Formula& a, const Formula& b) {
476 return Formula(std::to_string(a.result() + b.result()));
477 }
478
479 INLINE
480 Formula operator-(const Formula& a, const Formula& b) {
481 return Formula(std::to_string(a.result() - b.result()));
482 }
483
484 INLINE
485 Formula operator*(const Formula& a, const Formula& b) {
486 return Formula(std::to_string(a.result() * b.result()));
487 }
488
489 INLINE
490 Formula operator/(const Formula& a, const Formula& b) {
491 return Formula(std::to_string(a.result() / b.result()));
492 }
493
494 INLINE
495 std::string to_string(const Formula& f) { return std::to_string(f.result()); }
496
497 INLINE
498 std::ostream& operator<<(std::ostream& os, const Formula& f) {
499 os << f.result();
500 return os;
501 }
502
503} // namespace gum
Represents part of a formula.
Definition formula.h:79
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...
int precedence() const
Returns the precedence priority of the value stored in this gum::FormulaPart.
Definition formula_inl.h:88
size_t _function_argc_() const
Returns the number of arguments expected by the function stored in this gum::FormulaPart.
token_function function
The value stored by this gum::FormulaPart.
Definition formula.h:99
FormulaPart()
Class constructor.
Definition formula.cpp:105
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...
double number
The value stored by this gum::FormulaPart.
Definition formula.h:97
char character
The value stored by this gum::FormulaPart.
Definition formula.h:98
bool isLeftAssociative() const
Returns true if this gum::FormulaPart is left associative.
Definition formula_inl.h:53
size_t argc() const
Returns the number of argument of the function stored in this gum::FormulaPart.
size_t _operator_argc_() const
Returns the number of arguments expected by the operator stored in this gum::FormulaPart.
token_type type
The token_type stored by this gum::FormulaPart.
Definition formula.h:88
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...
bool isRightAssociative() const
Returns true if this gum::FormulaPart is right associative.
Definition formula_inl.h:76
Evaluates a string as a algebraic formula.
Definition formula.h:293
void _push_unaryOperator_(char o)
Push an unary operator.
void _push_output_(FormulaPart t)
Push the gum::FormulaPart in the output vector.
void _push_variable_(const std::string &var)
Push a variable in the formula.
void _push_leftParenthesis_()
Push a left parenthesis in the formula.
void _push_stack_(FormulaPart t)
Push the gum::FormulaPart in the stack.
bool _isUnaryOperator_(char o)
Returns true if o is an unary operator.
const std::string & formula() const
Returns the formula.
void _finalize_()
Finalize the formula and prepare it for evaluation.
void _push_function_(const std::string &func)
Push a function in the formula.
void _push_comma_()
Push a comma in the formula.
std::string _formula_
The formula to evaluate.
Definition formula.h:461
void _reduceOperatorOrFunction_(FormulaPart item, std::stack< FormulaPart > &stack) const
Evaluate an operator or function and push its result.
HashTable< std::string, double > _variables_
The variables available in this formula.
Definition formula.h:479
double result() const
Returns the result of this gum::Formula.
Definition formula.cpp:313
bool _popOperator_(FormulaPart o)
Pop the operator in the inner formula's stack.
std::vector< FormulaPart > _output_
The output stack, will contain one value after evaluation.
Definition formula.h:473
void _push_operator_(char o)
Push an operator in the formula.
void _push_rightParenthesis_()
Push a right parenthesis in the formula.
void _push_identifier_(const std::string &ident)
Use this if you don't know if ident is a function or a variable.
FormulaPart _last_token_
The last token added to the formula.
Definition formula.h:470
std::stack< FormulaPart > _stack_
A stack used during evaluation.
Definition formula.h:476
void _push_number_(const double &v)
Push a number in the formula.
HashTable< std::string, double > & variables()
Returns the variables used by this gum::Formula.
Exception : operation not allowed.
#define GUM_ERROR(type, msg)
Definition exceptions.h:72
Headers files for the gum::FormulaPart and gum::Formula classes.
gum is the global namespace for all aGrUM entities
Definition agrum.h:46
value_type & operator*()
Returns the value pointed to by the iterator.
std::ostream & operator<<(std::ostream &stream, const AVLTree< Val, Cmp > &tree)
display the content of a tree
Definition AVLTree.h:913
Formula operator/(const Formula &a, const Formula &b)
std::string to_string(const Formula &f)
HashTableIteratorSafe< Key, Val > operator+(Size i) const
Returns a new iterator pointing to i elements further in the hashtable.
ListConstIterator< Val >::difference_type operator-(const ListConstIterator< Val > &iter1, const ListConstIterator< Val > &iter2)
For STL compliance, a distance operator.
Definition list_tpl.h:349