Skip to content

Advanced Transformation Topics

Advanced techniques for model transformations in LunaModel.

Sequential Passes

Apply multiple passes in sequence using PassManager.

Python
from luna_model.transformation import PassManager
from luna_model.transformation.passes import ChangeSensePass, BinarySpinPass
from luna_model import Sense, Vtype

# Apply passes in sequence
pm = PassManager([
    ChangeSensePass(Sense.MIN),
    BinarySpinPass(Vtype.SPIN, prefix=None),
])

ir = pm.run(model)
transformed = ir.model

Pipeline

Group passes together as a single unit.

Python
from luna_model.transformation import Pipeline, PassManager
from luna_model.transformation.passes import ChangeSensePass, BinarySpinPass
from luna_model import Sense, Vtype

# Create a named pipeline
preprocessing = Pipeline([
    ChangeSensePass(Sense.MIN),
    BinarySpinPass(Vtype.SPIN, prefix=None),
], name="preprocessing")

# Use in PassManager
pm = PassManager([preprocessing])
ir = pm.run(model)

Conditional Execution with IfElsePass

Execute different passes based on runtime conditions.

Python
from luna_model.transformation import PassManager, Pipeline, IfElsePass
from luna_model.transformation import analyse
from luna_model.transformation.passes import BinarySpinPass, MaxBiasAnalysis
from luna_model import Vtype

# Analysis to check model properties
@analyse(name="model-complexity")
def check_model_complexity(model, cache):
    """Analyze model complexity."""
    num_vars = model.num_variables()
    num_constraints = model.num_constraints()
    return {"vars": num_vars, "constraints": num_constraints}

# Conditional transformation based on model size
conditional = IfElsePass(
    requires=["model-complexity"],
    condition=lambda cache: cache["model-complexity"]["vars"] > 100,
    then=Pipeline([BinarySpinPass(Vtype.SPIN, prefix=None)]),
    otherwise=Pipeline([]),
    name="conditional-spin",
)

pm = PassManager([check_model_complexity, conditional])
ir = pm.run(model)

Using AnalysisCache

Passes can share data through the AnalysisCache.

Python
from luna_model.transformation import analyse, transform, ActionType, PassManager

# Analysis pass stores data in cache
@analyse(name="compute-stats")
def compute_stats(model, cache):
    """Compute model statistics."""
    return {
        "num_vars": model.num_variables(),
        "num_constraints": model.num_constraints(),
    }

# Transformation uses cached analysis
@transform(name="use-stats", requires=["compute-stats"])
def use_stats(model, cache):
    """Transform based on cached statistics."""
    stats = cache["compute-stats"]

    # Only apply transformation if model is small enough
    if stats["num_vars"] < 50:
        model.sense = Sense.MIN
        return model, ActionType.DID_TRANSFORM

    return model, ActionType.DID_NOTHING

pm = PassManager([compute_stats, use_stats])
ir = pm.run(model)

Backwards Transformation

Map solutions from transformed models back to original variable space.

Python
from luna_model.transformation import PassManager
from luna_model.transformation.passes import BinarySpinPass
from luna_model import Vtype

# Transform model
pm = PassManager([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 to original model variables
# original_solution = pm.backwards(solution, ir)

Creating Reusable Pipelines

Python
from luna_model.transformation import Pipeline
from luna_model.transformation.passes import ChangeSensePass, BinarySpinPass
from luna_model import Sense, Vtype

def create_spin_conversion_pipeline():
    """Create pipeline for spin variable conversion."""
    return Pipeline([
        ChangeSensePass(Sense.MIN),
        BinarySpinPass(Vtype.SPIN, prefix=None),
    ], name="spin-conversion")

# Use the pipeline
spin_pipeline = create_spin_conversion_pipeline()
pm = PassManager([spin_pipeline])
ir = pm.run(model)

See Also