Skip to content

Add output objective semantics to Instance and ParametricInstance - #1167

Draft
termoshtt wants to merge 19 commits into
mainfrom
codex/instance-output-objective
Draft

Add output objective semantics to Instance and ParametricInstance#1167
termoshtt wants to merge 19 commits into
mainfrom
codex/instance-output-objective

Conversation

@termoshtt

@termoshtt termoshtt commented Aug 20, 2026

Copy link
Copy Markdown
Member

Summary

  • Add a v2 OutputObjective to Instance and ParametricInstance so the active solver formulation can differ from the objective reported by evaluate() and evaluate_samples(). Parameter materialization and state reconstruction preserve that output meaning; v1 serialization rejects models that it cannot represent losslessly.
  • Make objective conversion an explicit Preparation phase, add canonical QUBO/HUBO input classes and policy factories, and define to_qubo() / to_hubo() as in-place Preparation followed by format extraction. Whole-problem as_minimization_problem() / as_maximization_problem() conversions keep their original meaning.
  • Map solver optimality through the output-objective contract in the HiGHS, PySCIPOpt, and Python-MIP adapters. A finite-penalty optimum remains Optimality.Unspecified when it does not prove optimality for the reported objective.

Behavior change

QUBO/HUBO conversion now keeps the prepared minimization energy as the active Instance, while evaluated results retain the input instance's output semantics:

from ommx import DecisionVariable, Instance, Sense

x = DecisionVariable.binary(0)
instance = Instance.from_components(
    sense=Sense.Maximize,
    objective=x,
    decision_variables=[x],
    constraints={0: x == 1},
)

qubo, offset = instance.to_qubo(uniform_penalty_weight=2.0)
state = {0: 0.0}

# Solver-facing energy: minimize -x + 2 (x - 1)^2.
assert instance.sense == Sense.Minimize
assert instance.objective.evaluate(state) == 2.0

# User-facing output: the input Maximize / x objective.
solution = instance.evaluate(state)
sample_set = instance.evaluate_samples({0: state})
assert solution.sense == Sense.Maximize
assert solution.objective == 0.0
assert sample_set.sense == Sense.Maximize
assert sample_set.objectives[0] == 0.0

This intentionally corrects the Python SDK v2 behavior, which restored the active sense but evaluated the final penalized energy. Returned QUBO/HUBO coefficients retain their existing meaning. The equivalent editable workflow is prepare(InstanceClass.qubo(), PreparationPolicy.for_qubo(...)) followed by as_qubo_format(); HUBO has matching helpers.

@termoshtt termoshtt added rust PR changes the Rust SDK public API proto Protobuf schema or generated protobuf contract changes breaking change Accepted work intentionally breaks compatibility labels Aug 20, 2026
@termoshtt termoshtt added the python PR changes the Python SDK public API, generated stubs, or adapter public API label Aug 20, 2026
@termoshtt termoshtt changed the title Add output objective semantics to Instance Add output objective semantics to Instance and ParametricInstance Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking change Accepted work intentionally breaks compatibility proto Protobuf schema or generated protobuf contract changes python PR changes the Python SDK public API, generated stubs, or adapter public API rust PR changes the Rust SDK public API

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant