Skip to content

Archived LunaModel 0.5.9 documentation

You are reading the old LunaModel 0.5.9 documentation. The regular documentation describes LunaModel >=0.6.0; use the latest documentation unless you explicitly need the old release.

Variable Types

LunaModel supports four different variable types, each suited for different optimization scenarios.

Overview of Variable Types

Type Domain Use Case
BINARY {0, 1} Yes/no decisions, selection problems
INTEGER Whole numbers Counting, discrete quantities
SPIN {-1, +1} Ising models, quantum annealing
REAL Continuous Measurements, rates, percentages

Binary Variables

Binary variables represent boolean decisions: yes/no, true/false, selected/not selected.

Creating Binary Variables

Python
from luna_model import Model, Vtype

model = Model()
x = model.add_variable("x", vtype=Vtype.BINARY)

Common Use Cases

Selection problems:

Python
# Select items from a set
items = ['A', 'B', 'C', 'D']
selected = {item: model.add_variable(f"select_{item}", vtype=Vtype.BINARY)
            for item in items}

# Select exactly 2 items
model.add_constraint(sum(selected.values()) == 2)

Activation/deactivation:

Python
# Activate at most 3 features
features = [model.add_variable(f"feature_{i}", vtype=Vtype.BINARY) 
            for i in range(5)]
model.add_constraint(sum(features) <= 3)

Logical conditions:

Python
# If x then y
x = model.add_variable("x", vtype=Vtype.BINARY)
y = model.add_variable("y", vtype=Vtype.BINARY)
model.add_constraint(y <= x)  # y can only be 1 if x is 1

# x OR y (at least one must be true)
model.add_constraint(x + y >= 1)

# x XOR y (exactly one must be true)
model.add_constraint(x + y == 1)

Properties

  • Domain: {0, 1}
  • No need to specify bounds (implicit)
  • Most efficient for boolean decisions
  • Can be converted to/from SPIN variables

Integer Variables

Integer variables represent discrete quantities that can take whole number values.

Creating Integer Variables

Python
# Basic integer variable
x = model.add_variable("x", vtype=Vtype.INTEGER, lower=0, upper=100)

# Unbounded integer (not recommended)
y = model.add_variable("y", vtype=Vtype.INTEGER)

# Negative integers allowed
z = model.add_variable("z", vtype=Vtype.INTEGER, lower=-10, upper=10)

Common Use Cases

Counting:

Python
# Number of items to produce
num_items = model.add_variable("num_items", 
                               vtype=Vtype.INTEGER, 
                               lower=0, 
                               upper=1000)

# Number of workers to assign
num_workers = model.add_variable("num_workers",
                                 vtype=Vtype.INTEGER,
                                 lower=1,  # At least one worker
                                 upper=50)

Quantities:

Python
# Inventory levels
inventory = {}
for product in ['A', 'B', 'C']:
    inventory[product] = model.add_variable(
        f"inv_{product}",
        vtype=Vtype.INTEGER,
        lower=0,     # Non-negative
        upper=10000  # Warehouse capacity
    )

Discrete choices:

Python
# Select a priority level (1-5)
priority = model.add_variable("priority", vtype=Vtype.INTEGER, lower=1, upper=5)

# Time periods (0-23 for hours)
hour = model.add_variable("hour", vtype=Vtype.INTEGER, lower=0, upper=23)

Properties

  • Domain: Whole numbers (ℤ)
  • Always specify bounds (lb and ub) for better performance
  • More flexible than BINARY but slower to optimize
  • Can be converted to BINARY variables using transformations

Integer vs. Binary

When to use INTEGER vs. multiple BINARY variables:

Python
# Approach 1: Single integer (more compact)
quantity = model.add_variable("qty", vtype=Vtype.INTEGER, lower=0, upper=5)

# Approach 2: Multiple binaries (more constraints)
# Useful when you need to reference individual quantities
binary_vars = [model.add_variable(f"qty_{i}", vtype=Vtype.BINARY) 
               for i in range(6)]
quantity_value = sum(i * binary_vars[i] for i in range(6))
model.add_constraint(sum(binary_vars) == 1)  # Exactly one selected

Use INTEGER when: - The value itself is important - Range is large (>10) - Linear relationships suffice

Use multiple BINARYs when: - You need to reference specific values - Complex logical constraints apply - Targeting binary optimization solvers

Spin Variables

Spin variables are used in Ising models and quantum annealing applications.

Creating Spin Variables

Python
s = model.add_variable("s", vtype=Vtype.SPIN)

Common Use Cases

Ising models:

Python
# Create spin system
n = 5
spins = [model.add_variable(f"s_{i}", vtype=Vtype.SPIN) for i in range(n)]

# Ising objective: minimize energy
# H = -Σ J_ij * s_i * s_j - Σ h_i * s_i
J = [[0, 1, -1, 0, 0],
     [1, 0, 1, -1, 0],
     [-1, 1, 0, 1, -1],
     [0, -1, 1, 0, 1],
     [0, 0, -1, 1, 0]]

energy = 0
for i in range(n):
    for j in range(i+1, n):
        energy = energy - J[i][j] * spins[i] * spins[j]

model.objective = energy

Quantum annealing:

Python
# Spins for quantum annealer
qubits = [model.add_variable(f"q_{i}", vtype=Vtype.SPIN) 
          for i in range(10)]

# QUBO-style objective
objective = sum(qubits[i] * qubits[j] 
                for i in range(10) 
                for j in range(i+1, 10))
