Expressions¶
Expression functions for extracting values from interval variables.
Basic Accessors¶
start_of¶
- pycsp3_scheduling.expressions.interval_expr.start_of(interval, absent_value=0)[source]¶
Return an expression representing the start time of an interval.
If the interval is absent (optional and not selected), returns absent_value.
- Parameters:
interval (IntervalVar) – The interval variable.
absent_value (int) – Value to return if interval is absent (default: 0).
- Returns:
An expression representing the start time.
- Return type:
Example
>>> task = IntervalVar(size=10, name="task") >>> expr = start_of(task) >>> # Can be used in constraints: start_of(task) >= 5
end_of¶
- pycsp3_scheduling.expressions.interval_expr.end_of(interval, absent_value=0)[source]¶
Return an expression representing the end time of an interval.
If the interval is absent (optional and not selected), returns absent_value.
FIXME: end_of() still returns an internal IntervalExpr; for pycsp3 objectives use end_time() for now.
- Parameters:
interval (IntervalVar) – The interval variable.
absent_value (int) – Value to return if interval is absent (default: 0).
- Returns:
An expression representing the end time.
- Return type:
Example
>>> task = IntervalVar(size=10, name="task") >>> expr = end_of(task) >>> # Can be used in constraints: end_of(task) <= 100
size_of¶
- pycsp3_scheduling.expressions.interval_expr.size_of(interval, absent_value=0)[source]¶
Return an expression representing the size (duration) of an interval.
If the interval is absent (optional and not selected), returns absent_value.
- Parameters:
interval (IntervalVar) – The interval variable.
absent_value (int) – Value to return if interval is absent (default: 0).
- Returns:
An expression representing the size.
- Return type:
Example
>>> task = IntervalVar(size=(5, 20), name="task") >>> expr = size_of(task) >>> # Can be used in constraints: size_of(task) >= 10
length_of¶
- pycsp3_scheduling.expressions.interval_expr.length_of(interval, absent_value=0)[source]¶
Return an expression representing the length of an interval.
Length can differ from size when intensity functions are used. If the interval is absent, returns absent_value.
- Parameters:
interval (IntervalVar) – The interval variable.
absent_value (int) – Value to return if interval is absent (default: 0).
- Returns:
An expression representing the length.
- Return type:
Example
>>> task = IntervalVar(size=10, length=(8, 12), name="task") >>> expr = length_of(task)
presence_of¶
- pycsp3_scheduling.expressions.interval_expr.presence_of(interval)[source]¶
Return a boolean expression representing whether the interval is present.
For mandatory intervals, this is always true. For optional intervals, this is a decision variable.
- Parameters:
interval (IntervalVar) – The interval variable.
- Returns:
A boolean expression (0 or 1) for presence.
- Return type:
Example
>>> task = IntervalVar(size=10, optional=True, name="task") >>> expr = presence_of(task) >>> # Can be used: presence_of(task) == 1 means task is selected
overlap_length¶
- pycsp3_scheduling.expressions.interval_expr.overlap_length(interval1, interval2, absent_value=0)[source]¶
Return an expression for the overlap length between two intervals.
The overlap is max(0, min(end1, end2) - max(start1, start2)). If either interval is absent, returns absent_value.
- Parameters:
interval1 (IntervalVar) – First interval variable.
interval2 (IntervalVar) – Second interval variable.
absent_value (int) – Value to return if either interval is absent.
- Returns:
An expression representing the overlap length.
- Return type:
Example
>>> task1 = IntervalVar(size=10, name="task1") >>> task2 = IntervalVar(size=15, name="task2") >>> expr = overlap_length(task1, task2) >>> # expr == 0 means no overlap
Utility Functions¶
expr_min¶
- pycsp3_scheduling.expressions.interval_expr.expr_min(*args)[source]¶
Return the minimum of multiple expressions.
- Parameters:
*args (IntervalExpr | int) – Expressions or integers to take minimum of.
- Returns:
An expression representing the minimum.
- Return type:
expr_max¶
- pycsp3_scheduling.expressions.interval_expr.expr_max(*args)[source]¶
Return the maximum of multiple expressions.
- Parameters:
*args (IntervalExpr | int) – Expressions or integers to take maximum of.
- Returns:
An expression representing the maximum.
- Return type:
IntervalExpr Class¶
- class pycsp3_scheduling.expressions.interval_expr.IntervalExpr(expr_type, interval=None, absent_value=0, operands=<factory>, value=None, _id=-1)[source]¶
Bases:
objectBase class for interval-related expressions.
These expressions represent values derived from interval variables that can be used in constraints and objectives.
- expr_type¶
The type of expression.
- Type:
ExprType
- interval¶
The interval variable (if applicable).
- Type:
IntervalVar | None
- operands¶
Child expressions for compound expressions.
- Type:
- expr_type: ExprType¶
- interval: IntervalVar | None = None¶
- operands: list[IntervalExpr]¶
- __init__(expr_type, interval=None, absent_value=0, operands=<factory>, value=None, _id=-1)¶
Sequence Accessor Expressions¶
These functions access properties of neighboring intervals in a sequence.
Next Accessors¶
Function |
Description |
|---|---|
|
Start time of next interval |
|
End time of next interval |
|
Size of next interval |
|
Length of next interval |
|
ID of next interval |
Previous Accessors¶
Function |
Description |
|---|---|
|
Start time of previous interval |
|
End time of previous interval |
|
Size of previous interval |
|
Length of previous interval |
|
ID of previous interval |
Element Expressions¶
ElementArray¶
A 1D array wrapper that supports transparent array[variable] indexing syntax.
- class pycsp3_scheduling.expressions.element.ElementArray(data)[source]¶
Bases:
SequenceA wrapper that allows transparent array[variable_index] syntax.
This class wraps a list of values and overrides __getitem__ to create pycsp3 element expressions when indexed with a variable or expression.
Unlike regular Python lists, ElementArray supports: - Integer indexing (returns the value directly) - Variable indexing (returns a pycsp3 element expression)
Example
from pycsp3_scheduling.expressions import ElementArray
# Create an ElementArray from costs costs = ElementArray([10, 20, 30, 40, 50])
# Index with a constant - returns 30 costs[2]
# Index with a variable/expression - returns element expression idx = next_arg(route, interval) cost = costs[idx] # Creates element(costs, idx) automatically
# Use in objective minimize(Sum(costs[next_arg(route, v)] for v in visits))
- data¶
The underlying list of values.
- _var_array¶
Cached pycsp3 VarArray for element constraints.
- __getitem__(index: int) int | float[source]¶
- __getitem__(index: Any) Any
Index the array, supporting both constants and variables.
- Parameters:
index (int | Any) – An integer constant or a pycsp3 variable/expression.
- Returns:
Returns the value at that index. - If index is a variable/expression: Returns a pycsp3 element expression.
- Return type:
If index is an int
Example
arr = ElementArray([10, 20, 30]) arr[1] # Returns 20 arr[var_idx] # Returns element expression
ElementMatrix¶
A 2D matrix that supports indexing with pycsp3 expressions, similar to CP Optimizer’s IloNumArray2.
Supports both M[i, j] (tuple) and M[i][j] (chained) syntax.
- class pycsp3_scheduling.expressions.element.ElementMatrix(matrix, last_value=0, absent_value=0, _flat_vars=None, _n_rows=-1, _n_cols=-1, _last_type=-1, _absent_type=-1)[source]¶
Bases:
objectA 2D matrix that can be indexed with expressions.
This class wraps a 2D list of values and provides element-style indexing where indices can be pycsp3 variables or expressions. It’s designed to work with next_arg() for computing transition costs in scheduling.
The matrix supports two special values for boundary cases: - last_value: Used when an interval is the last in its sequence - absent_value: Used when an interval is absent (optional and not selected)
- Example (CP Optimizer pattern):
# Travel distance matrix indexed by customer types M = ElementMatrix(
matrix=travel_times, # 2D list [from_type][to_type] last_value=depot_distances, # 1D list or scalar for return to depot absent_value=0, # 0 cost if interval is absent
)
# Objective: minimize total travel distance for k in vehicles:
- for i in intervals:
cost = M[type_i, next_arg(route[k], visit[k][i])]
- last_value¶
Value(s) when next is “last” (end of sequence). Can be a scalar or 1D list indexed by from_type.
- absent_value¶
Value when interval is absent (scalar or 1D list).
- n_rows¶
Number of rows (from_types).
- n_cols¶
Number of columns (to_types).
- build_extended_matrix()[source]¶
Build the full matrix including last and absent columns.
- Returns:
columns 0..n_cols-1 are regular transitions
column n_cols is the “last” value
column n_cols+1 is the “absent” value
- Return type:
Matrix of shape [n_rows][n_cols + 2] where
- __getitem__(index)[source]¶
Index the matrix with expressions.
Supports two syntaxes: - M[row, col] - tuple indexing - M[row][col] - chained indexing (row returns a proxy)
- Parameters:
index (int | tuple | Any) – Can be: - tuple (row, col): Returns element at (row, col) - int: Returns an _ElementMatrixRowProxy for chained indexing - variable/expression: Returns a proxy for deferred column access
- Returns:
A pycsp3 element expression for matrix[row][col] - If int/variable: A proxy for M[row][col] chained access
- Return type:
If tuple
Example
M = ElementMatrix(travel_times, last_value=depot, absent_value=0) cost = M[type_i, next_arg(route, interval)] # tuple syntax cost = M[type_i][next_arg(route, interval)] # chained syntax
- get_value(row, col)[source]¶
Get a constant value from the matrix (no expression).
Use this for debugging or when indices are known constants. For variable indices, use __getitem__ instead.
- __init__(matrix, last_value=0, absent_value=0, _flat_vars=None, _n_rows=-1, _n_cols=-1, _last_type=-1, _absent_type=-1)¶
element¶
- pycsp3_scheduling.expressions.element.element(array, index)[source]¶
Create an element expression for array indexing with a variable index.
This provides a clean way to access array[index] where index is a pycsp3 variable or expression.
- Parameters:
- Returns:
A pycsp3 element expression.
- Return type:
Example
costs = [10, 20, 30, 40, 50] idx = next_arg(route, interval) cost = element(costs, idx) # Returns costs[next_arg(…)]
element2d¶
- pycsp3_scheduling.expressions.element.element2d(matrix, row_idx, col_idx)[source]¶
Create an element expression for 2D array indexing with variable indices.
This provides matrix[row][col] access where row and col can be expressions.
- Parameters:
- Returns:
A pycsp3 element expression.
- Return type:
Example
travel = [[0, 10, 20], [10, 0, 15], [20, 15, 0]] i = type_of(interval_from) j = next_arg(route, interval_from) cost = element2d(travel, i, j)
Usage Examples¶
Basic Expression Usage¶
from pycsp3_scheduling import IntervalVar, start_of, end_of, size_of, presence_of
task = IntervalVar(size=(5, 15), optional=True, name="task")
# Get expressions (internal representation)
start_expr = start_of(task)
end_expr = end_of(task)
size_expr = size_of(task)
presence_expr = presence_of(task)
# With absent value for optional intervals
start_expr = start_of(task, absent_value=-1)
Expression Arithmetic¶
from pycsp3_scheduling import start_of, end_of
task1 = IntervalVar(size=10, name="task1")
task2 = IntervalVar(size=15, name="task2")
# Arithmetic operations
gap = start_of(task2) - end_of(task1)
total_duration = size_of(task1) + size_of(task2)
Comparison Expressions¶
from pycsp3_scheduling import start_of, end_of
# Build constraint expressions
must_start_early = start_of(task) <= 100
must_end_late = end_of(task) >= 50
Min/Max of Multiple Expressions¶
from pycsp3_scheduling import expr_min, expr_max, start_of, end_of
tasks = [IntervalVar(size=10, name=f"task{i}") for i in range(3)]
# Earliest start
earliest = expr_min(*(start_of(t) for t in tasks))
# Latest end (makespan)
makespan = expr_max(*(end_of(t) for t in tasks))
next_arg for Distance Objectives (VRPTW Pattern)¶
The next_arg function returns the ID of the next interval in a sequence,
enabling CP Optimizer-style distance objectives. Similar to pycsp3’s maximum_arg pattern:
from pycsp3 import minimize, Sum
from pycsp3_scheduling import IntervalVar, SequenceVar
from pycsp3_scheduling.expressions.sequence_expr import next_arg
from pycsp3_scheduling.expressions.element import ElementMatrix
# Create intervals with IDs (types)
visits = [IntervalVar(size=5, optional=True, name=f"v{i}") for i in range(n)]
route = SequenceVar(intervals=visits, types=list(range(n)), name="route")
# Build cost matrix with boundary values
M = ElementMatrix(
matrix=travel_costs, # [from_id][to_id] distances
last_value=depot_return_costs, # Cost when interval is last
absent_value=0, # No cost when interval is absent
)
# Objective: minimize total transition costs
distance_terms = []
for i, visit in enumerate(visits):
next_id = next_arg(
route, visit,
last_value=M.last_type, # Column index for "last"
absent_value=M.absent_type, # Column index for "absent"
)
distance_terms.append(M[i, next_id])
minimize(Sum(distance_terms))
ElementMatrix for Transition Costs¶
from pycsp3_scheduling.expressions.element import ElementMatrix
# Travel distance matrix between customers
travel_costs = [
[0, 10, 15], # From customer 0
[10, 0, 8], # From customer 1
[15, 8, 0], # From customer 2
]
# Return-to-depot distances (per customer)
depot_distances = [20, 18, 22]
# Create matrix with boundary values
M = ElementMatrix(
matrix=travel_costs,
last_value=depot_distances, # When interval is last in sequence
absent_value=0, # When interval is not scheduled
)
# Access properties
print(M.n_rows, M.n_cols) # 3, 3
print(M.last_type) # 3 (column index for last)
print(M.absent_type) # 4 (column index for absent)
# Get constant value (debugging)
print(M.get_value(0, 1)) # 10 (travel from 0 to 1)
print(M.get_value(1, M.last_type)) # 18 (return from 1 to depot)
# Use with expressions - both syntaxes work
cost = M[id_i, next_arg(route, interval, M.last_type, M.absent_type)] # tuple
cost = M[id_i][next_arg(route, interval, M.last_type, M.absent_type)] # chained
ElementArray for Simple Array Indexing¶
from pycsp3_scheduling import ElementArray
# Create an array with transparent variable indexing
costs = ElementArray([10, 20, 30, 40, 50])
# Integer indexing - returns value directly
costs[2] # → 30
# Variable indexing - returns pycsp3 element expression
idx = next_arg(route, interval)
cost = costs[idx] # Creates element constraint automatically
# Use in objective
minimize(Sum(costs[type_of_next(route, v)] for v in visits))