omatrix.py

aggr.py

# postfixeval.py¶

SIMO optimization postfix evaluator

## class PostfixEvaluator:¶

Class for evaluating expressions in postfix stacks:

```>>> epsilon = 0.00001

>>> from simo.optimization.tools.postfixeval import PostfixEvaluator
>>> evaluator = PostfixEvaluator()
```
def evaluate(self, postfx, opindx, data, exprtype, exprind, dims=3,
aggr_over_units=True):

Evaluate postfix expression, where postfx is the expression in Reverse Polish Notation (RPN) or postfix form.

postfx – expression in postfix form opindx – unique operand index data – unique operand data in a dict exprtype – expression type, either ‘s’ for subobjective or ‘c’

for constraint

exprind – expression indice dims – data dimensions, int aggr_over_units – aggregate over units, boolean

Operand index contains the indices of unique subobjective or constraint operands:

```>>> operand_index = {0: 0,
...                  1: 1,
...                  2: 2}
```

Value arrays in the data dictionary can be arrays of two possible shapes: either the multiple data values of multiple objects (dims == 3) or single date for single object (dims == 1).

When the values are for a single date of single unit (dims=1), the values are always in a simple list

```>>> values1 = [1.0, 2.0]
```

When values contain the values of multiple dates for multiple objects, the data dimensions are: (object, branch, timestep)

```>>> import numpy
>>> nan = numpy.NaN

>>> values2 = {0: numpy.array([[[nan, nan, nan, 1]],
...                            [[nan, nan, nan, 2]],
...                            [[nan, nan, nan, 3]]],
...                           dtype=float),
...            1: numpy.array([[[nan, nan, nan, 1]],
...                            [[nan, nan, nan, 2]],
...                            [[nan, nan, nan, 3]]],
...                           dtype=float)}
```

Unit range is a numpy integer array with range [0..n[

```>>> unitrange = numpy.array([0,1,2], dtype=int)
```

Branch can be a 1D numpy array of size n or an integer scalar

```>>> branch = numpy.array([0], dtype=int)
```

Date locations index is a mapping from operand indice to date locations in the data arrays

```>>> dlocs = {0: (0, 3), 1: (0, 3), 2: (0, 3)}
```

Evaluate: sum(X + Y), one dimension

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a + b),)]

>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values1, 1)
>>> abs(x - 3) < epsilon
True
```

Evaluate: sum(X / Y), one dimension

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a / b),)]

>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values1, 1)
>>> abs(x - 0.5) < epsilon
True
```

Evaluate: sum(X + Y), three dimensions

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a + b),),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values2)
>>> abs(x - 12) < epsilon
True
```

Evaluate: sum(X * Y)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a * b),),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values2)
>>> abs(x - 14) < epsilon
True
```

Evaluate: sum(X) == sum(Y)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('aggr', numpy.nansum,),
...            ('data', 'Y', (1, 1)),
...            ('aggr', numpy.nansum,),
...            ('eq', (lambda a,b: a == b),)]
>>> evaluator.evaluate(unitrange, branch, postfix, dlocs, values2)
True
```

Evaluate: sum(X + Y / Z)

```>>> values3 = {0: numpy.array([[[nan, nan, nan, 1]],
...                            [[nan, nan, nan, 2]],
...                            [[nan, nan, nan, 3]]],
...                           dtype=float),
...            1: numpy.array([[[nan, nan, nan, 1]],
...                            [[nan, nan, nan, 2]],
...                            [[nan, nan, nan, 3]]],
...                           dtype=float),
...            2: numpy.array([[[nan, nan, nan, 2]],
...                            [[nan, nan, nan, 5]],
...                            [[nan, nan, nan, 10]]],
...                           dtype=float)}

>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('data', 'Z', (2, 2)),
...            ('ari', (lambda a,b: a / b)),
...            ('ari', (lambda a,b: a + b)),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
>>> abs(x - 7.2) < epsilon
True
```

Evaluate: sum(X * Y / Z)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a * b)),
...            ('data', 'Z', (2, 2)),
...            ('ari', (lambda a,b: a / b)),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
>>> abs(x - 2.2) < epsilon
True
```

Evaluate: sum(X + Y) < sum(Z)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a + b)),
...            ('aggr', numpy.nansum,),
...            ('data', 'Z', (2, 2)),
...            ('aggr', numpy.nansum,),
...            ('eq', (lambda a,b: a < b))]
>>> evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
True
```

Evaluate: sum(X + Y) < sum(Z)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a + b)),
...            ('aggr', numpy.nansum,),
...            ('data', 'Z', (2, 2)),
...            ('aggr', numpy.nansum,),
...            ('eq', (lambda a,b: a < b))]
>>> evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
True
```

Evaluate: (sum(X) / sum(Y)) == 1.0

```>>> postfix = [('data', 'X', (0, 0)),
...            ('aggr', numpy.nansum,),
...            ('data', 'Y', (1, 1)),
...            ('aggr', numpy.nansum,),
...            ('ari', (lambda a,b: a / b)),
...            ('value', 1.0,),
...            ('eq', (lambda a,b: a == b))]
>>> evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
True
```

Evaluate: sum((X + Y) * X) == 84.0

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a + b)),
...            ('data', 'Z', (2, 2)),
...            ('ari', (lambda a,b: a * b)),
...            ('aggr', numpy.nansum,),
...            ('value', 84.0),
...            ('eq', (lambda a,b: a == b))]
>>> evaluator.evaluate(unitrange, branch, postfix, dlocs, values3)
True
```

Evaluate: sum(X * Y), but at single unit level (no aggregation over units)

```>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a * b),),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values2, aggr_over_units=False)
>>> print x
[ 1.  4.  9.]
```

Evaluate: sum(X * Y), but at single unit level (no aggregation over units) and missing date locs

```>>> dlocs = {0: (None, None), 1: (None, None), 2: (None, None)}
>>> postfix = [('data', 'X', (0, 0)),
...            ('data', 'Y', (1, 1)),
...            ('ari', (lambda a,b: a * b),),
...            ('aggr', numpy.nansum,)]
>>> x = evaluator.evaluate(unitrange, branch, postfix, dlocs, values2, aggr_over_units=False)
>>> print x
[ 0.  0.  0.]
```