Skip to content

Commit ca6cb0a

Browse files
committed
add changes in lp with validate_bound and maximize_term
Signed-off-by: Lev Nachmanson <levnach@hotmail.com>
1 parent ebd4d1a commit ca6cb0a

12 files changed

+365
-213
lines changed

src/math/lp/lar_core_solver.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class lar_core_solver {
122122
m_r_solver.m_d.resize(m_r_A.column_count());
123123

124124
m_stacked_simplex_strategy.pop(k);
125-
m_r_solver.m_settings.set_simplex_strategy(m_stacked_simplex_strategy);
125+
m_r_solver.m_settings.simplex_strategy() = m_stacked_simplex_strategy;
126126
m_infeasible_linear_combination.reset();
127127
lp_assert(m_r_solver.basis_heading_is_correct());
128128
}

src/math/lp/lar_solver.cpp

+256-111
Large diffs are not rendered by default.

src/math/lp/lar_solver.h

+20-7
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,20 @@ class lar_solver : public column_namer {
155155
lpvar& crossed_bounds_column() { return m_crossed_bounds_column; }
156156

157157

158-
private:
158+
private:
159+
bool validate_bound(lpvar j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
160+
void add_dep_constraints_to_solver(lar_solver& ls, u_dependency* dep);
161+
void add_bound_negation_to_solver(lar_solver& ls, lpvar j, lconstraint_kind kind, const mpq& right_side);
162+
void add_constraint_to_validate(lar_solver& ls, constraint_index ci);
163+
bool m_validate_blocker = false;
159164
void update_column_type_and_bound_check_on_equal(unsigned j, const mpq& right_side, constraint_index ci, unsigned&);
160165
void update_column_type_and_bound(unsigned j, const mpq& right_side, constraint_index ci);
161166
public:
162-
void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
163-
private:
167+
bool validate_blocker() const { return m_validate_blocker; }
168+
bool & validate_blocker() { return m_validate_blocker; }
169+
void update_column_type_and_bound(unsigned j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
170+
private:
171+
void require_nbasis_sort() { m_mpq_lar_core_solver.m_r_solver.m_nbasis_sort_counter = 0; }
164172
void update_column_type_and_bound_with_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
165173
void update_column_type_and_bound_with_no_ub(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
166174
void update_bound_with_ub_lb(var_index j, lconstraint_kind kind, const mpq& right_side, u_dependency* dep);
@@ -203,7 +211,9 @@ class lar_solver : public column_namer {
203211
bool reduced_costs_are_zeroes_for_r_solver() const;
204212
void set_costs_to_zero(const lar_term& term);
205213
void prepare_costs_for_r_solver(const lar_term& term);
206-
bool maximize_term_on_corrected_r_solver(lar_term& term, impq& term_max);
214+
bool maximize_term_on_feasible_r_solver(lar_term& term, impq& term_max, vector<std::pair<mpq,lpvar>>* max_coeffs);
215+
u_dependency* get_dependencies_of_maximum(const vector<std::pair<mpq,lpvar>>& max_coeffs);
216+
207217
void pop_core_solver_params();
208218
void pop_core_solver_params(unsigned k);
209219
void set_upper_bound_witness(var_index j, u_dependency* ci);
@@ -263,7 +273,12 @@ class lar_solver : public column_namer {
263273
mutable std::unordered_set<mpq> m_set_of_different_singles;
264274
mutable mpq m_delta;
265275

266-
public:
276+
public:
277+
u_dependency* find_improved_bound(lpvar j, bool is_lower, mpq& bound);
278+
279+
std::ostream& print_explanation(
280+
std::ostream& out, const explanation& exp,
281+
std::function<std::string(lpvar)> var_str = [](lpvar j) { return std::string("j") + T_to_string(j); }) const;
267282
// this function just looks at the status
268283
bool is_feasible() const;
269284

@@ -302,8 +317,6 @@ class lar_solver : public column_namer {
302317

303318
lp_status maximize_term(unsigned j_or_term, impq& term_max);
304319

305-
bool improve_bound(lpvar j, bool is_lower);
306-
307320
inline core_solver_pretty_printer<lp::mpq, lp::impq> pp(std::ostream& out) const {
308321
return core_solver_pretty_printer<lp::mpq, lp::impq>(m_mpq_lar_core_solver.m_r_solver, out);
309322
}

src/math/lp/lp_core_solver_base.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,8 @@ Revision History:
2323
#include "util/vector.h"
2424
#include <functional>
2525
#include "math/lp/lp_core_solver_base_def.h"
26-
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &);
2726
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::basis_heading_is_correct() const ;
2827
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::column_is_dual_feasible(unsigned int) const;
29-
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &);
3028
template void lp::lp_core_solver_base<lp::mpq, lp::mpq>::add_delta_to_entering(unsigned int, const lp::mpq&);
3129
template void lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::init();
3230
template void lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::init_basis_heading_and_non_basic_columns_vector();
@@ -35,7 +33,6 @@ template lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::lp_core_s
3533
vector<unsigned int >&, vector<unsigned> &, vector<int> &, vector<lp::numeric_pair<lp::mpq> >&, vector<lp::mpq>&, lp::lp_settings&, const column_namer&, const vector<lp::column_type >&,
3634
const vector<lp::numeric_pair<lp::mpq> >&,
3735
const vector<lp::numeric_pair<lp::mpq> >&);
38-
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair<lp::mpq>, std::ostream&);
3936

4037
template void lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::add_delta_to_entering(unsigned int, const lp::numeric_pair<lp::mpq>&);
4138
template lp::lp_core_solver_base<lp::mpq, lp::mpq>::lp_core_solver_base(
@@ -50,7 +47,6 @@ template lp::lp_core_solver_base<lp::mpq, lp::mpq>::lp_core_solver_base(
5047
const vector<lp::column_type >&,
5148
const vector<lp::mpq>&,
5249
const vector<lp::mpq>&);
53-
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &);
5450
template std::string lp::lp_core_solver_base<lp::mpq, lp::mpq>::column_name(unsigned int) const;
5551
template void lp::lp_core_solver_base<lp::mpq, lp::mpq>::pretty_print(std::ostream & out);
5652
template std::string lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::column_name(unsigned int) const;

src/math/lp/lp_core_solver_base.h

+4-6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Revision History:
1919
--*/
2020
#pragma once
2121
#include <set>
22+
#include <list>
2223
#include "util/vector.h"
2324
#include <string>
2425
#include "math/lp/lp_utils.h"
@@ -88,7 +89,7 @@ class lp_core_solver_base {
8889
const vector<column_type> & m_column_types;
8990
const vector<X> & m_lower_bounds;
9091
const vector<X> & m_upper_bounds;
91-
unsigned m_basis_sort_counter;
92+
unsigned m_nbasis_sort_counter;
9293
vector<unsigned> m_trace_of_basis_change_vector; // the even positions are entering, the odd positions are leaving
9394
bool m_tracing_basis_changes;
9495
// these rows are changed by adding to them a multiple of the pivot row
@@ -165,10 +166,6 @@ class lp_core_solver_base {
165166

166167
void print_statistics(char const* str, X cost, std::ostream & message_stream);
167168

168-
bool print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream & message_stream);
169-
170-
bool print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const* str, std::ostream & message_stream);
171-
172169
bool print_statistics_with_cost_and_check_that_the_time_is_over(X cost, std::ostream & message_stream);
173170

174171
unsigned total_iterations() const { return m_total_iterations; }
@@ -277,7 +274,7 @@ class lp_core_solver_base {
277274
bool non_basis_has_no_doubles() const;
278275

279276
bool basis_is_correctly_represented_in_heading() const ;
280-
bool non_basis_is_correctly_represented_in_heading() const ;
277+
bool non_basis_is_correctly_represented_in_heading(std::list<unsigned>*) const ;
281278

282279
bool basis_heading_is_correct() const;
283280

@@ -416,6 +413,7 @@ class lp_core_solver_base {
416413
TRACE("lp_core", tout << "inf col "; print_column_info(j, tout) << "\n";);
417414
return false;
418415
}
416+
419417
return true;
420418
}
421419

src/math/lp/lp_core_solver_base_def.h

+31-47
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ lp_core_solver_base(static_matrix<T, X> & A,
5656
m_column_types(column_types),
5757
m_lower_bounds(lower_bound_values),
5858
m_upper_bounds(upper_bound_values),
59-
m_basis_sort_counter(0),
59+
m_nbasis_sort_counter(0),
6060
m_tracing_basis_changes(false),
6161
m_touched_rows(nullptr),
6262
m_look_for_feasible_solution_only(false) {
@@ -133,37 +133,6 @@ print_statistics(char const* str, X cost, std::ostream & out) {
133133
<< ", nonzeros = " << m_A.number_of_non_zeroes() << std::endl;
134134
}
135135

136-
template <typename T, typename X> bool lp_core_solver_base<T, X>::
137-
print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream & str) {
138-
unsigned total_iterations = inc_total_iterations();
139-
if (m_settings.report_frequency != 0) {
140-
if (m_settings.print_statistics && (total_iterations % m_settings.report_frequency == 0)) {
141-
print_statistics("", X(), str);
142-
}
143-
}
144-
return time_is_over();
145-
}
146-
147-
template <typename T, typename X> bool lp_core_solver_base<T, X>::
148-
print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const* str, std::ostream & out) {
149-
unsigned total_iterations = inc_total_iterations();
150-
if (m_settings.report_frequency != 0)
151-
if (m_settings.print_statistics && (total_iterations % m_settings.report_frequency == 0)) {
152-
print_statistics(str, get_cost(), out);
153-
}
154-
return time_is_over();
155-
}
156-
157-
template <typename T, typename X> bool lp_core_solver_base<T, X>::
158-
print_statistics_with_cost_and_check_that_the_time_is_over(X cost, std::ostream & out) {
159-
unsigned total_iterations = inc_total_iterations();
160-
if (m_settings.report_frequency != 0)
161-
if (m_settings.print_statistics && (total_iterations % m_settings.report_frequency == 0)) {
162-
print_statistics("", cost, out);
163-
}
164-
return time_is_over();
165-
}
166-
167136
template <typename T, typename X> bool lp_core_solver_base<T, X>::
168137
column_is_dual_feasible(unsigned j) const {
169138
switch (m_column_types[j]) {
@@ -194,18 +163,6 @@ d_is_not_positive(unsigned j) const {
194163
return m_d[j] <= numeric_traits<T>::zero();
195164
}
196165

197-
198-
template <typename T, typename X> bool lp_core_solver_base<T, X>::
199-
time_is_over() {
200-
if (m_settings.get_cancel_flag()) {
201-
m_status = lp_status::TIME_EXHAUSTED;
202-
return true;
203-
}
204-
else {
205-
return false;
206-
}
207-
}
208-
209166
template <typename T, typename X> void lp_core_solver_base<T, X>::
210167
rs_minus_Anx(vector<X> & rs) {
211168
unsigned row = m_m();
@@ -360,15 +317,42 @@ basis_is_correctly_represented_in_heading() const {
360317
return true;
361318
}
362319
template <typename T, typename X> bool lp_core_solver_base<T, X>::
363-
non_basis_is_correctly_represented_in_heading() const {
320+
non_basis_is_correctly_represented_in_heading(std::list<unsigned>* non_basis_list) const {
364321
for (unsigned i = 0; i < m_nbasis.size(); i++)
365322
if (m_basis_heading[m_nbasis[i]] != - static_cast<int>(i) - 1)
366323
return false;
367324

368325
for (unsigned j = 0; j < m_A.column_count(); j++)
369326
if (m_basis_heading[j] >= 0)
370327
lp_assert(static_cast<unsigned>(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j);
371-
328+
329+
if (non_basis_list == nullptr) return true;
330+
331+
std::unordered_set<unsigned> nbasis_set(this->m_nbasis.size());
332+
for (unsigned j : this->m_nbasis)
333+
nbasis_set.insert(j);
334+
335+
if (non_basis_list->size() != nbasis_set.size()) {
336+
TRACE("lp_core", tout << "non_basis_list.size() = " << non_basis_list->size() << ", nbasis_set.size() = " << nbasis_set.size() << "\n";);
337+
return false;
338+
}
339+
for (auto it = non_basis_list->begin(); it != non_basis_list->end(); it++) {
340+
if (nbasis_set.find(*it) == nbasis_set.end()) {
341+
TRACE("lp_core", tout << "column " << *it << " is in m_non_basis_list but not in m_nbasis\n";);
342+
return false;
343+
}
344+
}
345+
346+
// check for duplicates in m_non_basis_list
347+
nbasis_set.clear();
348+
for (auto it = non_basis_list->begin(); it != non_basis_list->end(); it++) {
349+
if (nbasis_set.find(*it) != nbasis_set.end()) {
350+
TRACE("lp_core", tout << "column " << *it << " is in m_non_basis_list twice\n";);
351+
return false;
352+
}
353+
nbasis_set.insert(*it);
354+
}
355+
372356
return true;
373357
}
374358

@@ -390,7 +374,7 @@ template <typename T, typename X> bool lp_core_solver_base<T, X>::
390374
if (!basis_is_correctly_represented_in_heading())
391375
return false;
392376

393-
if (!non_basis_is_correctly_represented_in_heading())
377+
if (!non_basis_is_correctly_represented_in_heading(nullptr))
394378
return false;
395379

396380
return true;

src/math/lp/lp_primal_core_solver.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ namespace lp {
592592
theta = zero_of_type<X>();
593593
}
594594
}
595-
595+
bool correctly_moved_to_bounds(lpvar) const;
596596
bool column_is_benefitial_for_entering_basis(unsigned j) const;
597597
void init_infeasibility_costs();
598598
void print_column(unsigned j, std::ostream &out);

src/math/lp/lp_primal_core_solver_def.h

+33-25
Original file line numberDiff line numberDiff line change
@@ -40,49 +40,57 @@ void lp_primal_core_solver<T, X>::sort_non_basis() {
4040
if (ca != 0 && cb == 0) return true;
4141
return ca < cb;
4242
});
43-
44-
m_non_basis_list.clear();
45-
// reinit m_basis_heading
46-
for (unsigned j = 0; j < this->m_nbasis.size(); j++) {
47-
unsigned col = this->m_nbasis[j];
48-
this->m_basis_heading[col] = - static_cast<int>(j) - 1;
49-
m_non_basis_list.push_back(col);
43+
m_non_basis_list.resize(this->m_nbasis.size());
44+
// initialize m_non_basis_list from m_nbasis by using an iterator on m_non_basis_list
45+
auto it = m_non_basis_list.begin();
46+
unsigned j = 0;
47+
for (; j < this->m_nbasis.size(); j++, ++it) {
48+
unsigned col = *it = this->m_nbasis[j];
49+
this->m_basis_heading[col] = -static_cast<int>(j) - 1;
5050
}
5151
}
5252

53+
template <typename T, typename X>
54+
bool lp_primal_core_solver<T, X>::correctly_moved_to_bounds(unsigned j) const {
55+
switch (this->m_column_types[j]) {
56+
case column_type::fixed:
57+
return this->m_x[j] == this->m_lower_bounds[j];
58+
case column_type::boxed:
59+
return this->m_x[j] == this->m_lower_bounds[j] || this->m_x[j] == this->m_upper_bounds[j];
60+
case column_type::lower_bound:
61+
return this->m_x[j] == this->m_lower_bounds[j];
62+
case column_type::upper_bound:
63+
return this->m_x[j] == this->m_upper_bounds[j];
64+
case column_type::free_column:
65+
return true;
66+
default:
67+
UNREACHABLE();
68+
return false;
69+
}
70+
}
5371

5472

5573
template <typename T, typename X>
5674
bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis(unsigned j) const {
5775
const T& dj = this->m_d[j];
58-
TRACE("lar_solver", tout << "dj=" << dj << "\n";);
76+
if (dj.is_zero()) return false;
77+
TRACE("lar_solver", tout << "d[" << j <<"] = " << dj << "\n";);
78+
SASSERT(correctly_moved_to_bounds(j));
5979
switch (this->m_column_types[j]) {
6080
case column_type::fixed: break;
6181
case column_type::free_column:
62-
if (!is_zero(dj))
63-
return true;
64-
break;
82+
return true;
6583
case column_type::lower_bound:
6684
if (dj > zero_of_type<T>()) return true;
67-
if (dj < 0 && this->m_x[j] > this->m_lower_bounds[j]){
68-
return true;
69-
}
7085
break;
7186
case column_type::upper_bound:
7287
if (dj < zero_of_type<T>()) return true;
73-
if (dj > 0 && this->m_x[j] < this->m_upper_bounds[j]) {
74-
return true;
75-
}
7688
break;
7789
case column_type::boxed:
78-
if (dj > zero_of_type<T>()) {
79-
if (this->m_x[j] < this->m_upper_bounds[j])
80-
return true;
81-
break;
82-
} else if (dj < zero_of_type<T>()) {
83-
if (this->m_x[j] > this->m_lower_bounds[j])
84-
return true;
85-
}
90+
if (dj > zero_of_type<T>() && this->m_x[j] == this->m_lower_bounds[j])
91+
return true;
92+
if (dj < zero_of_type<T>() && this->m_x[j] == this->m_upper_bounds[j])
93+
return true;
8694
break;
8795
default:
8896
UNREACHABLE();

src/math/lp/lp_primal_core_solver_tableau_def.h

+12-10
Original file line numberDiff line numberDiff line change
@@ -44,19 +44,22 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_e
4444
advance_on_entering_and_leaving_tableau(entering, leaving, t);
4545
}
4646

47+
4748
template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_entering_column_tableau() {
4849
//this moment m_y = cB * B(-1)
49-
unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter();
50-
51-
if (number_of_benefitial_columns_to_go_over == 0)
52-
return -1;
53-
if (this->m_basis_sort_counter == 0) {
50+
if (this->m_nbasis_sort_counter == 0) {
5451
sort_non_basis();
55-
this->m_basis_sort_counter = 20;
52+
this->m_nbasis_sort_counter = 20;
5653
}
5754
else {
58-
this->m_basis_sort_counter--;
55+
this->m_nbasis_sort_counter--;
56+
SASSERT(non_basis_is_correctly_represented_in_heading(&m_non_basis_list));
5957
}
58+
unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter();
59+
60+
if (number_of_benefitial_columns_to_go_over == 0)
61+
return -1;
62+
6063
unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size
6164
std::list<unsigned>::iterator entering_iter = m_non_basis_list.end();
6265
unsigned n = 0;
@@ -98,7 +101,8 @@ unsigned lp_primal_core_solver<T, X>::solve() {
98101
}
99102

100103
do {
101-
if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over( "feas t", * this->m_settings.get_message_ostream())) {
104+
if (this->m_settings.get_cancel_flag()) {
105+
this->set_status(lp_status::CANCELLED);
102106
return this->total_iterations();
103107
}
104108
if (this->m_settings.use_tableau_rows()) {
@@ -256,8 +260,6 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
256260
}
257261
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tableau() {
258262
lp_assert(basis_columns_are_set_correctly());
259-
this->m_basis_sort_counter = 0; // to initiate the sort of the basis
260-
// this->set_total_iterations(0);
261263
this->iters_with_no_cost_growing() = 0;
262264
lp_assert(this->inf_heap_is_correct());
263265
if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)

0 commit comments

Comments
 (0)