Python getting started
The Python package exposes a compact public API:
solve()solves an OMMX instance.SolveOptionsconfigures detailed solver behavior.Structureenables structure-aware presets and handlers.
Build and solve a model with JijModeling
Define a binary knapsack model with JijModeling, evaluate it with concrete
data to create an OMMX instance, and pass that instance directly to solve:
import jijmodeling as jm
from jijzept_solver import solve
problem = jm.Problem("knapsack", sense=jm.ProblemSense.MAXIMIZE)
values = problem.Float("values", ndim=1)
weights = problem.Float("weights", ndim=1)
capacity = problem.Float("capacity")
selected = problem.BinaryVar("selected", shape=values.len_at(0))
problem += (values * selected).sum()
problem += problem.Constraint(
"capacity",
(weights * selected).sum() <= capacity,
)
instance = problem.eval(
{
"values": [10, 13, 18, 31],
"weights": [11, 15, 20, 35],
"capacity": 47,
}
)
solution = solve(
instance,
time_limit=60.0,
gap_limit=0.01,
verbosity=1,
)
print(f"feasible: {solution.feasible}")
print(f"objective: {solution.objective}")
Problem.eval() evaluates the placeholders and produces the OMMX instance
accepted by JijZept Solver. There is no separate JijModeling-to-OMMX
conversion step.
Solve an MPS model
If a model is already available as MPS, load it as an OMMX instance and call
solve in the same way:
from ommx.v1 import Instance
from jijzept_solver import solve
instance = Instance.load_mps("model.mps")
solution = solve(
instance,
time_limit=60.0,
gap_limit=0.01,
verbosity=1,
)
print(f"feasible: {solution.feasible}")
print(f"objective: {solution.objective}")
gap_limit=0.01 stops once the relative optimality gap reaches one percent.
Omit time_limit, or pass it explicitly as None, to run without a time
limit.
Configure detailed options
Use SolveOptions for settings that are not part of the convenience
arguments on solve:
from jijzept_solver import SolveOptions, solve
options = SolveOptions(
branching="reliability",
node_selector="depth-first",
enable_feasibility_pump=True,
num_threads=4,
)
solution = solve(instance, options=options, time_limit=60.0)
Settings have the following precedence, from lowest to highest:
Solver defaults
A
StructurepresetSolveOptionsConvenience arguments passed directly to
solve
This makes it possible to reuse an options object while overriding a small number of values for one solve.
Save and load options
Options can be shared as a TOML file:
from jijzept_solver import SolveOptions
options = SolveOptions(time_limit=120.0, num_threads=8)
options.to_file("solver-options.toml")
loaded = SolveOptions.from_file("solver-options.toml")
To create a documented template containing every option:
SolveOptions.write_template("solver-options.toml")
Use a structure preset
The following example builds a five-city traveling-salesperson problem with
JijModeling. The binary variable x[i, j] represents whether the tour uses
the directed edge from city i to city j.
import jijmodeling as jm
from jijzept_solver import Structure, solve
num_cities = 5
distances = [
[float(abs(i - j)) for j in range(num_cities)]
for i in range(num_cities)
]
# Keep self-loops out of the objective's attractive choices. The TSP
# structure handler also prohibits them when it builds the route constraints.
for city in range(num_cities):
distances[city][city] = 1_000_000.0
problem = jm.Problem("TSP", sense=jm.ProblemSense.MINIMIZE)
distance = problem.Float("distance", ndim=2)
num_cities_expr = problem.NamedExpr("N", distance.len_at(0))
x = problem.BinaryVar("x", shape=(num_cities_expr, num_cities_expr))
problem += (distance * x).sum()
# Structure.tsp("x") supplies the in-degree, out-degree, self-loop, and
# subtour-elimination constraints, so the JijModeling problem only needs the
# edge-cost objective.
instance = problem.eval({"distance": distances})
structure = Structure.tsp("x")
solution = solve(
instance,
structure=structure,
time_limit=60.0,
verbosity=1,
)
print(f"feasible: {solution.feasible}")
print(f"tour length: {solution.objective}")
The string passed to Structure.tsp() must exactly match the JijModeling
variable’s base name, x in this example. JijModeling preserves that name in
the OMMX variable metadata, which lets the specialized route handler find the
edge variables. The handler installs the route constraints and applies its
recommended solver-option preset. Explicit options still take precedence.
Handle interruption
solve supports Ctrl+C. If an incumbent exists, the solver returns the best
solution found so far and emits a warning. If no solution has been found, it
raises KeyboardInterrupt.
See the Python API reference for the complete signatures and option descriptions.