-
Notifications
You must be signed in to change notification settings - Fork 136
Add cuts to MIP solver #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
Changes from 5 commits
5205471
0584337
74fff99
099a1df
1882892
96ed386
6ff7952
20b5777
ca571a0
9dea7ce
42af00c
dddf42d
d97ff6b
f341e34
b8e9959
3c36836
369e755
b48e05b
78cb1dc
1e17743
ec883a0
3744548
f8e6fbe
6fc7e99
67b57c7
b704390
89dafc2
49bdd7f
f11838d
fb85947
62606f8
bfaf95c
be4e181
377ffb1
425f289
98a8c57
a2b845d
94a191f
1f09143
8635cc3
daeaba8
29e4797
34513c5
61e5a2c
8b9225a
2c68d94
89d73e7
5954aa0
350e0a7
121af29
59d4ac0
c52b065
7baff43
6c2f5f4
b5bbd3e
2d54a9d
ca4108f
392338a
cf23f6f
ac0fdf1
75dc6e5
b5345ec
cc60651
da36c56
a043f6d
a85361b
f22c49c
43be050
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++; | ||
| } | ||
| } | ||
coderabbitai[bot] marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| 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 | ||
|
Comment on lines
+1206
to
+1241
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. Replace Similar to the CHECK_W block, line 1237 calls 🔧 Suggested fix if (std::abs(CB_col_dense[l] - CB_column[l]) > 1e-6) {
printf("V: col %d CB_col_dense[%d] = %e CB_column[%d] = %e\n",
k,
l,
CB_col_dense[l],
l,
CB_column[l]);
- exit(1);
+ return -1; // Signal error to caller
}🤖 Prompt for AI Agents |
||
| } 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); | ||
| } | ||
chris-maes marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| 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; | ||
| } | ||
|
Comment on lines
+1111
to
+1323
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. Replace This is solver-core code and can run in multi-threaded contexts;
Sketch (convert hard exits to status returns)- 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);
+ settings.log.printf(
+ "append_cuts CHECK_W failed: col %d row %d expected %e got %e\n",
+ k, h, CBT_col_dense[h], CBT_col[h]);
+ return 1;
...
- printf("L_nz %d predicted_nz %d\n", L_nz, predicted_nz);
- exit(1);
+ settings.log.printf("append_cuts: L nnz mismatch %d predicted %d\n", L_nz, predicted_nz);
+ return 1;
|
||
|
|
||
| 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 | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.