Built-in Transformation Passes
LunaModel ships with built-in passes for common optimization-model rewrites and analyses.
Built-in pipelines
ToUnconstrainedBinaryPipeline
ToUnconstrainedBinaryPipeline converts a model to an unconstrained binary model.
Typical workflow:
- convert integer variables to binary representation
- normalize/convert constraints
- move constraints into the objective as penalties
Use it when a downstream solver expects QUBO-style unconstrained binary input.
ToBinaryMinimizationPipeline
ToBinaryMinimizationPipeline converts spin/integer-containing models to binary and normalizes the objective to minimization.
Use it when downstream tooling expects binary decision variables and minimization objective sense.
Built-in transformation passes
BinarySpinPass
Converts variable domains between binary ({0, 1}) and spin ({-1, +1}).
from luna_model import Vtype
from luna_model.transformation.passes import BinarySpinPass
to_spin = BinarySpinPass(vtype=Vtype.SPIN)
to_binary = BinarySpinPass(vtype=Vtype.BINARY)
ChangeSensePass
Converts objective sense (MIN/MAX), including objective sign adjustments as needed.
from luna_model import Sense
from luna_model.transformation.passes import ChangeSensePass
to_min = ChangeSensePass(sense=Sense.MIN)
IntegerToBinaryPass
Re-encodes integer variables into binary expansion variables.
from luna_model.transformation.passes import IntegerToBinaryPass
pass_ = IntegerToBinaryPass()
GeToLeConstraintsPass
Rewrites >= constraints into equivalent <= constraints.
LeToEqConstraintsPass
Rewrites <= constraints into equivalent == constraints (typically by adding slack variables).
EqualityConstraintsToQuadraticPenaltyPass
Moves equality constraints into the objective as quadratic penalties.
This pass is usually used with prerequisite analyses (for example max-bias scaling).
Built-in analysis passes
MaxBiasAnalysis
Computes information about objective coefficient magnitudes used by penalty/scaling passes.
MinValueForConstraintAnalysis
Computes per-constraint lower-bound information used by constraint normalization passes.
SpecsAnalysis
Computes model specification metadata (ModelSpecs) for downstream decisions.
CheckModelSpecsAnalysis
Validates that the current model satisfies required specs and fails early if not.
CheckInfeasibleConstraintsAnalysis
Checks linear constraints for provable infeasibility before compilation. For each constraint it derives the achievable range of the left-hand side (LHS) from the involved variables' bounds and compares it against the right-hand side (RHS):
lhs <= rhsis infeasible ifmin(lhs) > rhslhs >= rhsis infeasible ifmax(lhs) < rhslhs == rhsis infeasible ifrhsis outside[min(lhs), max(lhs)]
If any constraint is provably infeasible, the pass raises ModelInfeasibleError.
from luna_model.transformation import PassManager
from luna_model.transformation.passes import CheckInfeasibleConstraintsAnalysis
from luna_model.errors import ModelInfeasibleError
try:
PassManager([CheckInfeasibleConstraintsAnalysis()]).run(model)
except ModelInfeasibleError as e:
print(f"Model has infeasible constraints: {e}")
The check is sound but incomplete: every constraint it flags is genuinely infeasible, but it does not catch every infeasibility (for example integrality gaps such as 2 * x == 1), and constraints with unbounded ranges are skipped. Passing this analysis therefore does not prove the whole model is feasible. It also runs as part of ToUnconstrainedBinaryPipeline.
Built-in control-flow passes
IfElsePass
Runs one of two branch pipelines based on a predicate evaluated against the current model/context.
from luna_model.transformation import PassManager, Pipeline
from luna_model.transformation.passes import IfElsePass, BinarySpinPass
from luna_model import Vtype
if_else = IfElsePass(
condition=lambda model, ctx: model.num_variables() > 100,
then=Pipeline([BinarySpinPass(vtype=Vtype.SPIN)], name="then"),
otherwise=Pipeline([], name="else"),
)
output = PassManager([if_else]).run(model)
Example: combine built-ins
from luna_model.transformation import PassManager
from luna_model.transformation.passes import (
IntegerToBinaryPass,
MaxBiasAnalysis,
EqualityConstraintsToQuadraticPenaltyPass,
)
pm = PassManager([
IntegerToBinaryPass(),
MaxBiasAnalysis(),
EqualityConstraintsToQuadraticPenaltyPass(),
])
output = pm.run(model)
Then map solver results back using: