friendlysam.parts.Node.constraints

Node.constraints

For defining and generating constraints.

This is a ConstraintCollection instance. Add functions or iterables of functions to it. Each function should return a constraint or an iterable of constraints. (In this context, a constraint is Constraint, Relation, SOS1 or SOS2.)

If a constraint function returns a Relation, it automatically packaged in a Constraint object and marked with origin after creation. A constraint function may also return an iterable of constraints, even a generator.

All the added constraint functions are called when make() is called.

Examples

There are many ways to formulate constraint functions. Here is a wonderfully contrived example:

>>> from friendlysam.opt import VariableCollection, Constraint, Eq
>>> class MyNode(Node):
...     def __init__(self, k):
...         self.k = k
...         self.var = VariableCollection('x')
...         self.production['foo'] = self.var
...         # += and .add() are just alternative syntaxes
...         self.constraints.add(lambda t: self.var(t) >= k[t] - 1)
...         self.constraints += self.constraint_func_1, self.constraint_func_2
...         self.constraints.add(self.constraint_func_3)
...
...     def constraint_func_1(self, t):
...         return Constraint(
...             self.var(t) <= self.k[t] * 2,
...             desc='Some description')
...
...     def constraint_func_2(self, t):
...         constraints = []
...         t_plus_1 = self.step_time(t, 1)
...         constraints.append(self.var(t) <= self.k[t] * self.var(t_plus_1))
...         constraints.append(self.var(t) >= self.k[t_plus_1] * self.var(t_plus_1))
...         return constraints
...
...     def constraint_func_3(self, t):
...         for prev in self.times_between(0, t):
...             expr = Eq(self.k[prev] * self.var(prev), self.k[t] * self.var(t))
...             desc = 'Why make such a constraint? (k(t)={})'.format(self.k[t])
...             yield Constraint(expr, desc=desc)
...
>>> my_k = {i: i ** 2.4 for i in range(100)}
>>> node = MyNode(my_k)
>>> constraints = node.constraints.make(20)
>>> len(constraints)
26

Constraints can also be added from “outside”:

>>> node.constraints += lambda index: node.production['foo'](index) >= index
>>> constraints = node.constraints.make(20)
>>> len(constraints)
27