Dict-Indexed Variables

Model named entities like products, locations or time-slots directly using VariableDict
Published

May 28, 2026

1 Introduction

In many real-world problems (diet optimization, logistics, shifts), decisions are naturally indexed by strings or categorical data rather than flat integers. VariableDict allows you to manage arrays of decision variables using robust dictionary-like indexing.

2 Creating a VariableDict

Supply a base name and a list of keys:

from optyx import VariableDict

foods = ["Apple", "Banana", "Carrot", "Donut"]
buy = VariableDict("buy", keys=foods, lb=0)

# Access individual variables by key
print(buy["Apple"])   # Equivalent to Variable("buy[Apple]", lb=0)
Variable('buy[Apple]', lb=0.0, ub=None)

You can also pass a dictionary of bounds to set per-key limits. When using a dict, you must provide an entry for every key:

# Per-key bounds: every key must be listed
lower_bounds = {"Apple": 2, "Banana": 0, "Carrot": 0, "Donut": 0}
upper_bounds = {"Apple": 10, "Banana": 10, "Carrot": 10, "Donut": 5}

buy2 = VariableDict(
    "buy", 
    keys=foods, 
    lb=lower_bounds,
    ub=upper_bounds,
)

3 Vectorized Aggregations

Just like VectorVariable, VariableDict exposes native aggregation methods that avoid constructing deep loop-based expression trees.

3.1 Weighted Sums (.prod())

If you have a dictionary of coefficients (like costs or weights), .prod() operates exactly like a dot-product. Unlisted keys are assumed to have a 0 coefficient.

from optyx import Problem

costs = {"Apple": 0.50, "Banana": 0.30, "Carrot": 0.20, "Donut": 1.50}

prob = Problem("diet")
# Effectively: 0.5*buy[Apple] + 0.3*buy[Banana] + ...
prob.minimize(buy.prod(costs))
Problem(name='diet', objective=minimize, n_vars=4, n_constraints=0)

3.2 Subsetting (.sum())

You can sum all elements, or sum over a specific subset of keys using .sum(keys=...).

calories = {"Apple": 95, "Banana": 105, "Carrot": 25, "Donut": 400}

# Total calories must be >= 1000
prob.subject_to(buy.prod(calories) >= 1000)

# Limit sugary foods to at most 1 item
sugary_items = ["Donut"]
prob.subject_to(buy.sum(sugary_items) <= 1)
Problem(name='diet', objective=minimize, n_vars=4, n_constraints=2)

4 Extracting Solutions

When you solve the problem, you can extract solution values by iterating over the VariableDict keys:

sol = prob.solve()

# Extract values using standard key iteration
results = {key: sol[f"buy[{key}]"] for key in buy.keys()}

print("Optimal Diet:")
for food, quantity in results.items():
    if quantity > 1e-4:
        print(f"{food}: {quantity:.2f}")
Optimal Diet:
Banana: 9.52

5 Use Cases

VariableDict pairs powerfully with the new domain="binary" and domain="integer" parameters. Use them to cleanly implement job-shop schedules (keys=[f"{job}_{machine}" for job in jobs for machine in machines]), stock picking assignments, or supply chain routes.