From ee63c643e6eda4a60236da6f6458a974c8cafa3f Mon Sep 17 00:00:00 2001 From: Zedong Peng Date: Sat, 3 Jan 2026 22:34:01 -0500 Subject: [PATCH 1/4] update PSLP to 0.0.4 and fix the primal objective value bug --- CMakeLists.txt | 2 +- src/presolve.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cb97822..b4682d6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -77,7 +77,7 @@ endif() include(FetchContent) -set(PSLP_VERSION_TAG "v0.0.3") +set(PSLP_VERSION_TAG "v0.0.4") FetchContent_Declare( pslp diff --git a/src/presolve.c b/src/presolve.c index 9396c19..fa9477b 100644 --- a/src/presolve.c +++ b/src/presolve.c @@ -169,8 +169,7 @@ void pslp_postsolve(cupdlpx_presolve_info_t *info, postsolve(info->presolver, result->primal_solution, result->dual_solution, - result->reduced_cost, - result->primal_objective_value); + result->reduced_cost); result->num_reduced_variables = info->presolver->reduced_prob->n; result->num_reduced_constraints = info->presolver->reduced_prob->m; From 522dc1afd2f7ab95c902a6645cc0ac1ad566537a Mon Sep 17 00:00:00 2001 From: Zedong Peng Date: Sat, 3 Jan 2026 22:40:27 -0500 Subject: [PATCH 2/4] update to v0.2.3 --- CMakeLists.txt | 2 +- src/presolve.c | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b4682d6..0f22cdf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(cupdlpx LANGUAGES C CXX CUDA) set(CUPDLPX_VERSION_MAJOR 0) set(CUPDLPX_VERSION_MINOR 2) -set(CUPDLPX_VERSION_PATCH 2) +set(CUPDLPX_VERSION_PATCH 3) set(CUPDLPX_VERSION "${CUPDLPX_VERSION_MAJOR}.${CUPDLPX_VERSION_MINOR}.${CUPDLPX_VERSION_PATCH}") add_compile_definitions(CUPDLPX_VERSION="${CUPDLPX_VERSION}") diff --git a/src/presolve.c b/src/presolve.c index fa9477b..9e81d77 100644 --- a/src/presolve.c +++ b/src/presolve.c @@ -183,7 +183,6 @@ void pslp_postsolve(cupdlpx_presolve_info_t *info, memcpy(result->primal_solution, info->presolver->sol->x, original_prob->num_variables * sizeof(double)); memcpy(result->dual_solution, info->presolver->sol->y, original_prob->num_constraints * sizeof(double)); memcpy(result->reduced_cost, info->presolver->sol->z, original_prob->num_variables * sizeof(double)); - // result->primal_objective_value = info->presolver->sol->obj; // This is a bug in PSLP. We don't need to updated primal_objective_value since offset has been updated during presolve. Therefore, the original problem and reduced problem have the same objective value. result->presolve_time = info->presolve_time; // if (info->presolver->stats != NULL) { // result->presolve_stats = *(info->presolver->stats); From 8dc558388edce6be216be7b426f94ae040debd12 Mon Sep 17 00:00:00 2001 From: Zedong Peng Date: Mon, 12 Jan 2026 20:09:25 -0500 Subject: [PATCH 3/4] fix instance solved during presolve issue --- internal/presolve.h | 2 +- src/presolve.c | 52 ++++++++++++++++++++++++++++----------------- 2 files changed, 34 insertions(+), 20 deletions(-) diff --git a/internal/presolve.h b/internal/presolve.h index 71b5d1e..a852cef 100644 --- a/internal/presolve.h +++ b/internal/presolve.h @@ -26,7 +26,7 @@ extern "C" const char *get_presolve_status_str(enum PresolveStatus_ status); - void pslp_postsolve(cupdlpx_presolve_info_t *info, + void pslp_postsolve(const cupdlpx_presolve_info_t *info, cupdlpx_result_t *reduced_result, const lp_problem_t *original_prob); diff --git a/src/presolve.c b/src/presolve.c index 9e81d77..2858745 100644 --- a/src/presolve.c +++ b/src/presolve.c @@ -100,9 +100,14 @@ cupdlpx_presolve_info_t *pslp_presolve(const lp_problem_t *original_prob, const { printf(" %-15s : %s\n", "status", get_presolve_status_str(status)); printf(" %-15s : %.3g sec\n", "presolve time", info->presolve_time); + printf(" %-15s : %d rows, %d columns, %d nonzeros\n", + "reduced problem", + info->presolver->reduced_prob->m, + info->presolver->reduced_prob->n, + info->presolver->reduced_prob->nnz); } - if (status & INFEASIBLE || status & UNBNDORINFEAS) + if (status & INFEASIBLE || status & UNBNDORINFEAS || info->presolver->reduced_prob->n == 0) { info->problem_solved_during_presolve = true; info->reduced_problem = NULL; @@ -110,14 +115,6 @@ cupdlpx_presolve_info_t *pslp_presolve(const lp_problem_t *original_prob, const else { info->problem_solved_during_presolve = false; - if (params->verbose) - { - printf(" %-15s : %d rows, %d columns, %d nonzeros\n", - "reduced problem", - info->presolver->reduced_prob->m, - info->presolver->reduced_prob->n, - info->presolver->reduced_prob->nnz); - } info->reduced_problem = convert_pslp_to_cupdlpx(info->presolver->reduced_prob); } return info; @@ -127,6 +124,14 @@ cupdlpx_result_t *create_result_from_presolve(const cupdlpx_presolve_info_t *inf { cupdlpx_result_t *result = (cupdlpx_result_t *)safe_calloc(1, sizeof(cupdlpx_result_t)); + result->num_variables = original_prob->num_variables; + result->num_constraints = original_prob->num_constraints; + result->num_nonzeros = original_prob->constraint_matrix_num_nonzeros; + result->num_reduced_variables = info->presolver->reduced_prob->n; + result->num_reduced_constraints = info->presolver->reduced_prob->m; + result->num_reduced_nonzeros = info->presolver->reduced_prob->nnz; + result->presolve_status = info->presolve_status; + result->presolve_time = info->presolve_time; if (info->presolve_status == INFEASIBLE) { @@ -136,20 +141,17 @@ cupdlpx_result_t *create_result_from_presolve(const cupdlpx_presolve_info_t *inf { result->termination_reason = TERMINATION_REASON_INFEASIBLE_OR_UNBOUNDED; } + else if (info->presolver->reduced_prob->n == 0) + { + result->termination_reason = TERMINATION_REASON_OPTIMAL; + pslp_postsolve(info, result, original_prob); + return result; + } else { result->termination_reason = TERMINATION_REASON_UNSPECIFIED; } - result->num_variables = original_prob->num_variables; - result->num_constraints = original_prob->num_constraints; - result->num_nonzeros = original_prob->constraint_matrix_num_nonzeros; - result->num_reduced_variables = info->presolver->reduced_prob->n; - result->num_reduced_constraints = info->presolver->reduced_prob->m; - result->num_reduced_nonzeros = info->presolver->reduced_prob->nnz; - result->presolve_status = info->presolve_status; - result->presolve_time = info->presolve_time; // result->presolve_stats = *(info->presolver->stats); - // TODO: Verify if setting solution pointers to NULL affects Python/Julia bindings. if (result->num_variables > 0) { result->primal_solution = (double *)safe_calloc(result->num_variables, sizeof(double)); @@ -162,7 +164,7 @@ cupdlpx_result_t *create_result_from_presolve(const cupdlpx_presolve_info_t *inf return result; } -void pslp_postsolve(cupdlpx_presolve_info_t *info, +void pslp_postsolve(const cupdlpx_presolve_info_t *info, cupdlpx_result_t *result, const lp_problem_t *original_prob) { @@ -184,9 +186,21 @@ void pslp_postsolve(cupdlpx_presolve_info_t *info, memcpy(result->dual_solution, info->presolver->sol->y, original_prob->num_constraints * sizeof(double)); memcpy(result->reduced_cost, info->presolver->sol->z, original_prob->num_variables * sizeof(double)); result->presolve_time = info->presolve_time; + if (info->presolver->reduced_prob->n == 0) + { + double obj = 0.0; + for (int i = 0; i < original_prob->num_variables; i++) + { + obj += original_prob->objective_vector[i] * result->primal_solution[i]; + } + obj += original_prob->objective_constant; + result->primal_objective_value = obj; + result->dual_objective_value = obj; + } // if (info->presolver->stats != NULL) { // result->presolve_stats = *(info->presolver->stats); // } + return; } void cupdlpx_presolve_info_free(cupdlpx_presolve_info_t *info) From 9a00b0c55d3dc62db943ed7f55254da10c09fa20 Mon Sep 17 00:00:00 2001 From: Zedong Peng Date: Mon, 12 Jan 2026 21:01:20 -0500 Subject: [PATCH 4/4] add cudaGetLastError at end --- src/solver.cu | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solver.cu b/src/solver.cu index 3e61fad..46245f7 100644 --- a/src/solver.cu +++ b/src/solver.cu @@ -197,6 +197,7 @@ cupdlpx_result_t *optimize(const pdhg_parameters_t *params, pdhg_final_log(result, params); pdhg_solver_state_free(state); + CUDA_CHECK(cudaGetLastError()); return result; }