Numpy Array objects#

Summary#

Data types#

variable_ndarray

A numpy.ndarray sub class which ties variables to the indices of the numpy.ndarray.

ge_polyhedron

A numpy.ndarray sub class and a system of linear inequalities forming a polyhedron. The “ge” stands for “greater or equal” (\(\ge\)) which represents the relation between \(A\) and \(b\) (as in \(Ax \ge b\)), i.e. polyhedron \(P=\{x \in R^n \ |\ Ax \ge b\}\).

ge_polyhedron_config

A ge_polyhedron sub class with configurator features.

integer_ndarray

A numpy.ndarray sub class with only integers.

boolean_ndarray

A numpy.ndarray sub class with only booleans.

Variable ndarray#

class variable_ndarray(input_array: numpy.ndarray, variables: List[variable] = [], index: List[Union[int, variable]] = [], dtype: Type = numpy.int64)#

Bases: ndarray

A numpy.ndarray sub class which ties variables to the indices of the numpy.ndarray.

Raises
ValueError

If shapes between input_array, variables and index mismatch

Attributes
Seenumpy.ndarray

Methods

variable_indices(variable_dtype)

Variable indices of variable type puan.Dtype.BOOL or puan.Dtype.INT.

boolean_variable_indices

Variable indices where variable dtype is puan.Dtype.BOOL.

integer_variable_indices

Variable indices where variable dtype is puan.Dtype.INT.

construct(variable_values[, default_value, ...])

Constructs a variable_ndarray from a dict of variable ids and integers.

property boolean_variable_indices: numpy.ndarray#

Variable indices where variable dtype is puan.Dtype.BOOL.

Returns
outnumpy.ndarray

Examples

>>> ge_polyhedron = ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1],
... ]), [puan.variable("0",(-10,10)), puan.variable("a",(0,10)), puan.variable("b"), puan.variable("c",(-2,2)), puan.variable("d")])
>>> ge_polyhedron.boolean_variable_indices
array([2, 4])
construct(variable_values: Dict[str, int], default_value: Optional[Callable[[variable], Union[int, float]]] = None, dtype: Type = numpy.int64) numpy.ndarray#

Constructs a variable_ndarray from a dict of variable ids and integers.

Parameters
variable_values: Dict[str, int]

List of tuples with variable id and value

default_valueCallable

function taking self and returning a numpy.ndarray with default values with shape equal to the number of variables. Default is 0 when dtype is numpy.int64 and numpy.nan otherwise.

dtypeType

Type of resulting numpy.ndarray. Default is numpy.int64.

Returns
outnumpy.ndarray

Notes

If a variable in variable_values is not in self.variables, it will be ignored.

Examples

Constructing a new 1d variable ndarray shadow from this array and setting x = 5
>>> vnd = variable_ndarray([[1,2,3], [2,3,4]], [puan.variable("x"), puan.variable("y"), puan.variable("z")])
>>> vnd.construct({"x": 5})
array([5, 0, 0])
property integer_variable_indices: numpy.ndarray#

Variable indices where variable dtype is puan.Dtype.INT.

Returns
outnumpy.ndarray

Examples

>>> ge_polyhedron = ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1],
... ]), [puan.variable("0",(-10,10)), puan.variable("a",(0,10)), puan.variable("b"), puan.variable("c",(-2,2)), puan.variable("d")])
>>> ge_polyhedron.integer_variable_indices
array([0, 1, 3])
variable_indices(variable_dtype: Dtype) numpy.ndarray#

Variable indices of variable type puan.Dtype.BOOL or puan.Dtype.INT.

Parameters
variable_dtypepuan.Dtype

Variable type where “bool” gives :class:puan.Dtype.BOOL and 1 gives :class:puan.Dtype.INT.

Returns
outnumpy.ndarray
Raises
ValueError

If variable_dtype is not of type puan.Dtype

Notes

Variables of bounds other than (0,1) are considered of type puan.Dtype.INT.

Ge polyhedron#

class ge_polyhedron(input_array: numpy.ndarray, variables: List[variable] = [], index: List[Union[int, variable]] = [], dtype: Type = numpy.int64)#

Bases: variable_ndarray

A numpy.ndarray sub class and a system of linear inequalities forming a polyhedron. The “ge” stands for “greater or equal” (\(\ge\)) which represents the relation between \(A\) and \(b\) (as in \(Ax \ge b\)), i.e. polyhedron \(P=\{x \in R^n \ |\ Ax \ge b\}\).

Attributes
Seenumpy.ndarray

Methods

to_linalg()

Assumes support vector index 0 in polyhedron and returns \(A, b\) as in \(Ax \ge b\)

reducable_columns_approx()

Returns which columns are reducable under approximate condition.

reduce_columns(columns_vector)

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning not assume.

reducable_rows()

Returns a boolean vector indicating what rows are reducable.

reduce_rows(rows_vector)

Reduces rows from a rows_vector where num of rows of ge_polyhedron equals size of rows_vector.

reducable_rows_and_columns()

Returns reducable rows and columns of given polyhedron.

reduce([rows_vector, columns_vector])

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

row_bounds()

Returns the row equation bounds, including the bias.

row_distribution(row_index)

Returns a distribution of all combinations for each row and their values.

row_stretch()

This shows the proportion of the number of value spots for each row equation with respect to the number of combinations from active variable bounds.

row_stretch_int(row_index)

Row bounds range from one number to another.

neglectable_columns(patterns)

Returns neglectable columns of given polyhedron ge_polyhedron based on given patterns.

neglect_columns(columns_vector)

Neglects columns in \(A\) from columns_vector.

separable(points)

Checks if points are separable by a hyperplane from the polyhedron.

ineq_separate_points(points)

Checks if a linear inequality of the polyhedron separates any point from the polyhedron.

property A: puan.ndarray.integer_ndarray#

Matrix \(A\), as in \(Ax \ge b\).

