Constraint¶
PyOptInterface supports the following types of constraints:
Linear Constraint
Quadratic Constraint
Second-Order Cone Constraint
Special Ordered Set (SOS) Constraint
Note
Not all optimizers support all types of constraints. Please refer to the documentation of the optimizer you are using to see which types of constraints are supported.
import pyoptinterface as poi
from pyoptinterface import copt
model = copt.Model()
2025-10-01 15:49:10 [INFO] checks license for COPT v7.2.8 20250516
2025-10-01 15:49:10 [WARN] no license files in current working folder: /home/runner/work/PyOptInterface/PyOptInterface/docs/source
2025-10-01 15:49:10 [WARN] no license files in binary folder: /opt/hostedtoolcache/Python/3.12.11/x64/bin
2025-10-01 15:49:10 [WARN] no license files in HOME folder: /home/runner/copt
2025-10-01 15:49:10 [INFO] empty environment variable: COPT_LICENSE_DIR
2025-10-01 15:49:10 [WARN] no license files in EV 'COPT_LICENSE_DIR':
No license found. Starting COPT with size limitations for non-commercial use
Please apply for a license from www.shanshu.ai/copt
Constraint Sense¶
The sense of a constraint can be one of the following:
poi.Eq: equalpoi.Leq: less than or equalpoi.Geq: greater than or equal
They are the abbreviations of poi.ConstraintSense.Equal, poi.ConstraintSense.LessEqual or poi.ConstraintSense.GreaterEqual and can be used in the sense argument of the constraint creation functions.
Linear Constraint¶
It is defined as:
It can be added to the model using the add_linear_constraint method of the Model class.
x = model.add_variable(name="x")
y = model.add_variable(name="y")
con = model.add_linear_constraint(2.0*x + 3.0*y, poi.Leq, 1.0)
- model.add_linear_constraint(expr, sense, rhs[, name=""])¶
add a linear constraint to the model
- Parameters:
expr – the expression of the constraint
sense (pyoptinterface.ConstraintSense) – the sense of the constraint
rhs (float) – the right-hand side of the constraint
name (str) – the name of the constraint, optional
- Returns:
the handle of the constraint
Note
PyOptInterface provides pyoptinterface.Eq, pyoptinterface.Leq, and pyoptinterface.Geq as alias of pyoptinterface.ConstraintSense to represent the sense of the constraint with a shorter name.
The linear constraint can also be created with a comparison operator, like <=, ==, or >=:
model.add_linear_constraint(2.0*x + 3.0*y <= 1.0)
model.add_linear_constraint(2.0*x + 3.0*y == 1.0)
model.add_linear_constraint(2.0*x + 3.0*y >= 1.0)
<pyoptinterface._src.core_ext.ConstraintIndex at 0x7fafa0f53050>
If you want to express a two-sided linear constraint, you can use the add_linear_constraint method with a tuple to represent the left-hand side and right-hand side of the constraint like:
model.add_linear_constraint(2.0*x + 3.0*y, (1.0, 2.0))
<pyoptinterface._src.core_ext.ConstraintIndex at 0x7fafa0f535d0>
which is equivalent to:
model.add_linear_constraint(2.0*x + 3.0*y, poi.Leq, 2.0)
model.add_linear_constraint(2.0*x + 3.0*y, poi.Geq, 1.0)
<pyoptinterface._src.core_ext.ConstraintIndex at 0x7fafa0f53630>
Note
The two-sided linear constraint is not implemented for Gurobi because of its special handling of range constraints.
Quadratic Constraint¶
Like the linear constraint, it is defined as:
It can be added to the model using the add_quadratic_constraint method of the Model class.
x = model.add_variable(name="x")
y = model.add_variable(name="y")
expr = x*x + 2.0*x*y + 4.0*y*y
con = model.add_quadratic_constraint(expr, poi.ConstraintSense.LessEqual, 1.0)
- model.add_quadratic_constraint(expr, sense, rhs[, name=""])¶
add a quadratic constraint to the model
- Parameters:
expr – the expression of the constraint
sense (pyoptinterface.ConstraintSense) – the sense of the constraint, which can be
GreaterEqual,Equal, orLessEqualrhs (float) – the right-hand side of the constraint
name (str) – the name of the constraint, optional
- Returns:
the handle of the constraint
Similarly, the quadratic constraint can also be created with a comparison operator, like <=, ==, or >=:
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y <= 1.0)
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y == 1.0)
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y >= 1.0)
Note
Some solvers like COPT (as of 7.2.9) only supports convex quadratic constraints, which means the quadratic term must be positive semidefinite. If you try to add a non-convex quadratic constraint, an exception will be raised.
The two-sided quadratic constraint can also be created with a tuple to represent the left-hand side and right-hand side of the constraint like:
model.add_quadratic_constraint(x*x + 2.0*x*y + 4.0*y*y, (1.0, 2.0))
Note
Currently, two-sided quadratic constraint is only implemented for IPOPT.
Second-Order Cone Constraint¶
It is defined as:
It can be added to the model using the add_second_order_cone_constraint method of the Model
class.
N = 6
vars = [model.add_variable() for i in range(N)]
con = model.add_second_order_cone_constraint(vars)
There is another form of second-order cone constraint called as rotated second-order cone constraint, which is defined as:
- model.add_second_order_cone_constraint(variables[, name="", rotated=False])¶
add a second order cone constraint to the model
- Parameters:
variables – the variables of the constraint, can be a list of variables
name (str) – the name of the constraint, optional
rotated (bool) – whether the constraint is a rotated second-order cone constraint, optional
- Returns:
the handle of the constraint
Exponential Cone Constraint¶
It is defined as:
The dual form is:
Currently, only COPT(after 7.1.4), Mosek support exponential cone constraint. It can be added to the model using the add_exp_cone_constraint method of the Model class.
- model.add_exp_cone_constraint(variables[, name="", dual=False])¶
add a second order cone constraint to the model
- Parameters:
variables – the variables of the constraint, can be a list of variables
name (str) – the name of the constraint, optional
dual (bool) – whether the constraint is dual form of exponential cone, optional
- Returns:
the handle of the constraint
Special Ordered Set (SOS) Constraint¶
SOS constraints are used to model special structures in the optimization problem.
It contains two types: SOS1 and SOS2, the details can be found in Wikipedia.
It can be added to the model using the add_sos_constraint method of the Model class.
N = 6
vars = [model.add_variable(domain=poi.VariableDomain.Binary) for i in range(N)]
con = model.add_sos_constraint(vars, poi.SOSType.SOS1)
- model.add_sos_constraint(variables, sos_type[, weights])¶
add a special ordered set constraint to the model
- Parameters:
variables – the variables of the constraint, can be a list of variables
sos_type (pyoptinterface.SOSType) – the type of the SOS constraint, which can be
SOS1orSOS2weights (list[float]) – the weights of the variables, optional, will be set to 1 if not provided
- Returns:
the handle of the constraint
Constraint Attributes¶
After a constraint is created, we can query or modify its attributes. The following table lists the standard constraint attributes:
Attribute name |
Type |
|---|---|
Name |
str |
Primal |
float |
Dual |
float |
IIS |
bool |
The most common attribute we will use is the Dual attribute, which represents the dual multiplier of the constraint after optimization.
# get the dual multiplier of the constraint after optimization
dual = model.get_constraint_attribute(con, poi.ConstraintAttribute.Dual)
Delete constraint¶
We can delete a constraint by calling the delete_constraint method of the model:
model.delete_constraint(con)
After a constraint is deleted, it cannot be used in the model anymore, otherwise an exception will be raised.
We can query whether a constraint is active by calling the is_constraint_active method of the
model:
is_active = model.is_constraint_active(con)
Modify constraint¶
For linear and quadratic constraints, we can modify the right-hand side of a constraint by
calling the set_normalized_rhs method of the model.
For linear constraints, we can modify the coefficients of the linear part of the constraint by
calling the set_normalized_coefficient method of the model.
con = model.add_linear_constraint(x + y, poi.Leq, 1.0)
# modify the right-hand side of the constraint
model.set_normalized_rhs(con, 2.0)
# modify the coefficient of the linear part of the constraint
model.set_normalized_coefficient(con, x, 2.0)