Python interface and modeling environment for SCIP optimization solver
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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.
Linear and polynomial expressions supporting arithmetic operations and constraint creation through operator overloading.
class Expr:
"""
Polynomial expression class supporting arithmetic operations.
Expressions are created by combining variables with arithmetic operators
and can be used to create constraints and objective functions.
"""
def __add__(self, other):
"""Addition: expr + other"""
def __sub__(self, other):
"""Subtraction: expr - other"""
def __mul__(self, other):
"""Multiplication: expr * other"""
def __truediv__(self, other):
"""Division: expr / other"""
def __pow__(self, other):
"""Exponentiation: expr ** other"""
def __le__(self, other):
"""Less than or equal: expr <= other (creates constraint)"""
def __ge__(self, other):
"""Greater than or equal: expr >= other (creates constraint)"""
def __eq__(self, other):
"""Equality: expr == other (creates constraint)"""
def __getitem__(self, term):
"""
Get coefficient of a term in the expression.
Parameters:
- term: Term to query (typically Term(var))
Returns:
float: Coefficient of the term
"""
def degree(self):
"""
Get degree of the polynomial expression.
Returns:
int: Maximum degree of any term in expression
"""
def normalize(self):
"""
Normalize the expression by combining like terms.
"""General expression class for nonlinear expressions that cannot be represented as polynomials.
class GenExpr:
"""
General expression class for nonlinear expressions.
Handles expressions involving transcendental functions (exp, log, sin, cos)
and other nonlinear operations that create expression trees.
"""
def __add__(self, other):
"""Addition with other expressions or constants"""
def __sub__(self, other):
"""Subtraction with other expressions or constants"""
def __mul__(self, other):
"""Multiplication with other expressions or constants"""
def __truediv__(self, other):
"""Division with other expressions or constants"""
def __le__(self, other):
"""Create nonlinear constraint: expr <= other"""
def __ge__(self, other):
"""Create nonlinear constraint: expr >= other"""
def __eq__(self, other):
"""Create nonlinear constraint: expr == other"""Constraint objects created from expressions using comparison operators.
class ExprCons:
"""
Constraint created from expression using comparison operators.
Created automatically when using <=, >=, == operators on expressions.
Supports both linear and nonlinear constraints.
"""
def __init__(self, expr, lhs=None, rhs=None):
"""
Create constraint from expression.
Parameters:
- expr: Expression object
- lhs (float): Left-hand side bound (for expr >= lhs)
- rhs (float): Right-hand side bound (for expr <= rhs)
"""Represents monomials (products of variables) in polynomial expressions.
class Term:
"""
Represents a monomial term in a polynomial expression.
Terms are products of variables, used for accessing coefficients
in expressions and building polynomial expressions.
"""
def __init__(self, *variables):
"""
Create term from variables.
Parameters:
- variables: Variable objects to multiply together
"""
def __add__(self, other):
"""Add terms together"""
def __hash__(self):
"""Hash function for using terms as dictionary keys"""
def __eq__(self, other):
"""Equality comparison for terms"""Fast aggregation functions for building large expressions efficiently.
def quicksum(termlist):
"""
Fast summation of expressions or terms.
More efficient than using + operator repeatedly for large sums.
Parameters:
- termlist: Iterable of expressions, variables, or numeric values
Returns:
Expr: Sum of all terms
Example:
quicksum([2*x[i] for i in range(1000)]) # Much faster than x[0] + x[1] + ...
"""
def quickprod(termlist):
"""
Fast multiplication of expressions or terms.
More efficient than using * operator repeatedly for large products.
Parameters:
- termlist: Iterable of expressions, variables, or numeric values
Returns:
Expr: Product of all terms
Example:
quickprod([x[i] for i in range(10)]) # Faster than x[0] * x[1] * ...
"""from pyscipopt import Model
model = Model("expressions")
# Create variables
x = model.addVar(name="x", lb=0)
y = model.addVar(name="y", lb=0)
z = model.addVar(name="z", lb=0)
# Build expressions using arithmetic operators
linear_expr = 2*x + 3*y - z
quadratic_expr = x*y + z**2
mixed_expr = 5 + 2*x - 3*y + x*z
# Use expressions in constraints
model.addCons(linear_expr <= 10, name="linear_constraint")
model.addCons(quadratic_expr >= 1, name="quadratic_constraint")
model.addCons(mixed_expr == 7, name="mixed_constraint")
# Use expression as objective
model.setObjective(linear_expr, "maximize")from pyscipopt import Model, Term
model = Model("coefficients")
x = model.addVar(name="x")
y = model.addVar(name="y")
# Build expression
expr = 3*x + 2*y + 5
# Access coefficients using Term objects
x_coeff = expr[Term(x)] # Returns 3.0
y_coeff = expr[Term(y)] # Returns 2.0
constant = expr[Term()] # Returns 5.0 (constant term)
print(f"Coefficient of x: {x_coeff}")
print(f"Coefficient of y: {y_coeff}")
print(f"Constant term: {constant}")
# Check expression degree
print(f"Expression degree: {expr.degree()}") # Returns 1 (linear)
# Normalize expression (combine like terms)
expr2 = 2*x + 3*x - x # Becomes 4*x after normalization
expr2.normalize()from pyscipopt import Model, quicksum
model = Model("large_sum")
# Create many variables
n = 1000
variables = [model.addVar(name=f"x_{i}", lb=0) for i in range(n)]
coefficients = [i+1 for i in range(n)] # 1, 2, 3, ..., 1000
# Efficient way to create large sum
large_sum = quicksum(coefficients[i] * variables[i] for i in range(n))
# Use in constraint
model.addCons(large_sum <= 500000, name="resource_constraint")
# Alternative: sum variables with unit coefficients
unit_sum = quicksum(variables)
model.addCons(unit_sum >= 100, name="minimum_selection")from pyscipopt import Model
model = Model("range_constraints")
x = model.addVar(name="x", lb=0)
y = model.addVar(name="y", lb=0)
# Single-sided constraints
model.addCons(x + y <= 10, name="upper_bound")
model.addCons(x + y >= 5, name="lower_bound")
# Range constraint (double-bounded)
model.addCons(5 <= x + y <= 10, name="range_constraint")
# Equivalent to range constraint using two separate constraints
expr = x + y
model.addCons(expr >= 5, name="range_lower")
model.addCons(expr <= 10, name="range_upper")from pyscipopt import Model, quicksum, quickprod
model = Model("complex_expressions")
# Variables for different product lines
production = {}
for product in ['A', 'B', 'C']:
for month in range(12):
production[product, month] = model.addVar(
name=f"prod_{product}_{month}", lb=0
)
# Total annual production per product using quicksum
annual_production = {}
for product in ['A', 'B', 'C']:
annual_production[product] = quicksum(
production[product, month] for month in range(12)
)
# Constraint: balanced production across products
total_production = quicksum(annual_production[product] for product in ['A', 'B', 'C'])
model.addCons(total_production <= 10000, name="capacity_limit")
# Product mix constraints using expressions
for product in ['A', 'B', 'C']:
model.addCons(
annual_production[product] >= 0.2 * total_production,
name=f"min_mix_{product}"
)
model.addCons(
annual_production[product] <= 0.5 * total_production,
name=f"max_mix_{product}"
)from pyscipopt import Model
model = Model("polynomial")
x = model.addVar(name="x", lb=0, ub=5)
y = model.addVar(name="y", lb=0, ub=5)
# Quadratic expressions
quadratic_obj = x**2 + 2*x*y + y**2
model.setObjective(quadratic_obj, "minimize")
# Higher degree polynomial
cubic_expr = x**3 + 2*x**2*y + x*y**2 + y**3
model.addCons(cubic_expr <= 100, name="polynomial_constraint")
# Check degree
print(f"Quadratic degree: {quadratic_obj.degree()}") # Returns 2
print(f"Cubic degree: {cubic_expr.degree()}") # Returns 3from pyscipopt import Model, Term
model = Model("manipulation")
x = model.addVar(name="x")
y = model.addVar(name="y")
z = model.addVar(name="z")
# Build expression step by step
expr = 0 # Start with zero
expr = expr + 3*x
expr = expr + 2*y
expr = expr - z
expr = expr + 5 # Add constant
# Equivalent using single expression
expr_direct = 3*x + 2*y - z + 5
# Both expressions are equivalent
print(f"Step-by-step coefficient of x: {expr[Term(x)]}")
print(f"Direct coefficient of x: {expr_direct[Term(x)]}")
# Modify existing expressions
doubled_expr = 2 * expr
combined_expr = expr + expr_direct
print(f"Combined expression constant: {combined_expr[Term()]}")Install with Tessl CLI
npx tessl i tessl/pypi-pyscipopt