lumix.indexing.cartesian.LXCartesianProduct¶
- class lumix.indexing.cartesian.LXCartesianProduct(dim1, dim2)[source]¶
Type-safe cartesian product of multiple index dimensions.
LXCartesianProduct combines two or more index dimensions to create a multi-dimensional index space. This enables variables and constraints indexed by tuples of data models, such as (Driver, Date) or (Warehouse, Product, TimePeriod).
The cartesian product generates all combinations of instances across dimensions, with optional cross-dimension filtering to create sparse index spaces (only valid combinations).
This class is the foundation of LumiX’s multi-model indexing capability, which is one of the library’s most powerful features for complex scheduling, routing, and allocation problems.
- Type Parameters:
TModel1: The data model type for the first dimension TModel2: The data model type for the second dimension
- Parameters:
dim1 (LXIndexDimension[TModel1])
dim2 (LXIndexDimension[TModel2])
- dimensions¶
List of LXIndexDimension objects defining each dimension
- _cross_filter¶
Optional predicate for filtering combinations across dimensions
Examples
Basic two-dimensional product:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) )
With cross-dimension filtering:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ).where(lambda driver, date: date not in driver.days_off)
Three-dimensional product:
product = ( LXCartesianProduct( LXIndexDimension(Warehouse, lambda w: w.id).from_data(warehouses), LXIndexDimension(Product, lambda p: p.sku).from_data(products) ) .add_dimension(LXIndexDimension(Month, lambda m: m.id).from_data(months)) .where(lambda w, p, m: w.stocks_product(p) and m.is_active) )
Used in variable definition:
from typing import Tuple assignment = ( LXVariable[Tuple[Driver, Date], int]("assignment") .binary() .indexed_by_product( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ) .where_multi(lambda driver, date: driver.is_available(date)) )
See also
LXIndexDimension: Individual dimensionslumix.core.variables.LXVariable.indexed_by_product(): Uses this classDriver Scheduling Example (examples/02_driver_scheduling): Complete example
Note
The cartesian product follows lazy evaluation - combinations are generated only when needed during model solving
Cross-dimension filters (where()) are applied after per-dimension filters
For N dimensions, the product generates O(n1 × n2 × … × nN) combinations before filtering
- __init__(dim1, dim2)[source]¶
Initialize a cartesian product with two dimensions.
Creates a two-dimensional cartesian product. Additional dimensions can be added via add_dimension() for 3D, 4D, or higher-dimensional index spaces.
- Parameters:
dim1 (
LXIndexDimension[TypeVar(TModel1)]) – First index dimensiondim2 (
LXIndexDimension[TypeVar(TModel2)]) – Second index dimension
Examples
Basic initialization:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) )
With per-dimension filters:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id) .from_data(drivers) .where(lambda d: d.is_active), LXIndexDimension(Date, lambda dt: dt.date) .from_data(dates) .where(lambda dt: dt.is_weekday) )
Methods
__init__(dim1, dim2)Initialize a cartesian product with two dimensions.
add_dimension(dim)Add another dimension to create 3D or higher-dimensional indexing.
where(predicate)Apply cross-dimension filtering to the cartesian product.
- __init__(dim1, dim2)[source]¶
Initialize a cartesian product with two dimensions.
Creates a two-dimensional cartesian product. Additional dimensions can be added via add_dimension() for 3D, 4D, or higher-dimensional index spaces.
- Parameters:
dim1 (
LXIndexDimension[TypeVar(TModel1)]) – First index dimensiondim2 (
LXIndexDimension[TypeVar(TModel2)]) – Second index dimension
Examples
Basic initialization:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) )
With per-dimension filters:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id) .from_data(drivers) .where(lambda d: d.is_active), LXIndexDimension(Date, lambda dt: dt.date) .from_data(dates) .where(lambda dt: dt.is_weekday) )
- __deepcopy__(memo)[source]¶
Custom deepcopy that handles dimensions and cross-filter functions.
This method enables what-if analysis on cartesian products by: 1. Deep copying all index dimensions (with ORM data materialization) 2. Safely copying the cross-filter lambda function
- Parameters:
memo – Dictionary for tracking circular references during deepcopy
- Returns:
Deep copy of this cartesian product with all dependencies resolved
- add_dimension(dim)[source]¶
Add another dimension to create 3D or higher-dimensional indexing.
This method extends a two-dimensional product to three or more dimensions. Each additional dimension multiplies the number of combinations (before filtering).
- Parameters:
dim (
LXIndexDimension) – Additional index dimension to add- Return type:
Self- Returns:
Self for method chaining
Examples
Three-dimensional indexing:
product = ( LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ) .add_dimension(LXIndexDimension(Shift, lambda s: s.id).from_data(shifts)) )
Four-dimensional indexing:
product = ( LXCartesianProduct( LXIndexDimension(Warehouse, lambda w: w.id).from_data(warehouses), LXIndexDimension(Product, lambda p: p.sku).from_data(products) ) .add_dimension(LXIndexDimension(Customer, lambda c: c.id).from_data(customers)) .add_dimension(LXIndexDimension(Month, lambda m: m.id).from_data(months)) )
Note
Dimensions can be added in any order
The cross-filter predicate (if set via where()) must match the number of dimensions
Each added dimension increases the computational complexity exponentially
- where(predicate)[source]¶
Apply cross-dimension filtering to the cartesian product.
This method adds a filter that operates across all dimensions simultaneously, allowing you to exclude invalid combinations based on relationships between the dimension models. This is essential for creating sparse index spaces.
The predicate function receives one instance from each dimension as arguments (in the order dimensions were added) and should return True for valid combinations.
This is different from per-dimension filters (applied via LXIndexDimension.where()), which filter within a single dimension before the cartesian product is formed.
- Parameters:
predicate (
Callable[[TypeVar(TModel1),TypeVar(TModel2)],bool]) – A function that takes one model instance from each dimension and returns True if the combination is valid, False otherwise- Return type:
Self- Returns:
Self for method chaining
Examples
Two-dimensional filtering:
product = LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ).where(lambda driver, date: date not in driver.days_off)
Three-dimensional filtering:
product = ( LXCartesianProduct( LXIndexDimension(Driver, lambda d: d.id).from_data(drivers), LXIndexDimension(Date, lambda dt: dt.date).from_data(dates) ) .add_dimension(LXIndexDimension(Shift, lambda s: s.id).from_data(shifts)) .where(lambda driver, date, shift: driver.can_work_shift(shift) and date not in driver.days_off and shift.requires_certification <= driver.certifications ) )
Complex business logic:
product = LXCartesianProduct( LXIndexDimension(Warehouse, lambda w: w.id).from_data(warehouses), LXIndexDimension(Customer, lambda c: c.id).from_data(customers) ).where(lambda warehouse, customer: warehouse.region == customer.region and warehouse.can_ship_to(customer.zip_code) and customer.preferred_warehouses is None or warehouse.id in customer.preferred_warehouses )
Note
The predicate is called for every combination after per-dimension filters
Multiple where() calls override previous filters (not combine them)
For best performance, use per-dimension filters first, then cross-dimension filters
The function signature must match the number of dimensions
- Performance Tip:
Apply filters that reduce data size at the dimension level (via LXIndexDimension.where()) before applying cross-dimension filters here. This reduces the number of combinations that need to be evaluated.
See also
lumix.indexing.dimensions.LXIndexDimension.where(): Per-dimension filteringlumix.core.variables.LXVariable.where_multi(): Alternative syntax