Skip to content

Commit 181aef4

Browse files
committed
added a dual simplex method for calculating the phase 2 from an existing basis_update_mpf_t.
1 parent 1b0c32f commit 181aef4

File tree

4 files changed

+183
-60
lines changed

4 files changed

+183
-60
lines changed

cpp/src/dual_simplex/basis_updates.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
* limitations under the License.
1616
*/
1717

18+
#include <dual_simplex/basis_solves.hpp>
1819
#include <dual_simplex/basis_updates.hpp>
20+
#include <dual_simplex/initial_basis.hpp>
1921
#include <dual_simplex/triangle_solve.hpp>
2022

2123
#include <cmath>
@@ -2046,6 +2048,67 @@ void basis_update_mpf_t<i_t, f_t>::multiply_lu(csc_matrix_t<i_t, f_t>& out) cons
20462048
out.nz_max = B_nz;
20472049
}
20482050

2051+
template <typename i_t, typename f_t>
2052+
int basis_update_mpf_t<i_t, f_t>::factorize_basis(
2053+
const csc_matrix_t<i_t, f_t>& A,
2054+
const simplex_solver_settings_t<i_t, f_t>& settings,
2055+
std::vector<i_t>& basic_list,
2056+
std::vector<i_t>& nonbasic_list,
2057+
std::vector<variable_status_t>& vstatus)
2058+
{
2059+
std::vector<i_t> deficient;
2060+
std::vector<i_t> slacks_needed;
2061+
2062+
if (dual_simplex::factorize_basis(A,
2063+
settings,
2064+
basic_list,
2065+
L0_,
2066+
U0_,
2067+
row_permutation_,
2068+
inverse_row_permutation_,
2069+
col_permutation_,
2070+
deficient,
2071+
slacks_needed) == -1) {
2072+
settings.log.debug("Initial factorization failed\n");
2073+
basis_repair(A, settings, deficient, slacks_needed, basic_list, nonbasic_list, vstatus);
2074+
2075+
#ifdef CHECK_BASIS_REPAIR
2076+
csc_matrix_t<i_t, f_t> B(m, m, 0);
2077+
form_b(A, basic_list, B);
2078+
for (i_t k = 0; k < deficient.size(); ++k) {
2079+
const i_t j = deficient[k];
2080+
const i_t col_start = B.col_start[j];
2081+
const i_t col_end = B.col_start[j + 1];
2082+
const i_t col_nz = col_end - col_start;
2083+
if (col_nz != 1) { settings.log.printf("Deficient column %d has %d nonzeros\n", j, col_nz); }
2084+
const i_t i = B.i[col_start];
2085+
if (i != slacks_needed[k]) {
2086+
settings.log.printf("Slack %d needed but found %d instead\n", slacks_needed[k], i);
2087+
}
2088+
}
2089+
#endif
2090+
2091+
if (dual_simplex::factorize_basis(A,
2092+
settings,
2093+
basic_list,
2094+
L0_,
2095+
U0_,
2096+
row_permutation_,
2097+
inverse_row_permutation_,
2098+
col_permutation_,
2099+
deficient,
2100+
slacks_needed) == -1) {
2101+
return deficient.size();
2102+
}
2103+
settings.log.printf("Basis repaired\n");
2104+
}
2105+
2106+
assert(col_permutation_.size() == A.m);
2107+
reorder_basic_list(col_permutation_, basic_list);
2108+
reset();
2109+
return 0;
2110+
}
2111+
20492112
#ifdef DUAL_SIMPLEX_INSTANTIATE_DOUBLE
20502113
template class basis_update_t<int, double>;
20512114
template class basis_update_mpf_t<int, double>;

cpp/src/dual_simplex/basis_updates.hpp

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
#pragma once
1919

