0
# Expression System
1
2
Polynomial and general expression classes that enable natural mathematical notation in Python for optimization modeling. The expression system supports arithmetic operations, constraint creation, and nonlinear expression trees with automatic operator overloading.
3
4
## Capabilities
5
6
### Polynomial Expressions (Expr)
7
8
Linear and polynomial expressions supporting arithmetic operations and constraint creation through operator overloading.
9
10
```python { .api }
11
class Expr:
12
"""
13
Polynomial expression class supporting arithmetic operations.
14
15
Expressions are created by combining variables with arithmetic operators
16
and can be used to create constraints and objective functions.
17
"""
18
19
def __add__(self, other):
20
"""Addition: expr + other"""
21
22
def __sub__(self, other):
23
"""Subtraction: expr - other"""
24
25
def __mul__(self, other):
26
"""Multiplication: expr * other"""
27
28
def __truediv__(self, other):
29
"""Division: expr / other"""
30
31
def __pow__(self, other):
32
"""Exponentiation: expr ** other"""
33
34
def __le__(self, other):
35
"""Less than or equal: expr <= other (creates constraint)"""
36
37
def __ge__(self, other):
38
"""Greater than or equal: expr >= other (creates constraint)"""
39
40
def __eq__(self, other):
41
"""Equality: expr == other (creates constraint)"""
42
43
def __getitem__(self, term):
44
"""
45
Get coefficient of a term in the expression.
46
47
Parameters:
48
- term: Term to query (typically Term(var))
49
50
Returns:
51
float: Coefficient of the term
52
"""
53
54
def degree(self):
55
"""
56
Get degree of the polynomial expression.
57
58
Returns:
59
int: Maximum degree of any term in expression
60
"""
61
62
def normalize(self):
63
"""
64
Normalize the expression by combining like terms.
65
"""
66
```
67
68
### General Expressions (GenExpr)
69
70
General expression class for nonlinear expressions that cannot be represented as polynomials.
71
72
```python { .api }
73
class GenExpr:
74
"""
75
General expression class for nonlinear expressions.
76
77
Handles expressions involving transcendental functions (exp, log, sin, cos)
78
and other nonlinear operations that create expression trees.
79
"""
80
81
def __add__(self, other):
82
"""Addition with other expressions or constants"""
83
84
def __sub__(self, other):
85
"""Subtraction with other expressions or constants"""
86
87
def __mul__(self, other):
88
"""Multiplication with other expressions or constants"""
89
90
def __truediv__(self, other):
91
"""Division with other expressions or constants"""
92
93
def __le__(self, other):
94
"""Create nonlinear constraint: expr <= other"""
95
96
def __ge__(self, other):
97
"""Create nonlinear constraint: expr >= other"""
98
99
def __eq__(self, other):
100
"""Create nonlinear constraint: expr == other"""
101
```
102
103
### Expression Constraints (ExprCons)
104
105
Constraint objects created from expressions using comparison operators.
106
107
```python { .api }
108
class ExprCons:
109
"""
110
Constraint created from expression using comparison operators.
111
112
Created automatically when using <=, >=, == operators on expressions.
113
Supports both linear and nonlinear constraints.
114
"""
115
116
def __init__(self, expr, lhs=None, rhs=None):
117
"""
118
Create constraint from expression.
119
120
Parameters:
121
- expr: Expression object
122
- lhs (float): Left-hand side bound (for expr >= lhs)
123
- rhs (float): Right-hand side bound (for expr <= rhs)
124
"""
125
```
126
127
### Term Class
128
129
Represents monomials (products of variables) in polynomial expressions.
130
131
```python { .api }
132
class Term:
133
"""
134
Represents a monomial term in a polynomial expression.
135
136
Terms are products of variables, used for accessing coefficients
137
in expressions and building polynomial expressions.
138
"""
139
140
def __init__(self, *variables):
141
"""
142
Create term from variables.
143
144
Parameters:
145
- variables: Variable objects to multiply together
146
"""
147
148
def __add__(self, other):
149
"""Add terms together"""
150
151
def __hash__(self):
152
"""Hash function for using terms as dictionary keys"""
153
154
def __eq__(self, other):
155
"""Equality comparison for terms"""
156
```
157
158
### Utility Functions for Expressions
159
160
Fast aggregation functions for building large expressions efficiently.
161
162
```python { .api }
163
def quicksum(termlist):
164
"""
165
Fast summation of expressions or terms.
166
167
More efficient than using + operator repeatedly for large sums.
168
169
Parameters:
170
- termlist: Iterable of expressions, variables, or numeric values
171
172
Returns:
173
Expr: Sum of all terms
174
175
Example:
176
quicksum([2*x[i] for i in range(1000)]) # Much faster than x[0] + x[1] + ...
177
"""
178
179
def quickprod(termlist):
180
"""
181
Fast multiplication of expressions or terms.
182
183
More efficient than using * operator repeatedly for large products.
184
185
Parameters:
186
- termlist: Iterable of expressions, variables, or numeric values
187
188
Returns:
189
Expr: Product of all terms
190
191
Example:
192
quickprod([x[i] for i in range(10)]) # Faster than x[0] * x[1] * ...
193
"""
194
```
195
196
## Usage Examples
197
198
### Basic Expression Operations
199
200
```python
201
from pyscipopt import Model
202
203
model = Model("expressions")
204
205
# Create variables
206
x = model.addVar(name="x", lb=0)
207
y = model.addVar(name="y", lb=0)
208
z = model.addVar(name="z", lb=0)
209
210
# Build expressions using arithmetic operators
211
linear_expr = 2*x + 3*y - z
212
quadratic_expr = x*y + z**2
213
mixed_expr = 5 + 2*x - 3*y + x*z
214
215
# Use expressions in constraints
216
model.addCons(linear_expr <= 10, name="linear_constraint")
217
model.addCons(quadratic_expr >= 1, name="quadratic_constraint")
218
model.addCons(mixed_expr == 7, name="mixed_constraint")
219
220
# Use expression as objective
221
model.setObjective(linear_expr, "maximize")
222
```
223
224
### Working with Coefficients
225
226
```python
227
from pyscipopt import Model, Term
228
229
model = Model("coefficients")
230
x = model.addVar(name="x")
231
y = model.addVar(name="y")
232
233
# Build expression
234
expr = 3*x + 2*y + 5
235
236
# Access coefficients using Term objects
237
x_coeff = expr[Term(x)] # Returns 3.0
238
y_coeff = expr[Term(y)] # Returns 2.0
239
constant = expr[Term()] # Returns 5.0 (constant term)
240
241
print(f"Coefficient of x: {x_coeff}")
242
print(f"Coefficient of y: {y_coeff}")
243
print(f"Constant term: {constant}")
244
245
# Check expression degree
246
print(f"Expression degree: {expr.degree()}") # Returns 1 (linear)
247
248
# Normalize expression (combine like terms)
249
expr2 = 2*x + 3*x - x # Becomes 4*x after normalization
250
expr2.normalize()
251
```
252
253
### Using quicksum for Large Expressions
254
255
```python
256
from pyscipopt import Model, quicksum
257
258
model = Model("large_sum")
259
260
# Create many variables
261
n = 1000
262
variables = [model.addVar(name=f"x_{i}", lb=0) for i in range(n)]
263
coefficients = [i+1 for i in range(n)] # 1, 2, 3, ..., 1000
264
265
# Efficient way to create large sum
266
large_sum = quicksum(coefficients[i] * variables[i] for i in range(n))
267
268
# Use in constraint
269
model.addCons(large_sum <= 500000, name="resource_constraint")
270
271
# Alternative: sum variables with unit coefficients
272
unit_sum = quicksum(variables)
273
model.addCons(unit_sum >= 100, name="minimum_selection")
274
```
275
276
### Range Constraints with Expressions
277
278
```python
279
from pyscipopt import Model
280
281
model = Model("range_constraints")
282
x = model.addVar(name="x", lb=0)
283
y = model.addVar(name="y", lb=0)
284
285
# Single-sided constraints
286
model.addCons(x + y <= 10, name="upper_bound")
287
model.addCons(x + y >= 5, name="lower_bound")
288
289
# Range constraint (double-bounded)
290
model.addCons(5 <= x + y <= 10, name="range_constraint")
291
292
# Equivalent to range constraint using two separate constraints
293
expr = x + y
294
model.addCons(expr >= 5, name="range_lower")
295
model.addCons(expr <= 10, name="range_upper")
296
```
297
298
### Complex Expression Building
299
300
```python
301
from pyscipopt import Model, quicksum, quickprod
302
303
model = Model("complex_expressions")
304
305
# Variables for different product lines
306
production = {}
307
for product in ['A', 'B', 'C']:
308
for month in range(12):
309
production[product, month] = model.addVar(
310
name=f"prod_{product}_{month}", lb=0
311
)
312
313
# Total annual production per product using quicksum
314
annual_production = {}
315
for product in ['A', 'B', 'C']:
316
annual_production[product] = quicksum(
317
production[product, month] for month in range(12)
318
)
319
320
# Constraint: balanced production across products
321
total_production = quicksum(annual_production[product] for product in ['A', 'B', 'C'])
322
model.addCons(total_production <= 10000, name="capacity_limit")
323
324
# Product mix constraints using expressions
325
for product in ['A', 'B', 'C']:
326
model.addCons(
327
annual_production[product] >= 0.2 * total_production,
328
name=f"min_mix_{product}"
329
)
330
model.addCons(
331
annual_production[product] <= 0.5 * total_production,
332
name=f"max_mix_{product}"
333
)
334
```
335
336
### Polynomial Expressions
337
338
```python
339
from pyscipopt import Model
340
341
model = Model("polynomial")
342
x = model.addVar(name="x", lb=0, ub=5)
343
y = model.addVar(name="y", lb=0, ub=5)
344
345
# Quadratic expressions
346
quadratic_obj = x**2 + 2*x*y + y**2
347
model.setObjective(quadratic_obj, "minimize")
348
349
# Higher degree polynomial
350
cubic_expr = x**3 + 2*x**2*y + x*y**2 + y**3
351
model.addCons(cubic_expr <= 100, name="polynomial_constraint")
352
353
# Check degree
354
print(f"Quadratic degree: {quadratic_obj.degree()}") # Returns 2
355
print(f"Cubic degree: {cubic_expr.degree()}") # Returns 3
356
```
357
358
### Expression Manipulation
359
360
```python
361
from pyscipopt import Model, Term
362
363
model = Model("manipulation")
364
x = model.addVar(name="x")
365
y = model.addVar(name="y")
366
z = model.addVar(name="z")
367
368
# Build expression step by step
369
expr = 0 # Start with zero
370
expr = expr + 3*x
371
expr = expr + 2*y
372
expr = expr - z
373
expr = expr + 5 # Add constant
374
375
# Equivalent using single expression
376
expr_direct = 3*x + 2*y - z + 5
377
378
# Both expressions are equivalent
379
print(f"Step-by-step coefficient of x: {expr[Term(x)]}")
380
print(f"Direct coefficient of x: {expr_direct[Term(x)]}")
381
382
# Modify existing expressions
383
doubled_expr = 2 * expr
384
combined_expr = expr + expr_direct
385
386
print(f"Combined expression constant: {combined_expr[Term()]}")
387
```