ommx.v1

Submodules

Attributes

ToSamples

Type alias for convertible types to Samples.

ToState

Type alias for convertible types to State.

Classes

Constraint

Constraints

DecisionVariable

Idiomatic wrapper of ommx.v1.DecisionVariable protobuf message.

Function

Helper class that provides a standard way to create an ABC using

Instance

Idiomatic wrapper of ommx.v1.Instance protobuf message.

Linear

Modeler API for linear function

Parameter

Idiomatic wrapper of ommx.v1.Parameter protobuf message.

ParametricInstance

Idiomatic wrapper of ommx.v1.ParametricInstance protobuf message.

Polynomial

Helper class that provides a standard way to create an ABC using

Quadratic

Helper class that provides a standard way to create an ABC using

SampleSet

The output of sampling-based optimization algorithms, e.g. simulated annealing (SA).

SampledValues

Solution

Idiomatic wrapper of ommx.v1.Solution protobuf message.

Package Contents

class ommx.v1.Constraint(*, function: int | float | DecisionVariable | Linear | Quadratic | Polynomial | Function, equality: constraint_pb2.Equality.ValueType, id: int | None = None, name: str | None = None, description: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None)

Constraints

Examples

>>> x = DecisionVariable.integer(1)
>>> y = DecisionVariable.integer(2)
>>> x + y == 1
Constraint(Function(x1 + x2 - 1) == 0)

To set the name or other attributes, use methods like :py:meth:`add_name`.

>>> (x + y <= 5).add_name("constraint 1")
Constraint(Function(x1 + x2 - 5) <= 0)
add_description(description: str) Constraint
add_name(name: str) Constraint
add_parameters(parameters: dict[str, str]) Constraint
add_subscripts(subscripts: list[int]) Constraint
static from_bytes(data: bytes) Constraint
static from_raw(raw: constraint_pb2.Constraint) Constraint
set_id(id: int) Constraint

Overwrite the constraint ID.

to_bytes() bytes
EQUAL_TO_ZERO
LESS_THAN_OR_EQUAL_TO_ZERO
property description: str | None
property equality: constraint_pb2.Equality.ValueType
property function: Function
property id: int
property name: str | None
property parameters: dict[str, str]
raw: constraint_pb2.Constraint
property subscripts: list[int]
class ommx.v1.DecisionVariable

Idiomatic wrapper of ommx.v1.DecisionVariable protobuf message.

Note that this object overloads == for creating a constraint, not for equality comparison for better integration to mathematical programming.

>>> x = DecisionVariable.integer(1)
>>> x == 1
Constraint(...)

To compare two objects, use equals_to() method.

