Skip to content

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 requires property
  • 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

Python
# Create empty PassManager (no passes will be executed)
pm = 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