Code for solving LP on GPU using first-order methods.
This is the C implementation of the Julia version cuPDLP.jl.
We use CMAKE to build CUPDLP. The current version is built on the Coin-OR CLP project. Please install the dependencies therein.
Once you setup CLP and CUDA, set the following environment variables.
export CLP_HOME=/path-to-clp
export COIN_HOME=/path-to-coinutils
export CUDA_HOME=/path-to-cudaYou can build the project with CUDA by setting -DBUILD_CUDA=ON (by default OFF, i.e., the CPU version):
- in the debug mode:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_CUDA=ON ..
cmake --build . --target plcthen you can find the binary plc in the folder build/bin/.
To build the python extension culpy:
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_CUDA=ON ..
cmake --build . --target culpythen you can find the dynamic library culpy.so/culpy.pyd in the folder build/lib/.
When using the release mode, we suggest the following options,
cmake -DBUILD_CUDA=ON \
-DCMAKE_C_FLAGS_RELEASE="-O2 -DNDEBUG" \
-DCMAKE_CXX_FLAGS_RELEASE="-O2 -DNDEBUG" \
-DCMAKE_CUDA_FLAGS_RELEASE="-O2 -DNDEBUG" ..
Usage example: set nIterLim to 5000 and solve.
./bin/plc -fname <mpsfile> -nIterLim 5000| Param | Type | Range | Default | Description |
|---|---|---|---|---|
fname |
str |
|
|
.mps or .mps.gz file of the LP instance |
fout |
str |
|
./solution.json |
.json file to save result |
savesol |
bool |
true, false |
false |
whether to write solution to .json output |
ifScaling |
bool |
true, false |
true |
Whether to use scaling |
ifRuizScaling |
bool |
true, false |
true |
Whether to use Ruiz scaling (10 times) |
ifL2Scaling |
bool |
true, false |
false |
Whether to use L2 scaling |
ifPcScaling |
bool |
true, false |
true |
Whether to use Pock-Chambolle scaling |
nIterLim |
int |
>=0 |
10000000 |
Maximum iteration number |
eLineSearchMethod |
int |
0-2 |
2 |
Choose line search: 0-fixed, 1-Malitsky, 2-Adaptive |
dPrimalTol |
double |
>=0 |
1e-4 |
Primal feasibility tolerance for termination |
dDualTol |
double |
>=0 |
1e-4 |
Dual feasibility tolerance for termination |
dGapTol |
double |
>=0 |
1e-4 |
Duality gap tolerance for termination |
dFeasTol |
double |
>=0 |
1e-8 |
Not used yet, maybe infeasibility tolerance |
dTimeLim |
double |
>0 |
3600 |
Time limit (in seconds) |
eRestartMethod |
int |
0-1 |
1 |
Choose restart: 0-none, 1-GPU |
Copy the lib culpy.so/culpy.pyd to (somewhere python can find). Then you can import culpy in Python. Currently there is only one function, solve, in culpy, whose signature is given by
def solve(
nRows: int, nCols: int, nnz: int, nEqs: int,
colMatBeg: np.ndarray, colMatIdx: np.ndarray, colMatElem: np.ndarray,
b: np.ndarray, c: np.ndarray, params: dict[str, float | int],
) -> Dict[str, Any]: ...A nRows x nCols sparse matrix (A) with nnz nonzero elements is given by colMatBeg, colMatIdx, colMatElem in CSC format. b should have length nRows and c should have length nCols. The first nEqs rows of A and b give the equation constraints, while the following (nRows - nEqs) rows give the inequality constraints. All parameters (except fname and fout) in the previous section could be overwrite in the params dict.
The result dictionary has the following items:
statusprimal_vars: Numpy array format.dual_vars: Numpy array format.pcostsolve_timesetup_timenum_iters
A simple example of calling culpy could be found in py/culpy_test.py.
We recommend utilize the culpy package via cvxpy rather than call solve directly.
Consider the generic linear programming problem:
Equivalently, we solve the following saddle-point problem,
where dual variables
Primal-Dual Hybrid Gradient (PDHG) algorithm takes the step as follows,
The termination criteria contain the primal feasibility, dual feasibility, and duality gap.
where
Dongdong Ge, Haodong Hu, Qi Huangfu, Jinsong Liu, Tianhao Liu, Haihao Lu, Jinwen Yang, Yinyu Ye, Chuwen Zhang
- Jinsong Liu <github.com/JinsongLiu6>
- Tianhao Liu <github.com/SkyLiu0>
- Chuwen Zhang <github.com/bzhangcw>