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
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
158
FormulaPart
::
operator_eval__
(
const
std
::
vector
<
FormulaPart
>&
args
)
const
{
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
193
FormulaPart
::
function_eval__
(
const
std
::
vector
<
FormulaPart
>&
args
)
const
{
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
}
207
case
FormulaPart
::
token_function
::
sqrt
: {
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
219
FormulaPart
FormulaPart
::
eval
(
const
std
::
vector
<
FormulaPart
>&
args
)
const
{
220
switch
(
type
) {
221
case
OPERATOR
: {
222
return
FormulaPart
(
token_type
::
NUMBER
,
operator_eval__
(
args
));
223
}
224
225
case
FUNCTION
: {
226
return
FormulaPart
(
token_type
::
NUMBER
,
function_eval__
(
args
));
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
) {
248
FormulaPart
t
(
FormulaPart
::
token_type
::
NUMBER
,
v
);
249
push_output__
(
t
);
250
}
251
252
INLINE
253
bool
Formula
::
popOperator__
(
FormulaPart
o
) {
254
if
(
stack__
.
empty
()
255
||
stack__
.
top
().
type
!=
FormulaPart
::
token_type
::
OPERATOR
) {
256
return
false
;
257
}
258
259
if
(
o
.
isLeftAssociative
() &&
o
.
precedence
() <=
stack__
.
top
().
precedence
()) {
260
return
true
;
261
}
262
263
if
(
o
.
isRightAssociative
() &&
o
.
precedence
() <
stack__
.
top
().
precedence
()) {
264
return
true
;
265
}
266
267
return
false
;
268
}
269
270
INLINE
271
void
Formula
::
push_operator__
(
char
o
) {
272
if
(
isUnaryOperator__
(
o
)) {
273
push_unaryOperator__
(
o
);
274
275
}
else
{
276
FormulaPart
t
(
FormulaPart
::
token_type
::
OPERATOR
,
o
);
277
push_operator__
(
t
);
278
}
279
}
280
281
INLINE
282
bool
Formula
::
isUnaryOperator__
(
char
o
) {
283
switch
(
last_token__
.
type
) {
284
case
FormulaPart
::
token_type
::
OPERATOR
:
285
case
FormulaPart
::
token_type
::
NIL
:
286
case
FormulaPart
::
token_type
::
ARG_SEP
: {
287
return
o
==
'-'
;
288
}
289
290
case
FormulaPart
::
token_type
::
PARENTHESIS
: {
291
return
(
o
==
'-'
) && (
last_token__
.
character
==
'('
);
292
}
293
294
default
: {
295
return
false
;
296
}
297
}
298
}
299
300
INLINE
301
void
Formula
::
push_unaryOperator__
(
char
o
) {
302
// Only unary operator is the negative sign -
303
FormulaPart
t
(
FormulaPart
::
token_type
::
OPERATOR
,
'_'
);
304
push_operator__
(
t
);
305
}
306
307
INLINE
308
void
Formula
::
push_operator__
(
FormulaPart
t
) {
309
while
(
popOperator__
(
t
)) {
310
push_output__
(
stack__
.
top
());
311
stack__
.
pop
();
312
}
313
314
push_stack__
(
t
);
315
}
316
317
INLINE
318
void
Formula
::
push_leftParenthesis__
() {
319
FormulaPart
t
(
FormulaPart
::
token_type
::
PARENTHESIS
,
'('
);
320
push_stack__
(
t
);
321
}
322
323
INLINE
324
void
Formula
::
push_rightParenthesis__
() {
325
while
((!
stack__
.
empty
()) && (
stack__
.
top
().
character
!=
'('
)) {
326
push_output__
(
stack__
.
top
());
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
())
340
&&
stack__
.
top
().
type
==
FormulaPart
::
token_type
::
FUNCTION
) {
341
push_output__
(
stack__
.
top
());
342
stack__
.
pop
();
343
}
344
last_token__
=
FormulaPart
(
FormulaPart
::
token_type
::
PARENTHESIS
,
')'
);
345
}
346
347
INLINE
348
void
Formula
::
finalize__
() {
349
while
(!
stack__
.
empty
()) {
350
if
(
stack__
.
top
().
character
==
'('
) {
351
GUM_ERROR
(
OperationNotAllowed
,
"expecting ')'"
);
352
}
353
354
push_output__
(
stack__
.
top
());
355
stack__
.
pop
();
356
}
357
}
358
359
INLINE
360
void
361
Formula
::
reduceOperatorOrFunction__
(
FormulaPart
item
,
362
std
::
stack
<
FormulaPart
>&
stack
)
const
{
363
std
::
vector
<
FormulaPart
>
args
;
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
378
void
Formula
::
push_output__
(
FormulaPart
t
) {
379
output__
.
push_back
(
t
);
380
last_token__
=
t
;
381
}
382
383
INLINE
384
void
Formula
::
push_stack__
(
FormulaPart
t
) {
385
stack__
.
push
(
t
);
386
last_token__
=
t
;
387
}
388
389
INLINE
390
void
Formula
::
push_function__
(
const
std
::
string
&
func
) {
391
if
(
func
==
"exp"
) {
392
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
393
FormulaPart
::
token_function
::
exp
);
394
push_stack__
(
t
);
395
396
}
else
if
(
func
==
"log"
) {
397
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
398
FormulaPart
::
token_function
::
log
);
399
push_stack__
(
t
);
400
401
}
else
if
(
func
==
"ln"
) {
402
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
403
FormulaPart
::
token_function
::
ln
);
404
push_stack__
(
t
);
405
406
}
else
if
(
func
==
"pow"
) {
407
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
408
FormulaPart
::
token_function
::
pow
);
409
push_stack__
(
t
);
410
411
}
else
if
(
func
==
"sqrt"
) {
412
FormulaPart
t
(
FormulaPart
::
token_type
::
FUNCTION
,
413
FormulaPart
::
token_function
::
sqrt
);
414
push_stack__
(
t
);
415
416
}
else
{
417
GUM_ERROR
(
OperationNotAllowed
,
"unknown function"
);
418
}
419
}
420
421
INLINE
422
void
Formula
::
push_comma__
() {
423
while
((!
stack__
.
empty
()) && (
stack__
.
top
().
character
!=
'('
)) {
424
push_output__
(
stack__
.
top
());
425
stack__
.
pop
();
426
}
427
428
if
(
stack__
.
empty
() ||
stack__
.
top
().
character
!=
'('
) {
429
GUM_ERROR
(
OperationNotAllowed
,
"expecting a '('"
);
430
}
431
432
last_token__
=
FormulaPart
(
FormulaPart
::
token_type
::
ARG_SEP
,
','
);
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
444
void
Formula
::
push_variable__
(
const
std
::
string
&
var
) {
445
if
(
variables__
.
exists
(
var
)) {
446
push_number__
(
variables__
[
var
]);
447
448
}
else
{
449
GUM_ERROR
(
OperationNotAllowed
,
"unknonw variable"
);
450
}
451
}
452
453
INLINE
454
void
Formula
::
push_identifier__
(
const
std
::
string
&
ident
) {
455
try
{
456
push_function__
(
ident
);
457
458
}
catch
(
OperationNotAllowed
&) {
459
try
{
460
push_variable__
(
ident
);
461
462
}
catch
(
OperationNotAllowed
&) {
463
GUM_ERROR
(
OperationNotAllowed
,
"unknown identifier"
);
464
}
465
}
466
}
467
468
// ========================================================================
469
// @name Arithmetic Operators
470
// ========================================================================
471
472
INLINE
473
Formula
operator
-(
const
Formula
&
a
) {
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
501
std
::
ostream
&
operator
<<(
std
::
ostream
&
os
,
const
Formula
&
f
) {
502
os
<<
f
.
result
();
503
return
os
;
504
}
505
506
}
// namespace gum
gum::Set::emplace
INLINE void emplace(Args &&... args)
Definition:
set_tpl.h:669