ommx_highs_adapter.adapter#
Classes#
Post-processor for HiGHS diagnostics. |
|
HiGHS MIP solve progress observed from one logging callback. |
|
HiGHS-side termination summary recorded after |
|
OMMX Adapter for HiGHS solver. |
Module Contents#
- class HighsDiagnosticsAnalyzer(diagnostics: Iterable[Any])#
Post-processor for HiGHS diagnostics.
The analyzer accepts either typed diagnostics collected by
ommx.adapter.DiagnosticCollectoror dictionaries loaded fromommx.experiment.Solve.diagnostics.- property dual_bound: Any#
Return MIP dual bounds indexed by solving time.
- property event: Any#
Return progress event names indexed by solving time.
- property gap: Any#
Return MIP gaps indexed by solving time.
- property ipm_iteration_count: Any#
Return interior-point iteration counts indexed by solving time.
- property mip_dual_bound: Any#
Alias for
dual_bound.
- property mip_node_count: Any#
Return MIP node counts indexed by solving time.
- property mip_primal_bound: Any#
Alias for
primal_bound.
- property node_count: Any#
Alias for
mip_node_count.
- property objective_value: Any#
Return objective values indexed by solving time.
- property pdlp_iteration_count: Any#
Return PDLP iteration counts indexed by solving time.
- property primal_bound: Any#
Return MIP primal bounds indexed by solving time.
- property progress_history_df: Any#
Return progress snapshots as a pandas DataFrame indexed by time.
- property progress_history_records: list[dict[str, object]]#
Return one dictionary per HiGHS MIP logging callback.
- property progress_snapshots: tuple[HighsProgressSnapshot, ...]#
Typed progress snapshots in the order they were recorded.
- property simplex_iteration_count: Any#
Return simplex iteration counts indexed by solving time.
- property termination_mip_dual_bound: float | None#
Return the terminal HiGHS MIP dual bound, if present.
- property termination_mip_node_count: int | None#
Return the terminal HiGHS MIP node count, if present.
- property termination_objective_value: float | None#
Return the terminal objective value, if present.
- class HighsProgressSnapshot#
HiGHS MIP solve progress observed from one logging callback.
- classmethod from_callback_event(event: Any) HighsProgressSnapshot#
- class HighsTerminationReport#
HiGHS-side termination summary recorded after
model.run().The HiGHS adapter records this report before decoding the optimized HiGHS model back into an OMMX solution. It is therefore available even when decoding raises an adapter exception such as infeasible or unbounded detection.
- classmethod from_model(model: highspy.Highs) HighsTerminationReport#
- class OMMXHighsAdapter(ommx_instance: Instance, *, verbose: bool = False)#
OMMX Adapter for HiGHS solver.
This adapter translates OMMX optimization problems (ommx.Instance) into HiGHS-compatible formats and converts HiGHS solutions back to OMMX format (ommx.Solution).
Translation Specifications#
Decision Variables#
The adapter handles the following translations for decision variables:
ID Management:
OMMX: Variables managed by IDs (non-sequential integers)
HiGHS: Variables managed by array indices (0-based sequential)
Mapping maintained internally for bidirectional conversion
Variable Types:
OMMX Type
HiGHS Type
Bounds
Kind.BinaryHighsVarType.kInteger[0, 1]Kind.IntegerHighsVarType.kInteger[var.bound.lower, var.bound.upper]Kind.ContinuousHighsVarType.kContinuous[var.bound.lower, var.bound.upper]Kind.SemiIntegerNot supported (support planned)
-
Kind.SemiContinuousNot supported (support planned)
-
Note: Semi-integer and semi-continuous variables are planned for future support but are currently unsupported. Exact-input APIs reject these kinds with
AdapterNotApplicableError; the easy API reports that recommended Preparation could not reachINPUT_CLASS.Constraints#
Supported Function Types:
Constant functions (ommx.Function.constant)
Linear functions (ommx.Function.linear)
Constraint Types:
OMMX Constraint
Mathematical Form
HiGHS Constraint
Equality.EqualToZerof(x) = 0
const_expr == 0Equality.LessThanOrEqualToZerof(x) ≤ 0
const_expr <= 0Constant Constraint Handling:
Equality: Skip if |constant| ≤ 1e-10, error if |constant| > 1e-10
Inequality: Skip if constant ≤ 1e-10, error if constant > 1e-10
Constraint ID Management:
OMMX constraint IDs converted to HiGHS constraint names via
str(constraint.id)
Objective Function#
Optimization Direction:
OMMX Direction
HiGHS Method
Sense.Minimizemodel.minimize(...)Sense.Maximizemodel.maximize(...)Function Types:
Constant objectives: Processing skipped
Linear objectives: Converted to HiGHS linear expressions
Solution Decoding#
Variable Values: Extracted from HiGHS
solution.col_valueusing maintained ID mappingOptimality Status:
A HiGHS
kOptimalstatus becomesOPTIMALITY_UNSPECIFIEDwhen it does not transport to the output objective
Dual Variables: Extracted from
solution.row_dualwhen the active objective is also the output objective. They are omitted when output-objective projection would require a dual mapping that OMMX does not define.Error Handling#
Unsupported Features:
Quadratic functions (HiGHS supports linear problems only)
Semi-integer variables (
Kind.SemiInteger) - support plannedSemi-continuous variables (
Kind.SemiContinuous) - support plannedConstraint types other than
Equality.EqualToZero/Equality.LessThanOrEqualToZero
Solver Status Mapping:
HiGHS Status
Exception
kInfeasibleInfeasibleDetectedkUnboundedUnboundedDetectedkNotsetOMMXHighsAdapterErrorLimitations#
Linear problems only (no quadratic constraints or objectives)
Constraint forms limited to equality (= 0) and inequality (≤ 0)
Variable types limited to Binary, Integer, and Continuous
Kind.SemiIntegersupport is planned but not yet implementedKind.SemiContinuoussupport is planned but not yet implemented
Examples#
>>> from ommx_highs_adapter import OMMXHighsAdapter >>> from ommx import DecisionVariable, Instance, Sense >>> >>> # Define problem >>> x = DecisionVariable.binary(0) >>> y = DecisionVariable.integer(1, lower=0, upper=10) >>> instance = Instance.from_components( ... decision_variables=[x, y], ... objective=2*x + 3*y, ... constraints={0: x + y <= 5}, ... sense=Sense.Maximize, ... ) >>> >>> # Solve >>> solution = OMMXHighsAdapter.solve(instance) >>> print(f"Optimal value: {solution.objective}") Optimal value: 15.0 >>> print(f"Variables: {solution.state.entries}") Variables: {0: 0.0, 1: 5.0}
- classmethod check_applicability(ommx_instance: Instance) InstanceClassMembershipReport#
Check
INPUT_CLASSmembership without mutation.
- decode(data: highspy.Highs) Solution#
Convert an optimized HiGHS model back to an OMMX Solution.
This method translates HiGHS solver results into OMMX format, including variable values, optimality status, and transportable dual variable information. Backend optimality is mapped through the instance’s output-objective semantics and remains unspecified when it does not transport.
Parameters#
- datahighspy.Highs
The HiGHS model that has been optimized. Must be the same model returned by solver_input property.
Returns#
- Solution
Complete OMMX solution containing: - Variable values mapped back to original OMMX IDs - Constraint evaluations and feasibility status - Optimality information from HiGHS when transportable to the output objective - Dual variables for linear constraints without output-objective projection
Raises#
- OMMXHighsAdapterError
If the model has not been optimized yet
- InfeasibleDetected
If HiGHS determined the problem is infeasible
- UnboundedDetected
If HiGHS determined the problem is unbounded
Notes#
This method should only be used after solving the model with HiGHS. Any modifications to the HiGHS model structure after creation may make the decoding process incompatible.
When the active objective is also the output objective, dual variables are extracted from HiGHS’s
row_dualand mapped to OMMX constraints based on their order. Ifoutput_objectiveis present, every dual is omitted because OMMX does not define how the active formulation’s dual certificate maps to the projected output semantics.Examples#
>>> from ommx_highs_adapter import OMMXHighsAdapter >>> from ommx import Instance, DecisionVariable >>> >>> x = DecisionVariable.binary(0) >>> instance = Instance.from_components( ... decision_variables=[x], ... objective=x, ... constraints={}, ... sense=Sense.Maximize, ... ) >>> >>> adapter = OMMXHighsAdapter(instance) >>> model = adapter.solver_input >>> model.run() <...> >>> solution = adapter.decode(model) >>> solution.objective 1.0
- decode_to_state(data: highspy.Highs) State#
Extract variable values from an optimized HiGHS model as an OMMX State.
Parameters#
- datahighspy.Highs
The optimized HiGHS model
Returns#
- State
OMMX state containing variable values mapped to original OMMX IDs
Raises#
- OMMXHighsAdapterError
If the model has not been optimized
- InfeasibleDetected
If the model is infeasible
- UnboundedDetected
If the model is unbounded
Examples#
>>> from ommx_highs_adapter import OMMXHighsAdapter >>> from ommx import Instance, DecisionVariable >>> >>> x1 = DecisionVariable.integer(1, lower=0, upper=5) >>> instance = Instance.from_components( ... decision_variables=[x1], ... objective=x1, ... constraints={}, ... sense=Sense.Minimize, ... ) >>> adapter = OMMXHighsAdapter(instance) >>> model = adapter.solver_input >>> model.run() <...> >>> state = adapter.decode_to_state(model) >>> state.entries {1: 0.0}
- classmethod recommended_preparation_policy() PreparationPolicy#
Recommend lowering special constraints before using HiGHS.
HiGHS accepts both optimization senses, Binary, Integer, and Continuous variables, and linear regular constraints directly. Its recommendation therefore enables only lowering for the special-constraint families currently understood by OMMX. The easy API applies a fresh policy to an isolated copy; callers may instead edit and apply one before invoking
solve_without_preparation().
- classmethod require_applicable(ommx_instance: Instance) InstanceClassMembershipReport#
Return the membership report or raise
AdapterNotApplicableError.
- classmethod solve(ommx_instance: Instance, *, verbose: bool = False, diagnostics: DiagnosticsSink | None = None) Solution#
Solve an OMMX optimization problem using HiGHS solver.
This method provides a convenient interface for solving optimization problems without needing to manually instantiate the adapter. It handles the complete workflow: translation to HiGHS format, solving, and result conversion.
Parameters#
- ommx_instanceInstance
The OMMX optimization problem to solve. The input is not modified; an isolated copy is prepared with the recommended HiGHS policy.
- verbosebool, default=False
If True, enable HiGHS’s console logging for debugging
Returns#
- Solution
The solution containing: - Variable values in solution.state.entries - Objective value in solution.objective - Constraint evaluations in solution.constraints - Optimality status in solution.optimality - Dual variables when the active and output objectives coincide
Raises#
- InfeasibleDetected
When the optimization problem has no feasible solution
- UnboundedDetected
When the optimization problem is unbounded
- PreparationTargetNotReachedError
When the recommended preparation cannot reach the Adapter input class
- OMMXHighsAdapterError
When conversion or HiGHS encounters an adapter-specific error
Examples#
Knapsack Problem
>>> from ommx import Instance, DecisionVariable, Solution >>> from ommx_highs_adapter import OMMXHighsAdapter >>> >>> p = [10, 13, 18, 32, 7, 15] # profits >>> w = [11, 15, 20, 35, 10, 33] # weights >>> x = [DecisionVariable.binary(i) for i in range(6)] >>> instance = Instance.from_components( ... decision_variables=x, ... objective=sum(p[i] * x[i] for i in range(6)), ... constraints={0: sum(w[i] * x[i] for i in range(6)) <= 47}, ... sense=Sense.Maximize, ... ) >>> >>> solution = OMMXHighsAdapter.solve(instance) >>> sorted([(id, value) for id, value in solution.state.entries.items()]) [(0, 1.0), (1, 0.0), (2, 0.0), (3, 1.0), (4, 0.0), (5, 0.0)] >>> solution.feasible True >>> assert solution.optimality == Solution.OPTIMAL >>> solution.objective 42.0
Infeasible Problem
>>> x = DecisionVariable.integer(0, upper=3, lower=0) >>> instance = Instance.from_components( ... decision_variables=[x], ... objective=x, ... constraints={0: x >= 4}, # Impossible: x ≤ 3 and x ≥ 4 ... sense=Sense.Maximize, ... ) >>> OMMXHighsAdapter.solve(instance) Traceback (most recent call last): ... ommx.InfeasibleDetected: Model was infeasible
- classmethod solve_without_preparation(ommx_instance: Instance, *, verbose: bool = False, diagnostics: DiagnosticsSink | None = None) Solution#
Solve an exact HiGHS Adapter input without preparing it.
- INPUT_CLASS: ClassVar[InstanceClass]#
Required condition for an exact Adapter input.
- property solver_input: highspy.Highs#
The HiGHS model generated from the OMMX instance.
Returns#
- highspy.Highs
The HiGHS model ready for optimization. This model contains: - Decision variables translated from OMMX IDs to HiGHS indices - Constraints converted to HiGHS linear expressions - Objective function set according to optimization direction