Returns
outinteger_ndarray

Examples

>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]])).A
integer_ndarray([[-1,  1,  0,  0],
                 [ 0, -1,  1,  0],
                 [ 0,  0, -1,  1]])
property A_max: puan.ndarray.integer_ndarray#

Returns the maximum coefficient value based on variable’s initial bounds.

Returns
outinteger_ndarray
Raises
Exception

If matrix A is empty.

Examples

>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]])).A_max
integer_ndarray([[0, 1, 0, 0],
                 [0, 0, 1, 0],
                 [0, 0, 0, 1]])
property A_min: puan.ndarray.integer_ndarray#

Returns the minimum coefficient value based on variable’s initial bounds.

Returns
outinteger_ndarray
Raises
Exception

If matrix A is empty.

Examples

>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]])).A_min
integer_ndarray([[-1,  0,  0,  0],
                 [ 0, -1,  0,  0],
                 [ 0,  0, -1,  0]])
property b: puan.ndarray.integer_ndarray#

Support vector \(b\), as in \(Ax \ge b\).

Returns
outinteger_ndarray

Examples

>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]])).b
integer_ndarray([0, 0, 0])
column_bounds() integer_ndarray#

Returns the initial bounds for each variable.

Returns
outnumpy.ndarray
ineq_separate_points(points: numpy.ndarray) boolean_ndarray#

Checks if a linear inequality of the polyhedron separates any point from the polyhedron.

One linear equalities separates one of the given points here:

           -/ \-
          -/   \-  x <- point
point -> -/  x  \-
        -/_ _ _ _\- <- polyhedron
          / / / /
Parameters
pointsnumpy.ndarray
Returns
outboolean_ndarray

boolean vector indicating if linear inequality enfolds all points

See also

separable()

Checks if points are inside the polyhedron.

Notes

This function is the inverse of separable()

Examples

Points in 1d

>>> points = numpy.array([0, 1])
>>> ge_polyhedron(numpy.array([
...     [-1,  0, -1],
...     [ 2,  1,  1],
...     [ 0, -1,  1]])).ineq_separate_points(points)
boolean_ndarray([0, 1, 0])

Points in 2d

>>> points = numpy.array([[1, 1], [4, 2]])
>>> ge_polyhedron(numpy.array([
...     [ 0, 1, 0],
...     [ 0, 1,-1],
...     [-1,-1, 1]])).ineq_separate_points(points)
boolean_ndarray([0, 0, 1])

Points in 3d

>>> points = numpy.array([
...     [[1, 1, 1],
...      [4, 2, 1]],
...     [[0, 1, 0],
...      [1, 2, 1]]])
>>> ge_polyhedron(numpy.array([
...     [ 0, 1, 0,-1],
...     [ 0, 1,-1, 0],
...     [-1,-1, 1,-1]])).ineq_separate_points(points)
boolean_ndarray([[0, 0, 1],
                 [0, 1, 0]])
ineqs_satisfied(points: numpy.ndarray) boolean_ndarray#

Checks if the linear inequalities in the polyhedron are satisfied given the points, i.e. \(Ap \ge b\), given \(p\) in points.

Parameters
pointsnumpy.ndarray
Returns
outboolean_ndarray

boolean vector indicating if the linear inequality is satisfied given all points

Examples

Points in 1d

>>> points = numpy.array([1, 0, 3, 2])
>>> ge_polyhedron(numpy.array([
...     [0, 1, 1, -1, 1],
...     [5, 2, 1,  1, 0]])).ineqs_satisfied(points)
True

Points in 2d

>>> points = numpy.array([[1, 1], [4, 2]])
>>> ge_polyhedron(numpy.array([
...     [ 0, 1, 0],
...     [ 0, 1,-1],
...     [-1,-1, 1]])).ineqs_satisfied(points)
boolean_ndarray([1, 0])

Points in 3d

>>> points = numpy.array([
...     [[1, 1, 1],
...      [4, 2, 1]],
...     [[0, 1, 0],
...      [1, 2, 1]]])
>>> ge_polyhedron(numpy.array([
...     [ 0, 1, 0,-1],
...     [ 0, 1,-1, 0],
...     [-1,-1, 1,-1]])).ineqs_satisfied(points)
boolean_ndarray([[1, 0],
                 [0, 0]])
property n_row_combinations: numpy.ndarray#

The number of combinations for variables with non-zero coefficients row wise excluding its constraint.

Returns
outnumpy.ndarray

Examples

>>> puan.ndarray.ge_polyhedron([[1,1,1,0,0],[1,1,0,0,0]]).n_row_combinations
array([4, 2])
>>> puan.ndarray.ge_polyhedron([[3,4,5,6,0],[7,6,5,4,3]]).n_row_combinations
array([ 8, 16])
>>> puan.ndarray.ge_polyhedron([[3,4,5]], variables=[puan.variable("0"), puan.variable("a", (-2,2)), puan.variable("b", (-10,10))]).n_row_combinations
array([105])
neglect_columns(columns_vector: numpy.ndarray) ge_polyhedron#

Neglects columns in \(A\) from columns_vector. The entire column for col in columns_vector \(>0\) is set to \(0\) and the support vector is updated.

Parameters
columns_vectornumpy.ndarray

A 1d ndarray of length equal to the number of columns of \(A\). Sets the entire column of \(A\) to zero for corresponding entries of columns_vector which are \(>0\).

Returns
outge_polyhedron

ge_polyhedron with neglected columns set to zero and support vector updated accordingly.

See also

neglectable_columns()

Returns neglectable columns of given polyhedron ge_polyhedron based on given patterns.

Examples

>>> ge_polyhedron = ge_polyhedron(numpy.array([[0,-1, 1, 0, 0], [0, 0,-1, 1, 0], [0, 0, 0,-1, 1]]))
>>> columns_vector = numpy.array([1, 0, 1, 0])
>>> neglect_columns(ge_polyhedron, columns_vector)
ge_polyhedron([[ 1,  0,  1,  0,  0],
               [-1,  0, -1,  0,  0],
               [ 1,  0,  0,  0,  1]])