20+
#include <dual_simplex/initial_basis.hpp>
21+
#include <dual_simplex/simplex_solver_settings.hpp>
2022
#include <dual_simplex/sparse_matrix.hpp>
2123
#include <dual_simplex/sparse_vector.hpp>
2224
#include <dual_simplex/types.hpp>
@@ -176,6 +178,33 @@ class basis_update_t {
176178
template <typename i_t, typename f_t>
177179
class basis_update_mpf_t {
178180
public:
181+
basis_update_mpf_t(i_t n, const i_t refactor_frequency)
182+
: L0_(n, n, 1),
183+
U0_(n, n, 1),
184+
row_permutation_(n),
185+
inverse_row_permutation_(n),
186+
S_(n, 0, 0),
187+
col_permutation_(n),
188+
inverse_col_permutation_(n),
189+
xi_workspace_(2 * n, 0),
190+
x_workspace_(n, 0.0),
191+
U0_transpose_(1, 1, 1),
192+
L0_transpose_(1, 1, 1),
193+
refactor_frequency_(refactor_frequency),
194+
total_sparse_L_transpose_(0),
195+
total_dense_L_transpose_(0),
196+
total_sparse_L_(0),
197+
total_dense_L_(0),
198+
total_sparse_U_transpose_(0),
199+
total_dense_U_transpose_(0),
200+
total_sparse_U_(0),
201+
total_dense_U_(0),
202+
hypersparse_threshold_(0.05)
203+
{
204+
clear();
205+
reset_stats();
206+
}
207+
179208
basis_update_mpf_t(const csc_matrix_t<i_t, f_t>& Linit,
180209
const csc_matrix_t<i_t, f_t>& Uinit,
181210
const std::vector<i_t>& p,
@@ -205,7 +234,7 @@ class basis_update_mpf_t {
205234
inverse_permutation(row_permutation_, inverse_row_permutation_);
206235
clear();
207236
compute_transposes();
208-
reset_stas();
237+
reset_stats();
209238
}
210239

211240
void print_stats() const
@@ -226,7 +255,7 @@ class basis_update_mpf_t {
226255
// clang-format on
227256
}
228257

229-
void reset_stas()
258+
void reset_stats()
230259
{
231260
num_calls_L_ = 0;
232261
num_calls_U_ = 0;
@@ -249,7 +278,16 @@ class basis_update_mpf_t {
249278
inverse_permutation(row_permutation_, inverse_row_permutation_);
250279
clear();
251280
compute_transposes();
252-
reset_stas();
281+
reset_stats();
282+
return 0;
283+
}
284+
285+
i_t reset()
286+
{
287+
inverse_permutation(row_permutation_, inverse_row_permutation_);
288+
clear();
289+
compute_transposes();
290+
reset_stats();
253291
return 0;
254292
}
255293

@@ -332,6 +370,13 @@ class basis_update_mpf_t {
332370

333371
void multiply_lu(csc_matrix_t<i_t, f_t>& out) const;
334372

373+
// Compute L*U = A(p, basic_list)
374+
int factorize_basis(const csc_matrix_t<i_t, f_t>& A,
375+
const simplex_solver_settings_t<i_t, f_t>& settings,
376+
std::vector<i_t>& basic_list,
377+
std::vector<i_t>& nonbasic_list,
378+
std::vector<variable_status_t>& vstatus);
379+
335380
private:
336381
void clear()
337382
{

cpp/src/dual_simplex/phase2.cpp

Lines changed: 58 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,6 +2195,57 @@ dual::status_t dual_phase2(i_t phase,
21952195
std::vector<i_t> nonbasic_list;
21962196
std::vector<i_t> superbasic_list;
21972197

2198+
phase2::bound_info(lp, settings);
2199+
get_basis_from_vstatus(m, vstatus, basic_list, nonbasic_list, superbasic_list);
2200+
assert(superbasic_list.size() == 0);
2201+
assert(nonbasic_list.size() == n - m);
2202+
2203+
basis_update_mpf_t<i_t, f_t> ft(m, settings.refactor_frequency);
2204+
2205+
if (ft.factorize_basis(lp.A, settings, basic_list, nonbasic_list, vstatus) > 0) {
2206+
return dual::status_t::NUMERICAL;
2207+
}
2208+
2209+
if (toc(start_time) > settings.time_limit) { return dual::status_t::TIME_LIMIT; }
2210+
return dual_phase2_with_basis_update(phase,
2211+
slack_basis,
2212+
start_time,
2213+
lp,
2214+
settings,
2215+
vstatus,
2216+
ft,
2217+
basic_list,
2218+
nonbasic_list,
2219+
sol,
2220+
iter,
2221+
delta_y_steepest_edge);
2222+
}
2223+
2224+
template <typename i_t, typename f_t>
2225+
dual::status_t dual_phase2_with_basis_update(i_t phase,
2226+
i_t slack_basis,
2227+
f_t start_time,
2228+
const lp_problem_t<i_t, f_t>& lp,
2229+
const simplex_solver_settings_t<i_t, f_t>& settings,
2230+
std::vector<variable_status_t>& vstatus,
2231+
basis_update_mpf_t<i_t, f_t>& ft,
2232+
std::vector<i_t>& basic_list,
2233+
std::vector<i_t>& nonbasic_list,
2234+
lp_solution_t<i_t, f_t>& sol,
2235+
i_t& iter,
2236+
std::vector<f_t>& delta_y_steepest_edge)
2237+
{
2238+
const i_t m = lp.num_rows;
2239+
const i_t n = lp.num_cols;
2240+
assert(m <= n);
2241+
assert(vstatus.size() == n);
2242+
assert(lp.A.m == m);
2243+
assert(lp.A.n == n);
2244+
assert(lp.objective.size() == n);
2245+
assert(lp.lower.size() == n);
2246+
assert(lp.upper.size() == n);
2247+
assert(lp.rhs.size() == m);
2248+
21982249
std::vector<f_t>& x = sol.x;
21992250
std::vector<f_t>& y = sol.y;
22002251
std::vector<f_t>& z = sol.z;
@@ -2208,35 +2259,6 @@ dual::status_t dual_phase2(i_t phase,
22082259
std::vector<variable_status_t> vstatus_old = vstatus;
22092260
std::vector<f_t> z_old = z;
22102261

2211-
phase2::bound_info(lp, settings);
2212-
get_basis_from_vstatus(m, vstatus, basic_list, nonbasic_list, superbasic_list);
2213-
assert(superbasic_list.size() == 0);
2214-
assert(nonbasic_list.size() == n - m);
2215-
2216-
// Compute L*U = A(p, basic_list)
2217-
csc_matrix_t<i_t, f_t> L(m, m, 1);
2218-
csc_matrix_t<i_t, f_t> U(m, m, 1);
2219-
std::vector<i_t> pinv(m);
2220-
std::vector<i_t> p;
2221-
std::vector<i_t> q;
2222-
std::vector<i_t> deficient;
2223-
std::vector<i_t> slacks_needed;
2224-
2225-
if (factorize_basis(lp.A, settings, basic_list, L, U, p, pinv, q, deficient, slacks_needed) ==
2226-
-1) {
2227-
settings.log.debug("Initial factorization failed\n");
2228-
basis_repair(lp.A, settings, deficient, slacks_needed, basic_list, nonbasic_list, vstatus);
2229-
if (factorize_basis(lp.A, settings, basic_list, L, U, p, pinv, q, deficient, slacks_needed) ==
2230-
-1) {
2231-
return dual::status_t::NUMERICAL;
2232-
}
2233-
settings.log.printf("Basis repaired\n");
2234-
}
2235-
if (toc(start_time) > settings.time_limit) { return dual::status_t::TIME_LIMIT; }
2236-
assert(q.size() == m);
2237-
reorder_basic_list(q, basic_list);
2238-
basis_update_mpf_t<i_t, f_t> ft(L, U, p, settings.refactor_frequency);
2239-
22402262
std::vector<f_t> c_basic(m);
22412263
for (i_t k = 0; k < m; ++k) {
22422264
const i_t j = basic_list[k];
@@ -2872,48 +2894,27 @@ dual::status_t dual_phase2(i_t phase,
28722894
#endif
28732895
if (should_refactor) {
28742896
bool should_recompute_x = false;
2875-
if (factorize_basis(lp.A, settings, basic_list, L, U, p, pinv, q, deficient, slacks_needed) ==
2876-
-1) {
2897+
if (ft.factorize_basis(lp.A, settings, basic_list, nonbasic_list, vstatus) > 0) {
28772898
should_recompute_x = true;
28782899
settings.log.printf("Failed to factorize basis. Iteration %d\n", iter);
28792900
if (toc(start_time) > settings.time_limit) { return dual::status_t::TIME_LIMIT; }
2880-
basis_repair(lp.A, settings, deficient, slacks_needed, basic_list, nonbasic_list, vstatus);
28812901
i_t count = 0;
2882-
while (factorize_basis(
2883-
lp.A, settings, basic_list, L, U, p, pinv, q, deficient, slacks_needed) == -1) {
2902+
i_t deficient_size;
2903+
while ((deficient_size =
2904+
ft.factorize_basis(lp.A, settings, basic_list, nonbasic_list, vstatus)) > 0) {
28842905
settings.log.printf("Failed to repair basis. Iteration %d. %d deficient columns.\n",
28852906
iter,
2886-
static_cast<int>(deficient.size()));
2907+
static_cast<int>(deficient_size));
28872908
if (toc(start_time) > settings.time_limit) { return dual::status_t::TIME_LIMIT; }
28882909
settings.threshold_partial_pivoting_tol = 1.0;
2910+
28892911
count++;
28902912
if (count > 10) { return dual::status_t::NUMERICAL; }
2891-
basis_repair(
2892-
lp.A, settings, deficient, slacks_needed, basic_list, nonbasic_list, vstatus);
2893-
2894-
#ifdef CHECK_BASIS_REPAIR
2895-
csc_matrix_t<i_t, f_t> B(m, m, 0);
2896-
form_b(lp.A, basic_list, B);
2897-
for (i_t k = 0; k < deficient.size(); ++k) {
2898-
const i_t j = deficient[k];
2899-
const i_t col_start = B.col_start[j];
2900-
const i_t col_end = B.col_start[j + 1];
2901-
const i_t col_nz = col_end - col_start;
2902-
if (col_nz != 1) {
2903-
settings.log.printf("Deficient column %d has %d nonzeros\n", j, col_nz);
2904-
}
2905-
const i_t i = B.i[col_start];
2906-
if (i != slacks_needed[k]) {
2907-
settings.log.printf("Slack %d needed but found %d instead\n", slacks_needed[k], i);
2908-
}
2909-
}
2910-
#endif
29112913
}
29122914

29132915
settings.log.printf("Successfully repaired basis. Iteration %d\n", iter);
29142916
}
2915-
reorder_basic_list(q, basic_list);
2916-
ft.reset(L, U, p);
2917+
29172918
phase2::reset_basis_mark(basic_list, nonbasic_list, basic_mark, nonbasic_mark);
29182919
if (should_recompute_x) {
29192920
std::vector<f_t> unperturbed_x(n);

cpp/src/dual_simplex/phase2.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#pragma once
1919

20+
#include <dual_simplex/basis_updates.hpp>
2021
#include <dual_simplex/initial_basis.hpp>
2122
#include <dual_simplex/logger.hpp>
2223
#include <dual_simplex/presolve.hpp>
@@ -66,4 +67,17 @@ dual::status_t dual_phase2(i_t phase,
6667
i_t& iter,
6768
std::vector<f_t>& steepest_edge_norms);
6869

70+
template <typename i_t, typename f_t>
71+
dual::status_t dual_phase2_with_basis_update(i_t phase,
72+
i_t slack_basis,
73+
f_t start_time,
74+
const lp_problem_t<i_t, f_t>& lp,
75+
const simplex_solver_settings_t<i_t, f_t>& settings,
76+
std::vector<variable_status_t>& vstatus,
77+
basis_update_mpf_t<i_t, f_t>& ft,
78+
std::vector<i_t>& basic_list,
79+
std::vector<i_t>& nonbasic_list,
80+
lp_solution_t<i_t, f_t>& sol,
81+
i_t& iter,
82+
std::vector<f_t>& delta_y_steepest_edge);
6983
} // namespace cuopt::linear_programming::dual_simplex

0 commit comments

Comments
 (0)