ParametricInstance#
- class ParametricInstance#
A family of optimization problems with fixed variables and constraints.
A ParametricInstance leaves some coefficients or constants symbolic as
Parameterobjects. The model’s caller supplies their values withwith_parameters()to obtain an ordinaryInstancefor evaluation, preparation, or a solver adapter. Parameters are inputs chosen before solving; they are not decision variables for the solver to optimize.Reuse a problem under different numerical conditions
Here the two items and their scores stay fixed, while the allowed number of selected items changes. The original family remains available after each call to
with_parameters.>>> from ommx import ConstraintID, DecisionVariable, Parameter, ParametricInstance, Sense >>> xs = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(2)] >>> capacity = Parameter(2, name="capacity", description="Maximum selected items") >>> family = ParametricInstance.from_components( ... decision_variables=xs, parameters=[capacity], ... objective=3 * xs[0] + 2 * xs[1], ... constraints={0: xs[0] + xs[1] <= capacity}, sense=Sense.Maximize, ... ) >>> one_item = family.with_parameters({capacity.id: 1}) >>> two_items = family.with_parameters({capacity.id: 2}) >>> candidate = {xs[0].id: 1, xs[1].id: 1} >>> assert not one_item.evaluate(candidate).feasible >>> assert two_items.evaluate(candidate).feasible >>> assert two_items.evaluate(candidate).objective == 5.0 >>> assert {v.id for v in one_item.decision_variables} == {v.id for v in two_items.decision_variables} >>> assert set(one_item.constraints) == set(two_items.constraints) == {ConstraintID(0)} >>> assert family.parameter_ids == {capacity.id}
Materialization preserves decision-variable and constraint IDs. Those IDs let callers associate results with the same items and conditions across instances; they do not imply identical feasibility or optimal solutions. Parameters can also appear as objective and constraint coefficients, as in the weighted knapsack example in
from_components().Parameter identities and modeling labels
Parameters and decision variables use one ID space and must not overlap. Here the decision variables have IDs 0 and 1, and the parameter has ID 2. Both can appear in arithmetic expressions, but only decision variables receive candidate values after materialization. Parameter names, subscripts, string-valued metadata, and descriptions describe model inputs; the IDs identify the numerical values passed to
with_parameters.parametersandparameter_idslist declared parameters.parameters_df()collects their definitions and labels into a DataFrame, not a table of supplied numerical values.>>> table = family.parameters_df() >>> assert table.loc[capacity.id, "name"] == "capacity" >>> assert table.loc[capacity.id, "description"] == "Maximum selected items"
decision_variables_df()andconstraints_df()provide the corresponding model tables; the latter requires an explicitkind. For required IDs, extra keys, and numerical substitution rules, readwith_parameters().When to rebuild the model
Parameter values do not generate variable or constraint definitions. If an input changes the number of items or the model’s structure, build new components in Python or use a modeler that generates that structure. This differs from changing numerical coefficients within an existing family. No Experiment is needed to construct or materialize a ParametricInstance. Use
Experimentseparately when recording the conditions and results of multiple trials is useful.- __copy__() ParametricInstance#
- __repr__() str#
- __str__() str#
- add_constraint(constraint: Constraint) AttachedConstraint#
Add a regular constraint to this parametric instance.
Picks an unused
ConstraintID, drains the wrapper’s context snapshot into this parametric instance’s SoA store, and returns anAttachedConstraintbound to the new id. The inputConstraintis not mutated; subsequent writes that should land on this parametric instance must go through the returned handle.Raises
ValueErrorif the constraint references an id that is neither a defined decision variable nor a defined parameter, or if it references an id currently used as a substitution-dependency key.
- add_decision_variable(variable: DecisionVariable) AttachedDecisionVariable#
Add a decision variable to this parametric instance. Returns an
AttachedDecisionVariablebound to the variable’s id — a write-through handle for further label updates.Raises
ValueErrorif the variable’s id collides with an existing decision variable or parameter. Substituted variables retain their ids and therefore also count as existing decision variables.
- add_indicator_constraint(constraint: IndicatorConstraint) AttachedIndicatorConstraint#
Add an indicator constraint to this parametric instance.
Picks an unused
IndicatorConstraintID, drains the wrapper’s context snapshot into this parametric instance’s SoA store, and returns anAttachedIndicatorConstraintbound to the new id.Raises
ValueErrorif the constraint references an id that is neither a defined decision variable nor a defined parameter, or if it references an id currently used as a substitution-dependency key.
- add_one_hot_constraint(constraint: OneHotConstraint) AttachedOneHotConstraint#
Add a one-hot constraint to this parametric instance.
- add_sos1_constraint(constraint: Sos1Constraint) AttachedSos1Constraint#
Add a SOS1 constraint to this parametric instance.
- add_user_annotation(key: str, value: str, *, annotation_namespace: str = 'org.ommx.user.') None#
- add_user_annotations(annotations: Mapping[str, str], *, annotation_namespace: str = 'org.ommx.user.') None#
- attached_decision_variable(variable_id: int) AttachedDecisionVariable#
Look up the
AttachedDecisionVariablefor the given id — a write-through handle.
- constraint_context_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint context DataFrame (id-indexed). See
ommx.Instance.constraint_context_df()for column /kind=semantics.
- constraint_parameters_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint parameters DataFrame (long format).
- constraint_provenance_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Constraint provenance DataFrame (long format).
- constraint_removed_reasons_df(*, kind: ConstraintKind[ConstraintIDBase]) DataFrame#
Removed-constraint reasons DataFrame (long format).
- constraints_df(*, kind: ConstraintKind[ConstraintIDBase], include: Optional[Sequence[str]] = None, removed: bool = False) DataFrame#
DataFrame of constraints, dispatched on
kind=. Seeommx.Instance.constraints_df()for column /kind=/include=/removed=semantics.
- decision_variables_df(include: Optional[Sequence[str]] = None) DataFrame#
DataFrame of decision variables
-
display_function(function: builtins.int | builtins.float |
numpy.integer|numpy.floating| DecisionVariable | AttachedDecisionVariable | Parameter | Linear | Quadratic | Polynomial | Function, max_terms: Optional[int] = 100, max_chars: Optional[int] = 20000) FunctionDisplay# Build a bounded notebook display object for a function in this parametric instance’s context.
By default this returns a preview capped at 100 complete terms and 20,000 characters. Pass
Noneto disable either limit. Parameter labels are available before materialization, just as informat_function().The returned
FunctionDisplayhas the same preview text and truncation metadata asdisplay_function(). Useformat_functionwithout limits for a complete plain text string.>>> from ommx import DecisionVariable, Parameter, ParametricInstance, Sense >>> x = DecisionVariable.binary(0, name="x") >>> p = Parameter(100, name="p") >>> model = ParametricInstance.from_components( ... sense=Sense.Minimize, objective=x + p, decision_variables=[x], ... parameters=[p], constraints={}, ... ) >>> preview = model.display_function(model.objective) >>> assert preview.text == "x + p" >>> assert not preview.truncated
- empty() ParametricInstance#
Create trivial empty instance of minimization with zero objective, no constraints, and no decision variables and parameters.
- extract_constraints(name: str) dict[tuple[int, ...], ConstraintView]#
Extract active constraints of every family by name, keyed by subscript tuples.
Values are attached handles, just as in
constraints: edits update this model. The returned dictionary snapshots the matching keys; it does not track later label or membership changes. Removed constraints are excluded. Parameters and descriptions do not participate in matching.Raises KeyError if no active constraint has this name, and ValueError if matching constraints share subscripts, including across different families. Use typed-ID lookup in
constraintsto distinguish ambiguous labels.
-
format_function(function: builtins.int | builtins.float |
numpy.integer|numpy.floating| DecisionVariable | AttachedDecisionVariable | Parameter | Linear | Quadratic | Polynomial | Function, max_terms: Optional[int] = None, max_chars: Optional[int] = None) str# Format a function using this parametric instance’s decision-variable and parameter labels.
The plain
repr()/strrepresentation ofFunctionremains context-free and renders rawx<id>symbols such asx1. This method resolves both variable and parameter labels before any parameter values have been supplied.>>> from ommx import DecisionVariable, Parameter, ParametricInstance, Sense >>> x = DecisionVariable.binary(0, name="x") >>> p = Parameter(100, name="p", parameters={"scenario": "base"}) >>> model = ParametricInstance.from_components( ... sense=Sense.Minimize, objective=x + p, decision_variables=[x], ... parameters=[p], constraints={}, ... ) >>> assert model.format_function(model.objective) == "x + p[scenario=base]"
Every referenced ID must belong to exactly one of this instance’s decision variables or parameters. The lookup uses IDs, not names from another model, and validates them before applying output limits.
max_termsandmax_charsboth default toNonefor no limit; their meaning is the same as informat_function(). For a preview with truncation metadata, usedisplay_function().
-
from_components(*, sense: Sense, objective: builtins.int | builtins.float |
numpy.integer|numpy.floating| DecisionVariable | AttachedDecisionVariable | Parameter | Linear | Quadratic | Polynomial | Function, decision_variables: Sequence[DecisionVariable], constraints: Mapping[ConstraintID, Constraint] | Mapping[int, Constraint] | ConstraintID | int | Constraint, parameters: Sequence[Parameter], indicator_constraints: Mapping[IndicatorConstraintID, IndicatorConstraint] | Mapping[int, IndicatorConstraint] | IndicatorConstraintID | int | IndicatorConstraint = None, one_hot_constraints: Mapping[OneHotConstraintID, OneHotConstraint] | Mapping[int, OneHotConstraint] | OneHotConstraintID | int | OneHotConstraint = None, sos1_constraints: Mapping[Sos1ConstraintID, Sos1Constraint] | Mapping[int, Sos1Constraint] | Sos1ConstraintID | int | Sos1Constraint = None, named_functions: Optional[Sequence[NamedFunction]] = None, description: Optional[InstanceDescription] = None) ParametricInstance# Build a parametric instance from its model components.
Constraint mappings accept integer keys or IDs of the matching family. Integers are promoted to that family’s ID. IDs of another family raise
TypeError; keys that become duplicates raiseValueError. Returned collections always use typed IDs.Raises
ValueErrorif a decision variable and parameter use the same ID.Parameterize objective coefficients, weights, and a capacity
This two-item knapsack family fixes the item count and uses parameters for both coefficients and the right-hand-side constant. Parameter IDs are separate from the decision-variable IDs in the shared ID space.
>>> from ommx import DecisionVariable, Parameter, ParametricInstance, Sense >>> n = 2 >>> xs = [DecisionVariable.binary(i, name="x", subscripts=[i]) for i in range(n)] >>> profits = [Parameter(n + i, name="profit", subscripts=[i]) for i in range(n)] >>> weights = [Parameter(2 * n + i, name="weight", subscripts=[i]) for i in range(n)] >>> capacity = Parameter(3 * n, name="capacity") >>> family = ParametricInstance.from_components( ... decision_variables=xs, parameters=profits + weights + [capacity], ... objective=sum(p * x for p, x in zip(profits, xs)), ... constraints={0: sum(w * x for w, x in zip(weights, xs)) <= capacity}, ... sense=Sense.Maximize, ... ) >>> values = {p.id: value for p, value in zip(profits, [3, 2])} >>> values.update({w.id: value for w, value in zip(weights, [2, 1])}) >>> values[capacity.id] = 2 >>> instance = family.with_parameters(values) >>> solution = instance.evaluate({xs[0].id: 1, xs[1].id: 0}) >>> assert solution.feasible and solution.objective == 3.0 >>> assert not instance.evaluate({xs[0].id: 1, xs[1].id: 1}).feasible
- from_v1_bytes(bytes: bytes) ParametricInstance#
Deserialize a parametric instance from v1 protobuf bytes.
Raises
ValueErrorif the protobuf payload is malformed or semantically invalid.
- from_v2_bytes(bytes: bytes) ParametricInstance#
Deserialize a parametric instance from v2 protobuf bytes.
Raises
ValueErrorif the protobuf payload is malformed or semantically invalid.
- get_decision_variable_by_id(variable_id: int) DecisionVariable#
Get a specific decision variable by ID
- get_named_function_by_id(named_function_id: int) NamedFunction#
Get a specific named function by ID
- get_parameter_by_id(parameter_id: int) Parameter#
Get a specific parameter by ID
- get_user_annotation(key: str, *, annotation_namespace: str = 'org.ommx.user.') str#
- get_user_annotations(*, annotation_namespace: str = 'org.ommx.user.') dict[str, str]#
- parameters_df(include: Optional[Sequence[str]] = None) DataFrame#
Collect declared parameter definitions and modeling labels into a DataFrame.
The index is the parameter ID, named
id. By default, the table includesname,subscripts,description, and flattenedparameters.<key>metadata columns.include=[]omits optional columns;include=["label"]selects the modeling labels andinclude=["parameters"]selects the string-valued metadata.These labels are not the numerical assignments supplied to
with_parameters(). Editing the DataFrame does not change this ParametricInstance. See the class example for selecting a parameter’s name and description by ID.
-
substitute(assignments: Mapping[int, builtins.int | builtins.float |
numpy.integer|numpy.floating| DecisionVariable | AttachedDecisionVariable | Parameter | Linear | Quadratic | Polynomial | Function]) None# Substitute decision variables with function expressions (in-place).
Replaces each given decision variable with the provided function in the objective and all active constraints. Replacement functions may still reference parameters; those parameter references remain in this parametric instance and are evaluated later by
with_parameters(). Assignment targets must be existing decision variable IDs. Replacement expressions may only reference existing decision variable or parameter IDs; parameter IDs cannot be assignment targets.Args:
assignments: A dict mapping decision variable IDs to the function expressions that should replace them.
Important: This method performs an algebraic rewrite. It does not automatically translate the substituted variable’s bound or kind into constraints on the replacement expression. If the substitution must preserve the optimization problem, the caller must provide a domain-preserving encoding or add the required linking and bound constraints explicitly.
Raises
ValueErroron cyclic or recursive assignments, undefined IDs, when a parameter ID is used as an assignment target, or when substituting a variable that is a member of an indicator, one-hot, or SOS1 constraint.Postconditions#
Substitution rewrites active expressions while materialized output evaluation restores the substituted variable.
>>> from ommx import DecisionVariable, Instance, Sense >>> x = DecisionVariable.binary(0) >>> b = DecisionVariable.binary(1) >>> source = Instance.from_components( ... decision_variables=[x, b], objective=x, constraints={}, sense=Sense.Maximize ... ) >>> assert source.convert_active_objective(Sense.Minimize) >>> parametric = source.as_parametric_instance() >>> parametric.substitute({0: b}) >>> materialized = parametric.with_parameters({}) >>> assert materialized.required_ids() == {1} >>> assert materialized.objective.evaluate({1: 1}) == -1.0 >>> solution = materialized.evaluate({1: 1}) >>> assert (solution.sense, solution.objective) == (Sense.Maximize, 1.0)
- to_v1_bytes() bytes#
Serialize this parametric instance in the OMMX v1 wire format.
Errors#
Serialization raises
RuntimeErrorwhenever an output objective is present because v1 cannot represent it.>>> from ommx import DecisionVariable, Instance, Sense >>> x = DecisionVariable.binary(0) >>> instance = Instance.from_components( ... decision_variables=[x], objective=x, constraints={}, sense=Sense.Maximize ... ) >>> assert instance.convert_active_objective(Sense.Minimize) >>> assert instance.convert_active_objective(Sense.Maximize) >>> parametric = instance.as_parametric_instance() >>> try: ... parametric.to_v1_bytes() ... except RuntimeError: ... pass ... else: ... raise AssertionError("v1 serialization accepted an output objective")
- to_v2_bytes() bytes#
Serialize this parametric instance in the OMMX v2 wire format.
Postconditions#
A v2 round-trip preserves both active and output objective semantics through materialization.
>>> from ommx import DecisionVariable, Instance, ParametricInstance, Sense >>> x = DecisionVariable.binary(0) >>> source = Instance.from_components( ... decision_variables=[x], objective=x, constraints={7: x == 1}, sense=Sense.Minimize ... ) >>> parametric = source.uniform_penalty_method() >>> parameter_id = parametric.parameters[0].id >>> restored = ParametricInstance.from_v2_bytes(parametric.to_v2_bytes()) >>> materialized = restored.with_parameters({parameter_id: 2.0}) >>> assert materialized.sense == Sense.Minimize >>> assert materialized.objective.evaluate({0: 0}) == 2.0 >>> solution = materialized.evaluate({0: 0}) >>> assert (solution.sense, solution.objective) == (Sense.Minimize, 0.0)
- variable_labels_df() DataFrame#
Decision-variable modeling-label DataFrame (id-indexed).
- variable_parameters_df() DataFrame#
Decision-variable parameters DataFrame (long format).
- with_parameters(parameters: Mapping[int, float]) Instance#
Substitute parameters to yield an instance.
Provide a dict mapping every declared parameter ID to its numerical value, including parameters not referenced by an expression. The original
ParametricInstanceis unchanged and can be materialized again. Missing declared IDs raiseRuntimeError.The method checks that declared IDs are included, not that the key sets are equal. Additional keys are accepted and participate in substitution wherever referenced. In particular, an extra decision-variable ID can also substitute that coordinate in expressions. For parameter-only materialization, supply exactly the IDs listed by
parameters.Substitution uses the SDK’s default absolute tolerance and the expression partial-evaluation rules; see
partial_evaluate(). This is not a feasibility check or decision-variable kind/bound validation. There is no blanket finiteness check of all supplied values: a referenced non-finite value can fail during substitution, while an unreferenced value need not be examined. Successful materialization does not prove that all supplied values are finite or that the resulting problem is feasible.>>> from ommx import DecisionVariable, Parameter, ParametricInstance, Sense >>> x = DecisionVariable.binary(0) >>> p, unused = Parameter(1, name="p"), Parameter(2, name="unused") >>> family = ParametricInstance.from_components( ... decision_variables=[x], parameters=[p, unused], objective=x + p, ... constraints={}, sense=Sense.Minimize ... ) >>> try: ... family.with_parameters({p.id: 3}) ... except RuntimeError as error: ... assert "Missing parameters" in str(error) ... else: ... raise AssertionError("an omitted declared parameter was accepted") >>> concrete = family.with_parameters({p.id: 3, unused.id: 0}) >>> assert concrete.objective.evaluate({x.id: 1}) == 4.0
Postconditions#
Penalty conversion preserves existing output semantics, or captures the pre-penalty active objective when no output objective exists. Materialization substitutes parameters in the active energy, and an existing output objective remains explicit even if specialization makes it structurally equal to the active objective.
>>> from ommx import DecisionVariable, Instance, Sense >>> x = DecisionVariable.binary(0) >>> source = Instance.from_components( ... decision_variables=[x], objective=x, constraints={7: x == 1}, sense=Sense.Minimize ... ) >>> parametric = source.uniform_penalty_method() >>> parameter_id = parametric.parameters[0].id >>> materialized = parametric.with_parameters({parameter_id: 2.0}) >>> assert materialized.objective.evaluate({0: 0}) == 2.0 >>> solution = materialized.evaluate({0: 0}) >>> assert (solution.sense, solution.objective, solution.feasible) == (Sense.Minimize, 0.0, False)
- property annotations: MappingProxyType[str, str]#
Read-only property.
Returns a read-only mapping of flat annotations.
Use
add_user_annotation(), metadata properties, orreplace_annotations()to modify annotations.
- property authors: list[str]#
- property constraint_names: set[str]#
Read-only property.
Unique names across all constraint families, as a set of strings.
Only active constraints are included. The scope matches
extract_constraints. Unnamed constraints are excluded; an explicitly empty name is included. Duplicate names appear once, even when extraction would reject duplicate subscripts. Each access returns a fresh set; editing it does not change this owner.
- property constraints: ConstraintCollection#
Read-only property.
Live mapping of all active constraint families, keyed by typed IDs. The view retains this owner and fetches each constraint on demand.
- property decision_variable_ids: set[int]#
Read-only property.
- property decision_variable_names: set[str]#
Read-only property.
Unique decision-variable names as a set of strings, excluding parameters. Unnamed variables are excluded; explicitly empty names are included. Each access returns a fresh set; editing it does not change this owner.
- property decision_variables: list[AttachedDecisionVariable]#
Read-only property.
List of all decision variables in the parametric instance sorted by their IDs.
Returns a list of
AttachedDecisionVariablewrite-through handles. Seedecision_variablesfor the same shape onInstance.
- property named_functions: list[NamedFunction]#
Read-only property.
- property output_objective: Optional[OutputObjective]#
Read-only property.
Read-only output objective retained through parameter materialization, if one has been captured.
Postconditions#
Conversion preserves both absence and an explicit output objective equal to the active pair.
>>> from ommx import DecisionVariable, Instance, Sense >>> x = DecisionVariable.binary(0) >>> source = Instance.from_components( ... decision_variables=[x], objective=x, constraints={}, sense=Sense.Maximize ... ) >>> assert source.as_parametric_instance().output_objective is None >>> assert source.convert_active_objective(Sense.Minimize) >>> assert source.convert_active_objective(Sense.Maximize) >>> parametric = source.as_parametric_instance() >>> output = parametric.output_objective >>> assert output is not None >>> assert output.sense == parametric.sense >>> assert output.function.almost_equal(parametric.objective)
- property parameter_ids: set[int]#
Read-only property.
IDs of all declared parameters, including those unused in expressions.
with_parameters()requires a value for every ID in this set. The set is independent of the owner.
- property parameters: list[Parameter]#
Read-only property.
Declared parameters and their modeling labels, sorted by ID.
These are independent definitions, not assigned numerical values. Supply values through
with_parameters().
- property removed_constraints: RemovedConstraintCollection#
Read-only property.
Live mapping of all removed constraint families, keyed by typed IDs. The view retains this owner and fetches each constraint on demand.
- property sense: Sense#
Read-only property.