>>> y = DecisionVariable.integer(2)
>>> x.equals_to(y)
False
static binary(id: int, *, name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
static continuous(id: int, *, lower: float = float('-inf'), upper: float = float('inf'), name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
equals_to(other: DecisionVariable) bool

Alternative to == operator to compare two decision variables.

static from_bytes(data: bytes) DecisionVariable
static integer(id: int, *, lower: float = float('-inf'), upper: float = float('inf'), name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
static of_type(kind: Kind, id: int, *, lower: float, upper: float, name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
static semi_continuous(id: int, *, lower: float = float('-inf'), upper: float = float('inf'), name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
static semi_integer(id: int, *, lower: float = float('-inf'), upper: float = float('inf'), name: str | None = None, subscripts: list[int] | None = None, parameters: dict[str, str] | None = None, description: str | None = None) DecisionVariable
to_bytes() bytes
BINARY
CONTINUOUS
INTEGER
Kind
SEMI_CONTINUOUS
SEMI_INTEGER
property bound: decision_variables_pb2.Bound
property description: str
property id: int
property kind: Kind
property name: str
property parameters: dict[str, str]
raw: decision_variables_pb2.DecisionVariable
property subscripts: list[int]
class ommx.v1.Function(inner: int | float | DecisionVariable | Linear | Quadratic | Polynomial | function_pb2.Function)

Helper class that provides a standard way to create an ABC using inheritance.

almost_equal(other: Function, *, atol: float = 1e-10) bool

Compare two functions have almost equal coefficients as a polynomial

evaluate(state: ToState) tuple[float, set]

Evaluate the function with the given state.

Examples

Evaluate `2 x1 x2 + 3 x2 x3 + 1` with `x1 = 3, x2 = 4, x3 = 5`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = Function(2*x1*x2 + 3*x2*x3 + 1)
>>> f
Function(2*x1*x2 + 3*x2*x3 + 1)

>>> f.evaluate({1: 3, 2: 4, 3: 5})
(85.0, {1, 2, 3})

Missing ID raises an error
>>> f.evaluate({1: 3})
Traceback (most recent call last):
...
RuntimeError: Variable id (2) is not found in the solution
static from_bytes(data: bytes) Function
partial_evaluate(state: ToState) tuple[Function, set]

Partially evaluate the function with the given state.

Examples

Evaluate `2 x1 x2 + 3 x2 x3 + 1` with `x1 = 3`, yielding `3 x2 x3 + 6 x2 + 1`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = Function(2*x1*x2 + 3*x2*x3 + 1)
>>> f
Function(2*x1*x2 + 3*x2*x3 + 1)

>>> f.partial_evaluate({1: 3})
(Function(3*x2*x3 + 6*x2 + 1), {1})
to_bytes() bytes
raw: function_pb2.Function
property terms: dict[tuple[int, Ellipsis], float]
class ommx.v1.Instance

Idiomatic wrapper of ommx.v1.Instance protobuf message.

Note that this class also contains annotations like title which are not contained in protobuf message but stored in OMMX artifact. These annotations are loaded from annotations while reading from OMMX artifact.

Examples

Create an instance for KnapSack Problem

>>> from ommx.v1 import Instance, DecisionVariable

Profit and weight of items

>>> p = [10, 13, 18, 31, 7, 15]
>>> w = [11, 15, 20, 35, 10, 33]

Decision variables

>>> x = [DecisionVariable.binary(i) for i in range(6)]

Objective and constraint

>>> objective = sum(p[i] * x[i] for i in range(6))
>>> constraint = sum(w[i] * x[i] for i in range(6)) <= 47

Compose as an instance

>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=objective,
...     constraints=[constraint],
...     sense=Instance.MAXIMIZE,
... )
add_user_annotation(key: str, value: str, *, annotation_namespace: str = 'org.ommx.user.')

Add a user annotation to the instance.

Examples

>>> instance = Instance.empty()
>>> instance.add_user_annotation("author", "Alice")
>>> instance.get_user_annotations()
{'author': 'Alice'}
>>> instance.annotations
{'org.ommx.user.author': 'Alice'}
as_minimization_problem()

Convert the instance to a minimization problem.

If the instance is already a minimization problem, this does nothing.

Examples

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[sum(x) == 1],
...     sense=Instance.MAXIMIZE,
... )
>>> instance.sense == Instance.MAXIMIZE
True
>>> instance.objective
Function(x0 + x1 + x2)

Convert to a minimization problem

>>> instance.as_minimization_problem()
>>> instance.sense == Instance.MINIMIZE
True
>>> instance.objective
Function(-x0 - x1 - x2)
as_parametric_instance() ParametricInstance

Convert the instance to a ParametricInstance.

as_pubo_format() dict[tuple[int, Ellipsis], float]

Convert unconstrained polynomial instance to simple PUBO format.

This method is designed for better composability rather than easy-to-use. This does not execute any conversion of the instance, only translates the data format.

as_qubo_format() tuple[dict[tuple[int, int], float], float]

Convert unconstrained quadratic instance to PyQUBO-style format.

This method is designed for better composability rather than easy-to-use. This does not execute any conversion of the instance, only translates the data format.

static empty() Instance

Create trivial empty instance of minimization with zero objective, no constraints, and no decision variables.

evaluate(state: ToState) Solution
evaluate_samples(samples: ToSamples) SampleSet

Evaluate the instance with multiple states.

static from_bytes(data: bytes) Instance
static from_components(*, objective: int | float | DecisionVariable | Linear | Quadratic | Polynomial | function_pb2.Function, constraints: Iterable[Constraint | constraint_pb2.Constraint], sense: instance_pb2.Instance.Sense.ValueType, decision_variables: Iterable[DecisionVariable | decision_variables_pb2.DecisionVariable], description: instance_pb2.Instance.Description | None = None) Instance
get_constraint(constraint_id: int) Constraint

Get a constraint by ID.

get_constraints() list[Constraint]

Get constraints as a list of Constraint instances.

get_decision_variable(variable_id: int) DecisionVariable

Get a decision variable by ID.

get_decision_variables() list[DecisionVariable]

Get decision variables as a list of DecisionVariable instances.

get_removed_constraint(removed_constraint_id: int) RemovedConstraint

Get a removed constraint by ID.

get_removed_constraints() list[RemovedConstraint]

Get removed constraints as a list of RemovedConstraint instances.

get_user_annotation(key: str, *, annotation_namespace: str = 'org.ommx.user.')

Get a user annotation from the instance.

Examples

>>> instance = Instance.empty()
>>> instance.add_user_annotation("author", "Alice")
>>> instance.get_user_annotation("author")
'Alice'
get_user_annotations(*, annotation_namespace: str = 'org.ommx.user.') dict[str, str]

Get user annotations from the instance.

See also add_user_annotation().

static load_mps(path: str) Instance
static load_qplib(path: str) Instance
partial_evaluate(state: ToState) Instance
penalty_method() ParametricInstance

Convert to a parametric unconstrained instance by penalty method.

Roughly, this converts a constrained problem

\[\begin{split}\begin{align*} \min_x & \space f(x) & \\ \text{ s.t. } & \space g_i(x) = 0 & (\forall i) \end{align*}\end{split}\]

to an unconstrained problem with parameters

\[\min_x f(x) + \sum_i \lambda_i g_i(x)^2\]

where \(\lambda_i\) are the penalty weight parameters for each constraint. If you want to use single weight parameter, use uniform_penalty_method() instead.

The removed constrains are stored in removed_constraints.

Raises:

RuntimeError – If the instance contains inequality constraints.

Examples

>>> from ommx.v1 import Instance, DecisionVariable, Constraint
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[x[0] + x[1] == 1, x[1] + x[2] == 1],
...     sense=Instance.MAXIMIZE,
... )
>>> instance.objective
Function(x0 + x1 + x2)

>>> pi = instance.penalty_method()

The constraint is put in `removed_constraints`

>>> pi.get_constraints()
[]
>>> len(pi.get_removed_constraints())
2
>>> pi.get_removed_constraints()[0]
RemovedConstraint(Function(x0 + x1 - 1) == 0, reason=penalty_method, parameter_id=3)
>>> pi.get_removed_constraints()[1]
RemovedConstraint(Function(x1 + x2 - 1) == 0, reason=penalty_method, parameter_id=4)

There are two parameters corresponding to the two constraints

>>> len(pi.get_parameters())
2
>>> p1 = pi.get_parameters()[0]
>>> p1.id, p1.name
(3, 'penalty_weight')
>>> p2 = pi.get_parameters()[1]
>>> p2.id, p2.name
(4, 'penalty_weight')

Substitute all parameters to zero to get the original objective

>>> instance0 = pi.with_parameters({p1.id: 0.0, p2.id: 0.0})
>>> instance0.objective
Function(x0 + x1 + x2)

Substitute all parameters to one

>>> instance1 = pi.with_parameters({p1.id: 1.0, p2.id: 1.0})
>>> instance1.objective
Function(x0*x0 + 2*x0*x1 + 2*x1*x1 + 2*x1*x2 + x2*x2 - x0 - 3*x1 - x2 + 2)
relax_constraint(constraint_id: int, reason: str, **parameters)

Remove a constraint from the instance. The removed constraint is stored in removed_constraints, and can be restored by restore_constraint().

Parameters:
  • constraint_id – The ID of the constraint to remove.

  • reason – The reason why the constraint is removed.

  • parameters – Additional parameters to describe the reason.

Examples

Relax constraint, and restore it.

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[(sum(x) == 3).set_id(1)],
...     sense=Instance.MAXIMIZE,
... )
>>> instance.get_constraints()
[Constraint(Function(x0 + x1 + x2 - 3) == 0)]

>>> instance.relax_constraint(1, "manual relaxation")
>>> instance.get_constraints()
[]
>>> instance.get_removed_constraints()
[RemovedConstraint(Function(x0 + x1 + x2 - 3) == 0, reason=manual relaxation)]

>>> instance.restore_constraint(1)
>>> instance.get_constraints()
[Constraint(Function(x0 + x1 + x2 - 3) == 0)]
>>> instance.get_removed_constraints()
[]

Evaluate relaxed instance, and show feasible_unrelaxed.

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[
...         (x[0] + x[1] == 2).set_id(0),
...         (x[1] + x[2] == 2).set_id(1),
...     ],
...     sense=Instance.MINIMIZE,
... )