neglectable_columns(patterns: numpy.ndarray) integer_ndarray#

Returns neglectable columns of given polyhedron ge_polyhedron based on given patterns. Neglectable columns are the columns which doesn’t differentiate the patterns in ge_polyhedron from the patterns not in ge_polyhedron

Parameters
patternsnumpy.ndarray

known patterns of variables in the polyhedron.

Returns
outinteger_ndarray

A 1d ndarray of length equal to the number of columns of the ge_polyhedron, with ones at corresponding columns which can be neglected, zero otherwise.

See also

neglect_columns()

Neglects columns in \(A\) from columns_vector.

Notes

This method is differentiating the patterns which are in ge_polyhedron from those that are not. Variables which are not in the patterns and has a positive number for any row in ge_polyhedron are considered non-neglectable.

Examples

Keep common pattern: ge_polyhedron with two out of three patterns. Variables 1 and 2 are not differentiating the patterns in ge_polyhedron from those that are not, and can therefore be neglected.

>>> patterns = numpy.array([[1, 1, 0], [0, 1, 1], [1, 0, 1]])
>>> ge_polyhedron(numpy.array([
...     [-1,-1,-1, 0, 0, 0, 1],
...     [-1,-1, 0,-1, 0, 0, 1]])).neglectable_columns(patterns)
integer_ndarray([0, 1, 1, 0, 0, 0])

Neglect common pattern: Variable 0 is part of all patterns and can therefore be neglected.

>>> patterns = numpy.array([[1, 1, 0], [1, 0, 1], [1, 0, 0]])
>>> ge_polyhedron(numpy.array([
...     [-1,-1,-1, 0, 0, 0, 1],
...     [-1,-1, 0,-1, 0, 0, 1]])).neglectable_columns(patterns)
integer_ndarray([1, 0, 0, 0, 0, 0])

All patterns are present and all those columns can therefore be neglected >>> patterns = numpy.array([[1, 1, 0], [1, 0, 1], [1, 0, 0]]) >>> ge_polyhedron(numpy.array([ … [-1,-1,-1, 0, 0, 0, 1], … [-1,-1, 0,-1, 0, 0, 1], … [-1,-1, 0, 0, 0, 0, 1]])).neglectable_columns(patterns) integer_ndarray([1, 1, 1, 0, 0, 0])

reducable_columns_approx() numpy.ndarray#

Returns which columns are reducable under approximate condition. The approximate condition is that only one row of ge_polyhedron is considered when deducing reducable columns. By considering combination of rows more reducable columns might be found.

Rows with values \(\neq0\) for any integer variable are neglected.

Returns
outnumpy.ndarray (vector)

Columns with positive values could be assumed. Columns with nonpositive values could be removed (not-assumed).

See also

reduce

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

reduce_columns

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning not assume.

reducable_rows_and_columns

Returns reducable rows and columns of given polyhedron.

reduce_rows

Reduces rows from rows_vector where num of rows of M equals size of rows_vector.

reducable_rows

Returns a boolean vector indicating what rows are reducable.

Examples

All columns could be assumed not since picking any of the corresponding variable would violate the inequlity

>>> ge_polyhedron(numpy.array([[0, -1, -1, -1]])).reducable_columns_approx()
array([0., 0., 0.])

All columns could be assumed since not picking any of the corresponding variable would violate the inequlity

>>> ge_polyhedron(numpy.array([[3, 1, 1, 1]])).reducable_columns_approx()
array([1., 1., 1.])

Combination of assume and not assume

>>> ge_polyhedron(numpy.array([[2, 1, 1, -1]])).reducable_columns_approx()
array([1., 1., 0.])
reducable_rows() boolean_ndarray#

Returns a boolean vector indicating what rows are reducable. A row is reducable iff it doesn’t constrain any variable.

Rows with values \(\neq0\) for any integer variable are neglected.

Returns
outinteger_ndarray (vector)

See also

reduce

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

reduce_columns

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning assume.

reducable_rows_and_columns

Returns reducable rows and columns of given polyhedron.

reduce_rows

Reduces rows from rows_vector where num of rows of M equals size of rows_vector.

reducable_columns_approx

Returns what columns are reducable under approximate condition.

Examples

The sum of all negative numbers of the row in \(A\) is \(\ge b\), i.e. \(Ax \ge b\) will always hold, regardless of \(x\).

>>> ge_polyhedron(numpy.array([[-3, -1, -1, 1, 0]])).reducable_rows()
boolean_ndarray([1])

All elements of the row in \(A\) is \(\ge 0\) and \(b\) is \(\le 0\), again \(Ax \ge b\) will always hold, regardless of \(x\).

>>> ge_polyhedron(numpy.array([[0, 1, 1, 1, 0]])).reducable_rows()
boolean_ndarray([1])
reducable_rows_and_columns() Tuple[boolean_ndarray, numpy.ndarray]#

Returns reducable rows and columns of given polyhedron.

Returns
outTuple[boolean_ndarray, numpy.ndarray]

out[0] : a vector equal size as ge_polyhedron’s row size where 1 represents a removed row and 0 represents a kept row

out[1] : a vector with equal size as ge_polyhedron’s column size where nan numbers represent a no-choice.

See also

reduce

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

reduce_rows

Reduces rows from rows_vector where num of rows of M equals size of rows_vector.

reducable_rows

Returns a boolean vector indicating what rows are reducable.

reduce_columns

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning assume.

reducable_columns_approx

Returns what columns are reducable under approximate condition.

Examples

