Class for parsing conditions in model chain into Reverse Polish Notation form.
Validator is responsible for providing the matrix indices for all the variable, level and operation definitions used in the condition expression:
>>> class Lexicon(object):
... def __init__(self):
... self.errors = []
... def variable_ind(self, level, variable):
... if variable == 'AGE':
... return (1, variable)
... elif variable == 'PEAT':
... return (1, variable)
... elif variable == 'SC':
... return (1, variable)
... elif variable == 'TS':
... return (1, variable)
... elif variable == 'MAIN_SP':
... return (1, variable)
... elif variable == 'SP':
... return (2, variable)
... elif variable == 'd':
... return (3, variable)
... elif variable[0] == 'X':
... return (1, variable)
... else:
... return (1,'past_thinning')
... def level_ind(self, level):
... return 2
... def operation_ind(self, operation):
... if operation == 'thinning':
... return 1
... else:
... return 2
... def add_error(self, msg):
... self.errors.append(msg)
>>> from simo.builder.modelchain.conditionparser import ConditionParser
>>> #from conditionparser import ConditionParser
>>> cp = ConditionParser(Lexicon(), 'comp_unit')
Note that normally the Lexicon methods return only indices, but here text is used to illustrate the structure of the parsed output.
Parses the SIMO condition expression into a nested list and further into a Reverse Polish notation / Postfix stack:
>>> s0 = 'comp_unit:AGE gt 1.0'
>>> c = cp.parse(s0)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
>>> s1 = 'comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0'
>>> c = cp.parse(s1)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
>>> s2 = '''(comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0)
... or
... stratum:SP in [1.0, 2.0, 3.0]'''
>>> c = cp.parse(s2)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('variable', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
>>> s3 = '''((comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0)
... or comp_unit:thinning since_gt 10)'''
>>> c = cp.parse(s3)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('operation', 1)
('value', 10.0)
('since', <function sgt at ...>)
('group', <function or_ at ...>)
>>> s4 = '''((comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0)
... or stratum:SP in [1.0, 2.0, 3.0])
... and
... ((comp_unit:thinning since_gt 10
... or comp_unit:thinning since_gt comp_unit:past_thinning)
... or stratum not exists)'''
>>> c = cp.parse(s4)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('variable', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
('operation', 1)
('value', 10.0)
('since', <function sgt at ...>)
('operation', 1)
('variable', (1, 'past_thinning', True))
('since', <function sgt at ...>)
('group', <function or_ at ...>)
('level', 2)
None
('ex', <function n_ext at ...>)
('group', <function or_ at ...>)
('group', <function and_ at ...>)
>>> s5 = '''(comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0
... or stratum:SP in [1.0, 2.0, 3.0])
... and
... (comp_unit:thinning since_gt 10
... or comp_unit:thinning since_gt comp_unit:past_thinning
... or stratum not exists)'''
>>> c = cp.parse(s5)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('variable', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
('operation', 1)
('value', 10.0)
('since', <function sgt at ...>)
('operation', 1)
('variable', (1, 'past_thinning', True))
('since', <function sgt at ...>)
('group', <function or_ at ...>)
('level', 2)
None
('ex', <function n_ext at ...>)
('group', <function or_ at ...>)
('group', <function and_ at ...>)
>>> s = 'stratum:SP in [2, 5]'
>>> c = cp.parse(s)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (2, 'SP', True))
('value', [2.0, 5.0])
('eq', <function in_ at ...>)
>>> s = 'stratum:SP not in [2, 5]'
>>> c = cp.parse(s)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (2, 'SP', True))
('value', [2.0, 5.0])
('eq', <function nin at ...>)
>>> s = '''comp_unit:AGE gt 1.0 or comp_unit:SC le 4.0
... or stratum:SP in [1.0, 2.0, 3.0]'''
>>> c = cp.parse(s)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('variable', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function or_ at ...>)
('variable', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
>>> s ='comp_unit:AGE exists'
>>> c = cp.parse(s)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (1, 'AGE', True))
None
('ex', <function ext at ...>)
>>> s = 'tree:d gt self:d'
>>> c = cp.parse(s)
>>> for i in c: print i # doctest: +ELLIPSIS
('variable', (3, 'd', True))
('variable', (3, 'd', False))
('eq', <function gte at ...>)
>>> cp.validator.errors
[]
>>> cp.validator.errors = []
>>> s = 'tree:d exists'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (3, 'd', True))
None
('ex', <function ext at ...>)
>>> s = 'function:random_number_0_1 lt 2.0'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('function', <function random_number_0_1 at ...>)
('value', 2.0)
('eq', <function lte at ...>)
Examples on how parenthesis affect (or do not affect) the parsed postfix structure
>>> s = '(comp_unit:SC eq 1 and comp_unit:PEAT eq 2) and (comp_unit:TS gt 1100 and comp_unit:MAIN_SP eq 3)'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('variable', (1, 'MAIN_SP', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function and_ at ...>)
>>> s = 'comp_unit:SC eq 1 and comp_unit:PEAT eq 2 and comp_unit:TS gt 1100 and comp_unit:MAIN_SP eq 3'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('variable', (1, 'MAIN_SP', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
>>> s = '((comp_unit:SC eq 1 and comp_unit:PEAT eq 2) and comp_unit:TS gt 1100) and comp_unit:MAIN_SP eq 3'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('variable', (1, 'MAIN_SP', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
>>> s = '(comp_unit:X1 eq 1) or \
... (comp_unit:X2 eq 2 and comp_unit:X3 eq 3) or \
... (comp_unit:X4 eq 4 and comp_unit:X5 eq 5 and comp_unit:X6 eq 6 and comp_unit:X7 eq 7) or \
... (comp_unit:X8 eq 8 and comp_unit:X9 eq 9 and comp_unit:X10 eq 10) or \
... (comp_unit:X11 eq 11 and comp_unit:X12 eq 12 and comp_unit:X13 eq 13)'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('variable', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('variable', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('variable', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('variable', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X13', True))
('value', 13.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
>>> s = '(comp_unit:X1 eq 1) or \
... (comp_unit:X2 eq 2 and comp_unit:X3 eq 3) or \
... (((comp_unit:X4 eq 4 and comp_unit:X5 eq 5) and comp_unit:X6 eq 6) and comp_unit:X7 eq 7) or \
... ((comp_unit:X8 eq 8 and comp_unit:X9 eq 9) and comp_unit:X10 eq 10) or \
... ((comp_unit:X11 eq 11 and comp_unit:X12 eq 12) and comp_unit:X13 eq 13)'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('variable', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('variable', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('variable', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('variable', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X13', True))
('value', 13.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
>>> s = '(comp_unit:X1 eq 1) or \
... (comp_unit:X2 eq 2 and comp_unit:X3 eq 3) or \
... ((comp_unit:X4 eq 4 and comp_unit:X5 eq 5) and (comp_unit:X6 eq 6 and comp_unit:X7 eq 7)) or \
... ((comp_unit:X8 eq 8 and comp_unit:X9 eq 9) and comp_unit:X10 eq 10) or \
... ((comp_unit:X11 eq 11 and comp_unit:X12 eq 12) and comp_unit:X13 eq 13)'
>>> c = cp.parse(s)
>>> for i in c:
... print i # doctest: +ELLIPSIS
('variable', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('variable', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('variable', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('variable', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('variable', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('variable', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('variable', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('variable', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('variable', (1, 'X13', True))
('value', 13.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
Failing conditions:
>>> f = 'comp_unit;AGE gt 1.0'
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "comp_unit;AGE gt 1.0", Expected ":" at char 9, got ";AGE"']
>>> cp.validator.errors = []
>>> f = 'comp_unit:AGE gt 1,0'
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "comp_unit:AGE gt 1,0", Expected end of text at char 18, got ",0"']
>>> cp.validator.errors = []
>>> f = 'comp_unit:AGE > 1.0'
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "comp_unit:AGE > 1.0", Expected Re:(\'gt|ge|eq|ue|le|lt\') at char 14, got ">"']
>>> cp.validator.errors = []
>>> f = 'comp_unit:AGE gt 1.0 and comp_unit:SC <= 4.0'
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "comp_unit:AGE gt 1.0 and comp_unit:SC <= 4.0", Expected Re:(\'gt|ge|eq|ue|le|lt\') at char 38, got "<="']
>>> cp.validator.errors = []
>>> f = '''((comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0)
... or stratum:SP in [1.0, 2.0, 3.0])
... and
... ((comp_unit:thinning since_gt 10
... or comp_unit:thinning since_gt comp_unit:past_thinning)
... or stratum not exist)'''
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "((comp_unit:AGE gt 1.0 and comp_unit:SC le 4.0) or stratum:SP in [1.0, 2.0, 3.0]) and ((comp_unit:thinning since_gt 10 or comp_unit:thinning since_gt comp_unit:past_thinning) or stratum not exist)", Expected ":" at char 186, got "not"']
>>> cp.validator.errors = []
>>> f = 'comp_unit:AGE gt 1.0 and SC lt 4.0'
>>> c = cp.parse(f)
>>> cp.validator.errors
['Error parsing expression "comp_unit:AGE gt 1.0 and SC lt 4.0", Expected ":" at char 28, got "lt"']
Responsible for the actual processing of the parsed nested list into a RPN stack.
Processess the atomic condition of [variable, operator, value] or [variable, operator, variable] or [level, exists operator] or [operation, operator, value] or [operation, operator, variable].
Also recursively calls the _construct_condition to divide the [condition, boolean operator, condition] cases.
Retrieves the indices needed for ‘variable’, ‘operation’ and ‘level’ type operands.