This allows you to specify a mathematical expression which, if true, will turn the job to unstbale
First the expression is split by logical operands of |,or,&,and,impl,imp,eq
Then it it is split by >,<, ==, !=, <=, >=, lt, gt, le, ge
Negation can be used only with logicalbrackets, strictly tied to left one - eg ![0 == 1]
each of the remaining parts is calcualted as mathematical expression. as powerfull as https://github.com/gbenroscience/ParserNG, with few extensions:
you can use L0 to access value of just finished build. L1 as value of last one before, L2 as two before and so on...Negative id on L is not allowed nowhere
points in chart chart with 4 bullets, wehich fifth build jsut finished would be L4 L3 L2 L1 L0
you can use ranges by `..`. Eg ..L1 is all before L0 (thus Ln...L2,L1). Similarly, L3.. would be L3,L2,L1. You can use also both limits - eg: L1..L3 o
Note, that the evaluation counts with what it see - if you denylist/allowlist, the points are filtered before given to formula. Similarly, if you show just last two point, you will get access only to L0 and L1. So show more :)
Expression : [[ avg(..L1)*1.1 < L0 ] || [L1*1.3 < L0 ]] || [ avgN(count(..L0)/4, ..L1)*1.1
Upon : 60,20,45,70
As : Ln...L1,L0
Expanded as: [[ avg(60,20,45)*1.1 < 70 ] || [45*1.3 < 70 ]] || [ avgN(count(60,20,45,70)/4, 60,20,45)*1.1<70 ]
brackets: [[ avg(60,20,45)*1.1 < 70 ] || [45*1.3 < 70 ]] || [ avgN(count(60,20,45,70)/4, 60,20,45)*1.1<70 ]
brackets: [ avg(60,20,45)*1.1 < 70 ] || [45*1.3 < 70 ]
evaluating: avg(60,20,45)*1.1 < 70
evaluating: avg(60,20,45)*1.1 < 70
evaluating: avg(60,20,45)*1.1
is: 45.833333333333336
evaluating: 70
is: 70
... 45.833333333333336 < 70
is: true
is: true
to: true || [45*1.3 < 70 ]
evaluating: 45*1.3 < 70
evaluating: 45*1.3 < 70
evaluating: 45*1.3
is: 58.5
evaluating: 70
is: 70
... 58.5 < 70
is: true
is: true
to: true || true
evaluating: true || true
evaluating: true
is: true
evaluating: true
is: true
... true | true
is: true
true
to: true || [ avgN(count(60,20,45,70)/4, 60,20,45)*1.1<70 ]
evaluating: avgN(count(60,20,45,70)/4, 60,20,45)*1.1<70
evaluating: avgN(count(60,20,45,70)/4, 60,20,45)*1.1<70
evaluating: avgN(count(60,20,45,70)/4, 60,20,45)*1.1
is: 45.833333337
evaluating: 70
is: 70
... 45.833333337 < 70
is: true
is: true
to: true || true
evaluating: true || true
evaluating: true
is: true
evaluating: true
is: true
... true | true
is: true
true
is: true
TRUE , thus job WILL be turned to unstable
Max number in L (and thus also in functions) is 99
The parser is far from being perfect, be nice to it.
The () brackets are avaiable only in side math expressions. The Logical part is using [] as separators. Eg:
1+1 < (2+0)*1 impl [ [5 == 6 || 33<(22-20)*2 ]xor [ [ 5-3 < 2 or 7*(5+2)<=5 ] and 1+1 == 2]] eq [ true && false ]
There is a special element MN, which represents count of input points, so you do not need to call `count(..L0)` arround and arround. So...
Expression : avg(..L1)*1.1-MN < L0 | L1*1.3 + MN< L0
Upon : 60,20,80,70
As : Ln...L1,L0
MN = 4
Expanded as: avg(60,20,80)*1.1-4 < 70 | 80*1.3 + 4< 70
...indeed.
Dynamic indexes
You can calculate the Lsomething by expressions. To do that, use L{expression}. Eg:
avg( ..L{MN/2}) < avg(L{MN/2}..)
Expression : avg( ..L{MN/2}) < avg(L{MN/2}..)
Upon : 2,4,6
As : Ln...L1,L0
MN = 3
L indexes brackets: avg( ..L{3/2}) < avg(L{3/2}..)
Expression : 3/2
Expanded as: 3/2
is: 1.5
3/2 = 1 (1.5)
to: avg( ..L 1 ) < avg(L{3/2}..)
Expression : 3/2
Expanded as: 3/2
is: 1.5
3/2 = 1 (1.5)
to: avg( ..L 1 ) < avg(L 1 ..)
Expanded as: avg( 2,4) < avg(4,6)
avg( 2,4) < avg(4,6)
brackets: avg( 2,4) < avg(4,6)
evaluating: avg( 2,4) < avg(4,6)
evaluating: avg( 2,4) < avg(4,6)
evaluating: avg( 2,4)
is: 3.0
evaluating: avg(4,6)
is: 5.0
... 3.0 < 5.0
is: true
is: true
true
is: true
true
Preset equations
There are some preset equations, usable in form of ID arg1 arg2 ... arg9. eg:
FINAL_DOWN_CUTTING_OK 2 5 5 5
To print them, use LIST_INTERNALS instead of expression or look onto
pre pprepared availabe embedded functions and exempalr config
You can add yours own preset expressions in main settings as url to file with definitions or as definitions themselves.
The syntax is as you saw
above:
- empty lines ignored
- behind hash(#) are comments and examples
- First comment si mandatory, and is ID
- after comments follow expression itself as by
ParserNG rules
- It can be multilined for readability (as ParserNG's --trim)
- parameters are included substitued into expression via /*1*/ for first param, /*2*/ for second and os on