>>> ge_polyhedron(numpy.array([
...     [ 0,-1, 1, 0, 0, 0],
...     [ 0, 0,-1, 1, 0, 0],
...     [-1,-1, 0,-1, 0, 0],
...     [ 1, 0, 0, 0, 1, 0],
...     [ 0, 0, 0, 0, 0,-1],
...     [ 0, 1, 1, 0, 1, 0],
...     [ 0, 1, 1, 0, 1,-1] 
... ])).reducable_rows_and_columns()
(boolean_ndarray([0, 0, 0, 1, 1, 1, 1]), array([nan, nan, nan,  1.,  0.]))
reduce(rows_vector: Optional[boolean_ndarray] = None, columns_vector: Optional[numpy.ndarray] = None) ge_polyhedron#

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

Parameters
rows_vectorboolean_ndarray (optional)

A vector of 0’s and 1’s where rows matching index of value 1 are removed.

columns_vectornumpy.ndarray (optional)

A vector of positive, nonpositive and NaN floats. The NaN’s represent a no-choice.

Returns
outge_polyhedron

Reduced polyhedron

See also

reducable_rows_and_columns

Returns reducable rows and columns of given polyhedron.

reduce_rows

Reduces rows from rows_vector where num of rows of M equals size of rows_vector.

reducable_rows

Returns a boolean vector indicating what rows are reducable.

reduce_columns

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning assume.

reducable_columns_approx

Returns what columns are reducable under approximate condition.

Examples

>>> ge_polyhedron = ge_polyhedron(numpy.array([
...     [ 0,-1, 1, 0, 0, 0, 0],
...     [ 0, 0,-1, 1, 0, 0, 0],
...     [-1, 0, 0,-1,-1, 0, 0],
...     [ 1, 0, 0, 0, 0, 1, 1]]))
>>> columns_vector = numpy.array([1,numpy.nan,numpy.nan,numpy.nan,numpy.nan,numpy.nan])
>>> ge_polyhedron.reduce(columns_vector=columns_vector)
ge_polyhedron([[ 1,  1,  0,  0,  0,  0],
               [ 0, -1,  1,  0,  0,  0],
               [-1,  0, -1, -1,  0,  0],
               [ 1,  0,  0,  0,  1,  1]])
reduce_columns(columns_vector: numpy.ndarray) ge_polyhedron#

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning not assume.

Parameters
columns_vectornumpy.ndarray

The polyhedron is reduced column-wise by equally many positives and nonpositive in columns_vector.

Returns
outge_polyhedron

See also

reduce

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

reducable_rows_and_columns

Returns reducable rows and columns of given polyhedron.

reduce_rows

Reduces rows from rows_vector where num of rows of M equals size of rows_vector.

reducable_rows

Returns a boolean vector indicating what rows are reducable.

reducable_columns_approx

Returns what columns are reducable under approximate condition.

Examples

>>> ge_polyhedron = ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]]))
>>> columns_vector = numpy.array([1, numpy.nan, 0, numpy.nan]) # meaning assume index 0 and not assume index 2
>>> ge_polyhedron.reduce_columns(columns_vector)
ge_polyhedron([[ 1,  1,  0],
               [ 0, -1,  0],
               [ 0,  0,  1]])
reduce_rows(rows_vector: boolean_ndarray) ge_polyhedron#

Reduces rows from a rows_vector where num of rows of ge_polyhedron equals size of rows_vector. Each row in rows_vector equal to 0 is kept.

Parameters
rows_vectorboolean_ndarray
Returns
outge_polyhedron

See also

reduce

Reduces matrix polyhedron by information passed in rows_vector and columns_vector.

reduce_columns

Reducing columns from polyhedron from columns_vector where a positive number meaning assume and a nonpositive number meaning assume.

reducable_rows_and_columns

Returns reducable rows and columns of given polyhedron.

reducable_rows

Returns a boolean vector indicating what rows are reducable.

reducable_columns_approx

Returns what columns are reducable under approximate condition.

Examples

>>> rows_vector = numpy.array([1, 0, 1])
>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0], # Reduce
...     [0, 0,-1, 1, 0], # Keep
...     [0, 0, 0,-1, 1]  # Reduce
... ])).reduce_rows(rows_vector)
ge_polyhedron([[ 0,  0, -1,  1,  0]])

rows_vector could be boolean

>>> rows_vector = numpy.array([True, False, True])
>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0], # Reduce
...     [0, 0,-1, 1, 0], # Keep
...     [0, 0, 0,-1, 1]  # Reduce
... ])).reduce_rows(rows_vector)
ge_polyhedron([[ 0,  0, -1,  1,  0]])
row_bounds() integer_ndarray#

Returns the row equation bounds, including the bias. For instance, \(x+y+z\ge1\) has bounds of (-1,2).

Returns
outinteger_ndarray

Examples

>>> ge_polyhedron(numpy.array([[-2, -3,  0,  0,  0]])).row_bounds()
integer_ndarray([[-1,  2]])
row_distribution(row_index: int) integer_ndarray#

Returns a distribution of all combinations for each row and their values. Data type is a 2d numpy array with two columns: Column index 0 is a range from lowest to highest value spot of row equation. Column index 1 is a counter of how many combinations, generated from variable bounds, evaluated into that value spot.

Example 1#
Equation = x+y+0
Result   = array([
    [0, 1],
    [1, 2],
    [2, 1]
])

2     |         <- 2 combinations ([1,0], [0,1]) results in value 1
1  |  |  |      <- 1 combination  ([0,0]) results in value 0
  ----------       and 1 combination ([1,1]) results in value 2
   0  1  2   
Example 2#
Equation = 2x+2y+0
Result   = array([
    [0, 1],
    [1, 0],
    [2, 2],
    [3, 0],
    [4, 1]
])

2        |   
1  |     |     |
  ---------------
   0  1  2  3  4
Returns
outinteger_ndarray
Raises
Exception
Row index out of bounds.
If variable mismatch between polyhedron variables and equation.

See also

row_stretch()

