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
32
bool
FormulaPart
::
isLeftAssociative
()
const
{
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
55
bool
FormulaPart
::
isRightAssociative
()
const
{
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
111
size_t
FormulaPart
::
_operator_argc_
()
const
{
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
131
size_t
FormulaPart
::
_function_argc_
()
const
{
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
}
145
case
FormulaPart
::
token_function
::
sqrt
: {
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
}
205
case
FormulaPart
::
token_function
::
sqrt
: {
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
217
FormulaPart
FormulaPart
::
eval
(
const
std
::
vector
<
FormulaPart
>&
args
)
const
{
218
switch
(
type
) {
219
case
OPERATOR
: {
220
return
FormulaPart
(
token_type
::
NUMBER
,
_operator_eval_
(
args
));
221
}
222
223
case
FUNCTION
: {
224
return
FormulaPart
(
token_type
::
NUMBER
,
_function_eval_
(
args
));
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
) {
246
FormulaPart
t
(
FormulaPart
::
token_type
::
NUMBER
,
v
);
247
_push_output_
(
t
);
248
}
249
250
INLINE
251
bool
Formula
::
_popOperator_
(
FormulaPart
o
) {
252
if
(
_stack_
.
empty
() ||
_stack_
.
top
().
type
!=
FormulaPart
::
token_type
::
OPERATOR
) {
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
)) {
266
_push_unaryOperator_
(
o
);
267
268
}
else
{
269
FormulaPart
t
(
FormulaPart
::
token_type
::
OPERATOR
,
o
);
270
_push_operator_
(
t
);
271
}
272
}
273
274
INLINE
275
bool
Formula
::
_isUnaryOperator_
(
char
o
) {
276
switch
(
_last_token_
.
type
) {
277
case
FormulaPart
::
token_type
::
OPERATOR
:
278
case
FormulaPart
::
token_type
::
NIL
:
279
case
FormulaPart
::
token_type
::
ARG_SEP
: {
280
return
o
==
'-'
;
281
}
282
283
case
FormulaPart
::
token_type
::
PARENTHESIS
: {
284
return
(
o
==
'-'
) && (
_last_token_
.
character
==
'('
);
285
}
286
287
default
: {
288
return
false
;
289
}
290
}
291
}
292
293
INLINE
294
void
Formula
::
_push_unaryOperator_
(
char
o
) {
295
// Only unary operator is the negative sign -
296
FormulaPart
t
(
FormulaPart
::
token_type
::
OPERATOR
,
'_'
);
297
_push_operator_
(
t
);
298
}
299
300
INLINE
301
void
Formula
::
_push_operator_
(
FormulaPart
t
) {
302
while
(
_popOperator_
(
t
)) {
303
_push_output_
(
_stack_
.
top
());
304
_stack_
.
pop
();
305
}
306
307
_push_stack_
(
t
);
308
}
309
310
INLINE
311
void
Formula
::
_push_leftParenthesis_
() {
312
FormulaPart
t
(
FormulaPart
::
token_type
::
PARENTHESIS
,
'('
);
313
_push_stack_
(
t
);
314
}
315
316
INLINE
317
void
Formula
::
_push_rightParenthesis_
() {
318
while
((!
_stack_
.
empty
()) && (
_stack_
.
top
().
character
!=
'('
)) {
319
_push_output_
(
_stack_
.
top
());
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
332
if
((!
_stack_
.
empty
()) &&
_stack_
.
top
().
type
==
FormulaPart
::
token_type
::
FUNCTION
) {
333
_push_output_
(
_stack_
.
top
());
334
_stack_
.
pop
();
335
}
336
_last_token_
=
FormulaPart
(
FormulaPart
::
token_type
::
PARENTHESIS
,
')'
);
337
}
338
339
INLINE
340
void
Formula
::
_finalize_
() {
341
while
(!
_stack_
.
empty
()) {
342
if
(
_stack_
.
top
().
character
==
'('
) {
GUM_ERROR
(
OperationNotAllowed
,
"expecting ')'"
) }
343
344
_push_output_
(
_stack_
.
top
());
345
_stack_
.
pop
();
346
}
347
}
348
349
INLINE
350
void
Formula
::
_reduceOperatorOrFunction_
(
FormulaPart
item
,
351
std
::
stack
<
FormulaPart
>&
stack
)
const
{
352
std
::
vector
<
FormulaPart
>
args
;
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
365
void
Formula
::
_push_output_
(
FormulaPart
t
) {
366
_output_
.
push_back
(
t
);
367
_last_token_
=
t
;
368
}
369
370
INLINE
371
void
Formula
::
_push_stack_
(
FormulaPart
t
) {
372
_stack_
.
push
(
t
);
373
_last_token_
=
t
;
374
}
375
376
INLINE
377
void
Formula
::
_push_function_
(
const
std
::
string
&
func
) {
378
if
(
func
==
"exp"
) {
379
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
FormulaPart
::
token_function
::
exp
);
380
_push_stack_
(
t
);
381
382
}
else
if
(
func
==
"log"
) {
383
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
FormulaPart
::
token_function
::
log
);
384
_push_stack_
(
t
);
385
386
}
else
if
(
func
==
"ln"
) {
387
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
FormulaPart
::
token_function
::
ln
);
388
_push_stack_
(
t
);
389
390
}
else
if
(
func
==
"pow"
) {
391
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
FormulaPart
::
token_function
::
pow
);
392
_push_stack_
(
t
);
393
394
}
else
if
(
func
==
"sqrt"
) {
395
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
FormulaPart
::
token_function
::
sqrt
);
396
_push_stack_
(
t
);
397
398
}
else
{
399
GUM_ERROR
(
OperationNotAllowed
,
"unknown function"
)
400
}
401
}
402
403
INLINE
404
void
Formula
::
_push_comma_
() {
405
while
((!
_stack_
.
empty
()) && (
_stack_
.
top
().
character
!=
'('
)) {
406
_push_output_
(
_stack_
.
top
());
407
_stack_
.
pop
();
408
}
409
410
if
(
_stack_
.
empty
() ||
_stack_
.
top
().
character
!=
'('
) {
411
GUM_ERROR
(
OperationNotAllowed
,
"expecting a '('"
)
412
}
413
414
_last_token_
=
FormulaPart
(
FormulaPart
::
token_type
::
ARG_SEP
,
','
);
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
424
void
Formula
::
_push_variable_
(
const
std
::
string
&
var
) {
425
if
(
_variables_
.
exists
(
var
)) {
426
_push_number_
(
_variables_
[
var
]);
427
428
}
else
{
429
GUM_ERROR
(
OperationNotAllowed
,
"unknonw variable"
)
430
}
431
}
432
433
INLINE
434
void
Formula
::
_push_identifier_
(
const
std
::
string
&
ident
) {
435
try
{
436
_push_function_
(
ident
);
437
438
}
catch
(
OperationNotAllowed
&) {
439
try
{
440
_push_variable_
(
ident
);
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
477
std
::
ostream
&
operator
<<(
std
::
ostream
&
os
,
const
Formula
&
f
) {
478
os
<<
f
.
result
();
479
return
os
;
480
}
481
482
}
// namespace gum
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:643