For x0=0, x1=1, x2=1
- x0 + x1 == 2 is not feasible
- x1 + x2 == 2 is feasible

>>> solution = instance.evaluate({0: 0, 1: 1, 2: 1})
>>> solution.feasible_relaxed
False
>>> solution.feasible_unrelaxed
False

Relax the constraint: x0 + x1 == 2

>>> instance.relax_constraint(0, "testing")
>>> solution = instance.evaluate({0: 0, 1: 1, 2: 1})
>>> solution.feasible_relaxed
True
>>> solution.feasible_unrelaxed
False
restore_constraint(constraint_id: int)

Restore a removed constraint to the instance.

Parameters:

constraint_id – The ID of the constraint to restore.

Note that this drops the removed reason and associated parameters. See relax_constraint() for details.

to_bytes() bytes
uniform_penalty_method() ParametricInstance

Convert to a parametric unconstrained instance by penalty method with uniform weight.

Roughly, this converts a constrained problem

\[\begin{split}\begin{align*} \min_x & \space f(x) & \\ \text{ s.t. } & \space g_i(x) = 0 & (\forall i) \end{align*}\end{split}\]

to an unconstrained problem with a parameter

\[\min_x f(x) + \lambda \sum_i g_i(x)^2\]

where \(\lambda\) is the uniform penalty weight parameter for all constraints.