Proportion of the number of value spots for each row equation.

row_stretch_int()

Row bounds range from one number to another.

Notes

This operation will generate all combinations from column bounds and may require heavy computation. It is supposed to be used as an analysis tool. Use it with caution.

Examples

>>> ge_polyhedron([[0,1,1,0],[0,2,2,0],[0,3,3,3]]).row_distribution(0)
integer_ndarray([[0, 1],
                 [1, 2],
                 [2, 1]])
>>> ge_polyhedron([[0,1,1,0],[0,2,2,0],[0,3,3,3]]).row_distribution(1)
integer_ndarray([[0, 1],
                 [1, 0],
                 [2, 2],
                 [3, 0],
                 [4, 1]])
>>> ge_polyhedron([[0,1,1,0],[0,2,2,0],[0,3,3,3]]).row_distribution(2)
integer_ndarray([[0, 1],
                 [1, 0],
                 [2, 0],
                 [3, 3],
                 [4, 0],
                 [5, 0],
                 [6, 3],
                 [7, 0],
                 [8, 0],
                 [9, 1]])
row_stretch() integer_ndarray#

This shows the proportion of the number of value spots for each row equation with respect to the number of combinations from active variable bounds. It will return a vector of equal size as number of rows in polyhedron. Each value less than 1 means that there are more value spots than the number of possible combinations for that row.

Returns
outinteger_ndarray

See also

row_distribution()

Distribution of possible equation outcomes.

row_stretch_int()

Row bounds range from one number to another.

Examples

>>> ge_polyhedron([[1,1,1,0,0],[2,2,2,0,0]]).row_stretch()
integer_ndarray([1.33333333, 0.8       ])
row_stretch_int(row_index: int) int#

Row bounds range from one number to another. They normally have at least one combination for each number in this range. This function returns a number \(\leq0\) for each row bound representing its “stretch”. If the number is \(<0\), then there exists a gap in that row’s bounds.

As in example 2, there are no valid combinations summing up to the value spots 2 or 4. What this means is that the equation has unnecessary large coefficients which may have negative effects on other methods assuming a certain underlying equation structure.

Returns
outint

See also

row_distribution()

Distribution of possible equation outcomes.

row_stretch()

Proportion of the number of value spots for each row equation.

Notes

This operation uses row_distribution() which will generate all combinations from variable bounds and may require heavy computation. It is supposed to be used as an analysis tool. Use it with caution.

Examples

>>> ph = ge_polyhedron([[0,1,1],[0,2,2]])
>>> ph.row_stretch_int(0)
0
>>> ph = ge_polyhedron([[0,1,1],[0,2,2]])
>>> ph.row_stretch_int(1)
-2
separable(points: numpy.ndarray) numpy.ndarray#

Checks if points are separable by a hyperplane from the polyhedron.

           / \
          /   \
point -> /  x  \
        /_ _ _ _\ <- polyhedron
Parameters
pointsnumpy.ndarray

Points to be evaluated if separable to polyhedron by a hyperplane.

Returns
outnumpy.ndarray

Boolean vector indicating T if separable to polyhedron by a hyperplane.

See also

ineq_separates_points()

Checks if a linear inequality of the polyhedron separates any point of given points.

Examples

>>> polyhedron = ge_polyhedron([[1, 1, 1], [-1, -1, -1]])
>>> polyhedron.separable(numpy.array([0, 0]))
True
>>> polyhedron = ge_polyhedron([[0,-2, 1, 1]])
>>> polyhedron.separable(numpy.array([
...     [1, 0, 1],
...     [1, 1, 1],
...     [0, 0, 0]]))
array([ True, False, False])
>>> polyhedron = ge_polyhedron([[-2,-1, -1, -1], [0, -1, 1, 0], [0, 0, -1, 1]])
>>> polyhedron.separable(numpy.array([[
...     [1, 0, 1]],
...     [[1, 1, 1]],
...     [[0, 0, 0]]]))
array([[ True],
       [ True],
       [False]])
tighten_column_bounds() integer_ndarray#

Returns maybe tighter column/variable bounds based on row constraints.

Returns
outinteger_ndarray

Notes

  • Array returned has two rows - first is the lower bound and the second is the upper bound, on each column.

  • Lower bound may be larger than upper bound. This implies contradiction but no exception is raised here.

Examples

>>> ge_polyhedron([[0,-2,1,1,0],[1,1,0,0,0],[1,0,0,0,1],[-3,0,0,0,-1]]).tighten_column_bounds()
integer_ndarray([[1, 0, 0, 1],
                 [1, 1, 1, 1]])
>>> ge_polyhedron([[3,1,1,1,0]]).tighten_column_bounds()
integer_ndarray([[1, 1, 1, 0],
                 [1, 1, 1, 1]])
>>> ge_polyhedron([[0,-1,-1,0,0]]).tighten_column_bounds()
integer_ndarray([[0, 0, 0, 0],
                 [0, 0, 1, 1]])
>>> ge_polyhedron([[2,-1,-1,0]], variables=[puan.variable(0, dtype="int"), puan.variable("a", bounds=(-2,1)), puan.variable("b"), puan.variable("c")]).tighten_column_bounds()
integer_ndarray([[-2,  0,  0],
                 [-2,  0,  1]])
to_linalg() Tuple[integer_ndarray, numpy.ndarray]#

Assumes support vector index 0 in polyhedron and returns \(A, b\) as in \(Ax \ge b\)

Returns
outTuple[integer_ndarray, numpy.ndarray]

out[0] : A

out[1] : b

Examples

>>> ge_polyhedron(numpy.array([
...     [0,-1, 1, 0, 0],
...     [0, 0,-1, 1, 0],
...     [0, 0, 0,-1, 1]])).to_linalg()
(integer_ndarray([[-1,  1,  0,  0],
                 [ 0, -1,  1,  0],
                 [ 0,  0, -1,  1]]), integer_ndarray([0, 0, 0]))

