-
Notifications
You must be signed in to change notification settings - Fork 104
Add constraints and warm start dual simplex from current basis #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5205471
0584337
74fff99
099a1df
1882892
96ed386
6ff7952
20b5777
ca571a0
9dea7ce
42af00c
3c36836
369e755
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1108,6 +1108,212 @@ i_t basis_update_t<i_t, f_t>::lower_triangular_multiply(const csc_matrix_t<i_t, | |
| return new_nz; | ||
| } | ||
|
|
||
| // Start of middle product form: basis_update_mpf_t | ||
|
|
||
| template <typename i_t, typename f_t> | ||
| i_t basis_update_mpf_t<i_t, f_t>::append_cuts(const csr_matrix_t<i_t, f_t>& cuts_basic) | ||
| { | ||
| const i_t m = L0_.m; | ||
|
|
||
| // Solve for U^T W^T = C_B^T | ||
| // We do this one row at a time of C_B | ||
| csc_matrix_t<i_t, f_t> WT(m, cuts_basic.m, 0); | ||
|
|
||
| i_t WT_nz = 0; | ||
| for (i_t k = 0; k < cuts_basic.m; k++) { | ||
| sparse_vector_t<i_t, f_t> rhs(cuts_basic, k); | ||
| u_transpose_solve(rhs); | ||
| WT.col_start[k] = WT_nz; | ||
| for (i_t q = 0; q < rhs.i.size(); q++) { | ||
| WT.i.push_back(rhs.i[q]); | ||
| WT.x.push_back(rhs.x[q]); | ||
| WT_nz++; | ||
| } | ||
| } | ||
| WT.col_start[cuts_basic.m] = WT_nz; | ||
|
|
||
|
|
||
| #ifdef CHECK_W | ||
| { | ||
| for (i_t k = 0; k < cuts_basic.m; k++) { | ||
| std::vector<f_t> WT_col(m, 0.0); | ||
| WT.load_a_column(k, WT_col); | ||
| std::vector<f_t> CBT_col(m, 0.0); | ||
| matrix_transpose_vector_multiply(U0_, 1.0, WT_col, 0.0, CBT_col); | ||
| sparse_vector_t<i_t, f_t> CBT_col_sparse(cuts_basic, k); | ||
| std::vector<f_t> CBT_col_dense(m); | ||
| CBT_col_sparse.to_dense(CBT_col_dense); | ||
| for (i_t h = 0; h < m; h++) { | ||
| if (std::abs(CBT_col_dense[h] - CBT_col[h]) > 1e-6) { | ||
| printf("col %d CBT_col_dense[%d] = %e CBT_col[%d] = %e\n", k, h, CBT_col_dense[h], h, CBT_col[h]); | ||
| exit(1); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
|
|
||
| csc_matrix_t<i_t, f_t> V(cuts_basic.m, m, 0); | ||
| if (num_updates_ > 0) { | ||
| // W = V T_0 ... T_{num_updates_ - 1} | ||
| // or V = W T_{num_updates_ - 1}^{-1} ... T_0^{-1} | ||
| // or V^T = T_0^{-T} ... T_{num_updates_ - 1}^{-T} W^T | ||
| // We can compute V^T column by column so that we have | ||
| // V^T(:, h) = T_0^{-T} ... T_{num_updates_ - 1}^{-T} W^T(:, h) | ||
| // or | ||
| // V(h, :) = T_0^{-T} ... T_{num_updates_ - 1}^{-T} W^T(:, h) | ||
| // So we can form V row by row in CSR and then covert it to CSC | ||
| // for appending to L0 | ||
|
|
||
| csr_matrix_t<i_t, f_t> V_row(cuts_basic.m, m, 0); | ||
| i_t V_nz = 0; | ||
| const f_t zero_tol = 1e-13; | ||
| for (i_t h = 0; h < cuts_basic.m; h++) { | ||
| sparse_vector_t rhs(WT, h); | ||
| scatter_into_workspace(rhs); | ||
| i_t nz = rhs.i.size(); | ||
| for (i_t k = num_updates_ - 1; k >= 0; --k) { | ||
| // T_k^{-T} = ( I - v u^T/(1 + u^T v)) | ||
| // T_k^{-T} * b = b - v * (u^T * b) / (1 + u^T * v) = b - theta * v, theta = u^T b / mu | ||
|
|
||
| const i_t u_col = 2 * k; | ||
| const i_t v_col = 2 * k + 1; | ||
| const f_t mu = mu_values_[k]; | ||
|
|
||
| // dot = u^T * b | ||
| f_t dot = dot_product(u_col, xi_workspace_, x_workspace_); | ||
| const f_t theta = dot / mu; | ||
| if (std::abs(theta) > zero_tol) { | ||
| add_sparse_column(S_, v_col, -theta, xi_workspace_, nz, x_workspace_); | ||
| } | ||
| } | ||
| gather_into_sparse_vector(nz, rhs); | ||
| V_row.row_start[h] = V_nz; | ||
| for (i_t q = 0; q < rhs.i.size(); q++) { | ||
| V_row.j.push_back(rhs.i[q]); | ||
| V_row.x.push_back(rhs.x[q]); | ||
| V_nz++; | ||
| } | ||
| } | ||
| V_row.row_start[cuts_basic.m] = V_nz; | ||
|
|
||
| V_row.to_compressed_col(V); | ||
|
|
||
|
|
||
| #ifdef CHECK_V | ||
| csc_matrix_t<i_t, f_t> CB_col(cuts_basic.m, m, 0); | ||
| cuts_basic.to_compressed_col(CB_col); | ||
| for (i_t k = 0; k < m; k++) { | ||
| std::vector<f_t> U_col(m, 0.0); | ||
| U0_.load_a_column(k, U_col); | ||
| for (i_t h = num_updates_ - 1; h >= 0; --h) { | ||
| // T_h = ( I + u_h v_h^T) | ||
| // T_h * x = x + u_h * v_h^T * x = x + theta * u_h | ||
| const i_t u_col = 2 * h; | ||
| const i_t v_col = 2 * h + 1; | ||
| f_t theta = dot_product(v_col, U_col); | ||
| const i_t col_start = S_.col_start[u_col]; | ||
| const i_t col_end = S_.col_start[u_col + 1]; | ||
| for (i_t p = col_start; p < col_end; ++p) { | ||
| const i_t i = S_.i[p]; | ||
| U_col[i] += theta * S_.x[p]; | ||
| } | ||
| } | ||
| std::vector<f_t> CB_column(cuts_basic.m, 0.0); | ||
| matrix_vector_multiply(V, 1.0, U_col, 0.0, CB_column); | ||
| std::vector<f_t> CB_col_dense(cuts_basic.m); | ||
| CB_col.load_a_column(k, CB_col_dense); | ||
| for (i_t l = 0; l < cuts_basic.m; l++) { | ||
| if (std::abs(CB_col_dense[l] - CB_column[l]) > 1e-6) { | ||
| printf("col %d CB_col_dense[%d] = %e CB_column[%d] = %e\n", k, l, CB_col_dense[l], l, CB_column[l]); | ||
| exit(1); | ||
| } | ||
| } | ||
| } | ||
| #endif | ||
| } else { | ||
| // W = V | ||
| WT.transpose(V); | ||
| } | ||
|
|
||
| // Extend u_i, v_i for i = 0, ..., num_updates_ - 1 | ||
| S_.m += cuts_basic.m; | ||
|
|
||
| // Adjust L and U | ||
| // L = [ L0 0 ] | ||
| // [ V I ] | ||
|
|
||
| i_t V_nz = V.col_start[m]; | ||
| i_t L_nz = L0_.col_start[m]; | ||
| csc_matrix_t<i_t, f_t> new_L(m + cuts_basic.m, m + cuts_basic.m, L_nz + V_nz + cuts_basic.m); | ||
| i_t predicted_nz = L_nz + V_nz + cuts_basic.m; | ||
| L_nz = 0; | ||
| for (i_t j = 0; j < m; ++j) { | ||
| new_L.col_start[j] = L_nz; | ||
| const i_t col_start = L0_.col_start[j]; | ||
| const i_t col_end = L0_.col_start[j + 1]; | ||
| for (i_t p = col_start; p < col_end; ++p) { | ||
| new_L.i[L_nz] = L0_.i[p]; | ||
| new_L.x[L_nz] = L0_.x[p]; | ||
| L_nz++; | ||
| } | ||
| const i_t V_col_start = V.col_start[j]; | ||
| const i_t V_col_end = V.col_start[j + 1]; | ||
| for (i_t p = V_col_start; p < V_col_end; ++p) { | ||
| new_L.i[L_nz] = V.i[p] + m; | ||
| new_L.x[L_nz] = V.x[p]; | ||
| L_nz++; | ||
| } | ||
| } | ||
| for (i_t j = m; j < m + cuts_basic.m; ++j) { | ||
| new_L.col_start[j] = L_nz; | ||
| new_L.i[L_nz] = j; | ||
| new_L.x[L_nz] = 1.0; | ||
| L_nz++; | ||
| } | ||
| new_L.col_start[m + cuts_basic.m] = L_nz; | ||
| if (L_nz != predicted_nz) { | ||
| printf("L_nz %d predicted_nz %d\n", L_nz, predicted_nz); | ||
| exit(1); | ||
| } | ||
|
Comment on lines
+1275
to
+1278
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Critical: This if (L_nz != predicted_nz) {
- printf("L_nz %d predicted_nz %d\n", L_nz, predicted_nz);
- exit(1);
+ // Internal consistency check failed - this indicates a bug in append_cuts logic
+ return -1; // Signal error to caller
}
🤖 Prompt for AI Agents |
||
|
|
||
| L0_ = new_L; | ||
|
|
||
| // Adjust U | ||
| // U = [ U0 0 ] | ||
| // [ 0 I ] | ||
|
|
||
| i_t U_nz = U0_.col_start[m]; | ||
| U0_.col_start.resize(m + cuts_basic.m + 1); | ||
| U0_.i.resize(U_nz + cuts_basic.m); | ||
| U0_.x.resize(U_nz + cuts_basic.m); | ||
| for (i_t k = m; k < m + cuts_basic.m; ++k) { | ||
| U0_.col_start[k] = U_nz; | ||
| U0_.i[U_nz] = k; | ||
| U0_.x[U_nz] = 1.0; | ||
| U_nz++; | ||
| } | ||
| U0_.col_start[m + cuts_basic.m] = U_nz; | ||
| U0_.n = m + cuts_basic.m; | ||
| U0_.m = m + cuts_basic.m; | ||
|
|
||
| compute_transposes(); | ||
|
|
||
| // Adjust row_permutation_ and inverse_row_permutation_ | ||
| row_permutation_.resize(m + cuts_basic.m); | ||
| inverse_row_permutation_.resize(m + cuts_basic.m); | ||
| for (i_t k = m; k < m + cuts_basic.m; ++k) { | ||
| row_permutation_[k] = k; | ||
| } | ||
| inverse_permutation(row_permutation_, inverse_row_permutation_); | ||
|
|
||
| // Adjust workspace sizes | ||
| xi_workspace_.resize(2 * (m + cuts_basic.m), 0); | ||
| x_workspace_.resize(m + cuts_basic.m, 0.0); | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| template <typename i_t, typename f_t> | ||
| void basis_update_mpf_t<i_t, f_t>::gather_into_sparse_vector(i_t nz, | ||
| sparse_vector_t<i_t, f_t>& out) const | ||
|
|
@@ -2061,7 +2267,7 @@ int basis_update_mpf_t<i_t, f_t>::refactor_basis( | |
| q, | ||
| deficient, | ||
| slacks_needed) == -1) { | ||
| settings.log.debug("Initial factorization failed\n"); | ||
| settings.log.printf("Initial factorization failed\n"); | ||
| basis_repair(A, settings, deficient, slacks_needed, basic_list, nonbasic_list, vstatus); | ||
|
|
||
| #ifdef CHECK_BASIS_REPAIR | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add template arguments to
sparse_vector_tconstruction@basis_update_mpf_t<i_t, f_t>::append_cutswon’t compile as written becausesparse_vector_tis a class template—there’s no deduction guide for the(WT, h)constructor, so the compiler can’t inferi_t/f_t. Please instantiate the template explicitly.📝 Committable suggestion
🤖 Prompt for AI Agents