From 5a819916421f8f1cc3589f1047c039ff9661f892 Mon Sep 17 00:00:00 2001 From: Bo Tang Date: Sun, 7 Jun 2026 14:10:23 -0400 Subject: [PATCH] Fix: handle MPS OBJSENSE MAXIMIZE in reader --- include/cupdlpx_types.h | 7 +++++++ internal/internal_types.h | 1 + src/mps_parser.c | 31 ++++++++++++++++++------------- src/presolve.c | 6 ++++-- src/solver.cu | 5 +++-- 5 files changed, 33 insertions(+), 17 deletions(-) diff --git a/include/cupdlpx_types.h b/include/cupdlpx_types.h index d874206..2d6e148 100644 --- a/include/cupdlpx_types.h +++ b/include/cupdlpx_types.h @@ -43,6 +43,12 @@ extern "C" NORM_TYPE_L_INF = 1 } norm_type_t; + typedef enum + { + OBJECTIVE_SENSE_MINIMIZE = 0, + OBJECTIVE_SENSE_MAXIMIZE = 1 + } objective_sense_t; + typedef struct { int num_variables; @@ -51,6 +57,7 @@ extern "C" double *variable_upper_bound; double *objective_vector; double objective_constant; + objective_sense_t objective_sense; int *constraint_matrix_row_pointers; int *constraint_matrix_col_indices; diff --git a/internal/internal_types.h b/internal/internal_types.h index 1302430..af577e2 100644 --- a/internal/internal_types.h +++ b/internal/internal_types.h @@ -43,6 +43,7 @@ typedef struct double *variable_upper_bound; double *objective_vector; double objective_constant; + double objective_sign; cu_sparse_matrix_csr_t *constraint_matrix; cu_sparse_matrix_csr_t *constraint_matrix_t; double *constraint_lower_bound; diff --git a/src/mps_parser.c b/src/mps_parser.c index c37687e..e36f1a8 100644 --- a/src/mps_parser.c +++ b/src/mps_parser.c @@ -326,7 +326,7 @@ typedef struct char *objective_row_name; char *current_col_name; double objective_constant; - bool is_maximize; + objective_sense_t objective_sense; int error_flag; } MpsParserState; @@ -454,17 +454,20 @@ lp_problem_t *read_mps_file(const char *filename) next_section = SEC_ENDATA; } - if (current_section == SEC_ROWS && next_section != SEC_ROWS && !rows_finalized) + if (next_section != SEC_NONE) { - if (finalize_rows(&state) != 0) - state.error_flag = 1; - rows_finalized = true; - } + if (current_section == SEC_ROWS && next_section != SEC_ROWS && !rows_finalized) + { + if (finalize_rows(&state) != 0) + state.error_flag = 1; + rows_finalized = true; + } - current_section = next_section; - if (current_section == SEC_ENDATA) - break; - continue; + current_section = next_section; + if (current_section == SEC_ENDATA) + break; + continue; + } } switch (current_section) @@ -472,7 +475,7 @@ lp_problem_t *read_mps_file(const char *filename) case SEC_OBJSENSE: if (n_tokens > 0 && (strcmp(tokens[0], "MAX") == 0 || strcmp(tokens[0], "MAXIMIZE") == 0)) { - state.is_maximize = true; + state.objective_sense = OBJECTIVE_SENSE_MAXIMIZE; } break; case SEC_ROWS: @@ -515,7 +518,9 @@ lp_problem_t *read_mps_file(const char *filename) prob->num_variables = state.col_map.size; prob->num_constraints = state.row_map.size; prob->constraint_matrix_num_nonzeros = state.coo_matrix.nnz; - prob->objective_constant = state.is_maximize ? -state.objective_constant : state.objective_constant; + prob->objective_constant = + (state.objective_sense == OBJECTIVE_SENSE_MAXIMIZE) ? -state.objective_constant : state.objective_constant; + prob->objective_sense = state.objective_sense; prob->objective_vector = state.objective_coeffs; prob->variable_lower_bound = state.var_lower_bounds; @@ -532,7 +537,7 @@ lp_problem_t *read_mps_file(const char *filename) state.constraint_lower_bounds = NULL; state.constraint_upper_bounds = NULL; - if (state.is_maximize) + if (state.objective_sense == OBJECTIVE_SENSE_MAXIMIZE) { for (int i = 0; i < prob->num_variables; ++i) { diff --git a/src/presolve.c b/src/presolve.c index 44b5437..ad5d613 100644 --- a/src/presolve.c +++ b/src/presolve.c @@ -39,6 +39,7 @@ lp_problem_t *convert_pslp_to_cupdlpx(PresolvedProblem *reduced_prob, const lp_p cupdlpx_prob->dual_start = NULL; cupdlpx_prob->objective_constant = original_prob->objective_constant + reduced_prob->obj_offset; + cupdlpx_prob->objective_sense = original_prob->objective_sense; cupdlpx_prob->objective_vector = reduced_prob->c; cupdlpx_prob->constraint_lower_bound = reduced_prob->lhs; @@ -216,8 +217,9 @@ void pslp_postsolve(const cupdlpx_presolve_info_t *info, cupdlpx_result_t *resul 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; + double objective_sign = (original_prob->objective_sense == OBJECTIVE_SENSE_MAXIMIZE) ? -1.0 : 1.0; + result->primal_objective_value = objective_sign * obj; + result->dual_objective_value = objective_sign * obj; } // if (info->presolver->stats != NULL) { // result->presolve_stats = *(info->presolver->stats); diff --git a/src/solver.cu b/src/solver.cu index 7ad9301..2160b5f 100644 --- a/src/solver.cu +++ b/src/solver.cu @@ -327,6 +327,7 @@ static pdhg_solver_state_t *initialize_solver_state(const lp_problem_t *working_ state->num_variables = n_vars; state->num_constraints = n_cons; state->objective_constant = working_problem->objective_constant; + state->objective_sign = (working_problem->objective_sense == OBJECTIVE_SENSE_MAXIMIZE) ? -1.0 : 1.0; state->constraint_matrix = (cu_sparse_matrix_csr_t *)safe_malloc(sizeof(cu_sparse_matrix_csr_t)); state->constraint_matrix_t = (cu_sparse_matrix_csr_t *)safe_malloc(sizeof(cu_sparse_matrix_csr_t)); @@ -1260,8 +1261,8 @@ static cupdlpx_result_t *create_result_from_state(pdhg_solver_state_t *state, co results->cumulative_time_sec = state->cumulative_time_sec; results->relative_primal_residual = state->relative_primal_residual; results->relative_dual_residual = state->relative_dual_residual; - results->primal_objective_value = state->primal_objective_value; - results->dual_objective_value = state->dual_objective_value; + results->primal_objective_value = state->objective_sign * state->primal_objective_value; + results->dual_objective_value = state->objective_sign * state->dual_objective_value; results->objective_gap = state->objective_gap; results->relative_objective_gap = state->relative_objective_gap; results->max_primal_ray_infeasibility = state->max_primal_ray_infeasibility;