The removed constrains are stored in removed_constraints.

Raises:

RuntimeError – If the instance contains inequality constraints.

Examples

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[sum(x) == 3],
...     sense=Instance.MAXIMIZE,
... )
>>> instance.objective
Function(x0 + x1 + x2)

>>> pi = instance.uniform_penalty_method()

The constraint is put in `removed_constraints`

>>> pi.get_constraints()
[]
>>> len(pi.get_removed_constraints())
1
>>> pi.get_removed_constraints()[0]
RemovedConstraint(Function(x0 + x1 + x2 - 3) == 0, reason=uniform_penalty_method)

There is only one parameter in the instance

>>> len(pi.get_parameters())
1
>>> p = pi.get_parameters()[0]
>>> p.id
3
>>> p.name
'uniform_penalty_weight'

Substitute `p = 0` to get the original objective

>>> instance0 = pi.with_parameters({p.id: 0.0})
>>> instance0.objective
Function(x0 + x1 + x2)

Substitute `p = 1`

>>> instance1 = pi.with_parameters({p.id: 1.0})
>>> instance1.objective
Function(x0*x0 + 2*x0*x1 + 2*x0*x2 + x1*x1 + 2*x1*x2 + x2*x2 - 5*x0 - 5*x1 - 5*x2 + 9)
write_mps(path: str)

Outputs the instance as an MPS file.

  • The outputted file is compressed by gzip.

  • Only linear problems are supported.

  • Various forms of metadata, like problem description and variable/constraint names, are not preserved.

Description
MAXIMIZE
MINIMIZE
annotation_namespace = 'org.ommx.v1.instance'
annotations: dict[str, str]

Arbitrary annotations stored in OMMX artifact. Use title or other specific attributes if possible.

authors

Authors of this instance, stored as org.ommx.v1.instance.authors annotation in OMMX artifact.

property constraints: pandas.DataFrame
created

The creation date of the instance, stored as org.ommx.v1.instance.created annotation in RFC3339 format in OMMX artifact.

dataset

Dataset name which this instance belongs to, stored as org.ommx.v1.instance.dataset annotation in OMMX artifact.

property decision_variables: pandas.DataFrame
property description: instance_pb2.Instance.Description
license

License of this instance in the SPDX license identifier. This is stored as org.ommx.v1.instance.license annotation in OMMX artifact.

num_constraints

Number of constraints in this instance, stored as org.ommx.v1.instance.constraints annotation in OMMX artifact.

num_variables

Number of variables in this instance, stored as org.ommx.v1.instance.variables annotation in OMMX artifact.

property objective: Function
raw: instance_pb2.Instance

The raw protobuf message.

property removed_constraints: pandas.DataFrame
property sense: instance_pb2.Instance.Sense.ValueType
title

The title of the instance, stored as org.ommx.v1.instance.title annotation in OMMX artifact.

class ommx.v1.Linear(*, terms: dict[int, float | int], constant: float | int = 0)

Modeler API for linear function

This is a wrapper of linear_pb2.Linear protobuf message.

Examples

Create a linear function :math:`f(x_1, x_2) = 2 x_1 + 3 x_2 + 1`
>>> f = Linear(terms={1: 2, 2: 3}, constant=1)

Or create via DecisionVariable
>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> g = 2*x1 + 3*x2 + 1

Compare two linear functions are equal in terms of a polynomial with tolerance
>>> assert f.almost_equal(g, atol=1e-12)

Note that `f == g` becomes an equality `Constraint`
>>> assert isinstance(f == g, Constraint)
almost_equal(other: Linear, *, atol: float = 1e-10) bool

Compare two linear functions have almost equal coefficients and constant.

equals_to(other: Linear) bool

Alternative to == operator to compare two linear functions.

evaluate(state: ToState) tuple[float, set]

Evaluate the linear function with the given state.

Examples

Evaluate `2 x1 + 3 x2 + 1` with `x1 = 3, x2 = 4, x3 = 5`

>>> f = Linear(terms={1: 2, 2: 3}, constant=1)
>>> value, used_ids = f.evaluate({1: 3, 2: 4, 3: 5}) # Unused ID `3` can be included

