ommx_pyscipopt_adapter.adapter#
Classes#
An abstract interface for OMMX Solver Adapters, defining how solvers should be used with OMMX. |
|
Pandas-like post-processor for PySCIPOpt diagnostics. |
|
SCIP solve progress observed during a solve. |
|
SCIP-side termination summary recorded after |
Module Contents#
- class OMMXPySCIPOptAdapter(ommx_instance: Instance, *, initial_state: ommx.ToState | None = None)#
An abstract interface for OMMX Solver Adapters, defining how solvers should be used with OMMX.
See the implementation guide for more details.
Concrete subclasses define applicability with
INPUT_CLASS. The easysolve()API prepares an isolated copy with the Adapter's recommended policy. Usesolve_without_preparation()when the caller owns preparation and wants the Adapter to require an exact input without modifying it.- classmethod check_applicability(ommx_instance: Instance) InstanceClassMembershipReport#
Check
INPUT_CLASSmembership without mutation.
- decode(data: pyscipopt.Model) Solution#
Convert optimized pyscipopt.Model and ommx.Instance to ommx.Solution.
This method is intended to be used if the model has been acquired with solver_input for further adjustment of the solver parameters, and separately optimizing the model.
Note that alterations to the model may make the decoding process incompatible -- decoding will only work if the model still describes effectively the same problem as the OMMX instance used to create the adapter.
Backend optimality is mapped through the instance's output-objective semantics. It remains unspecified when active-formulation optimality does not transport to that objective.
Examples#
>>> from ommx_pyscipopt_adapter import OMMXPySCIPOptAdapter >>> from ommx import Instance, DecisionVariable >>> p = [10, 13, 18, 32, 7, 15] >>> w = [11, 15, 20, 35, 10, 33] >>> 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, ... ) >>> adapter = OMMXPySCIPOptAdapter(instance) >>> model = adapter.solver_input >>> # ... some modification of model's parameters >>> model.optimize() >>> solution = adapter.decode(model) >>> solution.objective 42.0
- decode_to_state(data: pyscipopt.Model) State#
Create an ommx.State from an optimized PySCIPOpt Model.
Examples#
The following example shows how to solve an unconstrained linear optimization problem with `x1` as the objective function. >>> from ommx_pyscipopt_adapter import OMMXPySCIPOptAdapter >>> from ommx import Instance, DecisionVariable >>> x1 = DecisionVariable.integer(1, lower=0, upper=5) >>> ommx_instance = Instance.from_components( ... decision_variables=[x1], ... objective=x1, ... constraints={}, ... sense=Sense.Minimize, ... ) >>> adapter = OMMXPySCIPOptAdapter(ommx_instance) >>> model = adapter.solver_input >>> model.optimize() >>> ommx_state = adapter.decode_to_state(model) >>> ommx_state.entries {1: 0.0}
- classmethod recommended_preparation_policy() PreparationPolicy#
Recommend lowering OneHot constraints before using PySCIPOpt.
PySCIPOpt accepts Indicator and SOS1 constraints directly, so this recommendation preserves those families and lowers only OneHot constraints. 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, *, initial_state: ommx.ToState | None = None, diagnostics: DiagnosticsSink | None = None) Solution#
Solve the given ommx.Instance using PySCIPopt, returning an ommx.Solution.
The input instance is not modified. An isolated copy is prepared with the recommended PySCIPOpt policy before preparation-free execution.
- パラメータ:
ommx_instance -- The ommx.Instance to prepare and solve.
initial_state -- Optional initial solution state.
Examples#
KnapSack Problem
>>> from ommx import Instance, DecisionVariable >>> from ommx import Solution >>> from ommx_pyscipopt_adapter import OMMXPySCIPOptAdapter >>> p = [10, 13, 18, 32, 7, 15] >>> w = [11, 15, 20, 35, 10, 33] >>> 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, ... ) Solve it >>> solution = OMMXPySCIPOptAdapter.solve(instance) Check output >>> 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 p[0] + p[3] = 42 w[0] + w[3] = 46 <= 47 >>> solution.objective 42.0 >>> solution.get_constraint_value(0) -1.0
Infeasible Problem
>>> from ommx import Instance, DecisionVariable >>> from ommx_pyscipopt_adapter import OMMXPySCIPOptAdapter >>> x = DecisionVariable.integer(0, upper=3, lower=0) >>> instance = Instance.from_components( ... decision_variables=[x], ... objective=x, ... constraints={0: x >= 4}, ... sense=Sense.Maximize, ... ) >>> OMMXPySCIPOptAdapter.solve(instance) Traceback (most recent call last): ... ommx.InfeasibleDetected: Model was infeasible
Unbounded Problem
>>> from ommx import Instance, DecisionVariable >>> from ommx_pyscipopt_adapter import OMMXPySCIPOptAdapter >>> x = DecisionVariable.integer(0, lower=0) >>> instance = Instance.from_components( ... decision_variables=[x], ... objective=x, ... constraints={}, ... sense=Sense.Maximize, ... ) >>> OMMXPySCIPOptAdapter.solve(instance) Traceback (most recent call last): ... ommx.adapter.UnboundedDetected: Model was unbounded
- classmethod solve_without_preparation(ommx_instance: Instance, *, initial_state: ommx.ToState | None = None, diagnostics: DiagnosticsSink | None = None) Solution#
Solve an exact PySCIPOpt Adapter input without preparing it.
- INPUT_CLASS: ClassVar[InstanceClass]#
Required condition for an exact Adapter input.
- property solver_input: pyscipopt.Model#
The PySCIPOpt model generated from this OMMX instance
- class SCIPDiagnosticsAnalyzer(diagnostics: Iterable[Any])#
Pandas-like post-processor for PySCIPOpt diagnostics.
The analyzer accepts either typed diagnostics collected by
ommx.adapter.DiagnosticCollectoror dictionaries loaded fromommx.experiment.Solve.diagnostics.progress_history_recordsreturnslist[dict[str, object]]and does not require pandas. When diagnostics include a terminal SCIP report, the progress history includes a finalTERMINATIONrow derived from that report.progress_history_dfreturns a pandas DataFrame indexed bysolving_time_secand imports pandas lazily. Time-series properties such asdual_boundreturn pandas Series with the same index.termination_resultreturns the terminal SCIP report as a dictionary.- property dual_bound: Any#
Return dual bounds indexed by solving time.
- property event: Any#
Return progress event names indexed by solving time.
- property gap: Any#
Return relative gaps indexed by solving time.
- property incumbent_objective: Any#
Return incumbent objectives indexed by solving time.
- property lp_iteration_count: Any#
Return LP iteration counts indexed by solving time.
- property node_count: Any#
Return processed node counts indexed by solving time.
- property primal_bound: Any#
Return primal bounds indexed by solving time.
- property progress_history_df: Any#
Return progress history as a pandas DataFrame indexed by time.
- property progress_history_records: list[dict[str, object]]#
Return SCIP progress history, with
TERMINATIONwhen present.
- property progress_snapshots: tuple[SCIPProgressSnapshot, ...]#
Typed progress snapshots in the order they were recorded.
- property solution_count: Any#
Return stored solution counts indexed by solving time.
- property termination_result: dict[str, object] | None#
Return the terminal SCIP report as one dictionary, if present.
- property total_node_count: Any#
Return total processed node counts indexed by solving time.
- class SCIPProgressSnapshot#
SCIP solve progress observed during a solve.
The PySCIPOpt adapter records this snapshot for each tracked SCIP event and once more from the termination report after
model.optimize()finishes. It currently listens forBESTSOLFOUNDandDUALBOUNDIMPROVED. Event snapshots are the model state visible from that callback. SCIP may call aBESTSOLFOUNDcallback before every aggregate model statistic has been updated, so use theTERMINATIONsnapshot orSCIPTerminationReportfor terminal values.- classmethod from_event(model: pyscipopt.Model, event: pyscipopt.scip.Event) SCIPProgressSnapshot#
- classmethod from_termination_report(report: SCIPTerminationReport) SCIPProgressSnapshot#
- event: str#
Progress marker.
Callback snapshots use SCIP event names such as
"BESTSOLFOUND"and"DUALBOUNDIMPROVED". The terminal snapshot uses the synthetic"TERMINATION"marker.
- class SCIPTerminationReport#
SCIP-side termination summary recorded after
model.optimize().The PySCIPOpt adapter records this report before decoding the optimized SCIP 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: pyscipopt.Model) SCIPTerminationReport#