Table Of Contents

Previous topic

table.py

Next topic

modelchain.py

This Page

conditionparser.py

class ConditionParser(object):

Class for parsing conditions in model chain into Reverse Polish Notation form.

def __init__(self, expr, validator, name=None):

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.

def parse(self, expr, vars_to_indices=True, no_children=False):

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"']

def __construct_condition(self, cond):

Responsible for the actual processing of the parsed nested list into a RPN stack.

def __process_triplet(self, cond):

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.

def __set_variable(self, dtype, vardef):

Retrieves the indices needed for ‘data’, ‘op’ and ‘level’ type operands.