Using the PassManager
The PassManager orchestrates the execution of transformation and analysis passes on optimization models.
Overview
The PassManager:
- Executes passes in sequence
- Manages pass dependencies via the
requiresproperty - Returns an IR (Intermediate Representation) with the transformed model
- Supports backwards transformation of solutions via
backwards()
Basic Usage
Python
from luna_model import Model, Vtype
from luna_model.transformation import PassManager
from luna_model.transformation.passes import BinarySpinPass
# Create a model
model = Model()
x = model.add_variable("x", vtype=Vtype.BINARY)
y = model.add_variable("y", vtype=Vtype.BINARY)
model.objective = x + y
# Create pass manager with passes
pm = PassManager([
BinarySpinPass(vtype=Vtype.SPIN, prefix=None)
])
# Run transformation - returns IR
ir = pm.run(model)
transformed_model = ir.model
Creating a PassManager
With Passes
Python
from luna_model.transformation import PassManager
from luna_model.transformation.passes import ChangeSensePass, BinarySpinPass
from luna_model import Sense, Vtype
# Single pass
pm = PassManager([ChangeSensePass(Sense.MIN)])
# Multiple passes
pm = PassManager([
ChangeSensePass(Sense.MIN),
BinarySpinPass(Vtype.SPIN, prefix=None),
])
Empty PassManager
Note: PassManager supports adding passes after construction using the add() method, though it's recommended to provide all passes in the constructor for clarity.
Running Passes
Execute Transformation
Python
# Run pass manager on model - returns IR
ir = pm.run(model)
# Access transformed model from IR
new_model = ir.model
# Original model unchanged
print(f"Original: {model.num_variables()}")
print(f"Transformed: {new_model.num_variables()}")
Backwards Transformation
Convert solutions from the transformed model back to the original model space:
Python
# Run transformation
ir = pm.run(model)
# Solve the transformed model (solver not shown)
# solution = solve(ir.model)
# Map solution back to original model variables
original_solution = pm.backwards(solution, ir)
Pass Ordering
Pass order matters when passes have dependencies.
Example
Python
from luna_model import Model, Vtype, Sense
from luna_model.transformation import PassManager
from luna_model.transformation.passes import (
BinarySpinPass,
ChangeSensePass
)
model = Model(sense=Sense.MAX)
x = model.add_variable("x", vtype=Vtype.BINARY)
y = model.add_variable("y", vtype=Vtype.BINARY)
model.objective = 3 * x + 2 * y
# Apply passes in sequence
pm = PassManager([
ChangeSensePass(Sense.MIN),
BinarySpinPass(Vtype.SPIN, prefix=None),
])
ir = pm.run(model)
Complete Example
Python
from luna_model import Model, Vtype, Sense
from luna_model.transformation import PassManager
from luna_model.transformation.passes import (
ChangeSensePass,
BinarySpinPass,
)
# Original model
model = Model(name="QUBO", sense=Sense.MIN)
x = [model.add_variable(f"x_{i}", vtype=Vtype.BINARY) for i in range(10)]
# ... set objective ...
# Prepare transformations
pm = PassManager([
ChangeSensePass(Sense.MIN),
BinarySpinPass(Vtype.SPIN, prefix=None),
])
ir = pm.run(model)
transformed_model = ir.model
# Solve transformed model (solver not shown)
# solution = solve(transformed_model)
# Map solution back
# original_solution = pm.backwards(solution, ir)
See Also
- Built-in Passes - Available transformation passes
- Custom Passes - Creating custom transformations