Ge polyhedron config#

class ge_polyhedron_config(input_array: numpy.ndarray, default_prio_vector: Optional[numpy.ndarray] = None, variables: List[variable] = [], index: List[Union[int, variable]] = [], dtype=numpy.int64)#

Bases: ge_polyhedron

A ge_polyhedron sub class with specific configurator features.

Methods

select(*prios[, solver])

Select items to prioritize and receives a solution for each in prios list.

to_b64([str_decoding])

Packs data into a base64 string.

from_b64(base64_str)

Unpacks base64 string base64_str.

static from_b64(base64_str: str) ge_polyhedron_config#

Unpacks base64 string base64_str.

Parameters
base64_str: ``str``
Returns
outge_polyhedron_config
Raises
Exception

When error occurred during decompression.

select(*prios: List[Dict[str, int]], solver: Optional[Callable[[ge_polyhedron, Iterable[numpy.ndarray]], Iterable[Tuple[Optional[numpy.ndarray], Optional[int], int]]]] = None) starmap#

Select items to prioritize and receives a solution for each in prios list.

Parameters
*priostyping.List[typing.Dict[str, int]]

a list of dicts where each entry’s value is a prio

solver: typing.Callable[[ge_polyhedron, typing.Dict[str, int]], typing.List[(np.ndarray, int, int)]] = None

If None is provided puan’s own (beta) solver is used. If you want to provide another solver you have to send a function as solver parameter. That function has to take a ge_polyhedron and a 2d numpy array representing all objectives, as input. NOTE that the polyhedron does not provide constraints for variable bounds. Variable bounds are found under each variable under polyhedron.variables and constraints for these has to manually be created and added to the polyhedron matrix. The function should return a list, one for each objective, of tuples of (solution vector, objective value, status code). The solution vector is an integer ndarray vector of size equal to width of polyhedron.A. There are six different status codes from 1-6:

  • 1: solution is undefined

  • 2: solution is feasible

  • 3: solution is infeasible

  • 4: no feasible solution exists

  • 5: solution is optimal

  • 6: solution is unbounded

Checkout https://github.com/ourstudio-se/puan-solvers for quick how-to’s for common solvers.

Returns
outitertools.starmap
Raises
InfeasibleError

No solution could be found. Note that if solver raises another error, it will be shown within parantheses.

Examples

>>> ph = ge_polyhedron_config([[1,1,1,1,0],[-1,-1,-1,-1,0]])
>>> list(ph.select({"1": 1}))[0]
({1: 1, 2: 0, 3: 0, 4: 0}, -1, 5)
>>> ph = ge_polyhedron_config([[1,1,1,1,0],[-1,-1,-1,-1,0]])
>>> dummy_solver = lambda x, y: list(map(lambda v: (v, 0, 5), y))
>>> list(ph.select({"1": 1}, solver=dummy_solver))[0]
({1: -1, 2: -1, 3: -1, 4: -1}, 0, 5)
to_b64(str_decoding: str = 'utf8') str#

Packs data into a base64 string.

Parameters
str_decoding: str = ‘utf8’
Returns
outstr

Integer ndarray#

class integer_ndarray(input_array: numpy.ndarray, variables: List[variable] = [], index: List[Union[int, variable]] = [], dtype: Type = numpy.int64)#

Bases: variable_ndarray

A numpy.ndarray sub class with only integers in it.

Attributes
Seenumpy.ndarray

Methods

ndint_compress([method, axis])

Takes an integer ndarray and compresses it into a vector under different conditions given by method.

from_list(lst, context)

Turns a list (or list of list) of strings into an integer vector, where each value represents which order the string in lst was positioned.

get_neighbourhood([method, delta])

Computes all neighbourhoods to an integer_ndarray.

ranking()

Ranks an integer_ndarray.

reduce2d([method, axis])

Reduces integer ndarray to only keeping one value of the given axis (default is 0) according to the provided method.

static from_list(lst: List[str], context: List[str]) integer_ndarray#

Turns a list (or list of list) of strings into an integer vector, where each value represents which order the string in lst was positioned.

Parameters
lstList[str]
contextList[str]
Returns
outinteger_ndarray

Examples

>>> variables = ["a","c","b"]
>>> context = ["a","b","c","d"]
>>> integer_ndarray.from_list(variables, context)
integer_ndarray([1, 3, 2, 0])
>>> variables  = [["a", "c"], ["c", "b"], ["a", "b", "d"]]
>>> context = ["a","b","c","d"]
>>> integer_ndarray.from_list(variables, context)
integer_ndarray([[1, 0, 2, 0],
                 [0, 2, 1, 0],
                 [1, 2, 0, 3]])
get_neighbourhood(method: Literal['all', 'addition', 'subtraction'] = 'all', delta: Union[int, numpy.ndarray] = 1) integer_ndarray#

Computes all neighbourhoods to an integer_ndarray. A neighbourhood to the integer_ndarray \(x\) is defined as the integer_ndarray \(y\) which for one variable differs by delta, the values for the other variables are identical.

Parameters
method{‘all’, ‘addition’, ‘subtraction’}, optional

The method used to compute the neighbourhoods to the integer ndarray. The following methods are available (default is ‘all’)

  • ‘all’ computes all neighbourhoods, addition and subtraction.

  • ‘addition’ computes all neighbourhoods with delta added

  • ‘subtraction’ computes all neighbourhoods with delta subtracted

deltaint or numpy.ndarray, optional

The value added or subtracted for each variable to reach the neighbourhood, default is 1. If delta is given as an array it is interpreted as different deltas for each variable.

Returns
outinteger_ndarray

If input dimension is M-D the returned integer_ndarray is M+1-D

Examples

