From 0d1a2aef9fdb42c2a7a7c389a397e0208b0e63c1 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Tue, 7 Oct 2025 14:23:05 -0700 Subject: [PATCH 1/4] Fix post-solve crash on physicansched6-2 --- cpp/src/dual_simplex/presolve.cpp | 101 +++++++++++++++++------------- cpp/src/dual_simplex/presolve.hpp | 1 + cpp/src/dual_simplex/solve.cpp | 2 + 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/cpp/src/dual_simplex/presolve.cpp b/cpp/src/dual_simplex/presolve.cpp index b9351a9a77..035870726f 100644 --- a/cpp/src/dual_simplex/presolve.cpp +++ b/cpp/src/dual_simplex/presolve.cpp @@ -1411,6 +1411,7 @@ void uncrush_dual_solution(const user_problem_t& user_problem, template void uncrush_solution(const presolve_info_t& presolve_info, + const simplex_solver_settings_t& settings, const std::vector& crushed_x, const std::vector& crushed_y, const std::vector& crushed_z, @@ -1452,15 +1453,15 @@ void uncrush_solution(const presolve_info_t& presolve_info, matrix_transpose_vector_multiply(presolve_info.folding_info.C_s, 1.0, crushed_y, 0.0, ytilde); matrix_transpose_vector_multiply(presolve_info.folding_info.D_s, 1.0, crushed_z, 0.0, ztilde); - printf("|| y ||_2 = %e\n", vector_norm2(ytilde)); - printf("|| z ||_2 = %e\n", vector_norm2(ztilde)); + settings.log.debug("|| y ||_2 = %e\n", vector_norm2(ytilde)); + settings.log.debug("|| z ||_2 = %e\n", vector_norm2(ztilde)); std::vector dual_residual(previous_cols); for (i_t j = 0; j < previous_cols; j++) { dual_residual[j] = ztilde[j] - presolve_info.folding_info.c_tilde[j]; } matrix_transpose_vector_multiply( presolve_info.folding_info.A_tilde, 1.0, ytilde, 1.0, dual_residual); - printf("Unfolded dual residual = %e\n", vector_norm_inf(dual_residual)); + settings.log.printf("Unfolded dual residual = %e\n", vector_norm_inf(dual_residual)); // Now we need to map the solution back to the original problem // minimize c^T x @@ -1475,74 +1476,83 @@ void uncrush_solution(const presolve_info_t& presolve_info, input_z.resize(previous_cols - presolve_info.folding_info.num_upper_bounds); } - if (presolve_info.removed_constraints.size() == 0) { - uncrushed_y = input_y; - } else { - printf("Handling removed constraints %d\n", presolve_info.removed_constraints.size()); - // We removed some constraints, so we need to map the crushed solution back to the original - // constraints - const i_t m = - presolve_info.removed_constraints.size() + presolve_info.remaining_constraints.size(); - uncrushed_y.resize(m); - - i_t k = 0; - for (const i_t i : presolve_info.remaining_constraints) { - uncrushed_y[i] = input_y[k]; - k++; - } - for (const i_t i : presolve_info.removed_constraints) { - uncrushed_y[i] = 0.0; + const i_t num_free_variables = presolve_info.free_variable_pairs.size() / 2; + if (num_free_variables > 0) { + settings.log.printf("Post-solve: Handling free variables %d\n", num_free_variables); + // We added free variables so we need to map the crushed solution back to the original variables + for (i_t k = 0; k < 2 * num_free_variables; k += 2) { + const i_t u = presolve_info.free_variable_pairs[k]; + const i_t v = presolve_info.free_variable_pairs[k + 1]; + input_x[u] -= input_x[v]; } + input_z.resize(input_z.size() - num_free_variables); + input_x.resize(input_x.size() - num_free_variables); } - if (presolve_info.removed_variables.size() == 0) { - uncrushed_x = input_x; - uncrushed_z = input_z; - } else { - printf("Handling removed variables %d\n", presolve_info.removed_variables.size()); + if (presolve_info.removed_variables.size() > 0) { + settings.log.printf("Post-solve: Handling removed variables %d\n", presolve_info.removed_variables.size()); // We removed some variables, so we need to map the crushed solution back to the original // variables const i_t n = presolve_info.removed_variables.size() + presolve_info.remaining_variables.size(); - uncrushed_x.resize(n); - uncrushed_z.resize(n); + std::vector input_x_copy = input_x; + std::vector input_z_copy = input_z; + input_x_copy.resize(n); + input_z_copy.resize(n); i_t k = 0; for (const i_t j : presolve_info.remaining_variables) { - uncrushed_x[j] = input_x[k]; - uncrushed_z[j] = input_z[k]; + input_x_copy[j] = input_x[k]; + input_z_copy[j] = input_z[k]; k++; } k = 0; for (const i_t j : presolve_info.removed_variables) { - uncrushed_x[j] = presolve_info.removed_values[k]; - uncrushed_z[j] = presolve_info.removed_reduced_costs[k]; + input_x_copy[j] = presolve_info.removed_values[k]; + input_z_copy[j] = presolve_info.removed_reduced_costs[k]; k++; } + input_x = input_x_copy; + input_z = input_z_copy; } - const i_t num_free_variables = presolve_info.free_variable_pairs.size() / 2; - if (num_free_variables > 0) { - printf("Handling free variables %d\n", num_free_variables); - // We added free variables so we need to map the crushed solution back to the original variables - for (i_t k = 0; k < 2 * num_free_variables; k += 2) { - const i_t u = presolve_info.free_variable_pairs[k]; - const i_t v = presolve_info.free_variable_pairs[k + 1]; - uncrushed_x[u] -= uncrushed_x[v]; + if (presolve_info.removed_constraints.size() > 0) { + settings.log.printf("Post-solve: Handling removed constraints %d\n", presolve_info.removed_constraints.size()); + // We removed some constraints, so we need to map the crushed solution back to the original + // constraints + const i_t m = + presolve_info.removed_constraints.size() + presolve_info.remaining_constraints.size(); + std::vector input_y_copy = input_y; + input_y_copy.resize(m); + + i_t k = 0; + for (const i_t i : presolve_info.remaining_constraints) { + input_y_copy[i] = input_y[k]; + k++; } - const i_t n = uncrushed_x.size(); - uncrushed_x.resize(n - num_free_variables); - uncrushed_z.resize(n - num_free_variables); + for (const i_t i : presolve_info.removed_constraints) { + input_y_copy[i] = 0.0; + } + input_y = input_y_copy; } + + if (presolve_info.removed_lower_bounds.size() > 0) { - printf("Handling removed lower bounds %d\n", presolve_info.removed_lower_bounds.size()); + settings.log.printf("Post-solve: Handling removed lower bounds %d\n", presolve_info.removed_lower_bounds.size()); // We removed some lower bounds so we need to map the crushed solution back to the original // variables - for (i_t j = 0; j < uncrushed_x.size(); j++) { - uncrushed_x[j] += presolve_info.removed_lower_bounds[j]; + for (i_t j = 0; j < input_x.size(); j++) { + input_x[j] += presolve_info.removed_lower_bounds[j]; } } + assert(uncrushed_x.size() == input_x.size()); + assert(uncrushed_y.size() == input_y.size()); + assert(uncrushed_z.size() == input_z.size()); + + uncrushed_x = input_x; + uncrushed_y = input_y; + uncrushed_z = input_z; } #ifdef DUAL_SIMPLEX_INSTANTIATE_DOUBLE @@ -1585,6 +1595,7 @@ template void uncrush_dual_solution(const user_problem_t& user_z); template void uncrush_solution(const presolve_info_t& presolve_info, + const simplex_solver_settings_t& settings, const std::vector& crushed_x, const std::vector& crushed_y, const std::vector& crushed_z, diff --git a/cpp/src/dual_simplex/presolve.hpp b/cpp/src/dual_simplex/presolve.hpp index cdf0aaac0f..fa8a8db58b 100644 --- a/cpp/src/dual_simplex/presolve.hpp +++ b/cpp/src/dual_simplex/presolve.hpp @@ -180,6 +180,7 @@ void uncrush_dual_solution(const user_problem_t& user_problem, template void uncrush_solution(const presolve_info_t& presolve_info, + const simplex_solver_settings_t& settings, const std::vector& crushed_x, const std::vector& crushed_y, const std::vector& crushed_z, diff --git a/cpp/src/dual_simplex/solve.cpp b/cpp/src/dual_simplex/solve.cpp index 8584e3d802..dadb60cc6b 100644 --- a/cpp/src/dual_simplex/solve.cpp +++ b/cpp/src/dual_simplex/solve.cpp @@ -208,6 +208,7 @@ lp_status_t solve_linear_program_advanced(const lp_problem_t& original std::vector unscaled_z(lp.num_cols); unscale_solution(column_scales, solution.x, solution.z, unscaled_x, unscaled_z); uncrush_solution(presolve_info, + settings, unscaled_x, solution.y, unscaled_z, @@ -324,6 +325,7 @@ lp_status_t solve_linear_program_with_barrier(const user_problem_t& us // Undo presolve uncrush_solution(presolve_info, + barrier_settings, unscaled_x, barrier_solution.y, unscaled_z, From eb140d1ad09b2687bc30a5a0245d9790a2aed2e5 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Tue, 7 Oct 2025 14:24:36 -0700 Subject: [PATCH 2/4] Fix style --- cpp/src/dual_simplex/presolve.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cpp/src/dual_simplex/presolve.cpp b/cpp/src/dual_simplex/presolve.cpp index 035870726f..e2790858e3 100644 --- a/cpp/src/dual_simplex/presolve.cpp +++ b/cpp/src/dual_simplex/presolve.cpp @@ -1490,7 +1490,8 @@ void uncrush_solution(const presolve_info_t& presolve_info, } if (presolve_info.removed_variables.size() > 0) { - settings.log.printf("Post-solve: Handling removed variables %d\n", presolve_info.removed_variables.size()); + settings.log.printf("Post-solve: Handling removed variables %d\n", + presolve_info.removed_variables.size()); // We removed some variables, so we need to map the crushed solution back to the original // variables const i_t n = presolve_info.removed_variables.size() + presolve_info.remaining_variables.size(); @@ -1517,7 +1518,8 @@ void uncrush_solution(const presolve_info_t& presolve_info, } if (presolve_info.removed_constraints.size() > 0) { - settings.log.printf("Post-solve: Handling removed constraints %d\n", presolve_info.removed_constraints.size()); + settings.log.printf("Post-solve: Handling removed constraints %d\n", + presolve_info.removed_constraints.size()); // We removed some constraints, so we need to map the crushed solution back to the original // constraints const i_t m = @@ -1536,10 +1538,9 @@ void uncrush_solution(const presolve_info_t& presolve_info, input_y = input_y_copy; } - - if (presolve_info.removed_lower_bounds.size() > 0) { - settings.log.printf("Post-solve: Handling removed lower bounds %d\n", presolve_info.removed_lower_bounds.size()); + settings.log.printf("Post-solve: Handling removed lower bounds %d\n", + presolve_info.removed_lower_bounds.size()); // We removed some lower bounds so we need to map the crushed solution back to the original // variables for (i_t j = 0; j < input_x.size(); j++) { From 08cbac2da1ce44cdaf8151137f52c6b97335f3f2 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Tue, 7 Oct 2025 17:13:12 -0700 Subject: [PATCH 3/4] Fix UMA on problems where row nz greater than number of rows --- cpp/src/dual_simplex/barrier.cu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/src/dual_simplex/barrier.cu b/cpp/src/dual_simplex/barrier.cu index 62ccde07e4..95ce9fce69 100644 --- a/cpp/src/dual_simplex/barrier.cu +++ b/cpp/src/dual_simplex/barrier.cu @@ -1028,7 +1028,7 @@ class iteration_data_t { } } - std::vector histogram_row(m, 0); + std::vector histogram_row(n, 0); max_row_nz = 0; for (i_t k = 0; k < m; k++) { histogram_row[row_nz[k]]++; From e2449a9a68ce76594bdb4c7a5d5fcf6c861026c3 Mon Sep 17 00:00:00 2001 From: Christopher Maes Date: Tue, 7 Oct 2025 17:45:01 -0700 Subject: [PATCH 4/4] Fix undefined reference due to realloc of colors from emplace_back --- cpp/src/dual_simplex/folding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/src/dual_simplex/folding.cpp b/cpp/src/dual_simplex/folding.cpp index fe202647bd..913d86b0aa 100644 --- a/cpp/src/dual_simplex/folding.cpp +++ b/cpp/src/dual_simplex/folding.cpp @@ -521,7 +521,7 @@ i_t color_graph(const csc_matrix_t& A, // See if we need to split the column colors for (i_t color : colors_to_split) { split_colors(color, - refining_color.color, + colors[refining_color_index].color, kCol, vertex_to_sum, color_sums, @@ -543,7 +543,7 @@ i_t color_graph(const csc_matrix_t& A, // See if we need to split the row colors for (i_t color : colors_to_split) { split_colors(color, - refining_color.color, + colors[refining_color_index].color, kRow, vertex_to_sum, color_sums,