Python interface¶
The cupdlpx package solves LPs from NumPy
arrays or SciPy sparse
matrices. The Model class stores problem data, solver settings, and results.
Solution vectors are returned as read-only NumPy arrays.
To solve an MPS file, see Read MPS data. To build an LP from arrays, see the Quickstart.
Software requirements¶
| Component | Requirement |
|---|---|
| Python | 3.8+ |
| NumPy | 1.21+ |
| SciPy | 1.8+ |
NumPy and SciPy are installed automatically with the package.
See hardware requirements for supported GPUs and required CUDA or ROCm versions.
Installation¶
Install from PyPI:
Confirm that the package imports:
To install the current source tree instead:
Building from source requires CMake 3.21+ and a CUDA or ROCm toolchain. Pip may build the package locally if no compatible wheel is available.
Read MPS data¶
To solve an existing LP, replace instance.mps with the path to your file:
import cupdlpx
model = cupdlpx.read("instance.mps")
model.optimize()
if model.Status == cupdlpx.PDLP.OPTIMAL:
print("objective:", model.ObjVal)
print("x:", model.X)
else:
print("solver stopped with", model.StatusName)
cupdlpx.read(filename) accepts any path-like object and returns a new Model;
both .mps and .mps.gz files are supported. A missing path raises
FileNotFoundError; a file rejected by the native parser raises RuntimeError.
See Solve and inspect results for residuals, timings, and other solution fields.
Quickstart¶
This example solves
Every constraint is represented by a lower and an upper bound:
import numpy as np
from cupdlpx import Model, PDLP
c = np.array([1.0, 1.0])
A = np.array([
[1.0, 2.0],
[0.0, 1.0],
[3.0, 2.0],
])
model = Model(
objective_vector=c,
constraint_matrix=A,
constraint_lower_bound=np.array([5.0, -np.inf, -np.inf]),
constraint_upper_bound=np.array([5.0, 2.0, 8.0]),
variable_lower_bound=np.zeros(2),
variable_upper_bound=None,
)
model.Params.TimeLimit = 60
model.setParams(
OptimalityTol=1e-6,
FeasibilityTol=1e-6,
OutputFlag=False,
)
model.optimize()
if model.Status == PDLP.OPTIMAL:
print(f"objective: {model.ObjVal:.4f}")
print("x:", np.round(model.X, 4))
else:
print("solver stopped with", model.StatusName)
Output:
Passing None omits the corresponding lower or upper bounds.
Set OutputFlag=True to print the solver progress table; its fields are explained under Log
interpretation.
Create a model¶
from cupdlpx import Model
model = Model(
objective_vector=c,
constraint_matrix=A,
constraint_lower_bound=l,
constraint_upper_bound=u,
variable_lower_bound=lb,
variable_upper_bound=ub,
objective_constant=0.0,
)
constraint_matrix accepts a two-dimensional numpy.ndarray or a SciPy
sparse matrix.
| Argument | Type | Shape | Default | Description |
|---|---|---|---|---|
objective_vector |
array-like | (n,) |
required | Finite objective coefficients \(c\). |
constraint_matrix |
NumPy array or SciPy sparse matrix | (m,n) |
required | Finite constraint matrix \(A\). |
constraint_lower_bound |
array-like or None |
(m,) |
required | Lower bounds \(\ell_c\); None means all \(-\infty\). |
constraint_upper_bound |
array-like or None |
(m,) |
required | Upper bounds \(u_c\); None means all \(+\infty\). |
variable_lower_bound |
array-like or None |
(n,) |
None |
Lower bounds \(\ell_v\); None means all \(-\infty\). |
variable_upper_bound |
array-like or None |
(n,) |
None |
Upper bounds \(u_v\); None means all \(+\infty\). |
objective_constant |
real number | scalar | 0.0 |
Finite objective offset \(c_0\). |
Dense vectors and matrices are copied into C-contiguous float64 arrays.
Sparse matrices are copied to CSR with float64 values and 32-bit indices.
The stored arrays are read-only.
Construction raises TypeError for unsupported input types, ValueError for
invalid dimensions, bounds, or nonfinite data, and OverflowError when a
sparse matrix cannot use 32-bit CSR indices.
Models minimize by default. To maximize:
Solve and inspect results¶
Call optimize() to solve the model, then read its status and solution attributes:
| Property | Type after a solve | Description |
|---|---|---|
Status |
int |
Termination code; compare with a constant in cupdlpx.PDLP. |
StatusName |
str |
Symbolic termination name. |
X |
numpy.ndarrayshape (n,) |
Primal solution. |
Pi |
numpy.ndarrayshape (m,) |
Dual solution. |
RC |
numpy.ndarrayshape (n,) |
Dual slacks. |
ObjVal |
float |
Primal objective value. |
DualObj |
float |
Dual objective value. |
Gap |
float |
Absolute primal–dual objective gap. |
RelGap |
float |
Relative primal–dual objective gap. |
RelPrimalResidual |
float |
Relative primal feasibility residual. |
RelDualResidual |
float |
Relative dual feasibility residual. |
IterCount |
int |
Total iteration count. |
Runtime |
float |
Solve time in seconds. |
RescalingTime |
float |
Preconditioning time in seconds. |
MaxPrimalRayInfeas |
float |
Maximum primal-ray infeasibility. |
MaxDualRayInfeas |
float |
Maximum dual-ray infeasibility. |
PrimalRayLinObj |
float |
Primal-ray linear objective. |
DualRayObj |
float |
Dual-ray objective. |
Solution attributes are None before a solve and are cleared whenever model
data changes. PrimalInfeas and DualInfeas are aliases for
RelPrimalResidual and RelDualResidual. Invalid model bounds or objective
sense raise ValueError; native solver failures raise RuntimeError. See
results and status for status interpretation.
Set parameters¶
Each of these forms sets the same time limit:
To set several parameters at once, use
model.setParams(TimeLimit=120, OptimalityTol=1e-6).
C parameter names are also accepted:
Read or reset parameters with:
setParams validates every update before applying any of them. model.Params
is a live parameter view that supports attribute and item access, iteration,
and keys(), values(), and items().
An unknown name raises KeyError, a value of the wrong type raises
TypeError, and a value outside its allowed range raises ValueError. See the
parameter reference.
Update model data¶
Update model data by assigning properties or calling setter methods. Arrays returned by model properties are read-only; assign a new array instead of modifying individual entries in place:
model.c = new_objective
model.A = new_constraint_matrix
model.lb = new_variable_lower_bounds
model.ub = new_variable_upper_bounds
model.setObjectiveConstant(2.0)
model.setConstraintLowerBound(new_l)
model.setConstraintUpperBound(new_u)
| Property | Type | Validating setter |
|---|---|---|
c |
numpy.ndarrayshape (n,) |
setObjectiveVector(c) |
c0 |
float |
setObjectiveConstant(c0) |
A |
NumPy array or CSR matrix shape (m,n) |
setConstraintMatrix(A) |
constr_lb |
numpy.ndarray or Noneshape (m,) |
setConstraintLowerBound(lower) |
constr_ub |
numpy.ndarray or Noneshape (m,) |
setConstraintUpperBound(upper) |
lb |
numpy.ndarray or Noneshape (n,) |
setVariableLowerBound(lower) |
ub |
numpy.ndarray or Noneshape (n,) |
setVariableUpperBound(upper) |
ModelSense |
int |
Assign PDLP.MINIMIZE or PDLP.MAXIMIZE. |
num_vars |
int |
— |
num_constrs |
int |
— |
Changing model data clears the cached solution. The number of variables is
fixed at construction. To change the number of constraints, clear the
constraint bounds, replace A, and set new bounds with matching lengths.
Warm start¶
To warm-start the solver, disable presolve and provide a primal vector, a dual vector, or both:
Omitting an argument preserves its previous starting vector. Passing None
clears it:
The primal vector must have length model.num_vars; the dual vector must have
length model.num_constrs. A length mismatch or nonfinite value raises
ValueError.