>>> x = integer_ndarray([0,0,0])
>>> x.get_neighbourhood()
integer_ndarray([[ 1,  0,  0],
                 [ 0,  1,  0],
                 [ 0,  0,  1],
                 [-1,  0,  0],
                 [ 0, -1,  0],
                 [ 0,  0, -1]])
>>> x = integer_ndarray([[0,0,0], [0,0,0]])
>>> x.get_neighbourhood()
integer_ndarray([[[ 1,  0,  0],
                  [ 0,  1,  0],
                  [ 0,  0,  1],
                  [-1,  0,  0],
                  [ 0, -1,  0],
                  [ 0,  0, -1]],

                 [[ 1,  0,  0],
                  [ 0,  1,  0],
                  [ 0,  0,  1],
                  [-1,  0,  0],
                  [ 0, -1,  0],
                  [ 0,  0, -1]]])
>>> x = integer_ndarray([0, 1, 2])
>>> x.get_neighbourhood(delta=3)
integer_ndarray([[ 3,  1,  2],
                 [ 0,  4,  2],
                 [ 0,  1,  5],
                 [-3,  1,  2],
                 [ 0, -2,  2],
                 [ 0,  1, -1]])
>>> x.get_neighbourhood(delta=numpy.array([1, 2, 3]))
integer_ndarray([[ 1,  1,  2],
                 [ 0,  3,  2],
                 [ 0,  1,  5],
                 [-1,  1,  2],
                 [ 0, -1,  2],
                 [ 0,  1, -1]])
>>> x = integer_ndarray([[0,0,0], [0,0,0]])
>>> x.get_neighbourhood(method="addition")
integer_ndarray([[[1, 0, 0],
                  [0, 1, 0],
                  [0, 0, 1]],

                 [[1, 0, 0],
                  [0, 1, 0],
                  [0, 0, 1]]])
>>> x = integer_ndarray([[0,0,0], [0,0,0]])
>>> x.get_neighbourhood(method="subtraction")
integer_ndarray([[[-1,  0,  0],
                  [ 0, -1,  0],
                  [ 0,  0, -1]],

                 [[-1,  0,  0],
                  [ 0, -1,  0],
                  [ 0,  0, -1]]])
ndint_compress(method: Literal['first', 'last', 'min', 'max', 'prio', 'rank', 'shadow'] = 'min', axis: Optional[int] = None) integer_ndarray#

Takes an integer ndarray and compresses it into a vector under different conditions given by method.

Parameters
method{‘first’, ‘last’, ‘min’, ‘max’, ‘prio’, ‘rank’, ‘shadow’}, optional

The method used to compress the integer ndarray. The following methods are available (default is ‘min’)

  • ‘min’ Takes the minimum non-zero value

  • ‘max’ Takes the maximum value

  • ‘last’ Takes the last value

  • ‘prio’ Gives the normalized prio of the input

  • ‘rank’ Gives the rank of the input

  • ‘shadow’ Treats the values as prioritizations as for ‘prio’ but the result value of a higher prioritization totally shadows lower priorities

axis{None, int}, optional

Axis along which to perform the compressing. If None, the data array is first flattened.

Returns
outnumpy.ndarray

If input integer ndarray is input array is M-D the returned array is (M-1)-D

Raises
ValueError

If method is not one of ‘first’, ‘last’, ‘min’, ‘max’, ‘prio’, ‘rank’ or ‘shadow’

Examples

Method ‘min’
>>> integer_ndarray([[1, 2], [0, 3]]).ndint_compress()
integer_ndarray([1, 2, 0, 3])
>>> integer_ndarray([
...     [1, 2],
...     [0, 3]]).ndint_compress(method='min', axis=0)
integer_ndarray([1, 2])
>>> integer_ndarray([
...     [1, 2],
...     [0, 3]]).ndint_compress(method='min', axis=1)
integer_ndarray([1, 3])
Method ‘max’
>>> integer_ndarray([
...     [1, 2],
...     [0, 3]]).ndint_compress(method='max', axis=0)
integer_ndarray([1, 3])
>>> integer_ndarray([
...     [1, 2],
...     [0, 3]]).ndint_compress(method='max', axis=1)
integer_ndarray([2, 3])

Method ‘first’

>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='first', axis=0)
integer_ndarray([1, 2, 4, 6])
>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='first', axis=1)
integer_ndarray([1, 3, 5])

Method ‘last’

>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='last', axis=0)
integer_ndarray([5, 3, 4, 6])
>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='last', axis=1)
integer_ndarray([2, 4, 6])

Method ‘prio’

>>> integer_ndarray([
...     [1, -2, 0, 0],
...     [0,  3, 4, 0],
...     [5,  0, 0, -6]]).ndint_compress(method='prio', axis=0)
integer_ndarray([ 3,  1,  2, -4])
>>> integer_ndarray([
...     [1, -2, 0, 0],
...     [0,  3, 4, 0],
...     [5,  0, 0, -6]]).ndint_compress(method='prio', axis=1)
integer_ndarray([-1,  2, -3])
Method ‘rank’
>>> integer_ndarray([1, 2, 1, 0, 4, 4, 6]).ndint_compress(method='rank')
integer_ndarray([1, 2, 1, 0, 3, 3, 4])
>>> integer_ndarray([
...     [1, -2, 0, 0],
...     [0,  3, 4, 0],
...     [5,  0, 0, 6]]).ndint_compress(method='rank', axis=0)
integer_ndarray([3, 1, 2, 4])
>>> integer_ndarray([
...     [1, -2, 0, 0],
...     [0,  3, 4, 0],
...     [5,  0, 0, 6]]).ndint_compress(method='rank', axis=1)
integer_ndarray([0, 1, 2])
Method ‘shadow’
>>> integer_ndarray([1, 2, 1, 0, 4, 4, 6]).ndint_compress(method='shadow')
integer_ndarray([ 1,  3,  1,  0,  6,  6, 18])
>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='shadow', axis=0)
integer_ndarray([4, 1, 2, 8])
>>> integer_ndarray([
...     [1, 2, 0, 0],
...     [0, 3, 4, 0],
...     [5, 0, 0, 6]]).ndint_compress(method='shadow', axis=1)
integer_ndarray([1, 2, 4])
ranking() integer_ndarray#