model.objective = objective

Properties

  • Domain: {-1, +1}
  • No bounds needed (implicit)
  • Natural for physics-inspired optimization
  • Can be converted to/from BINARY variables

Spin-Binary Conversion

Relationship between SPIN and BINARY:

Python
# Mathematical relationship:
# spin = 2 * binary - 1
# binary = (spin + 1) / 2

# Convert using transformation passes
from luna_model.transformation import PassManager
from luna_model.transformation.passes import BinarySpinPass

# Convert all to SPIN
pm = PassManager([BinarySpinPass(Vtype.SPIN, None)])
result = pm.run(model)
spin_model = result.model

# Convert all to BINARY
pm = PassManager([BinarySpinPass(Vtype.BINARY, None)])
result = pm.run(model)
binary_model = result.model

Real Variables

Real variables represent continuous quantities.

Creating Real Variables

Python
# Bounded real variable
x = model.add_variable("x", vtype=Vtype.REAL, lower=0.0, upper=1.0)

# Percentage
percentage = model.add_variable("pct", vtype=Vtype.REAL, lower=0.0, upper=100.0)

# Rate (can be negative)
growth_rate = model.add_variable("rate", vtype=Vtype.REAL, lower=-0.5, upper=0.5)

Common Use Cases

Continuous measurements:

Python
# Temperature, pressure, etc.
temperature = model.add_variable("temp", 
                                 vtype=Vtype.REAL, 
                                 lower=-20.0, 
                                 upper=120.0)

Fractions and ratios:

Python
# Allocation percentage (0-1)
allocation = model.add_variable("alloc", vtype=Vtype.REAL, lower=0.0, upper=1.0)

# Multiple allocations that sum to 1
n = 5
allocations = [model.add_variable(f"alloc_{i}", vtype=Vtype.REAL, lower=0.0) 
               for i in range(n)]
model.add_constraint(sum(allocations) == 1.0)

Relaxations:

Python
# LP relaxation of integer/binary problems
# (solve continuous version first, then round)
x_relaxed = model.add_variable("x_relax", vtype=Vtype.REAL, lower=0.0, upper=1.0)

Properties

  • Domain: Real numbers (ℝ)
  • Requires explicit bounds for most solvers
  • Most flexible but may need rounding for discrete problems
  • Generally faster to optimize than INTEGER

Mixed Variable Types

You can mix different variable types in the same model:

Python
model = Model()

# Binary decisions
is_active = model.add_variable("active", vtype=Vtype.BINARY)

# Integer quantities
quantity = model.add_variable("qty", vtype=Vtype.INTEGER, lower=0, upper=100)

# Real measurements
efficiency = model.add_variable("eff", vtype=Vtype.REAL, lower=0.0, upper=1.0)

# Constraints mixing types
model.add_constraint(quantity <= 100 * is_active)  # Big-M constraint
model.add_constraint(efficiency * quantity >= 50)   # Bilinear constraint

Type Conversions

LunaModel provides built-in transformations:

Binary ↔ Spin

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

model = Model()
x = model.add_variable("x", vtype=Vtype.BINARY)
s = model.add_variable("s", vtype=Vtype.SPIN)

# Convert everything to SPIN
pm = PassManager([BinarySpinPass(Vtype.SPIN, None)])
result = pm.run(model)

Integer → Binary

Python
# Transform integer to binary encoding
# (handled automatically by transformation passes)

Choosing the Right Type

Decision guide:

Question Answer Recommended Type
Is it a yes/no decision? Yes BINARY
Is it a discrete count or quantity? Small range (< 10) Consider BINARY
Is it a discrete count or quantity? Large range INTEGER
Is it for quantum annealing? Yes SPIN
Is it continuous or fractional? Yes REAL

Performance Considerations

Variable Type Speed Support Notes
BINARY ✅ Fastest ✅ Universal Best for boolean decisions, easy to interpret
INTEGER ⚠️ Slower ✅ Good More compact than multiple binaries, always set bounds
SPIN ⚠️ Varies ⚠️ Limited Natural for quantum annealing, requires conversion for classical solvers
REAL ✅ Fast ✅ Good Fastest to optimize, may need rounding for discrete problems

Examples by Domain

Logistics (BINARY + INTEGER)

Python
# Route selection (binary)
routes = [model.add_variable(f"route_{i}", vtype=Vtype.BINARY) 
          for i in range(10)]

# Package quantities (integer)
packages = model.add_variable("packages", vtype=Vtype.INTEGER, lower=0, upper=100)

Scheduling (BINARY + REAL)

Python
# Task assignment (binary)
assigned = model.add_variable("assigned", vtype=Vtype.BINARY)

# Task duration (real)
duration = model.add_variable("duration", vtype=Vtype.REAL, lower=0.0, upper=8.0)

Quantum Computing (SPIN)

Python
# All spin for quantum annealer
qubits = [model.add_variable(f"q_{i}", vtype=Vtype.SPIN) 
          for i in range(100)]

Financial Optimization (REAL)

Python
# Portfolio weights (real, sum to 1)
n_assets = 10
weights = [model.add_variable(f"w_{i}", vtype=Vtype.REAL, lower=0.0) 
           for i in range(n_assets)]
model.add_constraint(sum(weights) == 1.0)

Next Steps

  • Expressions - Build expressions with your variables
  • Constraints - Add constraints for different variable types