2*3 + 3*4 + 1 = 19
>>> value
19.0

Since the value of ID `3` of `state` is not used, the it is not included in `used_ids`.
>>> used_ids
{1, 2}

Missing ID raises an error
>>> f.evaluate({1: 3})
Traceback (most recent call last):
...
RuntimeError: Variable id (2) is not found in the solution
static from_bytes(data: bytes) Linear
static from_raw(raw: linear_pb2.Linear) Linear
partial_evaluate(state: ToState) tuple[Linear, set]

Partially evaluate the linear function with the given state.

Examples

Evaluate `2 x1 + 3 x2 + 1` with `x1 = 3`, yielding `3 x2 + 7`

>>> f = Linear(terms={1: 2, 2: 3}, constant=1)
>>> new_f, used_ids = f.partial_evaluate({1: 3})
>>> new_f
Linear(3*x2 + 7)
>>> used_ids
{1}
>>> new_f.partial_evaluate({2: 4})
(Linear(19), {2})
to_bytes() bytes
property constant: float

Get the constant term of the linear function

property linear_terms: dict[int, float]

Get the terms of the linear function as a dictionary

raw: linear_pb2.Linear
property terms: dict[tuple[int, Ellipsis], float]

Linear terms and constant as a dictionary

class ommx.v1.Parameter

Idiomatic wrapper of ommx.v1.Parameter protobuf message.

equals_to(other: Parameter) bool

Alternative to == operator to compare two decision variables.

static from_bytes(data: bytes) Parameter
static new(id: int, *, name: str | None = None, subscripts: Iterable[int] = [], description: str | None = None)
to_bytes() bytes
property description: str
property id: int
property name: str
property parameters: dict[str, str]
raw: parametric_instance_pb2.Parameter
property subscripts: list[int]
class ommx.v1.ParametricInstance

Idiomatic wrapper of ommx.v1.ParametricInstance protobuf message.

Examples

Create an instance for KnapSack Problem with parameters

>>> from ommx.v1 import ParametricInstance, DecisionVariable, Parameter

Decision variables

>>> x = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(6)]

Profit and weight of items as parameters

>>> p = [Parameter.new(id=i+6, name="Profit", subscripts=[i]) for i in range(6)]
>>> w = [Parameter.new(id=i+12, name="Weight", subscripts=[i]) for i in range(6)]
>>> W = Parameter.new(id=18, name="Capacity")

Objective and constraint

>>> objective = sum(p[i] * x[i] for i in range(6))
>>> constraint = sum(w[i] * x[i] for i in range(6)) <= W

Compose as an instance

>>> parametric_instance = ParametricInstance.from_components(
...     decision_variables=x,
...     parameters=p + w + [W],
...     objective=objective,
...     constraints=[constraint],
...     sense=Instance.MAXIMIZE,
... )

Substitute parameters to get an instance

>>> p_values = { x.id: value for x, value in zip(p, [10, 13, 18, 31, 7, 15]) }
>>> w_values = { x.id: value for x, value in zip(w, [11, 15, 20, 35, 10, 33]) }
>>> W_value = { W.id: 47 }
>>> instance = parametric_instance.with_parameters({**p_values, **w_values, **W_value})
static empty() ParametricInstance

Create trivial empty instance of minimization with zero objective, no constraints, and no decision variables and parameters.

static from_bytes(data: bytes) ParametricInstance
static from_components(*, objective: int | float | DecisionVariable | Linear | Quadratic | Polynomial | function_pb2.Function, constraints: Iterable[Constraint | constraint_pb2.Constraint], sense: instance_pb2.Instance.Sense.ValueType, decision_variables: Iterable[DecisionVariable | decision_variables_pb2.DecisionVariable], parameters: Iterable[Parameter | parametric_instance_pb2.Parameter], description: instance_pb2.Instance.Description | None = None) ParametricInstance
get_constraint(constraint_id: int) Constraint

Get a constraint by ID.

get_constraints() list[Constraint]