Ranks an integer_ndarray.

Returns
outinteger_ndarray

Examples

>>> integer_ndarray([[1, 0, 5], [2, 2, 6]]).ranking()
integer_ndarray([[1, 0, 2],
                 [1, 1, 2]])
reduce2d(method: Literal['first', 'last'] = 'first', axis: int = 0) numpy.ndarray#

Reduces integer ndarray to only keeping one value of the given axis (default is 0) according to the provided method.

Parameters
methodLiteral[“first”, “last”]

Which value to keep. Default “first”.

axisint

Default 0.

Raises
ValueError
If dimension is not 2
If method is not ‘first’ or ‘last’

Examples

>>> integer_ndarray([[1, 2, 3], [4, 5, 6]]).reduce2d()
integer_ndarray([[1, 2, 3],
                 [0, 0, 0]])
>>> integer_ndarray([[1, 2, 3], [4, 5, 6]]).reduce2d(method="last", axis=1)
integer_ndarray([[0, 0, 3],
                 [0, 0, 6]])

Boolean ndarray#

class boolean_ndarray(input_array: numpy.ndarray, variables: List[variable] = [], index: List[Union[int, variable]] = [], dtype: Type = numpy.int64)#

Bases: variable_ndarray

A numpy.ndarray sub class with only booleans in it.

Attributes
Seenumpy.ndarray

Methods

from_list(lst, context)

Turns a list of strings into a boolean (0/1) vector.

to_list([skip_virtual_variables])

Returns a list of variables for each value in self equal 1.

get_neighbourhood([method])

Computes all neighbourhoods to a boolean_ndarray.

static from_list(lst: List[str], context: List[str]) boolean_ndarray#

Turns a list of strings into a boolean (0/1) vector.

Parameters
lstList[str]

list of variables ids

contextList[str]

list of context variables ids

Returns
outboolean_ndarray

booleans with same dimension as context

Examples

>>> variables = ["a","d","b"]
>>> context = ["a","b","c","d"]
>>> boolean_ndarray.from_list(variables, context)
boolean_ndarray([1, 1, 0, 1])
>>> variables  = [["a", "c"], ["c", "b"], ["a", "b", "d"]]
>>> context = ["a","b","c","d"]
>>> boolean_ndarray.from_list(variables, context)
boolean_ndarray([[1, 0, 1, 0],
                 [0, 1, 1, 0],
                 [1, 1, 0, 1]])
get_neighbourhood(method: Literal['on_off', 'on', 'off'] = 'on_off') boolean_ndarray#

Computes all neighbourhoods to a boolean_ndarray. A neighbourhood to the boolean ndarray \(x\) is defined as the boolean ndarray \(y\) which for one and only one variable in \(x\) is the complement.

Parameters
method{‘on_off’, ‘on’, ‘off’}, optional

The method used to compute the neighbourhoods to the boolean ndarray. The following methods are available (default is ‘on_off’)

  • ‘on_off’ the most natural way to define neighbourhoods, if a variable is True in the input it is False in its neighbourhood and vice versa.

  • ‘on’ do not include neighbourhoods with ‘off switches’, i.e. if a variable is True there is no neighbourhood to this variable.

  • ‘off’ do not include neighbourhoods with ‘on switches’, i.e. if a variable is False there is no neighbourhood to this variable.

Returns
outboolean_ndarray

If input dimension is M-D the returned integer ndarray is M+1-D

Raises
ValueError

If method is not one of ‘on_off’, ‘on’ or ‘off’

Examples

>>> x = boolean_ndarray([1, 0, 0, 1])
>>> x.get_neighbourhood(method="on_off")
boolean_ndarray([[False, False, False,  True],
                 [ True,  True, False,  True],
                 [ True, False,  True,  True],
                 [ True, False, False, False]])
>>> x = boolean_ndarray([1, 0, 0, 1])
>>> x.get_neighbourhood(method="on")
boolean_ndarray([[ True,  True, False,  True],
                 [ True, False,  True,  True]])
>>> x = boolean_ndarray([1, 1, 1, 1])
>>> x.get_neighbourhood(method="on")
boolean_ndarray([], shape=(0, 4), dtype=bool)
>>> x = boolean_ndarray([1, 0, 0, 1])
>>> x.get_neighbourhood(method="off")
boolean_ndarray([[False, False, False,  True],
                 [ True, False, False, False]])
>>> x = boolean_ndarray([0, 0, 0, 0])
>>> x.get_neighbourhood(method="off")
boolean_ndarray([], shape=(0, 4), dtype=bool)
to_list(skip_virtual_variables: bool = False) List[variable]#

Returns a list of variables for each value in self equal 1.

Returns
outList[puan.variable]

Examples

>>> boolean_ndarray([1, 1, 0, 1]).to_list()
[variable(id=0, bounds=Bounds(lower=1, upper=1)), variable(id=1, bounds=Bounds(lower=0, upper=1)), variable(id=3, bounds=Bounds(lower=0, upper=1))]
>>> boolean_ndarray([[1, 0, 1, 0],
...                  [0, 1, 1, 0],
...                  [1, 1, 0, 1]]).to_list()
[[variable(id=0, bounds=Bounds(lower=1, upper=1)), variable(id=2, bounds=Bounds(lower=0, upper=1))], [variable(id=1, bounds=Bounds(lower=0, upper=1)), variable(id=2, bounds=Bounds(lower=0, upper=1))], [variable(id=0, bounds=Bounds(lower=1, upper=1)), variable(id=1, bounds=Bounds(lower=0, upper=1)), variable(id=3, bounds=Bounds(lower=0, upper=1))]]