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):
... pass
... 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 is_child(self, level_1, level_2):
... return True
>>> class XMLObject(object):
... def __init__(self, lexicon):
... self.lexicon = lexicon
... self.errors = []
... def variable_ind(self, level, variable):
... return self.lexicon.variable_ind(level, variable)
... def level_ind(self, level):
... return self.lexicon.level_ind(level)
... def operation_ind(self, operation):
... if operation == 'thinning':
... return 1
... else:
... return 2
... def add_error(self, msg):
... self.errors.append(msg)
>>> lexicon = Lexicon()
>>> validator = XMLObject(lexicon)
>>> from simo.builder.modelchain.conditionparser import ConditionParser
>>> cp = ConditionParser(validator, 'comp_unit')
Note that normally the Lexicon methods return only indices, but here text is used to illustrate the structure of the parsed output.
Parameters
expr -- condition expression, string
vars_to_incides -- boolean indicating whether the variable names should be transformed to variable indices
no_childern -- boolean indicating if children of evaluation level should not be accepted (this is needed for model chain conditions)
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
('data', (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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('data', (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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('op', 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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('data', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
('op', 1)
('value', 10.0)
('since', <function sgt at ...>)
('op', 1)
('data', (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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function and_ at ...>)
('data', (2, 'SP', True))
('value', [1.0, 2.0, 3.0])
('eq', <function in_ at ...>)
('group', <function or_ at ...>)
('op', 1)
('value', 10.0)
('since', <function sgt at ...>)
('op', 1)
('data', (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
('data', (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
('data', (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
('data', (1, 'AGE', True))
('value', 1.0)
('eq', <function gte at ...>)
('data', (1, 'SC', True))
('value', 4.0)
('eq', <function lee at ...>)
('group', <function or_ at ...>)
('data', (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
('data', (1, 'AGE', True))
None
('ex', <function ext at ...>)
>>> s = 'tree:d gt self:d'
>>> c = cp.parse(s)
>>> for i in c: print i
('data', (3, 'd', True))
('data', (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
('data', (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
('function', <function random_number_0_1 at ...>)
('value', 2.0)
('eq', <function lte at ...>)
This condition is invalid as the variable level (stratum) is a child level of current evaluation level (comp_unit)
>>> s0 = 'stratum:SP eq 1'
>>> c = cp.parse(s0, no_children=True)
>>> for i in c:
... print i
('data', (2, 'SP', True))
('value', 1.0)
('eq', <function eee at ...>)
>>> cp.validator.errors
["variable 'stratum:SP' cannot be in 'comp_unit' level condition"]
>>> cp.validator.errors = []
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
('data', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('data', (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
('data', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('data', (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
('data', (1, 'SC', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'PEAT', True))
('value', 2.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'TS', True))
('value', 1100.0)
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('data', (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
('data', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('data', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('data', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('data', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('data', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (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
('data', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('data', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('data', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('data', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('data', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X13', True))
('value', 13.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
>>> s = 'comp_unit:open_area eq 0 and \
... (comp_unit:USE_RESTRICTION_HARVEST eq 0 or \
... (comp_unit:USE_RESTRICTION_HARVEST in [5, 6, 7, 8, 9] and \
... (comp_unit:year gt comp_unit:USE_RESTRICTION_UNTIL_YEAR or \
... (comp_unit:year eq comp_unit:USE_RESTRICTION_UNTIL_YEAR and \
... comp_unit:month gt comp_unit:USE_RESTRICTION_UNTIL_MONTH) or \
... (comp_unit:year eq comp_unit:USE_RESTRICTION_UNTIL_YEAR and \
... comp_unit:month eq comp_unit:USE_RESTRICTION_UNTIL_MONTH and \
... comp_unit:day gt comp_unit:USE_RESTRICTION_UNTIL_DAY))))'
>>> c = cp.parse(s)
>>> for i in c:
... print i
('data', (1, 'past_thinning', True))
('value', 0.0)
('eq', <function eee at ...>)
('data', (1, 'past_thinning', True))
('value', 0.0)
('eq', <function eee at ...>)
('data', (1, 'past_thinning', True))
('value', [5.0, 6.0, 7.0, 8.0, 9.0])
('eq', <function in_ at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function gte at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function eee at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function eee at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'past_thinning', True))
('data', (1, 'past_thinning', True))
('eq', <function gte at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('group', <function and_ at ...>)
('group', <function or_ 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
('data', (1, 'X1', True))
('value', 1.0)
('eq', <function eee at ...>)
('data', (1, 'X2', True))
('value', 2.0)
('eq', <function eee at ...>)
('data', (1, 'X3', True))
('value', 3.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X4', True))
('value', 4.0)
('eq', <function eee at ...>)
('data', (1, 'X5', True))
('value', 5.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X6', True))
('value', 6.0)
('eq', <function eee at ...>)
('data', (1, 'X7', True))
('value', 7.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X8', True))
('value', 8.0)
('eq', <function eee at ...>)
('data', (1, 'X9', True))
('value', 9.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (1, 'X10', True))
('value', 10.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('group', <function or_ at ...>)
('data', (1, 'X11', True))
('value', 11.0)
('eq', <function eee at ...>)
('data', (1, 'X12', True))
('value', 12.0)
('eq', <function eee at ...>)
('group', <function and_ at ...>)
('data', (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 ‘data’, ‘op’ and ‘level’ type operands.