Get constraints as a list of :class:`Constraint

get_decision_variable(variable_id: int) DecisionVariable

Get a decision variable by ID.

get_decision_variables() list[DecisionVariable]

Get decision variables as a list of DecisionVariable instances.

get_parameter(parameter_id: int) Parameter

Get a parameter by ID.

get_parameters() list[Parameter]

Get parameters as a list of Parameter.

get_removed_constraint(removed_constraint_id: int) RemovedConstraint

Get a removed constraint by ID.

get_removed_constraints() list[RemovedConstraint]

Get removed constraints as a list of RemovedConstraint instances.

to_bytes() bytes
with_parameters(parameters: instance_pb2.Parameters | Mapping[int, float]) Instance

Substitute parameters to yield an instance.

annotation_namespace = 'org.ommx.v1.parametric-instance'
annotations: dict[str, str]
authors

Authors of this instance, stored as org.ommx.v1.parametric-instance.authors annotation in OMMX artifact.

property constraints: pandas.DataFrame
created

The creation date of the instance, stored as org.ommx.v1.parametric-instance.created annotation in RFC3339 format in OMMX artifact.

dataset

Dataset name which this instance belongs to, stored as org.ommx.v1.parametric-instance.dataset annotation in OMMX artifact.

property decision_variables: pandas.DataFrame
license

License of this instance in the SPDX license identifier. This is stored as org.ommx.v1.parametric-instance.license annotation in OMMX artifact.

num_constraints

Number of constraints in this instance, stored as org.ommx.v1.parametric-instance.constraints annotation in OMMX artifact.

num_variables

Number of variables in this instance, stored as org.ommx.v1.parametric-instance.variables annotation in OMMX artifact.

property parameters: pandas.DataFrame
raw: parametric_instance_pb2.ParametricInstance
property removed_constraints: pandas.DataFrame
title

The title of the instance, stored as org.ommx.v1.parametric-instance.title annotation in OMMX artifact.

class ommx.v1.Polynomial(*, terms: dict[Iterable[int], float | int] = {})

Helper class that provides a standard way to create an ABC using inheritance.

almost_equal(other: Polynomial, *, atol: float = 1e-10) bool

Compare two polynomial have almost equal coefficients

evaluate(state: ToState) tuple[float, set]

Evaluate the polynomial with the given state.

Examples

Evaluate `2 x1 x2 x3 + 3 x2 x3 + 1` with `x1 = 3, x2 = 4, x3 = 5`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = 2*x1*x2*x3 + 3*x2*x3 + 1
>>> f
Polynomial(2*x1*x2*x3 + 3*x2*x3 + 1)

>>> f.evaluate({1: 3, 2: 4, 3: 5})
(181.0, {1, 2, 3})

Missing ID raises an error
>>> f.evaluate({1: 3})
Traceback (most recent call last):
...
RuntimeError: Variable id (2) is not found in the solution
static from_bytes(data: bytes) Polynomial
static from_raw(raw: polynomial_pb2.Polynomial) Polynomial
partial_evaluate(state: ToState) tuple[Polynomial, set]

Partially evaluate the polynomial with the given state.

Examples

Evaluate `2 x1 x2 x3 + 3 x2 x3 + 1` with `x1 = 3`, yielding `9 x2 x3 + 1`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = 2*x1*x2*x3 + 3*x2*x3 + 1
>>> f
Polynomial(2*x1*x2*x3 + 3*x2*x3 + 1)

>>> f.partial_evaluate({1: 3})
(Polynomial(9*x2*x3 + 1), {1})
to_bytes() bytes
raw: polynomial_pb2.Polynomial
property terms: dict[tuple[int, Ellipsis], float]
class ommx.v1.Quadratic(*, columns: Iterable[int], rows: Iterable[int], values: Iterable[float | int], linear: Linear | None = None)

Helper class that provides a standard way to create an ABC using inheritance.

almost_equal(other: Quadratic, *, atol: float = 1e-10) bool

Compare two quadratic functions have almost equal coefficients

evaluate(state: ToState) tuple[float, set]

Evaluate the quadratic function with the given state.

Examples

Evaluate `2 x1 x2 + 3 x2 x3 + 1` with `x1 = 3, x2 = 4, x3 = 5`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = 2*x1*x2 + 3*x2*x3 + 1
>>> f
Quadratic(2*x1*x2 + 3*x2*x3 + 1)

>>> f.evaluate({1: 3, 2: 4, 3: 5})
(85.0, {1, 2, 3})

Missing ID raises an error
>>> f.evaluate({1: 3})
Traceback (most recent call last):
...
RuntimeError: Variable id (2) is not found in the solution
static from_bytes(data: bytes) Quadratic
static from_raw(raw: quadratic_pb2.Quadratic) Quadratic
partial_evaluate(state: ToState) tuple[Quadratic, set]

Partially evaluate the quadratic function with the given state.

Examples

Evaluate `2 x1 x2 + 3 x2 x3 + 1` with `x1 = 3`, yielding `3 x2 x3 + 6 x2 + 1`

>>> x1 = DecisionVariable.integer(1)
>>> x2 = DecisionVariable.integer(2)
>>> x3 = DecisionVariable.integer(3)
>>> f = 2*x1*x2 + 3*x2*x3 + 1
>>> f
Quadratic(2*x1*x2 + 3*x2*x3 + 1)

>>> f.partial_evaluate({1: 3})
(Quadratic(3*x2*x3 + 6*x2 + 1), {1})
to_bytes() bytes
property linear: Linear | None
property quad_terms: dict[tuple[int, int], float]
raw: quadratic_pb2.Quadratic
property terms: dict[tuple[int, Ellipsis], float]
class ommx.v1.SampleSet

The output of sampling-based optimization algorithms, e.g. simulated annealing (SA).

  • Similar to Solution rather than solution_pb2.State. This class contains the sampled values of decision variables with the objective value, constraint violations, feasibility, and metadata of constraints and decision variables.

  • This class is usually created via Instance.evaluate_samples().

Examples

Let’s consider a simple optimization problem:

\[\begin{split}\begin{align*} \max &\quad x_1 + 2 x_2 + 3 x_3 \\ \text{s.t.} &\quad x_1 + x_2 + x_3 = 1 \\ &\quad x_1, x_2, x_3 \in \{0, 1\} \end{align*}\end{split}\]
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=x[0] + 2*x[1] + 3*x[2],
...     constraints=[sum(x) == 1],
...     sense=Instance.MAXIMIZE,
... )

with three samples:

>>> samples = {
...     0: {0: 1, 1: 0, 2: 0},  # x1 = 1, x2 = x3 = 0
...     1: {0: 0, 1: 0, 2: 1},  # x3 = 1, x1 = x2 = 0
...     2: {0: 1, 1: 1, 2: 0},  # x1 = x2 = 1, x3 = 0 (infeasible)
... } # ^ sample ID

Note that this will be done by sampling-based solvers, but we do it manually here. We can evaluate the samples with via Instance.evaluate_samples():

>>> sample_set = instance.evaluate_samples(samples)
>>> sample_set.summary  
           objective  feasible
sample_id
1                3.0      True
0                1.0      True
2                3.0     False

The summary attribute shows the objective value, feasibility of each sample. Note that this feasible column represents the feasibility of the original constraints, not the relaxed constraints. You can get each samples by get() as a Solution format:

>>> solution = sample_set.get(sample_id=0)
>>> solution.objective
1.0
>>> solution.decision_variables  
      kind  lower  upper  name subscripts description substituted_value  value
id
0   binary    0.0    1.0  <NA>         []        <NA>              <NA>    1.0
1   binary    0.0    1.0  <NA>         []        <NA>              <NA>    0.0
2   binary    0.0    1.0  <NA>         []        <NA>              <NA>    0.0

best_feasible() returns the best feasible sample, i.e. the largest objective value among feasible samples:

>>> solution = sample_set.best_feasible()
>>> solution.objective
3.0
>>> solution.decision_variables  
      kind  lower  upper  name subscripts description substituted_value  value
id
0   binary    0.0    1.0  <NA>         []        <NA>              <NA>    0.0
1   binary    0.0    1.0  <NA>         []        <NA>              <NA>    0.0
2   binary    0.0    1.0  <NA>         []        <NA>              <NA>    1.0

Of course, the sample of smallest objective value is returned for minimization problems.

best_feasible() Solution

Get the best feasible solution

best_feasible_unrelaxed() Solution

Get the best feasible solution without relaxation

extract_constraints(name: str, sample_id: int) dict[tuple[int, Ellipsis], float]

Extract evaluated constraint violations for a given constraint name and sample ID.

extract_decision_variables(name: str, sample_id: int) dict[tuple[int, Ellipsis], float]

Extract sampled decision variable values for a given name and sample ID.

static from_bytes(data: bytes) SampleSet
get(sample_id: int) Solution

Get a sample for a given ID as a solution format

to_bytes() bytes
annotation_namespace = 'org.ommx.v1.sample-set'
annotations: dict[str, str]

Arbitrary annotations stored in OMMX artifact. Use parameters or other specific attributes if possible.

property constraints: pandas.DataFrame
property decision_variables: pandas.DataFrame
end

When the optimization ended, stored as org.ommx.v1.sample-set.end annotation in RFC3339 format in OMMX artifact.

property feasible: dict[int, bool]

Feasibility in terms of the original constraints, an alias to feasible_unrelaxed.

Compatibility

The meaning of this property has changed from Python SDK 1.7.0. Previously, this property represents the feasibility of the remaining constraints only, i.e. excluding relaxed constraints. From Python SDK 1.7.0, this property represents the feasibility of all constraints, including relaxed constraints.

property feasible_relaxed: dict[int, bool]

Feasibility in terms of the remaining (non-removed) constraints.

For each sample_id, this property shows whether the sample is feasible for the all Instance.constraints

property feasible_unrelaxed: dict[int, bool]

Feasibility in terms of the original constraints without relaxation.

For each sample_id, this property shows whether the sample is feasible both for the all Instance.constraints and all Instance.removed_constraints.

instance

The digest of the instance layer, stored as org.ommx.v1.sample-set.instance annotation in OMMX artifact.

property objectives: dict[int, float]
parameters

The parameters used in the optimization, stored as org.ommx.v1.sample-set.parameters annotation as a JSON in OMMX artifact.

raw: sample_set_pb2.SampleSet
property sample_ids: list[int]
solver

The solver which generated this sample set, stored as org.ommx.v1.sample-set.solver annotation as a JSON in OMMX artifact.

start

When the optimization started, stored as org.ommx.v1.sample-set.start annotation in RFC3339 format in OMMX artifact.

property summary: pandas.DataFrame
property summary_with_constraints: pandas.DataFrame
class ommx.v1.SampledValues
as_series() pandas.Series
raw: sample_set_pb2.SampledValues
class ommx.v1.Solution

Idiomatic wrapper of ommx.v1.Solution protobuf message.

This also contains annotations not contained in protobuf message, and will be stored in OMMX artifact.

extract_constraints(name: str) dict[tuple[int, Ellipsis], float]

Extract the values of constraints based on the name with subscripts key.

Raises:

ValueError – If the constraint with parameters is found, or if the same subscript is found.

Examples

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i) for i in range(3)]
>>> c0 = (x[0] + x[1] == 1).add_name("c").add_subscripts([0])
>>> c1 = (x[1] + x[2] == 1).add_name("c").add_subscripts([1])
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[c0, c1],
...     sense=Instance.MAXIMIZE,
... )
>>> solution = instance.evaluate({0: 1, 1: 0, 2: 1})
>>> solution.extract_constraints("c")
{(0,): 0.0, (1,): 0.0}
extract_decision_variables(name: str) dict[tuple[int, Ellipsis], float]

Extract the values of decision variables based on the name with subscripts key.

Raises:

ValueError – If the decision variable with parameters is found, or if the same subscript is found.

Examples

>>> from ommx.v1 import Instance, DecisionVariable
>>> x = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(3)]
>>> instance = Instance.from_components(
...     decision_variables=x,
...     objective=sum(x),
...     constraints=[sum(x) == 1],
...     sense=Instance.MAXIMIZE,
... )
>>> solution = instance.evaluate({i: 1 for i in range(3)})
>>> solution.extract_decision_variables("x")
{(0,): 1.0, (1,): 1.0, (2,): 1.0}
static from_bytes(data: bytes) Solution
to_bytes() bytes
annotation_namespace = 'org.ommx.v1.solution'
annotations: dict[str, str]

Arbitrary annotations stored in OMMX artifact. Use parameters or other specific attributes if possible.

property constraints: pandas.DataFrame
property decision_variables: pandas.DataFrame
end

When the optimization ended, stored as org.ommx.v1.solution.end annotation in RFC3339 format in OMMX artifact.

property feasible: bool

Feasibility of the solution in terms of all constraints, including removed_constraints.

This is an alias for feasible_unrelaxed.

Compatibility

The meaning of this property has changed from Python SDK 1.7.0. Previously, this property represents the feasibility of the remaining constraints only, i.e. excluding relaxed constraints. From Python SDK 1.7.0, this property represents the feasibility of all constraints, including relaxed constraints.

property feasible_relaxed: bool

Feasibility of the solution in terms of remaining constraints, not including relaxed (removed) constraints.

property feasible_unrelaxed: bool

Feasibility of the solution in terms of all constraints, including relaxed (removed) constraints.

instance

The digest of the instance layer, stored as org.ommx.v1.solution.instance annotation in OMMX artifact.

This Solution is the solution of the mathematical programming problem described by the instance.

property objective: float
property optimality: solution_pb2.Optimality.ValueType
parameters

The parameters used in the optimization, stored as org.ommx.v1.solution.parameters annotation as a JSON in OMMX artifact.

raw: solution_pb2.Solution

The raw protobuf message.

property relaxation: solution_pb2.Relaxation.ValueType
solver

The solver which generated this solution, stored as org.ommx.v1.solution.solver annotation as a JSON in OMMX artifact.

start

When the optimization started, stored as org.ommx.v1.solution.start annotation in RFC3339 format in OMMX artifact.

property state: solution_pb2.State
ommx.v1.ToSamples: typing_extensions.TypeAlias

Type alias for convertible types to Samples.

ommx.v1.ToState: typing_extensions.TypeAlias

Type alias for convertible types to State.