From 885e93ccbd56581756bd4a1c12b04be145cfb609 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 11:30:59 -0800 Subject: [PATCH 01/36] before rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/CMakeLists.txt | 3 - src/math/lp/indexed_value.h | 11 - src/math/lp/lar_core_solver.h | 30 +- src/math/lp/lp_dual_simplex.cpp | 24 - src/math/lp/lp_dual_simplex.h | 93 --- src/math/lp/lp_dual_simplex_def.h | 376 ----------- src/math/lp/lp_primal_core_solver.h | 1 - src/math/lp/lp_primal_simplex.cpp | 35 - src/math/lp/lp_primal_simplex.h | 106 --- src/math/lp/lp_primal_simplex_def.h | 367 ----------- src/math/lp/lp_solver.cpp | 55 -- src/math/lp/lp_solver.h | 260 -------- src/math/lp/lp_solver_def.h | 571 ---------------- src/math/lp/mps_reader.h | 891 ------------------------- src/math/lp/static_matrix.cpp | 1 - src/sat/smt/arith_sls.h | 3 - src/sat/smt/arith_solver.h | 4 +- src/shell/CMakeLists.txt | 1 - src/shell/lp_frontend.cpp | 109 --- src/shell/lp_frontend.h | 7 - src/shell/main.cpp | 10 +- src/smt/theory_lra.cpp | 3 - src/test/lp/lp.cpp | 984 ++-------------------------- src/test/lp/smt_reader.h | 4 - src/test/lp/test_file_reader.h | 1 - 25 files changed, 71 insertions(+), 3879 deletions(-) delete mode 100644 src/math/lp/lp_dual_simplex.cpp delete mode 100644 src/math/lp/lp_dual_simplex.h delete mode 100644 src/math/lp/lp_dual_simplex_def.h delete mode 100644 src/math/lp/lp_primal_simplex.cpp delete mode 100644 src/math/lp/lp_primal_simplex.h delete mode 100644 src/math/lp/lp_primal_simplex_def.h delete mode 100644 src/math/lp/lp_solver.cpp delete mode 100644 src/math/lp/lp_solver.h delete mode 100644 src/math/lp/lp_solver_def.h delete mode 100644 src/math/lp/mps_reader.h delete mode 100644 src/shell/lp_frontend.cpp delete mode 100644 src/shell/lp_frontend.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 9f0fae6bcca..5719de44fae 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -20,11 +20,8 @@ z3_add_component(lp lar_core_solver.cpp lp_core_solver_base.cpp lp_dual_core_solver.cpp - lp_dual_simplex.cpp lp_primal_core_solver.cpp - lp_primal_simplex.cpp lp_settings.cpp - lp_solver.cpp lu.cpp lp_utils.cpp matrix.cpp diff --git a/src/math/lp/indexed_value.h b/src/math/lp/indexed_value.h index c4837647099..92d8f2adf1f 100644 --- a/src/math/lp/indexed_value.h +++ b/src/math/lp/indexed_value.h @@ -43,15 +43,4 @@ class indexed_value { m_value = val; } }; -#ifdef Z3DEBUG -template -bool check_vector_for_small_values(indexed_vector & w, lp_settings & settings) { - for (unsigned i : w.m_index) { - const X & v = w[i]; - if ((!is_zero(v)) && settings.abs_val_is_smaller_than_drop_tolerance(v)) - return false; - } - return true; -} -#endif } diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 8a6c64ef00f..de8fe68adb5 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -651,35 +651,7 @@ class lar_core_solver { } } - void scale_problem_for_doubles( - static_matrix& A, - vector & lower_bounds, - vector & upper_bounds) { - vector column_scale_vector; - vector right_side_vector(A.column_count()); - settings().reps_in_scaler = 5; - scaler scaler(right_side_vector, - A, - settings().scaling_minimum, - settings().scaling_maximum, - column_scale_vector, - settings()); - if (! scaler.scale()) { - // the scale did not succeed, unscaling - A.clear(); - create_double_matrix(A); - } else { - for (unsigned j = 0; j < A.column_count(); j++) { - if (m_r_solver.column_has_upper_bound(j)) { - upper_bounds[j] /= column_scale_vector[j]; - } - if (m_r_solver.column_has_lower_bound(j)) { - lower_bounds[j] /= column_scale_vector[j]; - } - } - } - - } + // returns the trace of basis changes vector find_solution_signature_with_doubles(lar_solution_signature & signature) { if (m_d_solver.m_factorization == nullptr || m_d_solver.m_factorization->get_status() != LU_status::OK) { diff --git a/src/math/lp/lp_dual_simplex.cpp b/src/math/lp/lp_dual_simplex.cpp deleted file mode 100644 index aaf612f5696..00000000000 --- a/src/math/lp/lp_dual_simplex.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include "math/lp/lp_dual_simplex_def.h" -template lp::mpq lp::lp_dual_simplex::get_current_cost() const; -template void lp::lp_dual_simplex::find_maximal_solution(); -template double lp::lp_dual_simplex::get_current_cost() const; -template void lp::lp_dual_simplex::find_maximal_solution(); diff --git a/src/math/lp/lp_dual_simplex.h b/src/math/lp/lp_dual_simplex.h deleted file mode 100644 index 75ef87492f2..00000000000 --- a/src/math/lp/lp_dual_simplex.h +++ /dev/null @@ -1,93 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once -#include "util/vector.h" -#include "math/lp/lp_utils.h" -#include "math/lp/lp_solver.h" -#include "math/lp/lp_dual_core_solver.h" -namespace lp { - -template -class lp_dual_simplex: public lp_solver { - lp_dual_core_solver * m_core_solver; - vector m_b_copy; - vector m_lower_bounds; // We don't have a convention here that all low bounds are zeros. At least it does not hold for the first stage solver - vector m_column_types_of_core_solver; - vector m_column_types_of_logicals; - vector m_can_enter_basis; -public: - ~lp_dual_simplex() override { - delete m_core_solver; - } - - lp_dual_simplex() : m_core_solver(nullptr) {} - - - void decide_on_status_after_stage1(); - - void fix_logical_for_stage2(unsigned j); - - void fix_structural_for_stage2(unsigned j); - - void unmark_boxed_and_fixed_columns_and_fix_structural_costs(); - - void restore_right_sides(); - - void solve_for_stage2(); - - void fill_x_with_zeros(); - - void stage1(); - - void stage2(); - - void fill_first_stage_solver_fields(); - - column_type get_column_type(unsigned j); - - void fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(unsigned j); - - void fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j); - - void fill_costs_and_bounds_and_column_types_for_the_first_stage_solver(); - - void set_type_for_logical(unsigned j, column_type col_type) { - this->m_column_types_of_logicals[j - this->number_of_core_structurals()] = col_type; - } - - void fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row, - unsigned & slack_var, - unsigned & artificial); - - void augment_matrix_A_and_fill_x_and_allocate_some_fields(); - - - - void copy_m_b_aside_and_set_it_to_zeros(); - - void find_maximal_solution() override; - - T get_column_value(unsigned column) const override { - return this->get_column_value_with_core_solver(column, m_core_solver); - } - - T get_current_cost() const override; -}; -} diff --git a/src/math/lp/lp_dual_simplex_def.h b/src/math/lp/lp_dual_simplex_def.h deleted file mode 100644 index 8af9d87c104..00000000000 --- a/src/math/lp/lp_dual_simplex_def.h +++ /dev/null @@ -1,376 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include "math/lp/lp_dual_simplex.h" -namespace lp{ - -template void lp_dual_simplex::decide_on_status_after_stage1() { - switch (m_core_solver->get_status()) { - case lp_status::OPTIMAL: - if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { - this->m_status = lp_status::FEASIBLE; - } else { - this->m_status = lp_status::UNBOUNDED; - } - break; - case lp_status::DUAL_UNBOUNDED: - lp_unreachable(); - case lp_status::TIME_EXHAUSTED: - this->m_status = lp_status::TIME_EXHAUSTED; - break; - case lp_status::FLOATING_POINT_ERROR: - this->m_status = lp_status::FLOATING_POINT_ERROR; - break; - default: - lp_unreachable(); - } -} - -template void lp_dual_simplex::fix_logical_for_stage2(unsigned j) { - lp_assert(j >= this->number_of_core_structurals()); - switch (m_column_types_of_logicals[j - this->number_of_core_structurals()]) { - case column_type::lower_bound: - m_lower_bounds[j] = numeric_traits::zero(); - m_column_types_of_core_solver[j] = column_type::lower_bound; - m_can_enter_basis[j] = true; - break; - case column_type::fixed: - this->m_upper_bounds[j] = m_lower_bounds[j] = numeric_traits::zero(); - m_column_types_of_core_solver[j] = column_type::fixed; - m_can_enter_basis[j] = false; - break; - default: - lp_unreachable(); - } -} - -template void lp_dual_simplex::fix_structural_for_stage2(unsigned j) { - column_info * ci = this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]; - switch (ci->get_column_type()) { - case column_type::lower_bound: - m_lower_bounds[j] = numeric_traits::zero(); - m_column_types_of_core_solver[j] = column_type::lower_bound; - m_can_enter_basis[j] = true; - break; - case column_type::fixed: - case column_type::upper_bound: - lp_unreachable(); - case column_type::boxed: - this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; - m_lower_bounds[j] = numeric_traits::zero(); - m_column_types_of_core_solver[j] = column_type::boxed; - m_can_enter_basis[j] = true; - break; - case column_type::free_column: - m_can_enter_basis[j] = true; - m_column_types_of_core_solver[j] = column_type::free_column; - break; - default: - lp_unreachable(); - } - // T cost_was = this->m_costs[j]; - this->set_scaled_cost(j); -} - -template void lp_dual_simplex::unmark_boxed_and_fixed_columns_and_fix_structural_costs() { - unsigned j = this->m_A->column_count(); - while (j-- > this->number_of_core_structurals()) { - fix_logical_for_stage2(j); - } - j = this->number_of_core_structurals(); - while (j--) { - fix_structural_for_stage2(j); - } -} - -template void lp_dual_simplex::restore_right_sides() { - unsigned i = this->m_A->row_count(); - while (i--) { - this->m_b[i] = m_b_copy[i]; - } -} - -template void lp_dual_simplex::solve_for_stage2() { - m_core_solver->restore_non_basis(); - m_core_solver->solve_yB(m_core_solver->m_y); - m_core_solver->fill_reduced_costs_from_m_y_by_rows(); - m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); - m_core_solver->set_status(lp_status::FEASIBLE); - m_core_solver->solve(); - switch (m_core_solver->get_status()) { - case lp_status::OPTIMAL: - this->m_status = lp_status::OPTIMAL; - break; - case lp_status::DUAL_UNBOUNDED: - this->m_status = lp_status::INFEASIBLE; - break; - case lp_status::TIME_EXHAUSTED: - this->m_status = lp_status::TIME_EXHAUSTED; - break; - case lp_status::FLOATING_POINT_ERROR: - this->m_status = lp_status::FLOATING_POINT_ERROR; - break; - default: - lp_unreachable(); - } - this->m_second_stage_iterations = m_core_solver->total_iterations(); - this->m_total_iterations = (this->m_first_stage_iterations + this->m_second_stage_iterations); -} - -template void lp_dual_simplex::fill_x_with_zeros() { - unsigned j = this->m_A->column_count(); - while (j--) { - this->m_x[j] = numeric_traits::zero(); - } -} - -template void lp_dual_simplex::stage1() { - lp_assert(m_core_solver == nullptr); - this->m_x.resize(this->m_A->column_count(), numeric_traits::zero()); - if (this->m_settings.get_message_ostream() != nullptr) - this->print_statistics_on_A(*this->m_settings.get_message_ostream()); - m_core_solver = new lp_dual_core_solver( - *this->m_A, - m_can_enter_basis, - this->m_b, // the right side vector - this->m_x, - this->m_basis, - this->m_nbasis, - this->m_heading, - this->m_costs, - this->m_column_types_of_core_solver, - this->m_lower_bounds, - this->m_upper_bounds, - this->m_settings, - *this); - m_core_solver->fill_reduced_costs_from_m_y_by_rows(); - m_core_solver->start_with_initial_basis_and_make_it_dual_feasible(); - if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) { - // skipping stage 1 - m_core_solver->set_status(lp_status::OPTIMAL); - m_core_solver->set_total_iterations(0); - } else { - m_core_solver->solve(); - } - decide_on_status_after_stage1(); - this->m_first_stage_iterations = m_core_solver->total_iterations(); -} - -template void lp_dual_simplex::stage2() { - unmark_boxed_and_fixed_columns_and_fix_structural_costs(); - restore_right_sides(); - solve_for_stage2(); -} - -template void lp_dual_simplex::fill_first_stage_solver_fields() { - unsigned slack_var = this->number_of_core_structurals(); - unsigned artificial = this->number_of_core_structurals() + this->m_slacks; - - for (unsigned row = 0; row < this->row_count(); row++) { - fill_first_stage_solver_fields_for_row_slack_and_artificial(row, slack_var, artificial); - } - fill_costs_and_bounds_and_column_types_for_the_first_stage_solver(); -} - -template column_type lp_dual_simplex::get_column_type(unsigned j) { - lp_assert(j < this->m_A->column_count()); - if (j >= this->number_of_core_structurals()) { - return m_column_types_of_logicals[j - this->number_of_core_structurals()]; - } - return this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]->get_column_type(); -} - -template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(unsigned j) { - // see 4.7 in the dissertation of Achim Koberstein - lp_assert(this->m_core_solver_columns_to_external_columns.find(j) != - this->m_core_solver_columns_to_external_columns.end()); - - T free_bound = T(1e4); // see 4.8 - unsigned jj = this->m_core_solver_columns_to_external_columns[j]; - lp_assert(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end()); - column_info * ci = this->m_map_from_var_index_to_column_info[jj]; - switch (ci->get_column_type()) { - case column_type::upper_bound: { - std::stringstream s; - s << "unexpected bound type " << j << " " - << column_type_to_string(get_column_type(j)); - throw_exception(s.str()); - break; - } - case column_type::lower_bound: { - m_can_enter_basis[j] = true; - this->set_scaled_cost(j); - this->m_lower_bounds[j] = numeric_traits::zero(); - this->m_upper_bounds[j] = numeric_traits::one(); - break; - } - case column_type::free_column: { - m_can_enter_basis[j] = true; - this->set_scaled_cost(j); - this->m_upper_bounds[j] = free_bound; - this->m_lower_bounds[j] = -free_bound; - break; - } - case column_type::boxed: - m_can_enter_basis[j] = false; - this->m_costs[j] = numeric_traits::zero(); - this->m_upper_bounds[j] = this->m_lower_bounds[j] = numeric_traits::zero(); // is it needed? - break; - default: - lp_unreachable(); - } - m_column_types_of_core_solver[j] = column_type::boxed; -} - -template void lp_dual_simplex::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j) { - this->m_costs[j] = 0; - lp_assert(get_column_type(j) != column_type::upper_bound); - if ((m_can_enter_basis[j] = (get_column_type(j) == column_type::lower_bound))) { - m_column_types_of_core_solver[j] = column_type::boxed; - this->m_lower_bounds[j] = numeric_traits::zero(); - this->m_upper_bounds[j] = numeric_traits::one(); - } else { - m_column_types_of_core_solver[j] = column_type::fixed; - this->m_lower_bounds[j] = numeric_traits::zero(); - this->m_upper_bounds[j] = numeric_traits::zero(); - } -} - -template void lp_dual_simplex::fill_costs_and_bounds_and_column_types_for_the_first_stage_solver() { - unsigned j = this->m_A->column_count(); - while (j-- > this->number_of_core_structurals()) { // go over logicals here - fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(j); - } - j = this->number_of_core_structurals(); - while (j--) { - fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_structural_column(j); - } -} - -template void lp_dual_simplex::fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row, - unsigned & slack_var, - unsigned & artificial) { - lp_assert(row < this->row_count()); - auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; - // we need to bring the program to the form Ax = b - T rs = this->m_b[row]; - switch (constraint.m_relation) { - case Equal: // no slack variable here - set_type_for_logical(artificial, column_type::fixed); - this->m_basis[row] = artificial; - this->m_costs[artificial] = numeric_traits::zero(); - (*this->m_A)(row, artificial) = numeric_traits::one(); - artificial++; - break; - - case Greater_or_equal: - set_type_for_logical(slack_var, column_type::lower_bound); - (*this->m_A)(row, slack_var) = - numeric_traits::one(); - if (rs > 0) { - // adding one artificial - set_type_for_logical(artificial, column_type::fixed); - (*this->m_A)(row, artificial) = numeric_traits::one(); - this->m_basis[row] = artificial; - this->m_costs[artificial] = numeric_traits::zero(); - artificial++; - } else { - // we can put a slack_var into the basis, and avoid adding an artificial variable - this->m_basis[row] = slack_var; - this->m_costs[slack_var] = numeric_traits::zero(); - } - slack_var++; - break; - case Less_or_equal: - // introduce a non-negative slack variable - set_type_for_logical(slack_var, column_type::lower_bound); - (*this->m_A)(row, slack_var) = numeric_traits::one(); - if (rs < 0) { - // adding one artificial - set_type_for_logical(artificial, column_type::fixed); - (*this->m_A)(row, artificial) = - numeric_traits::one(); - this->m_basis[row] = artificial; - this->m_costs[artificial] = numeric_traits::zero(); - artificial++; - } else { - // we can put slack_var into the basis, and avoid adding an artificial variable - this->m_basis[row] = slack_var; - this->m_costs[slack_var] = numeric_traits::zero(); - } - slack_var++; - break; - } -} - -template void lp_dual_simplex::augment_matrix_A_and_fill_x_and_allocate_some_fields() { - this->count_slacks_and_artificials(); - this->m_A->add_columns_at_the_end(this->m_slacks + this->m_artificials); - unsigned n = this->m_A->column_count(); - this->m_column_types_of_core_solver.resize(n); - m_column_types_of_logicals.resize(this->m_slacks + this->m_artificials); - this->m_costs.resize(n); - this->m_upper_bounds.resize(n); - this->m_lower_bounds.resize(n); - m_can_enter_basis.resize(n); - this->m_basis.resize(this->m_A->row_count()); -} - - - -template void lp_dual_simplex::copy_m_b_aside_and_set_it_to_zeros() { - for (unsigned i = 0; i < this->m_b.size(); i++) { - m_b_copy.push_back(this->m_b[i]); - this->m_b[i] = numeric_traits::zero(); // preparing for the first stage - } -} - -template void lp_dual_simplex::find_maximal_solution(){ - if (this->problem_is_empty()) { - this->m_status = lp_status::EMPTY; - return; - } - - this->flip_costs(); // do it for now, todo ( remove the flipping) - - this->cleanup(); - if (this->m_status == lp_status::INFEASIBLE) { - return; - } - this->fill_matrix_A_and_init_right_side(); - this->fill_m_b(); - this->scale(); - augment_matrix_A_and_fill_x_and_allocate_some_fields(); - fill_first_stage_solver_fields(); - copy_m_b_aside_and_set_it_to_zeros(); - stage1(); - if (this->m_status == lp_status::FEASIBLE) { - stage2(); - } -} - - -template T lp_dual_simplex::get_current_cost() const { - T ret = numeric_traits::zero(); - for (auto it : this->m_map_from_var_index_to_column_info) { - ret += this->get_column_cost_value(it.first, it.second); - } - return -ret; // we flip costs for now -} -} diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 4b6163df810..a60395ab014 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -30,7 +30,6 @@ Revision History: #include #include #include "math/lp/lu.h" -#include "math/lp/lp_solver.h" #include "math/lp/static_matrix.h" #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/lp_core_solver_base.h" diff --git a/src/math/lp/lp_primal_simplex.cpp b/src/math/lp/lp_primal_simplex.cpp deleted file mode 100644 index 634f529009b..00000000000 --- a/src/math/lp/lp_primal_simplex.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include -#include -#include "util/vector.h" -#include -#include "math/lp/lp_primal_simplex_def.h" -template bool lp::lp_primal_simplex::bounds_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template bool lp::lp_primal_simplex::row_constraints_hold(std::unordered_map, std::equal_to, std::allocator > > const&); -template double lp::lp_primal_simplex::get_current_cost() const; -template double lp::lp_primal_simplex::get_column_value(unsigned int) const; -template lp::lp_primal_simplex::~lp_primal_simplex(); -template lp::lp_primal_simplex::~lp_primal_simplex(); -template lp::mpq lp::lp_primal_simplex::get_current_cost() const; -template lp::mpq lp::lp_primal_simplex::get_column_value(unsigned int) const; -template void lp::lp_primal_simplex::find_maximal_solution(); -template void lp::lp_primal_simplex::find_maximal_solution(); diff --git a/src/math/lp/lp_primal_simplex.h b/src/math/lp/lp_primal_simplex.h deleted file mode 100644 index 77e12d0888e..00000000000 --- a/src/math/lp/lp_primal_simplex.h +++ /dev/null @@ -1,106 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once -#include "util/vector.h" -#include -#include -#include -#include "math/lp/lp_utils.h" -#include "math/lp/column_info.h" -#include "math/lp/lp_primal_core_solver.h" -#include "math/lp/lp_solver.h" -namespace lp { -template -class lp_primal_simplex: public lp_solver { - lp_primal_core_solver * m_core_solver; - vector m_lower_bounds; -private: - unsigned original_rows() { return this->m_external_rows_to_core_solver_rows.size(); } - - void fill_costs_and_x_for_first_stage_solver(unsigned original_number_of_columns); - - void init_buffer(unsigned k, vector & r); - - void refactor(); - - void set_scaled_costs(); -public: - lp_primal_simplex(): m_core_solver(nullptr) {} - - column_info * get_or_create_column_info(unsigned column); - - void set_status(lp_status status) { - this->m_status = status; - } - - lp_status get_status() { - return this->m_status; - } - - void fill_acceptable_values_for_x(); - - - void set_zero_bound(bool * bound_is_set, T * bounds, unsigned i); - - void fill_costs_and_x_for_first_stage_solver_for_row( - int row, - unsigned & slack_var, - unsigned & artificial); - - - - - void set_core_solver_bounds(); - - void find_maximal_solution() override; - - void fill_A_x_and_basis_for_stage_one_total_inf(); - - void fill_A_x_and_basis_for_stage_one_total_inf_for_row(unsigned row); - - void solve_with_total_inf(); - - - ~lp_primal_simplex() override; - - bool bounds_hold(std::unordered_map const & solution); - - T get_row_value(unsigned i, std::unordered_map const & solution, std::ostream * out); - - bool row_constraint_holds(unsigned i, std::unordered_map const & solution, std::ostream * out); - - bool row_constraints_hold(std::unordered_map const & solution); - - - T * get_array_from_map(std::unordered_map const & solution); - - bool solution_is_feasible(std::unordered_map const & solution) { - return bounds_hold(solution) && row_constraints_hold(solution); - } - - T get_column_value(unsigned column) const override { - return this->get_column_value_with_core_solver(column, m_core_solver); - } - - T get_current_cost() const override; - - -}; -} diff --git a/src/math/lp/lp_primal_simplex_def.h b/src/math/lp/lp_primal_simplex_def.h deleted file mode 100644 index 7ffe819b207..00000000000 --- a/src/math/lp/lp_primal_simplex_def.h +++ /dev/null @@ -1,367 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include "util/vector.h" -#include "math/lp/lp_primal_simplex.h" - -namespace lp { -template void lp_primal_simplex::fill_costs_and_x_for_first_stage_solver(unsigned original_number_of_columns) { - unsigned slack_var = original_number_of_columns; - unsigned artificial = original_number_of_columns + this->m_slacks; - - for (unsigned row = 0; row < this->row_count(); row++) { - fill_costs_and_x_for_first_stage_solver_for_row(row, slack_var, artificial); - } -} - -template void lp_primal_simplex::init_buffer(unsigned k, vector & r) { - for (unsigned i = 0; i < k; i++) { - r[i] = 0; - } - r[k] = 1; - for (unsigned i = this->row_count() -1; i > k; i--) { - r[i] = 0; - } -} - -template void lp_primal_simplex::refactor() { - m_core_solver->init_lu(); - if (m_core_solver->factorization()->get_status() != LU_status::OK) { - throw_exception("cannot refactor"); - } -} - -template void lp_primal_simplex::set_scaled_costs() { - unsigned j = this->number_of_core_structurals(); - while (j-- > 0) { - this->set_scaled_cost(j); - } -} - -template column_info * lp_primal_simplex::get_or_create_column_info(unsigned column) { - auto it = this->m_columns.find(column); - return (it == this->m_columns.end())? ( this->m_columns[column] = new column_info) : it->second; -} - -template void lp_primal_simplex::fill_acceptable_values_for_x() { - for (auto t : this->m_core_solver_columns_to_external_columns) { - this->m_x[t.first] = numeric_traits::zero(); - } -} - - -template void lp_primal_simplex::set_zero_bound(bool * bound_is_set, T * bounds, unsigned i) { - bound_is_set[i] = true; - bounds[i] = numeric_traits::zero(); -} - -template void lp_primal_simplex::fill_costs_and_x_for_first_stage_solver_for_row( - int row, - unsigned & slack_var, - unsigned & artificial) { - lp_assert(row >= 0 && row < this->row_count()); - auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[row]]; - // we need to bring the program to the form Ax = b - T rs = this->m_b[row]; - T artificial_cost = - numeric_traits::one(); - switch (constraint.m_relation) { - case Equal: // no slack variable here - this->m_column_types[artificial] = column_type::lower_bound; - this->m_costs[artificial] = artificial_cost; // we are maximizing, so the artificial, which is non-negatiive, will be pushed to zero - this->m_basis[row] = artificial; - if (rs >= 0) { - (*this->m_A)(row, artificial) = numeric_traits::one(); - this->m_x[artificial] = rs; - } else { - (*this->m_A)(row, artificial) = - numeric_traits::one(); - this->m_x[artificial] = - rs; - } - artificial++; - break; - - case Greater_or_equal: - this->m_column_types[slack_var] = column_type::lower_bound; - (*this->m_A)(row, slack_var) = - numeric_traits::one(); - - if (rs > 0) { - lp_assert(numeric_traits::is_zero(this->m_x[slack_var])); - // adding one artificial - this->m_column_types[artificial] = column_type::lower_bound; - (*this->m_A)(row, artificial) = numeric_traits::one(); - this->m_costs[artificial] = artificial_cost; - this->m_basis[row] = artificial; - this->m_x[artificial] = rs; - artificial++; - } else { - // we can put a slack_var into the basis, and atemplate void lp_primal_simplex::adding an artificial variable - this->m_basis[row] = slack_var; - this->m_x[slack_var] = - rs; - } - slack_var++; - break; - case Less_or_equal: - // introduce a non-negative slack variable - this->m_column_types[slack_var] = column_type::lower_bound; - (*this->m_A)(row, slack_var) = numeric_traits::one(); - - if (rs < 0) { - // adding one artificial - lp_assert(numeric_traits::is_zero(this->m_x[slack_var])); - this->m_column_types[artificial] = column_type::lower_bound; - (*this->m_A)(row, artificial) = - numeric_traits::one(); - this->m_costs[artificial] = artificial_cost; - this->m_x[artificial] = - rs; - this->m_basis[row] = artificial++; - } else { - // we can put slack_var into the basis, and atemplate void lp_primal_simplex::adding an artificial variable - this->m_basis[row] = slack_var; - this->m_x[slack_var] = rs; - } - slack_var++; - break; - } -} - - - - - -template void lp_primal_simplex::set_core_solver_bounds() { - unsigned total_vars = this->m_A->column_count() + this->m_slacks + this->m_artificials; - this->m_column_types.resize(total_vars); - this->m_upper_bounds.resize(total_vars); - for (auto cit : this->m_map_from_var_index_to_column_info) { - column_info * ci = cit.second; - unsigned j = ci->get_column_index(); - if (!is_valid(j)) - continue; // the variable is not mapped to a column - switch (this->m_column_types[j] = ci->get_column_type()){ - case column_type::fixed: - this->m_upper_bounds[j] = numeric_traits::zero(); - break; - case column_type::boxed: - this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j]; - break; - - default: break; // do nothing - } - } -} - - -template void lp_primal_simplex::find_maximal_solution() { - if (this->problem_is_empty()) { - this->m_status = lp_status::EMPTY; - return; - } - - this->cleanup(); - this->fill_matrix_A_and_init_right_side(); - if (this->m_status == lp_status::INFEASIBLE) { - return; - } - this->m_x.resize(this->m_A->column_count()); - this->fill_m_b(); - this->scale(); - fill_acceptable_values_for_x(); - this->count_slacks_and_artificials(); - set_core_solver_bounds(); - solve_with_total_inf(); -} - -template void lp_primal_simplex::fill_A_x_and_basis_for_stage_one_total_inf() { - for (unsigned row = 0; row < this->row_count(); row++) - fill_A_x_and_basis_for_stage_one_total_inf_for_row(row); -} - -template void lp_primal_simplex::fill_A_x_and_basis_for_stage_one_total_inf_for_row(unsigned row) { - lp_assert(row < this->row_count()); - auto ext_row_it = this->m_core_solver_rows_to_external_rows.find(row); - lp_assert(ext_row_it != this->m_core_solver_rows_to_external_rows.end()); - unsigned ext_row = ext_row_it->second; - auto constr_it = this->m_constraints.find(ext_row); - lp_assert(constr_it != this->m_constraints.end()); - auto & constraint = constr_it->second; - unsigned j = this->m_A->column_count(); // j is a slack variable - this->m_A->add_column(); - // we need to bring the program to the form Ax = b - this->m_basis[row] = j; - switch (constraint.m_relation) { - case Equal: - this->m_x[j] = this->m_b[row]; - (*this->m_A)(row, j) = numeric_traits::one(); - this->m_column_types[j] = column_type::fixed; - this->m_upper_bounds[j] = m_lower_bounds[j] = zero_of_type(); - break; - - case Greater_or_equal: - this->m_x[j] = - this->m_b[row]; - (*this->m_A)(row, j) = - numeric_traits::one(); - this->m_column_types[j] = column_type::lower_bound; - this->m_upper_bounds[j] = zero_of_type(); - break; - case Less_or_equal: - this->m_x[j] = this->m_b[row]; - (*this->m_A)(row, j) = numeric_traits::one(); - this->m_column_types[j] = column_type::lower_bound; - this->m_upper_bounds[j] = m_lower_bounds[j] = zero_of_type(); - break; - default: - lp_unreachable(); - } -} - -template void lp_primal_simplex::solve_with_total_inf() { - int total_vars = this->m_A->column_count() + this->row_count(); - if (total_vars == 0) { - this->m_status = lp_status::OPTIMAL; - return; - } - m_lower_bounds.clear(); - m_lower_bounds.resize(total_vars, zero_of_type()); // low bounds are shifted ot zero - this->m_x.resize(total_vars, numeric_traits::zero()); - this->m_basis.resize(this->row_count()); - this->m_costs.clear(); - this->m_costs.resize(total_vars, zero_of_type()); - fill_A_x_and_basis_for_stage_one_total_inf(); - if (this->m_settings.get_message_ostream() != nullptr) - this->print_statistics_on_A(*this->m_settings.get_message_ostream()); - set_scaled_costs(); - - m_core_solver = new lp_primal_core_solver(*this->m_A, - this->m_b, - this->m_x, - this->m_basis, - this->m_nbasis, - this->m_heading, - this->m_costs, - this->m_column_types, - m_lower_bounds, - this->m_upper_bounds, - this->m_settings, *this); - m_core_solver->solve(); - this->set_status(m_core_solver->get_status()); - this->m_total_iterations = m_core_solver->total_iterations(); -} - - -template lp_primal_simplex::~lp_primal_simplex() { - delete m_core_solver; -} - -template bool lp_primal_simplex::bounds_hold(std::unordered_map const & solution) { - for (auto it : this->m_map_from_var_index_to_column_info) { - auto sol_it = solution.find(it.second->get_name()); - if (sol_it == solution.end()) { - std::stringstream s; - s << "cannot find column " << it.first << " in solution"; - throw_exception(s.str() ); - } - - if (!it.second->bounds_hold(sol_it->second)) { - it.second->bounds_hold(sol_it->second); - return false; - } - } - return true; -} - -template T lp_primal_simplex::get_row_value(unsigned i, std::unordered_map const & solution, std::ostream * out) { - auto it = this->m_A_values.find(i); - if (it == this->m_A_values.end()) { - std::stringstream s; - s << "cannot find row " << i; - throw_exception(s.str() ); - } - T ret = numeric_traits::zero(); - for (auto & pair : it->second) { - auto cit = this->m_map_from_var_index_to_column_info.find(pair.first); - lp_assert(cit != this->m_map_from_var_index_to_column_info.end()); - column_info * ci = cit->second; - auto sol_it = solution.find(ci->get_name()); - lp_assert(sol_it != solution.end()); - T column_val = sol_it->second; - if (out != nullptr) { - (*out) << pair.second << "(" << ci->get_name() << "=" << column_val << ") "; - } - ret += pair.second * column_val; - } - if (out != nullptr) { - (*out) << " = " << ret << std::endl; - } - return ret; -} - -template bool lp_primal_simplex::row_constraint_holds(unsigned i, std::unordered_map const & solution, std::ostream *out) { - T row_val = get_row_value(i, solution, out); - auto & constraint = this->m_constraints[i]; - T rs = constraint.m_rs; - bool print = out != nullptr; - switch (constraint.m_relation) { - case Equal: - if (fabs(numeric_traits::get_double(row_val - rs)) > 0.00001) { - if (print) { - (*out) << "should be = " << rs << std::endl; - } - return false; - } - return true; - case Greater_or_equal: - if (numeric_traits::get_double(row_val - rs) < -0.00001) { - if (print) { - (*out) << "should be >= " << rs << std::endl; - } - return false; - } - return true;; - - case Less_or_equal: - if (numeric_traits::get_double(row_val - rs) > 0.00001) { - if (print) { - (*out) << "should be <= " << rs << std::endl; - } - return false; - } - return true;; - } - lp_unreachable(); - return false; // it is unreachable -} - -template bool lp_primal_simplex::row_constraints_hold(std::unordered_map const & solution) { - for (auto it : this->m_A_values) { - if (!row_constraint_holds(it.first, solution, nullptr)) { - row_constraint_holds(it.first, solution, nullptr); - return false; - } - } - return true; -} - -template T lp_primal_simplex::get_current_cost() const { - T ret = numeric_traits::zero(); - for (auto it : this->m_map_from_var_index_to_column_info) { - ret += this->get_column_cost_value(it.first, it.second); - } - return ret; -} -} diff --git a/src/math/lp/lp_solver.cpp b/src/math/lp/lp_solver.cpp deleted file mode 100644 index fc95140982b..00000000000 --- a/src/math/lp/lp_solver.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include "math/lp/lp_solver_def.h" -template void lp::lp_solver::add_constraint(lp::lp_relation, double, unsigned int); -template void lp::lp_solver::cleanup(); -template void lp::lp_solver::count_slacks_and_artificials(); -template void lp::lp_solver::fill_m_b(); -template void lp::lp_solver::fill_matrix_A_and_init_right_side(); -template void lp::lp_solver::flip_costs(); -template double lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; -template int lp::lp_solver::get_column_index_by_name(std::string) const; -template double lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; -template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); -template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lp::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lp::lp_solver::problem_is_empty(); -template void lp::lp_solver::scale(); -template void lp::lp_solver::set_scaled_cost(unsigned int); -template lp::lp_solver::~lp_solver(); -template void lp::lp_solver::add_constraint(lp::lp_relation, lp::mpq, unsigned int); -template void lp::lp_solver::cleanup(); -template void lp::lp_solver::count_slacks_and_artificials(); -template void lp::lp_solver::fill_m_b(); -template void lp::lp_solver::fill_matrix_A_and_init_right_side(); -template void lp::lp_solver::flip_costs(); -template lp::mpq lp::lp_solver::get_column_cost_value(unsigned int, lp::column_info*) const; -template int lp::lp_solver::get_column_index_by_name(std::string) const; -template lp::mpq lp::lp_solver::get_column_value_by_name(std::string) const; -template lp::mpq lp::lp_solver::get_column_value_with_core_solver(unsigned int, lp::lp_core_solver_base*) const; -template lp::column_info* lp::lp_solver::get_or_create_column_info(unsigned int); -template void lp::lp_solver::give_symbolic_name_to_column(std::string, unsigned int); -template void lp::lp_solver::print_statistics_on_A(std::ostream & out); -template bool lp::lp_solver::problem_is_empty(); -template void lp::lp_solver::scale(); -template void lp::lp_solver::set_scaled_cost(unsigned int); -template lp::lp_solver::~lp_solver(); -template double lp::lp_solver::get_column_value_by_name(std::string) const; diff --git a/src/math/lp/lp_solver.h b/src/math/lp/lp_solver.h deleted file mode 100644 index ab16a686fd6..00000000000 --- a/src/math/lp/lp_solver.h +++ /dev/null @@ -1,260 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include -#include -#include -#include "util/vector.h" -#include "math/lp/lp_settings.h" -#include "math/lp/column_info.h" -#include "math/lp/static_matrix.h" -#include "math/lp/lp_core_solver_base.h" -#include "math/lp/scaler.h" -#include "math/lp/bound_analyzer_on_row.h" -namespace lp { -enum lp_relation { - Less_or_equal, - Equal, - Greater_or_equal -}; - -template -struct lp_constraint { - X m_rs; // right side of the constraint - lp_relation m_relation; - lp_constraint() {} // empty constructor - lp_constraint(T rs, lp_relation relation): m_rs(rs), m_relation(relation) {} -}; - - -template -class lp_solver : public column_namer { - column_info * get_or_create_column_info(unsigned column); - -protected: - T get_column_cost_value(unsigned j, column_info * ci) const; -public: - unsigned m_total_iterations; - static_matrix* m_A; // this is the matrix of constraints - vector m_b; // the right side vector - unsigned m_first_stage_iterations; - unsigned m_second_stage_iterations; - std::unordered_map> m_constraints; - std::unordered_map*> m_map_from_var_index_to_column_info; - std::unordered_map > m_A_values; - std::unordered_map m_names_to_columns; // don't have to use it - std::unordered_map m_external_rows_to_core_solver_rows; - std::unordered_map m_core_solver_rows_to_external_rows; - std::unordered_map m_core_solver_columns_to_external_columns; - vector m_column_scale; - std::unordered_map m_name_map; - unsigned m_artificials; - unsigned m_slacks; - vector m_column_types; - vector m_costs; - vector m_x; - vector m_upper_bounds; - vector m_basis; - vector m_nbasis; - vector m_heading; - - - lp_status m_status; - - lp_settings m_settings; - lp_solver(): - m_A(nullptr), // this is the matrix of constraints - m_first_stage_iterations (0), - m_second_stage_iterations (0), - m_artificials (0), - m_slacks (0), - m_status(lp_status::UNKNOWN) - {} - - unsigned row_count() const { return this->m_A->row_count(); } - - void add_constraint(lp_relation relation, T right_side, unsigned row_index); - - void set_cost_for_column(unsigned column, T column_cost) { - get_or_create_column_info(column)->set_cost(column_cost); - } - std::string get_variable_name(unsigned j) const override; - - void set_row_column_coefficient(unsigned row, unsigned column, T const & val) { - m_A_values[row][column] = val; - } - // returns the current cost - virtual T get_current_cost() const = 0; - // do not have to call it - void give_symbolic_name_to_column(std::string name, unsigned column); - - virtual T get_column_value(unsigned column) const = 0; - - T get_column_value_by_name(std::string name) const; - - // returns -1 if not found - virtual int get_column_index_by_name(std::string name) const; - - void set_lower_bound(unsigned i, T bound) { - column_info *ci = get_or_create_column_info(i); - ci->set_lower_bound(bound); - } - - void set_upper_bound(unsigned i, T bound) { - column_info *ci = get_or_create_column_info(i); - ci->set_upper_bound(bound); - } - - void unset_lower_bound(unsigned i) { - get_or_create_column_info(i)->unset_lower_bound(); - } - - void unset_upper_bound(unsigned i) { - get_or_create_column_info(i)->unset_upper_bound(); - } - - void set_fixed_value(unsigned i, T val) { - column_info *ci = get_or_create_column_info(i); - ci->set_fixed_value(val); - } - - void unset_fixed_value(unsigned i) { - get_or_create_column_info(i)->unset_fixed(); - } - - lp_status get_status() const { - return m_status; - } - - void set_status(lp_status st) { - m_status = st; - } - - - ~lp_solver() override; - - void flip_costs(); - - virtual void find_maximal_solution() = 0; - void set_time_limit(unsigned time_limit_in_seconds) { - m_settings.time_limit = time_limit_in_seconds; - } - - -protected: - bool problem_is_empty(); - - void scale(); - - - void print_rows_scale_stats(std::ostream & out); - - void print_columns_scale_stats(std::ostream & out); - - void print_row_scale_stats(unsigned i, std::ostream & out); - - void print_column_scale_stats(unsigned j, std::ostream & out); - - void print_scale_stats(std::ostream & out); - - void get_max_abs_in_row(std::unordered_map & row_map); - - void pin_vars_down_on_row(std::unordered_map & row) { - pin_vars_on_row_with_sign(row, - numeric_traits::one()); - } - - void pin_vars_up_on_row(std::unordered_map & row) { - pin_vars_on_row_with_sign(row, numeric_traits::one()); - } - - void pin_vars_on_row_with_sign(std::unordered_map & row, T sign ); - - bool get_minimal_row_value(std::unordered_map & row, T & lower_bound); - - bool get_maximal_row_value(std::unordered_map & row, T & lower_bound); - - bool row_is_zero(std::unordered_map & row); - - bool row_e_is_obsolete(std::unordered_map & row, unsigned row_index); - - bool row_ge_is_obsolete(std::unordered_map & row, unsigned row_index); - - bool row_le_is_obsolete(std::unordered_map & row, unsigned row_index); - - // analyse possible max and min values that are derived from var boundaries - // Let us say that the we have a "ge" constraint, and the min value is equal to the rs. - // Then we know what values of the variables are. For each positive coeff of the row it has to be - // the low boundary of the var and for a negative - the upper. - - // this routing also pins the variables to the boundaries - bool row_is_obsolete(std::unordered_map & row, unsigned row_index ); - - void remove_fixed_or_zero_columns(); - - void remove_fixed_or_zero_columns_from_row(unsigned i, std::unordered_map & row); - - unsigned try_to_remove_some_rows(); - - void cleanup(); - - void map_external_rows_to_core_solver_rows(); - - void map_external_columns_to_core_solver_columns(); - - unsigned number_of_core_structurals() { - return static_cast(m_core_solver_columns_to_external_columns.size()); - } - - void restore_column_scales_to_one() { - for (unsigned i = 0; i < m_column_scale.size(); i++) m_column_scale[i] = numeric_traits::one(); - } - - void unscale(); - - void fill_A_from_A_values(); - - void fill_matrix_A_and_init_right_side(); - - void count_slacks_and_artificials(); - - void count_slacks_and_artificials_for_row(unsigned i); - - T lower_bound_shift_for_row(unsigned i); - - void fill_m_b(); - - T get_column_value_with_core_solver(unsigned column, lp_core_solver_base * core_solver) const; - void set_scaled_cost(unsigned j); - void print_statistics_on_A(std::ostream & out) { - out << "extended A[" << this->m_A->row_count() << "," << this->m_A->column_count() << "]" << std::endl; - } - -public: - lp_settings & settings() { return m_settings;} - void print_model(std::ostream & s) const { - s << "objective = " << get_current_cost() << std::endl; - s << "column values\n"; - for (auto & it : m_names_to_columns) { - s << it.first << " = " << get_column_value(it.second) << std::endl; - } - } -}; -} diff --git a/src/math/lp/lp_solver_def.h b/src/math/lp/lp_solver_def.h deleted file mode 100644 index 191832a2487..00000000000 --- a/src/math/lp/lp_solver_def.h +++ /dev/null @@ -1,571 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include -#include "util/vector.h" -#include "math/lp/lp_solver.h" -namespace lp { -template column_info * lp_solver::get_or_create_column_info(unsigned column) { - auto it = m_map_from_var_index_to_column_info.find(column); - return (it == m_map_from_var_index_to_column_info.end())? (m_map_from_var_index_to_column_info[column] = new column_info()) : it->second; -} - -template -std::string lp_solver::get_variable_name(unsigned j) const { // j here is the core solver index - if (!m_settings.print_external_var_name()) - return std::string("j")+T_to_string(j); - auto it = this->m_core_solver_columns_to_external_columns.find(j); - if (it == this->m_core_solver_columns_to_external_columns.end()) - return std::string("x")+T_to_string(j); - unsigned external_j = it->second; - auto t = this->m_map_from_var_index_to_column_info.find(external_j); - if (t == this->m_map_from_var_index_to_column_info.end()) { - return std::string("x") +T_to_string(external_j); - } - return t->second->get_name(); -} - -template T lp_solver::get_column_cost_value(unsigned j, column_info * ci) const { - if (ci->is_fixed()) { - return ci->get_cost() * ci->get_fixed_value(); - } - return ci->get_cost() * get_column_value(j); -} -template void lp_solver::add_constraint(lp_relation relation, T right_side, unsigned row_index) { - lp_assert(m_constraints.find(row_index) == m_constraints.end()); - lp_constraint cs(right_side, relation); - m_constraints[row_index] = cs; -} - -template void lp_solver::give_symbolic_name_to_column(std::string name, unsigned column) { - auto it = m_map_from_var_index_to_column_info.find(column); - column_info *ci; - if (it == m_map_from_var_index_to_column_info.end()){ - m_map_from_var_index_to_column_info[column] = ci = new column_info; - } else { - ci = it->second; - } - ci->set_name(name); - m_names_to_columns[name] = column; -} - - -template T lp_solver::get_column_value_by_name(std::string name) const { - auto it = m_names_to_columns.find(name); - if (it == m_names_to_columns.end()) { - std::stringstream s; - s << "get_column_value_by_name " << name; - throw_exception(s.str()); - } - return get_column_value(it -> second); -} - -// returns -1 if not found -template int lp_solver::get_column_index_by_name(std::string name) const { - auto t = m_names_to_columns.find(name); - if (t == m_names_to_columns.end()) { - return -1; - } - return t->second; -} - - -template lp_solver::~lp_solver(){ - delete m_A; - for (auto t : m_map_from_var_index_to_column_info) { - delete t.second; - } -} - -template void lp_solver::flip_costs() { - for (auto t : m_map_from_var_index_to_column_info) { - column_info *ci = t.second; - ci->set_cost(-ci->get_cost()); - } -} - -template bool lp_solver::problem_is_empty() { - for (auto & c : m_A_values) - if (!c.second.empty()) - return false; - return true; -} - -template void lp_solver::scale() { - if (numeric_traits::precise() || m_settings.use_scaling == false) { - m_column_scale.clear(); - m_column_scale.resize(m_A->column_count(), one_of_type()); - return; - } - - T smin = T(m_settings.scaling_minimum); - T smax = T(m_settings.scaling_maximum); - - scaler scaler(m_b, *m_A, smin, smax, m_column_scale, this->m_settings); - if (!scaler.scale()) { - unscale(); - } -} - - -template void lp_solver::print_rows_scale_stats(std::ostream & out) { - out << "rows max" << std::endl; - for (unsigned i = 0; i < m_A->row_count(); i++) { - print_row_scale_stats(i, out); - } - out << std::endl; -} - -template void lp_solver::print_columns_scale_stats(std::ostream & out) { - out << "columns max" << std::endl; - for (unsigned i = 0; i < m_A->column_count(); i++) { - print_column_scale_stats(i, out); - } - out << std::endl; -} - -template void lp_solver::print_row_scale_stats(unsigned i, std::ostream & out) { - out << "(" << std::min(m_A->get_min_abs_in_row(i), abs(m_b[i])) << " "; - out << std::max(m_A->get_max_abs_in_row(i), abs(m_b[i])) << ")"; -} - -template void lp_solver::print_column_scale_stats(unsigned j, std::ostream & out) { - out << "(" << m_A->get_min_abs_in_row(j) << " "; - out << m_A->get_max_abs_in_column(j) << ")"; -} - -template void lp_solver::print_scale_stats(std::ostream & out) { - print_rows_scale_stats(out); - print_columns_scale_stats(out); -} - -template void lp_solver::get_max_abs_in_row(std::unordered_map & row_map) { - T ret = numeric_traits::zero(); - for (auto jp : row_map) { - T ac = numeric_traits::abs(jp->second); - if (ac > ret) { - ret = ac; - } - } - return ret; -} - -template void lp_solver::pin_vars_on_row_with_sign(std::unordered_map & row, T sign ) { - for (auto t : row) { - unsigned j = t.first; - column_info * ci = m_map_from_var_index_to_column_info[j]; - T a = t.second; - if (a * sign > numeric_traits::zero()) { - lp_assert(ci->upper_bound_is_set()); - ci->set_fixed_value(ci->get_upper_bound()); - } else { - lp_assert(ci->lower_bound_is_set()); - ci->set_fixed_value(ci->get_lower_bound()); - } - } -} - -template bool lp_solver::get_minimal_row_value(std::unordered_map & row, T & lower_bound) { - lower_bound = numeric_traits::zero(); - for (auto & t : row) { - T a = t.second; - column_info * ci = m_map_from_var_index_to_column_info[t.first]; - if (a > numeric_traits::zero()) { - if (ci->lower_bound_is_set()) { - lower_bound += ci->get_lower_bound() * a; - } else { - return false; - } - } else { - if (ci->upper_bound_is_set()) { - lower_bound += ci->get_upper_bound() * a; - } else { - return false; - } - } - } - return true; -} - -template bool lp_solver::get_maximal_row_value(std::unordered_map & row, T & lower_bound) { - lower_bound = numeric_traits::zero(); - for (auto & t : row) { - T a = t.second; - column_info * ci = m_map_from_var_index_to_column_info[t.first]; - if (a < numeric_traits::zero()) { - if (ci->lower_bound_is_set()) { - lower_bound += ci->get_lower_bound() * a; - } else { - return false; - } - } else { - if (ci->upper_bound_is_set()) { - lower_bound += ci->get_upper_bound() * a; - } else { - return false; - } - } - } - return true; -} - -template bool lp_solver::row_is_zero(std::unordered_map & row) { - for (auto & t : row) { - if (!is_zero(t.second)) - return false; - } - return true; -} - -template bool lp_solver::row_e_is_obsolete(std::unordered_map & row, unsigned row_index) { - T rs = m_constraints[row_index].m_rs; - if (row_is_zero(row)) { - if (!is_zero(rs)) - m_status = lp_status::INFEASIBLE; - return true; - } - - T lower_bound; - bool lb = get_minimal_row_value(row, lower_bound); - if (lb) { - T diff = lower_bound - rs; - if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)){ - // lower_bound > rs + m_settings.refactor_epsilon - m_status = lp_status::INFEASIBLE; - return true; - } - if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ - pin_vars_down_on_row(row); - return true; - } - } - - T upper_bound; - bool ub = get_maximal_row_value(row, upper_bound); - if (ub) { - T diff = rs - upper_bound; - if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { - // upper_bound < rs - m_settings.refactor_tolerance - m_status = lp_status::INFEASIBLE; - return true; - } - if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ - pin_vars_up_on_row(row); - return true; - } - } - - return false; -} - -template bool lp_solver::row_ge_is_obsolete(std::unordered_map & row, unsigned row_index) { - T rs = m_constraints[row_index].m_rs; - if (row_is_zero(row)) { - if (rs > zero_of_type()) - m_status = lp_status::INFEASIBLE; - return true; - } - - T upper_bound; - if (get_maximal_row_value(row, upper_bound)) { - T diff = rs - upper_bound; - if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)) { - // upper_bound < rs - m_settings.refactor_tolerance - m_status = lp_status::INFEASIBLE; - return true; - } - if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ - pin_vars_up_on_row(row); - return true; - } - } - - return false; -} - -template bool lp_solver::row_le_is_obsolete(std::unordered_map & row, unsigned row_index) { - T lower_bound; - T rs = m_constraints[row_index].m_rs; - if (row_is_zero(row)) { - if (rs < zero_of_type()) - m_status = lp_status::INFEASIBLE; - return true; - } - - if (get_minimal_row_value(row, lower_bound)) { - T diff = lower_bound - rs; - if (!val_is_smaller_than_eps(diff, m_settings.refactor_tolerance)){ - // lower_bound > rs + m_settings.refactor_tolerance - m_status = lp_status::INFEASIBLE; - return true; - } - if (val_is_smaller_than_eps(-diff, m_settings.refactor_tolerance)){ - pin_vars_down_on_row(row); - return true; - } - } - - return false; -} - -// analyse possible max and min values that are derived from var boundaries -// Let us say that the we have a "ge" constraint, and the min value is equal to the rs. -// Then we know what values of the variables are. For each positive coeff of the row it has to be -// the low boundary of the var and for a negative - the upper. - -// this routing also pins the variables to the boundaries -template bool lp_solver::row_is_obsolete(std::unordered_map & row, unsigned row_index ) { - auto & constraint = m_constraints[row_index]; - switch (constraint.m_relation) { - case lp_relation::Equal: - return row_e_is_obsolete(row, row_index); - - case lp_relation::Greater_or_equal: - return row_ge_is_obsolete(row, row_index); - - case lp_relation::Less_or_equal: - return row_le_is_obsolete(row, row_index); - } - lp_unreachable(); - return false; // it is unreachable -} - -template void lp_solver::remove_fixed_or_zero_columns() { - for (auto & i_row : m_A_values) { - remove_fixed_or_zero_columns_from_row(i_row.first, i_row.second); - } -} - -template void lp_solver::remove_fixed_or_zero_columns_from_row(unsigned i, std::unordered_map & row) { - auto & constraint = m_constraints[i]; - vector removed; - for (auto & col : row) { - unsigned j = col.first; - lp_assert(m_map_from_var_index_to_column_info.find(j) != m_map_from_var_index_to_column_info.end()); - column_info * ci = m_map_from_var_index_to_column_info[j]; - if (ci->is_fixed()) { - removed.push_back(j); - T aj = col.second; - constraint.m_rs -= aj * ci->get_fixed_value(); - } else { - if (numeric_traits::is_zero(col.second)){ - removed.push_back(j); - } - } - } - - for (auto j : removed) { - row.erase(j); - } -} - -template unsigned lp_solver::try_to_remove_some_rows() { - vector rows_to_delete; - for (auto & t : m_A_values) { - if (row_is_obsolete(t.second, t.first)) { - rows_to_delete.push_back(t.first); - } - - if (m_status == lp_status::INFEASIBLE) { - return 0; - } - } - if (!rows_to_delete.empty()) { - for (unsigned k : rows_to_delete) { - m_A_values.erase(k); - } - } - remove_fixed_or_zero_columns(); - return static_cast(rows_to_delete.size()); -} - -template void lp_solver::cleanup() { - int n = 0; // number of deleted rows - int d; - while ((d = try_to_remove_some_rows()) > 0) - n += d; - - if (n == 1) { - LP_OUT(m_settings, "deleted one row" << std::endl); - } else if (n) { - LP_OUT(m_settings, "deleted " << n << " rows" << std::endl); - } -} - -template void lp_solver::map_external_rows_to_core_solver_rows() { - unsigned size = 0; - for (auto & row : m_A_values) { - m_external_rows_to_core_solver_rows[row.first] = size; - m_core_solver_rows_to_external_rows[size] = row.first; - size++; - } -} - -template void lp_solver::map_external_columns_to_core_solver_columns() { - unsigned size = 0; - for (auto & row : m_A_values) { - for (auto & col : row.second) { - if (col.second == numeric_traits::zero() || m_map_from_var_index_to_column_info[col.first]->is_fixed()) { - throw_exception("found fixed column"); - } - unsigned j = col.first; - auto column_info_it = m_map_from_var_index_to_column_info.find(j); - lp_assert(column_info_it != m_map_from_var_index_to_column_info.end()); - - auto j_column = column_info_it->second->get_column_index(); - if (!is_valid(j_column)) { // j is a newcomer - m_map_from_var_index_to_column_info[j]->set_column_index(size); - m_core_solver_columns_to_external_columns[size++] = j; - } - } - } -} - -template void lp_solver::unscale() { - delete m_A; - m_A = nullptr; - fill_A_from_A_values(); - restore_column_scales_to_one(); - fill_m_b(); -} - -template void lp_solver::fill_A_from_A_values() { - m_A = new static_matrix(static_cast(m_A_values.size()), number_of_core_structurals()); - for (auto & t : m_A_values) { - auto row_it = m_external_rows_to_core_solver_rows.find(t.first); - lp_assert(row_it != m_external_rows_to_core_solver_rows.end()); - unsigned row = row_it->second; - for (auto k : t.second) { - auto column_info_it = m_map_from_var_index_to_column_info.find(k.first); - lp_assert(column_info_it != m_map_from_var_index_to_column_info.end()); - column_info *ci = column_info_it->second; - unsigned col = ci->get_column_index(); - lp_assert(is_valid(col)); - bool col_is_flipped = m_map_from_var_index_to_column_info[k.first]->is_flipped(); - if (!col_is_flipped) { - (*m_A)(row, col) = k.second; - } else { - (*m_A)(row, col) = - k.second; - } - } - } -} - -template void lp_solver::fill_matrix_A_and_init_right_side() { - map_external_rows_to_core_solver_rows(); - map_external_columns_to_core_solver_columns(); - lp_assert(m_A == nullptr); - fill_A_from_A_values(); - m_b.resize(m_A->row_count()); -} - -template void lp_solver::count_slacks_and_artificials() { - for (int i = row_count() - 1; i >= 0; i--) { - count_slacks_and_artificials_for_row(i); - } -} - -template void lp_solver::count_slacks_and_artificials_for_row(unsigned i) { - lp_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); - auto & constraint = this->m_constraints[this->m_core_solver_rows_to_external_rows[i]]; - switch (constraint.m_relation) { - case Equal: - m_artificials++; - break; - case Greater_or_equal: - m_slacks++; - if (this->m_b[i] > 0) { - m_artificials++; - } - break; - case Less_or_equal: - m_slacks++; - if (this->m_b[i] < 0) { - m_artificials++; - } - break; - } -} - -template T lp_solver::lower_bound_shift_for_row(unsigned i) { - T ret = numeric_traits::zero(); - - auto row = this->m_A_values.find(i); - if (row == this->m_A_values.end()) { - throw_exception("cannot find row"); - } - for (auto col : row->second) { - ret += col.second * this->m_map_from_var_index_to_column_info[col.first]->get_shift(); - } - return ret; -} - -template void lp_solver::fill_m_b() { - for (int i = this->row_count() - 1; i >= 0; i--) { - lp_assert(this->m_constraints.find(this->m_core_solver_rows_to_external_rows[i]) != this->m_constraints.end()); - unsigned external_i = this->m_core_solver_rows_to_external_rows[i]; - auto & constraint = this->m_constraints[external_i]; - this->m_b[i] = constraint.m_rs - lower_bound_shift_for_row(external_i); - } -} - -template T lp_solver::get_column_value_with_core_solver(unsigned column, lp_core_solver_base * core_solver) const { - auto cit = this->m_map_from_var_index_to_column_info.find(column); - if (cit == this->m_map_from_var_index_to_column_info.end()) { - return numeric_traits::zero(); - } - - column_info * ci = cit->second; - - if (ci->is_fixed()) { - return ci->get_fixed_value(); - } - - unsigned cj = ci->get_column_index(); - if (cj != static_cast(-1)) { - T v = core_solver->get_var_value(cj) * this->m_column_scale[cj]; - if (ci->is_free()) { - return v; - } - if (!ci->is_flipped()) { - return v + ci->get_lower_bound(); - } - - // the flipped case when there is only upper bound - return -v + ci->get_upper_bound(); // - } - - return numeric_traits::zero(); // returns zero for out of boundary columns -} - -template void lp_solver::set_scaled_cost(unsigned j) { - // grab original costs but modify it with the column scales - lp_assert(j < this->m_column_scale.size()); - column_info * ci = this->m_map_from_var_index_to_column_info[this->m_core_solver_columns_to_external_columns[j]]; - T cost = ci->get_cost(); - if (ci->is_flipped()){ - cost *= T(-1); - } - lp_assert(ci->is_fixed() == false); - this->m_costs[j] = cost * this->m_column_scale[j]; -} -} diff --git a/src/math/lp/mps_reader.h b/src/math/lp/mps_reader.h deleted file mode 100644 index 8093954b11e..00000000000 --- a/src/math/lp/mps_reader.h +++ /dev/null @@ -1,891 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once - -// reads an MPS file representing a Mixed Integer Program -#include -#include -#include -#include "util/vector.h" -#include -#include -#include -#include -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/lp_dual_simplex.h" -#include "math/lp/lar_solver.h" -#include "math/lp/lp_utils.h" -#include "math/lp/lp_solver.h" -namespace lp { -inline bool my_white_space(const char & a) { - return a == ' ' || a == '\t'; -} -inline size_t number_of_whites(const std::string & s) { - size_t i = 0; - for(;i < s.size(); i++) - if (!my_white_space(s[i])) return i; - return i; -} -inline size_t number_of_whites_from_end(const std::string & s) { - size_t ret = 0; - for(int i = static_cast(s.size()) - 1;i >= 0; i--) - if (my_white_space(s[i])) ret++;else break; - - return ret; -} - - - // trim from start -inline std::string <rim(std::string &s) { - s.erase(0, number_of_whites(s)); - return s; -} - - - - - // trim from end -inline std::string &rtrim(std::string &s) { - // s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); - s.erase(s.end() - number_of_whites_from_end(s), s.end()); - return s; -} - // trim from both ends -inline std::string &trim(std::string &s) { - return ltrim(rtrim(s)); -} - -inline std::string trim(std::string const &r) { - std::string s = r; - return ltrim(rtrim(s)); -} - - -inline vector string_split(const std::string &source, const char *delimiter, bool keep_empty) { - vector results; - size_t prev = 0; - size_t next = 0; - while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { - if (keep_empty || (next - prev != 0)) { - results.push_back(source.substr(prev, next - prev)); - } - prev = next + 1; - } - if (prev < source.size()) { - results.push_back(source.substr(prev)); - } - return results; -} - -inline vector split_and_trim(const std::string &line) { - auto split = string_split(line, " \t", false); - vector ret; - for (auto s : split) { - ret.push_back(trim(s)); - } - return ret; -} - -template -class mps_reader { - enum row_type { Cost, Less_or_equal, Greater_or_equal, Equal }; - struct bound { - T m_low; - T m_upper; - bool m_low_is_set; - bool m_upper_is_set; - bool m_value_is_fixed; - T m_fixed_value; - bool m_free; - // constructor - bound() : m_low(numeric_traits::zero()), - m_low_is_set(true), - m_upper_is_set(false), - m_value_is_fixed(false), - m_free(false) {} // it seems all mps files I have seen have the default low value 0 on a variable - }; - - struct column { - std::string m_name; - bound * m_bound; - unsigned m_index; - column(const std::string &name, unsigned index): m_name(name), - m_bound(nullptr), - m_index(index) { - } - }; - - struct row { - row_type m_type; - std::string m_name; - std::unordered_map m_row_columns; - unsigned m_index; - T m_right_side; - T m_range; - row(row_type type, const std::string &name, unsigned index) : - m_type(type), - m_name(name), - m_index(index), - m_right_side(zero_of_type()), - m_range(zero_of_type()) - { - } - }; - - bool m_is_OK; - std::string m_file_name; - std::unordered_map m_rows; - std::unordered_map m_columns; - std::unordered_map m_names_to_var_index; - std::string m_line; - std::string m_name; - std::string m_cost_row_name; - std::ifstream m_file_stream; - // needed to adjust the index row - unsigned m_cost_line_count; - unsigned m_line_number; - std::ostream * m_message_stream; - - void set_m_ok_to_false() { - *m_message_stream << "setting m_is_OK to false" << std::endl; - m_is_OK = false; - } - - std::string get_string_from_position(unsigned offset) { - unsigned i = offset; - for (; i < m_line.size(); i++){ - if (m_line[i] == ' ') - break; - } - lp_assert(m_line.size() >= offset); - lp_assert(m_line.size() >> i); - lp_assert(i >= offset); - return m_line.substr(offset, i - offset); - } - - void set_boundary_for_column(unsigned col, bound * b, lp_solver * solver){ - if (b == nullptr) { - solver->set_lower_bound(col, numeric_traits::zero()); - return; - } - - if (b->m_free) { - return; - } - if (b->m_low_is_set) { - solver->set_lower_bound(col, b->m_low); - } - if (b->m_upper_is_set) { - solver->set_upper_bound(col, b->m_upper); - } - - if (b->m_value_is_fixed) { - solver->set_fixed_value(col, b->m_fixed_value); - } - } - - bool all_white_space() { - for (unsigned i = 0; i < m_line.size(); i++) { - char c = m_line[i]; - if (c != ' ' && c != '\t') { - return false; - } - } - return true; - } - - void read_line() { - while (m_is_OK) { - if (!getline(m_file_stream, m_line)) { - m_line_number++; - set_m_ok_to_false(); - *m_message_stream << "cannot read from file" << std::endl; - } - m_line_number++; - if (!m_line.empty() && m_line[0] != '*' && !all_white_space()) - break; - } - } - - void read_name() { - do { - read_line(); - if (m_line.find("NAME") != 0) { - continue; - } - m_line = m_line.substr(4); - m_name = trim(m_line); - break; - } while (m_is_OK); - } - - void read_rows() { - // look for start of the rows - read_line(); - do { - if (static_cast(m_line.find("ROWS")) >= 0) { - break; - } - } while (m_is_OK); - do { - read_line(); - if (m_line.find("COLUMNS") == 0) { - break; - } - add_row(); - } while (m_is_OK); - } - - void read_column_by_columns(const std::string & column_name, std::string column_data) { - // uph, let us try to work with columns - if (column_data.size() >= 22) { - std::string ss = column_data.substr(0, 8); - std::string row_name = trim(ss); - auto t = m_rows.find(row_name); - - if (t == m_rows.end()) { - *m_message_stream << "cannot find " << row_name << std::endl; - goto fail; - } else { - row * row = t->second; - row->m_row_columns[column_name] = numeric_traits::from_string(column_data.substr(8)); - if (column_data.size() > 24) { - column_data = column_data.substr(25); - if (column_data.size() >= 22) { - read_column_by_columns(column_name, column_data); - } - } - } - } else { - fail: - set_m_ok_to_false(); - *m_message_stream << "cannot understand this line\n" - "line = " << m_line << ", line number is " << m_line_number << std::endl; - return; - } - } - - void read_column(const std::string & column_name, const std::string & column_data){ - auto tokens = split_and_trim(column_data); - for (unsigned i = 0; i < tokens.size() - 1; i+= 2) { - auto row_name = tokens[i]; - if (row_name == "'MARKER'") return; // it is the integrality marker, no real data here - auto t = m_rows.find(row_name); - if (t == m_rows.end()) { - read_column_by_columns(column_name, column_data); - return; - } - row *r = t->second; - r->m_row_columns[column_name] = numeric_traits::from_string(tokens[i + 1]); - } - } - - void read_columns(){ - std::string column_name; - do { - read_line(); - if (m_line.find("RHS") == 0) { - break; - } - if (m_line.size() < 22) { - (*m_message_stream) << "line is too short for a column" << std::endl; - (*m_message_stream) << m_line << std::endl; - (*m_message_stream) << "line number is " << m_line_number << std::endl; - set_m_ok_to_false(); - return; - } - std::string column_name_tmp = trim(m_line.substr(4, 8)); - if (!column_name_tmp.empty()) { - column_name = column_name_tmp; - } - auto col_it = m_columns.find(column_name); - mps_reader::column * col; - if (col_it == m_columns.end()) { - col = new mps_reader::column(column_name, static_cast(m_columns.size())); - m_columns[column_name] = col; - // (*m_message_stream) << column_name << '[' << col->m_index << ']'<< std::endl; - } else { - col = col_it->second; - } - read_column(column_name, m_line.substr(14)); - } while (m_is_OK); - } - - void read_rhs() { - do { - read_line(); - if (m_line.find("BOUNDS") == 0 || m_line.find("ENDATA") == 0 || m_line.find("RANGES") == 0) { - break; - } - fill_rhs(); - } while (m_is_OK); - } - - - void fill_rhs_by_columns(std::string rhsides) { - // uph, let us try to work with columns - if (rhsides.size() >= 22) { - std::string ss = rhsides.substr(0, 8); - std::string row_name = trim(ss); - auto t = m_rows.find(row_name); - - if (t == m_rows.end()) { - (*m_message_stream) << "cannot find " << row_name << std::endl; - goto fail; - } else { - row * row = t->second; - row->m_right_side = numeric_traits::from_string(rhsides.substr(8)); - if (rhsides.size() > 24) { - rhsides = rhsides.substr(25); - if (rhsides.size() >= 22) { - fill_rhs_by_columns(rhsides); - } - } - } - } else { - fail: - set_m_ok_to_false(); - (*m_message_stream) << "cannot understand this line" << std::endl; - (*m_message_stream) << "line = " << m_line << ", line number is " << m_line_number << std::endl; - return; - } - } - - void fill_rhs() { - if (m_line.size() < 14) { - (*m_message_stream) << "line is too short" << std::endl; - (*m_message_stream) << m_line << std::endl; - (*m_message_stream) << "line number is " << m_line_number << std::endl; - set_m_ok_to_false(); - return; - } - std::string rhsides = m_line.substr(14); - vector splitted_line = split_and_trim(rhsides); - - for (unsigned i = 0; i < splitted_line.size() - 1; i += 2) { - auto t = m_rows.find(splitted_line[i]); - if (t == m_rows.end()) { - fill_rhs_by_columns(rhsides); - return; - } - row * row = t->second; - row->m_right_side = numeric_traits::from_string(splitted_line[i + 1]); - } - } - - void read_bounds() { - if (m_line.find("BOUNDS") != 0) { - return; - } - - do { - read_line(); - if (m_line[0] != ' ') { - break; - } - create_or_update_bound(); - } while (m_is_OK); - } - - void read_ranges() { - if (m_line.find("RANGES") != 0) { - return; - } - do { - read_line(); - auto sl = split_and_trim(m_line); - if (sl.size() < 2) { - break; - } - read_range(sl); - } while (m_is_OK); - } - - - void read_bound_by_columns(const std::string & colstr) { - if (colstr.size() < 14) { - (*m_message_stream) << "line is too short" << std::endl; - (*m_message_stream) << m_line << std::endl; - (*m_message_stream) << "line number is " << m_line_number << std::endl; - set_m_ok_to_false(); - return; - } - // uph, let us try to work with columns - if (colstr.size() >= 22) { - std::string ss = colstr.substr(0, 8); - std::string column_name = trim(ss); - auto t = m_columns.find(column_name); - - if (t == m_columns.end()) { - (*m_message_stream) << "cannot find " << column_name << std::endl; - goto fail; - } else { - vector bound_string; - bound_string.push_back(column_name); - if (colstr.size() > 14) { - bound_string.push_back(colstr.substr(14)); - } - mps_reader::column * col = t->second; - bound * b = col->m_bound; - if (b == nullptr) { - col->m_bound = b = new bound(); - } - update_bound(b, bound_string); - } - } else { - fail: - set_m_ok_to_false(); - (*m_message_stream) << "cannot understand this line" << std::endl; - (*m_message_stream) << "line = " << m_line << ", line number is " << m_line_number << std::endl; - return; - } - } - - void update_bound(bound * b, vector bound_string) { - /* - UP means an upper bound is applied to the variable. A bound of type LO means a lower bound is applied. A bound type of FX ("fixed") means that the variable has upper and lower bounds equal to a single value. A bound type of FR ("free") means the variable has neither lower nor upper bounds and so can take on negative values. A variation on that is MI for free negative, giving an upper bound of 0 but no lower bound. Bound type PL is for a free positive for zero to plus infinity, but as this is the normal default, it is seldom used. There are also bound types for use in MIP models - BV for binary, being 0 or 1. UI for upper integer and LI for lower integer. SC stands for semi-continuous and indicates that the variable may be zero, but if not must be equal to at least the value given. - */ - - std::string bound_type = get_string_from_position(1); - if (bound_type == "BV") { - b->m_upper_is_set = true; - b->m_upper = 1; - return; - } - - if (bound_type == "UP" || bound_type == "UI" || bound_type == "LIMITMAX") { - if (bound_string.size() <= 1){ - set_m_ok_to_false(); - return; - } - b->m_upper_is_set = true; - b->m_upper= numeric_traits::from_string(bound_string[1]); - } else if (bound_type == "LO" || bound_type == "LI") { - if (bound_string.size() <= 1){ - set_m_ok_to_false(); - return; - } - - b->m_low_is_set = true; - b->m_low = numeric_traits::from_string(bound_string[1]); - } else if (bound_type == "FR") { - b->m_free = true; - } else if (bound_type == "FX") { - if (bound_string.size() <= 1){ - set_m_ok_to_false(); - return; - } - - b->m_value_is_fixed = true; - b->m_fixed_value = numeric_traits::from_string(bound_string[1]); - } else if (bound_type == "PL") { - b->m_low_is_set = true; - b->m_low = 0; - } else if (bound_type == "MI") { - b->m_upper_is_set = true; - b->m_upper = 0; - } else { - (*m_message_stream) << "unexpected bound type " << bound_type << " at line " << m_line_number << std::endl; - set_m_ok_to_false(); - throw; - } - } - - void create_or_update_bound() { - const unsigned name_offset = 14; - lp_assert(m_line.size() >= 14); - vector bound_string = split_and_trim(m_line.substr(name_offset, m_line.size())); - - if (bound_string.empty()) { - set_m_ok_to_false(); - (*m_message_stream) << "error at line " << m_line_number << std::endl; - throw m_line; - } - - std::string name = bound_string[0]; - auto it = m_columns.find(name); - if (it == m_columns.end()){ - read_bound_by_columns(m_line.substr(14)); - return; - } - mps_reader::column * col = it->second; - bound * b = col->m_bound; - if (b == nullptr) { - col->m_bound = b = new bound(); - } - update_bound(b, bound_string); - } - - - - void read_range_by_columns(std::string rhsides) { - if (m_line.size() < 14) { - (*m_message_stream) << "line is too short" << std::endl; - (*m_message_stream) << m_line << std::endl; - (*m_message_stream) << "line number is " << m_line_number << std::endl; - set_m_ok_to_false(); - return; - } - // uph, let us try to work with columns - if (rhsides.size() >= 22) { - std::string ss = rhsides.substr(0, 8); - std::string row_name = trim(ss); - auto t = m_rows.find(row_name); - - if (t == m_rows.end()) { - (*m_message_stream) << "cannot find " << row_name << std::endl; - goto fail; - } else { - row * row = t->second; - row->m_range = numeric_traits::from_string(rhsides.substr(8)); - maybe_modify_current_row_and_add_row_for_range(row); - if (rhsides.size() > 24) { - rhsides = rhsides.substr(25); - if (rhsides.size() >= 22) { - read_range_by_columns(rhsides); - } - } - } - } else { - fail: - set_m_ok_to_false(); - (*m_message_stream) << "cannot understand this line" << std::endl; - (*m_message_stream) << "line = " << m_line << ", line number is " << m_line_number << std::endl; - return; - } - } - - - void read_range(vector & splitted_line){ - for (unsigned i = 1; i < splitted_line.size() - 1; i += 2) { - auto it = m_rows.find(splitted_line[i]); - if (it == m_rows.end()) { - read_range_by_columns(m_line.substr(14)); - return; - } - row * row = it->second; - row->m_range = numeric_traits::from_string(splitted_line[i + 1]); - maybe_modify_current_row_and_add_row_for_range(row); - } - } - - void maybe_modify_current_row_and_add_row_for_range(row * row_with_range) { - unsigned index= static_cast(m_rows.size() - m_cost_line_count); - std::string row_name = row_with_range->m_name + "_range"; - row * other_bound_range_row; - switch (row_with_range->m_type) { - case row_type::Greater_or_equal: - m_rows[row_name] = other_bound_range_row = new row(row_type::Less_or_equal, row_name, index); - other_bound_range_row->m_right_side = row_with_range->m_right_side + abs(row_with_range->m_range); - break; - case row_type::Less_or_equal: - m_rows[row_name] = other_bound_range_row = new row(row_type::Greater_or_equal, row_name, index); - other_bound_range_row->m_right_side = row_with_range->m_right_side - abs(row_with_range->m_range); - break; - case row_type::Equal: - if (row_with_range->m_range > 0) { - row_with_range->m_type = row_type::Greater_or_equal; // the existing row type change - m_rows[row_name] = other_bound_range_row = new row(row_type::Less_or_equal, row_name, index); - } else { // row->m_range < 0; - row_with_range->m_type = row_type::Less_or_equal; // the existing row type change - m_rows[row_name] = other_bound_range_row = new row(row_type::Greater_or_equal, row_name, index); - } - other_bound_range_row->m_right_side = row_with_range->m_right_side + row_with_range->m_range; - break; - default: - (*m_message_stream) << "unexpected bound type " << row_with_range->m_type << " at line " << m_line_number << std::endl; - set_m_ok_to_false(); - throw; - } - - for (auto s : row_with_range->m_row_columns) { - lp_assert(m_columns.find(s.first) != m_columns.end()); - other_bound_range_row->m_row_columns[s.first] = s.second; - } - } - - void add_row() { - if (m_line.length() < 2) { - return; - } - - m_line = trim(m_line); - char c = m_line[0]; - m_line = m_line.substr(1); - m_line = trim(m_line); - add_row(c); - } - - void add_row(char c) { - unsigned index= static_cast(m_rows.size() - m_cost_line_count); - switch (c) { - case 'E': - m_rows[m_line] = new row(row_type::Equal, m_line, index); - break; - case 'L': - m_rows[m_line] = new row(row_type::Less_or_equal, m_line, index); - break; - case 'G': - m_rows[m_line] = new row(row_type::Greater_or_equal, m_line, index); - break; - case 'N': - m_rows[m_line] = new row(row_type::Cost, m_line, index); - m_cost_row_name = m_line; - m_cost_line_count++; - break; - } - } - unsigned range_count() { - unsigned ret = 0; - for (auto s : m_rows) { - if (s.second->m_range != 0) { - ret++; - } - } - return ret; - } - - /* - If rhs is a constraint's right-hand-side value and range is the constraint's range value, then the range interval is defined according to the following table: - sense interval - G [rhs, rhs + |range|] - L [rhs - |range|, rhs] - E [rhs, rhs + |range|] if range > 0, - [rhs - |range|, rhs] if range < 0 - where |range| is range's absolute value. - */ - - lp_relation get_relation_from_row(row_type rt) { - switch (rt) { - case mps_reader::Less_or_equal: return lp_relation::Less_or_equal; - case mps_reader::Greater_or_equal: return lp_relation::Greater_or_equal; - case mps_reader::Equal: return lp_relation::Equal; - default: - (*m_message_stream) << "Unexpected rt " << rt << std::endl; - set_m_ok_to_false(); - throw; - } - } - - unsigned solver_row_count() { - return m_rows.size() - m_cost_line_count + range_count(); - } - - void fill_solver_on_row(row * row, lp_solver *solver) { - if (row->m_name != m_cost_row_name) { - solver->add_constraint(get_relation_from_row(row->m_type), row->m_right_side, row->m_index); - for (auto s : row->m_row_columns) { - lp_assert(m_columns.find(s.first) != m_columns.end()); - solver->set_row_column_coefficient(row->m_index, m_columns[s.first]->m_index, s.second); - } - } else { - set_solver_cost(row, solver); - } - } - - T abs(T & t) { return t < numeric_traits::zero() ? -t: t; } - - void fill_solver_on_rows(lp_solver * solver) { - for (auto row_it : m_rows) { - fill_solver_on_row(row_it.second, solver); - } - } - - - void fill_solver_on_columns(lp_solver * solver){ - for (auto s : m_columns) { - mps_reader::column * col = s.second; - unsigned index = col->m_index; - set_boundary_for_column(index, col->m_bound, solver); - // optional call - solver->give_symbolic_name_to_column(col->m_name, col->m_index); - } - } - - void fill_solver(lp_solver *solver) { - fill_solver_on_rows(solver); - fill_solver_on_columns(solver); - } - - void set_solver_cost(row * row, lp_solver *solver) { - for (auto s : row->m_row_columns) { - std::string name = s.first; - lp_assert(m_columns.find(name) != m_columns.end()); - mps_reader::column * col = m_columns[name]; - solver->set_cost_for_column(col->m_index, s.second); - } - } - -public: - - void set_message_stream(std::ostream * o) { - lp_assert(o != nullptr); - m_message_stream = o; - } - vector column_names() { - vector v; - for (auto s : m_columns) { - v.push_back(s.first); - } - return v; - } - - ~mps_reader() { - for (auto s : m_rows) { - delete s.second; - } - for (auto s : m_columns) { - auto col = s.second; - delete col->m_bound; - delete col; - } - } - - mps_reader(const std::string & file_name): - m_is_OK(true), - m_file_name(file_name), - m_file_stream(file_name), - m_cost_line_count(0), - m_line_number(0), - m_message_stream(& std::cout) {} - void read() { - if (!m_file_stream.is_open()){ - set_m_ok_to_false(); - return; - } - - read_name(); - read_rows(); - read_columns(); - read_rhs(); - if (m_line.find("BOUNDS") == 0) { - read_bounds(); - read_ranges(); - } else if (m_line.find("RANGES") == 0) { - read_ranges(); - read_bounds(); - } - } - - bool is_ok() { - return m_is_OK; - } - - lp_solver * create_solver(bool dual) { - lp_solver * solver = dual? (lp_solver*)new lp_dual_simplex() : new lp_primal_simplex(); - fill_solver(solver); - return solver; - } - - lconstraint_kind get_lar_relation_from_row(row_type rt) { - switch (rt) { - case Less_or_equal: return LE; - case Greater_or_equal: return GE; - case Equal: return EQ; - default: - (*m_message_stream) << "Unexpected rt " << rt << std::endl; - set_m_ok_to_false(); - throw; - } - } - - unsigned get_var_index(std::string s) { - auto it = m_names_to_var_index.find(s); - if (it != m_names_to_var_index.end()) - return it->second; - unsigned ret = static_cast(m_names_to_var_index.size()); - m_names_to_var_index[s] = ret; - return ret; - } - - void fill_lar_solver_on_row(row * row, lar_solver *solver, int row_index) { - if (row->m_name != m_cost_row_name) { - auto kind = get_lar_relation_from_row(row->m_type); - vector> ls; - for (auto s : row->m_row_columns) { - var_index i = solver->add_var(get_var_index(s.first), false); - ls.push_back(std::make_pair(s.second, i)); - } - unsigned j = solver->add_term(ls, row_index); - solver->add_var_bound(j, kind, row->m_right_side); - } else { - // ignore the cost row - } - } - - - void fill_lar_solver_on_rows(lar_solver * solver) { - int row_index = 0; - for (auto row_it : m_rows) { - fill_lar_solver_on_row(row_it.second, solver, row_index++); - } - } - - void create_low_constraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index, false); - solver->add_var_bound(i, GE, b->m_low); - } - - void create_upper_constraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index, false); - solver->add_var_bound(i, LE, b->m_upper); - } - - void create_equality_contraint_for_var(column* col, bound * b, lar_solver *solver) { - var_index i = solver->add_var(col->m_index, false); - solver->add_var_bound(i, LE, b->m_fixed_value); - solver->add_var_bound(i, GE, b->m_fixed_value); - } - - void fill_lar_solver_on_columns(lar_solver * solver) { - for (auto s : m_columns) { - mps_reader::column * col = s.second; - solver->add_var(col->m_index, false); - auto b = col->m_bound; - if (b == nullptr) return; - - if (b->m_free) continue; - - if (b->m_low_is_set) { - create_low_constraint_for_var(col, b, solver); - } - if (b->m_upper_is_set) { - create_upper_constraint_for_var(col, b, solver); - } - if (b->m_value_is_fixed) { - create_equality_contraint_for_var(col, b, solver); - } - } - } - - - void fill_lar_solver(lar_solver * solver) { - fill_lar_solver_on_columns(solver); - fill_lar_solver_on_rows(solver); - } - - lar_solver * create_lar_solver() { - lar_solver * solver = new lar_solver(); - fill_lar_solver(solver); - return solver; - } -}; -} diff --git a/src/math/lp/static_matrix.cpp b/src/math/lp/static_matrix.cpp index 571e9b1d06d..cde96277b5e 100644 --- a/src/math/lp/static_matrix.cpp +++ b/src/math/lp/static_matrix.cpp @@ -24,7 +24,6 @@ Revision History: #include "math/lp/static_matrix_def.h" #include "math/lp/lp_core_solver_base.h" #include "math/lp/lp_dual_core_solver.h" -#include "math/lp/lp_dual_simplex.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/scaler.h" #include "math/lp/lar_solver.h" diff --git a/src/sat/smt/arith_sls.h b/src/sat/smt/arith_sls.h index af3a462340b..09a56c84efd 100644 --- a/src/sat/smt/arith_sls.h +++ b/src/sat/smt/arith_sls.h @@ -19,9 +19,6 @@ Module Name: #include "util/obj_pair_set.h" #include "ast/ast_trail.h" #include "ast/arith_decl_plugin.h" -#include "math/lp/lp_solver.h" -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/lp_dual_simplex.h" #include "math/lp/indexed_value.h" #include "math/lp/lar_solver.h" #include "math/lp/nla_solver.h" diff --git a/src/sat/smt/arith_solver.h b/src/sat/smt/arith_solver.h index 9ae671c162b..68d5f802592 100644 --- a/src/sat/smt/arith_solver.h +++ b/src/sat/smt/arith_solver.h @@ -19,9 +19,7 @@ Module Name: #include "util/obj_pair_set.h" #include "ast/ast_trail.h" #include "ast/arith_decl_plugin.h" -#include "math/lp/lp_solver.h" -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/lp_dual_simplex.h" + #include "math/lp/indexed_value.h" #include "math/lp/lar_solver.h" #include "math/lp/nla_solver.h" diff --git a/src/shell/CMakeLists.txt b/src/shell/CMakeLists.txt index d9b74f162f9..c0e9c85050f 100644 --- a/src/shell/CMakeLists.txt +++ b/src/shell/CMakeLists.txt @@ -28,7 +28,6 @@ add_executable(shell opt_frontend.cpp smtlib_frontend.cpp z3_log_frontend.cpp - lp_frontend.cpp # FIXME: shell should really link against libz3 but it can't due to requiring # use of some hidden symbols. Also libz3 has the ``api_dll`` component which # we don't want (I think). diff --git a/src/shell/lp_frontend.cpp b/src/shell/lp_frontend.cpp deleted file mode 100644 index 8d6425533c8..00000000000 --- a/src/shell/lp_frontend.cpp +++ /dev/null @@ -1,109 +0,0 @@ -/*++ -Copyright (c) 2016 Microsoft Corporation - -Author: - - Lev Nachmanson 2016-10-27 - ---*/ - -#include "math/lp/lp_settings.h" -#include "math/lp/mps_reader.h" -#include "util/timeout.h" -#include "util/cancel_eh.h" -#include "util/scoped_timer.h" -#include "util/rlimit.h" -#include "util/gparams.h" -#include "util/mutex.h" -#include -#include -#include "smt/params/smt_params_helper.hpp" - -namespace { -static mutex *display_stats_mux = new mutex; - -static lp::lp_solver* g_solver = nullptr; - -static void display_statistics() { - lock_guard lock(*display_stats_mux); - if (g_solver && g_solver->settings().print_statistics) { - // TBD display relevant information about statistics - } -} - -static void STD_CALL on_ctrl_c(int) { - signal (SIGINT, SIG_DFL); - display_statistics(); - raise(SIGINT); -} - -static void on_timeout() { - display_statistics(); - _Exit(0); -} - -struct front_end_resource_limit : public lp::lp_resource_limit { - reslimit& m_reslim; - - front_end_resource_limit(reslimit& lim): - m_reslim(lim) - {} - - bool get_cancel_flag() override { return !m_reslim.inc(); } -}; - -void run_solver(smt_params_helper & params, char const * mps_file_name) { - - reslimit rlim; - unsigned timeout = gparams::get_ref().get_uint("timeout", 0); - unsigned rlimit = gparams::get_ref().get_uint("rlimit", 0); - front_end_resource_limit lp_limit(rlim); - - scoped_rlimit _rlimit(rlim, rlimit); - cancel_eh eh(rlim); - scoped_timer timer(timeout, &eh); - - std::string fn(mps_file_name); - lp::mps_reader reader(fn); - reader.set_message_stream(&std::cout); // can be redirected - reader.read(); - if (!reader.is_ok()) { - std::cerr << "cannot process " << mps_file_name << std::endl; - return; - } - lp::lp_solver * solver = reader.create_solver(false); // false - to create the primal solver - solver->settings().set_resource_limit(lp_limit); - g_solver = solver; - if (params.arith_min()) { - solver->flip_costs(); - } - solver->settings().set_message_ostream(&std::cout); - solver->settings().report_frequency = params.arith_rep_freq(); - solver->settings().print_statistics = params.arith_print_stats(); - solver->settings().set_simplex_strategy(lp:: simplex_strategy_enum::lu); - - solver->find_maximal_solution(); - - *(solver->settings().get_message_ostream()) << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lp::lp_status::OPTIMAL) { - if (params.arith_min()) { - solver->flip_costs(); - } - solver->print_model(std::cout); - } - - display_statistics(); - g_solver = nullptr; - delete solver; -} -} - -unsigned read_mps_file(char const * mps_file_name) { - signal(SIGINT, on_ctrl_c); - register_on_timeout_proc(on_timeout); - smt_params_helper p; - param_descrs r; - p.collect_param_descrs(r); - run_solver(p, mps_file_name); - return 0; -} diff --git a/src/shell/lp_frontend.h b/src/shell/lp_frontend.h deleted file mode 100644 index b24be811f18..00000000000 --- a/src/shell/lp_frontend.h +++ /dev/null @@ -1,7 +0,0 @@ -/* - Copyright (c) 2013 Microsoft Corporation. All rights reserved. - - Author: Lev Nachmanson -*/ -#pragma once -unsigned read_mps_file(char const * mps_file_name); diff --git a/src/shell/main.cpp b/src/shell/main.cpp index 4c26d91d968..26325d3d0a2 100644 --- a/src/shell/main.cpp +++ b/src/shell/main.cpp @@ -37,14 +37,13 @@ Revision History: #include "util/gparams.h" #include "util/env_params.h" #include "util/file_path.h" -#include "shell/lp_frontend.h" #include "shell/drat_frontend.h" #if defined( _WINDOWS ) && defined( __MINGW32__ ) && ( defined( __GNUG__ ) || defined( __clang__ ) ) #include #endif -typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_LP, IN_Z3_LOG, IN_MPS, IN_DRAT } input_kind; +typedef enum { IN_UNSPECIFIED, IN_SMTLIB_2, IN_DATALOG, IN_DIMACS, IN_WCNF, IN_OPB, IN_LP, IN_Z3_LOG, IN_DRAT } input_kind; static char const * g_input_file = nullptr; static char const * g_drat_input_file = nullptr; @@ -377,10 +376,6 @@ int STD_CALL main(int argc, char ** argv) { else if (strcmp(ext, "smt2") == 0) { g_input_kind = IN_SMTLIB_2; } - else if (strcmp(ext, "mps") == 0 || strcmp(ext, "sif") == 0 || - strcmp(ext, "MPS") == 0 || strcmp(ext, "SIF") == 0) { - g_input_kind = IN_MPS; - } } } switch (g_input_kind) { @@ -406,9 +401,6 @@ int STD_CALL main(int argc, char ** argv) { case IN_Z3_LOG: replay_z3_log(g_input_file); break; - case IN_MPS: - return_value = read_mps_file(g_input_file); - break; case IN_DRAT: return_value = read_drat(g_drat_input_file); break; diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index d61910ff20e..2aa988282d2 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -19,9 +19,6 @@ --*/ #include "util/stopwatch.h" -#include "math/lp/lp_solver.h" -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/lp_dual_simplex.h" #include "math/lp/indexed_value.h" #include "math/lp/lar_solver.h" #include "math/lp/nla_solver.h" diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index c82cdd0a4b4..78abf1a6f4d 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -33,8 +33,6 @@ #include #include #include "math/lp/lp_utils.h" -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/mps_reader.h" #include "test/lp/smt_reader.h" #include "math/lp/binary_heap_priority_queue.h" #include "test/lp/argument_parser.h" @@ -59,6 +57,71 @@ #include "math/lp/cross_nested.h" #include "math/lp/int_cube.h" #include "math/lp/emonics.h" + +bool my_white_space(const char & a) { + return a == ' ' || a == '\t'; +} +size_t number_of_whites(const std::string & s) { + size_t i = 0; + for(;i < s.size(); i++) + if (!my_white_space(s[i])) return i; + return i; +} +size_t number_of_whites_from_end(const std::string & s) { + size_t ret = 0; + for(int i = static_cast(s.size()) - 1;i >= 0; i--) + if (my_white_space(s[i])) ret++;else break; + + return ret; +} + + +std::string <rim(std::string &s) { + s.erase(0, number_of_whites(s)); + return s; +} + + + + + // trim from end +inline std::string &rtrim(std::string &s) { + // s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun(std::isspace))).base(), s.end()); + s.erase(s.end() - number_of_whites_from_end(s), s.end()); + return s; +} + // trim from both ends +inline std::string &trim(std::string &s) { + return ltrim(rtrim(s)); +} + + +vector string_split(const std::string &source, const char *delimiter, bool keep_empty) { + vector results; + size_t prev = 0; + size_t next = 0; + while ((next = source.find_first_of(delimiter, prev)) != std::string::npos) { + if (keep_empty || (next - prev != 0)) { + results.push_back(source.substr(prev, next - prev)); + } + prev = next + 1; + } + if (prev < source.size()) { + results.push_back(source.substr(prev)); + } + return results; +} + +vector split_and_trim(const std::string &line) { + auto split = string_split(line, " \t", false); + vector ret; + for (auto s : split) { + ret.push_back(trim(s)); + } + return ret; +} + + namespace nla { void test_horner(); void test_monics(); @@ -1395,169 +1458,15 @@ void update_settings(argument_parser & args_parser, lp_settings& settings) { } } -template -void setup_solver(unsigned time_limit, bool look_for_min, argument_parser & args_parser, lp_solver * solver) { - if (time_limit > 0) - solver->set_time_limit(time_limit); - - if (look_for_min) - solver->flip_costs(); - - update_settings(args_parser, solver->settings()); -} bool values_are_one_percent_close(double a, double b); -void print_x(mps_reader & reader, lp_solver * solver) { - for (const auto & name : reader.column_names()) { - std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; - } - std::cout << std::endl; -} -void compare_solutions(mps_reader & reader, lp_solver * solver, lp_solver * solver0) { - for (const auto & name : reader.column_names()) { - double a = solver->get_column_value_by_name(name); - double b = solver0->get_column_value_by_name(name); - if (!values_are_one_percent_close(a, b)) { - std::cout << "different values for " << name << ":" << a << " and " << b << std::endl; - } - } -} -void solve_mps_double(std::string file_name, bool look_for_min, unsigned time_limit, bool dual, bool compare_with_primal, argument_parser & args_parser) { - mps_reader reader(file_name); - reader.read(); - if (!reader.is_ok()) { - std::cout << "cannot process " << file_name << std::endl; - return; - } - - lp_solver * solver = reader.create_solver(dual); - setup_solver(time_limit, look_for_min, args_parser, solver); - stopwatch sw; - sw.start(); - if (dual) { - std::cout << "solving for dual" << std::endl; - } - solver->find_maximal_solution(); - sw.stop(); - double span = sw.get_seconds(); - std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lp_status::OPTIMAL) { - if (reader.column_names().size() < 20) { - print_x(reader, solver); - } - double cost = solver->get_current_cost(); - if (look_for_min) { - cost = -cost; - } - std::cout << "cost = " << cost << std::endl; - } - std::cout << "processed in " << span / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << " one iter for " << (double)span/solver->m_total_iterations << " ms" << std::endl; - if (compare_with_primal) { - auto * primal_solver = reader.create_solver(false); - setup_solver(time_limit, look_for_min, args_parser, primal_solver); - primal_solver->find_maximal_solution(); - if (solver->get_status() != primal_solver->get_status()) { - std::cout << "statuses are different: dual " << lp_status_to_string(solver->get_status()) << " primal = " << lp_status_to_string(primal_solver->get_status()) << std::endl; - } else { - if (solver->get_status() == lp_status::OPTIMAL) { - double cost = solver->get_current_cost(); - if (look_for_min) { - cost = -cost; - } - double primal_cost = primal_solver->get_current_cost(); - if (look_for_min) { - primal_cost = -primal_cost; - } - std::cout << "primal cost = " << primal_cost << std::endl; - if (!values_are_one_percent_close(cost, primal_cost)) { - compare_solutions(reader, primal_solver, solver); - print_x(reader, primal_solver); - std::cout << "dual cost is " << cost << ", but primal cost is " << primal_cost << std::endl; - lp_assert(false); - } - } - } - delete primal_solver; - } - delete solver; -} - -void solve_mps_rational(std::string file_name, bool look_for_min, unsigned time_limit, bool dual, argument_parser & args_parser) { - mps_reader reader(file_name); - reader.read(); - if (reader.is_ok()) { - auto * solver = reader.create_solver(dual); - setup_solver(time_limit, look_for_min, args_parser, solver); - stopwatch sw; - sw.start(); - solver->find_maximal_solution(); - std::cout << "Status: " << lp_status_to_string(solver->get_status()) << std::endl; - - if (solver->get_status() == lp_status::OPTIMAL) { - // for (auto name: reader.column_names()) { - // std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; - // } - lp::mpq cost = solver->get_current_cost(); - if (look_for_min) { - cost = -cost; - } - std::cout << "cost = " << cost.get_double() << std::endl; - } - std::cout << "processed in " << sw.get_current_seconds() / 1000.0 << " seconds, running for " << solver->m_total_iterations << " iterations" << std::endl; - delete solver; - } else { - std::cout << "cannot process " << file_name << std::endl; - } -} void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit); // forward definition -void solve_mps(std::string file_name, bool look_for_min, unsigned time_limit, bool solve_for_rational, bool dual, bool compare_with_primal, argument_parser & args_parser) { - if (!solve_for_rational) { - std::cout << "solving " << file_name << std::endl; - solve_mps_double(file_name, look_for_min, time_limit, dual, compare_with_primal, args_parser); - } - else { - std::cout << "solving " << file_name << " in rationals " << std::endl; - solve_mps_rational(file_name, look_for_min, time_limit, dual, args_parser); - } -} -void solve_mps(std::string file_name, argument_parser & args_parser) { - bool look_for_min = args_parser.option_is_used("--min"); - unsigned time_limit; - bool solve_for_rational = args_parser.option_is_used("--mpq"); - bool dual = args_parser.option_is_used("--dual"); - bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); - get_time_limit_and_max_iters_from_parser(args_parser, time_limit); - solve_mps(file_name, look_for_min, time_limit, solve_for_rational, dual, compare_with_primal, args_parser); -} - -void solve_mps_in_rational(std::string file_name, bool dual, argument_parser & /*args_parser*/) { - std::cout << "solving " << file_name << std::endl; - - mps_reader reader(file_name); - reader.read(); - if (reader.is_ok()) { - auto * solver = reader.create_solver(dual); - solver->find_maximal_solution(); - std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (solver->get_status() == lp_status::OPTIMAL) { - if (reader.column_names().size() < 20) { - for (const auto & name : reader.column_names()) { - std::cout << name << "=" << solver->get_column_value_by_name(name).get_double() << ' '; - } - } - std::cout << std::endl << "cost = " << numeric_traits::get_double(solver->get_current_cost()) << std::endl; - } - delete solver; - } else { - std::cout << "cannot process " << file_name << std::endl; - } -} void test_upair_queue() { int n = 10; @@ -1626,53 +1535,6 @@ void test_binary_priority_queue() { std::cout << " done" << std::endl; } -bool solution_is_feasible(std::string file_name, const std::unordered_map & solution) { - mps_reader reader(file_name); - reader.read(); - if (reader.is_ok()) { - lp_primal_simplex * solver = static_cast *>(reader.create_solver(false)); - return solver->solution_is_feasible(solution); - } - return false; -} - - -void solve_mps_with_known_solution(std::string file_name, std::unordered_map * solution, lp_status status, bool dual) { - std::cout << "solving " << file_name << std::endl; - mps_reader reader(file_name); - reader.read(); - if (reader.is_ok()) { - auto * solver = reader.create_solver(dual); - solver->find_maximal_solution(); - std::cout << "status is " << lp_status_to_string(solver->get_status()) << std::endl; - if (status != solver->get_status()){ - std::cout << "status should be " << lp_status_to_string(status) << std::endl; - lp_assert(status == solver->get_status()); - throw "status is wrong"; - } - if (solver->get_status() == lp_status::OPTIMAL) { - std::cout << "cost = " << solver->get_current_cost() << std::endl; - if (solution != nullptr) { - for (auto it : *solution) { - if (fabs(it.second - solver->get_column_value_by_name(it.first)) >= 0.000001) { - std::cout << "expected:" << it.first << "=" << - it.second <<", got " << solver->get_column_value_by_name(it.first) << std::endl; - } - lp_assert(fabs(it.second - solver->get_column_value_by_name(it.first)) < 0.000001); - } - } - if (reader.column_names().size() < 20) { - for (const auto & name : reader.column_names()) { - std::cout << name << "=" << solver->get_column_value_by_name(name) << ' '; - } - std::cout << std::endl; - } - } - delete solver; - } else { - std::cout << "cannot process " << file_name << std::endl; - } -} int get_random_rows() { return 5 + my_random() % 2; @@ -1686,55 +1548,6 @@ int get_random_int() { return -1 + my_random() % 2; // (1.0 + RAND_MAX); } -void add_random_row(lp_primal_simplex * solver, int cols, int row) { - solver->add_constraint(lp_relation::Greater_or_equal, 1, row); - for (int i = 0; i < cols; i++) { - solver->set_row_column_coefficient(row, i, get_random_int()); - } -} - -void add_random_cost(lp_primal_simplex * solver, int cols) { - for (int i = 0; i < cols; i++) { - solver->set_cost_for_column(i, get_random_int()); - } -} - -lp_primal_simplex * generate_random_solver() { - int rows = get_random_rows(); - int cols = get_random_columns(); - auto * solver = new lp_primal_simplex(); - for (int i = 0; i < rows; i++) { - add_random_row(solver, cols, i); - } - add_random_cost(solver, cols); - return solver; -} - - - -void random_test_on_i(unsigned i) { - if (i % 1000 == 0) { - std::cout << "."; - } - srand(i); - auto *solver = generate_random_solver(); - solver->find_maximal_solution(); - // std::cout << lp_status_to_string(solver->get_status()) << std::endl; - delete solver; -} - -void random_test() { - for (unsigned i = 0; i < std::numeric_limits::max(); i++) { - try { - random_test_on_i(i); - } - catch (const char * error) { - std::cout << "i = " << i << ", throwing at ' " << error << "'" << std::endl; - break; - } - } -} - #ifndef _WINDOWS void fill_file_names(vector &file_names, std::set & minimums) { char *home_dir = getenv("HOME"); @@ -1896,140 +1709,9 @@ void find_dir_and_file_name(std::string a, std::string & dir, std::string& fn) { // std::cout << "fn = " << fn << std::endl; } -void process_test_file(std::string test_dir, std::string test_file_name, argument_parser & args_parser, std::string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives); - -void solve_some_mps(argument_parser & args_parser) { - unsigned max_iters = UINT_MAX, time_limit = UINT_MAX; - get_time_limit_and_max_iters_from_parser(args_parser, time_limit); - unsigned successes = 0; - unsigned failures = 0; - unsigned inconclusives = 0; - std::set minimums; - vector file_names; - fill_file_names(file_names, minimums); - bool solve_for_rational = args_parser.option_is_used("--mpq"); - bool dual = args_parser.option_is_used("--dual"); - bool compare_with_primal = args_parser.option_is_used("--compare_with_primal"); - bool compare_with_glpk = args_parser.option_is_used("--compare_with_glpk"); - if (compare_with_glpk) { - std::string out_dir = args_parser.get_option_value("--out_dir"); - if (out_dir.size() == 0) { - out_dir = "/tmp/test"; - } - test_out_dir(out_dir); - for (auto& a : file_names) { - try { - std::string file_dir; - std::string file_name; - find_dir_and_file_name(a, file_dir, file_name); - process_test_file(file_dir, file_name, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); - } - catch(const char *s){ - std::cout<< "exception: "<< s << std::endl; - } - } - std::cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << std::endl; - return; - } - if (!solve_for_rational) { - solve_mps(file_names[6], false, time_limit, false, dual, compare_with_primal, args_parser); - solve_mps_with_known_solution(file_names[3], nullptr, lp_status::INFEASIBLE, dual); // chvatal: 135(d) - std::unordered_map sol; - sol["X1"] = 0; - sol["X2"] = 6; - sol["X3"] = 0; - sol["X4"] = 15; - sol["X5"] = 2; - sol["X6"] = 1; - sol["X7"] = 1; - sol["X8"] = 0; - solve_mps_with_known_solution(file_names[9], &sol, lp_status::OPTIMAL, dual); - solve_mps_with_known_solution(file_names[0], &sol, lp_status::OPTIMAL, dual); - sol.clear(); - sol["X1"] = 25.0/14.0; - // sol["X2"] = 0; - // sol["X3"] = 0; - // sol["X4"] = 0; - // sol["X5"] = 0; - // sol["X6"] = 0; - // sol["X7"] = 9.0/14.0; - solve_mps_with_known_solution(file_names[5], &sol, lp_status::OPTIMAL, dual); // chvatal: 135(e) - solve_mps_with_known_solution(file_names[4], &sol, lp_status::OPTIMAL, dual); // chvatal: 135(e) - solve_mps_with_known_solution(file_names[2], nullptr, lp_status::UNBOUNDED, dual); // chvatal: 135(c) - solve_mps_with_known_solution(file_names[1], nullptr, lp_status::UNBOUNDED, dual); // chvatal: 135(b) - solve_mps(file_names[8], false, time_limit, false, dual, compare_with_primal, args_parser); - // return; - for (auto& s : file_names) { - try { - solve_mps(s, minimums.find(s) != minimums.end(), time_limit, false, dual, compare_with_primal, args_parser); - } - catch(const char *s){ - std::cout<< "exception: "<< s << std::endl; - } - } - } else { - // unsigned i = 0; - for (auto& s : file_names) { - // if (i++ > 9) return; - try { - solve_mps_in_rational(s, dual, args_parser); - } - catch(const char *s){ - std::cout<< "exception: "<< s << std::endl; - } - } - } -} -#endif - -void solve_rational() { - lp_primal_simplex solver; - solver.add_constraint(lp_relation::Equal, lp::mpq(7), 0); - solver.add_constraint(lp_relation::Equal, lp::mpq(-3), 1); - - // setting the cost - int cost[] = {-3, -1, -1, 2, -1, 1, 1, -4}; - std::string var_names[8] = {"x1", "x2", "x3", "x4", "x5", "x6", "x7", "x8"}; - - for (unsigned i = 0; i < 8; i++) { - solver.set_cost_for_column(i, lp::mpq(cost[i])); - solver.give_symbolic_name_to_column(var_names[i], i); - } - - int row0[] = {1, 0, 3, 1, -5, -2 , 4, -6}; - for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(0, i, lp::mpq(row0[i])); - } - - int row1[] = {0, 1, -2, -1, 4, 1, -3, 5}; - for (unsigned i = 0; i < 8; i++) { - solver.set_row_column_coefficient(1, i, lp::mpq(row1[i])); - } - int bounds[] = {8, 6, 4, 15, 2, 10, 10, 3}; - for (unsigned i = 0; i < 8; i++) { - solver.set_lower_bound(i, lp::mpq(0)); - solver.set_upper_bound(i, lp::mpq(bounds[i])); - } - - std::unordered_map expected_sol; - expected_sol["x1"] = lp::mpq(0); - expected_sol["x2"] = lp::mpq(6); - expected_sol["x3"] = lp::mpq(0); - expected_sol["x4"] = lp::mpq(15); - expected_sol["x5"] = lp::mpq(2); - expected_sol["x6"] = lp::mpq(1); - expected_sol["x7"] = lp::mpq(1); - expected_sol["x8"] = lp::mpq(0); - solver.find_maximal_solution(); - lp_assert(solver.get_status() == lp_status::OPTIMAL); -#ifdef Z3DEBUG - for (const auto & it : expected_sol) { - (void)it; - lp_assert(it.second == solver.get_column_value_by_name(it.first)); - } #endif -} + std::string read_line(bool & end, std::ifstream & file) { @@ -2047,49 +1729,6 @@ bool contains(std::string const & s, char const * pattern) { } -std::unordered_map * get_solution_from_glpsol_output(std::string & file_name) { - std::ifstream file(file_name); - if (!file.is_open()){ - std::cerr << "cannot open " << file_name << std::endl; - return nullptr; - } - std::string s; - bool end; - do { - s = read_line(end, file); - if (end) { - std::cerr << "unexpected file end " << file_name << std::endl; - return nullptr; - } - if (contains(s, "Column name")){ - break; - } - } while (true); - - read_line(end, file); - if (end) { - std::cerr << "unexpected file end " << file_name << std::endl; - return nullptr; - } - - auto ret = new std::unordered_map(); - - do { - s = read_line(end, file); - if (end) { - std::cerr << "unexpected file end " << file_name << std::endl; - return nullptr; - } - auto split = string_split(s, " \t", false); - if (split.empty()) { - return ret; - } - - lp_assert(split.size() > 3); - (*ret)[split[1]] = atof(split[3].c_str()); - } while (true); -} - void test_init_U() { @@ -2189,7 +1828,6 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("--test_lp_0", "solve a small lp"); parser.add_option_with_help_string("--solve_some_mps", "solves a list of mps problems"); parser.add_option_with_after_string_with_help("--test_file_directory", "loads files from the directory for testing"); - parser.add_option_with_help_string("--compare_with_glpk", "compares the results by running glpsol"); parser.add_option_with_after_string_with_help("--out_dir", "setting the output directory for tests, if not set /tmp is used"); parser.add_option_with_help_string("--dual", "using the dual simplex solver"); parser.add_option_with_help_string("--compare_with_primal", "using the primal simplex solver for comparison"); @@ -2360,237 +1998,9 @@ std::string get_status(std::string file_name) { throw 0; } -// returns true if the costs should be compared too -bool compare_statuses(std::string glpk_out_file_name, std::string lp_out_file_name, unsigned & successes, unsigned & failures) { - std::string glpk_status = get_status(glpk_out_file_name); - std::string lp_tst_status = get_status(lp_out_file_name); - - if (glpk_status != lp_tst_status) { - if (glpk_status == "UNDEFINED" && (lp_tst_status == "UNBOUNDED" || lp_tst_status == "INFEASIBLE")) { - successes++; - return false; - } else { - std::cout << "glpsol and lp_tst disagree: glpsol status is " << glpk_status; - std::cout << " but lp_tst status is " << lp_tst_status << std::endl; - failures++; - return false; - } - } - return lp_tst_status == "OPTIMAL"; -} - -double get_glpk_cost(std::string file_name) { - std::ifstream f(file_name); - if (!f.is_open()) { - std::cout << "cannot open " << file_name << std::endl; - throw 0; - } - std::string str; - while (getline(f, str)) { - if (str.find("Objective") != std::string::npos) { - vector tokens = split_and_trim(str); - if (tokens.size() != 5) { - std::cout << "unexpected Objective std::string " << str << std::endl; - throw 0; - } - return atof(tokens[3].c_str()); - } - } - std::cout << "cannot find the Objective line in " << file_name << std::endl; - throw 0; -} - -double get_lp_tst_cost(std::string file_name) { - std::ifstream f(file_name); - if (!f.is_open()) { - std::cout << "cannot open " << file_name << std::endl; - throw 0; - } - std::string str; - std::string cost_string; - while (getline(f, str)) { - if (str.find("cost") != std::string::npos) { - cost_string = str; - } - } - if (cost_string.empty()) { - std::cout << "cannot find the cost line in " << file_name << std::endl; - throw 0; - } - - vector tokens = split_and_trim(cost_string); - if (tokens.size() != 3) { - std::cout << "unexpected cost string " << cost_string << std::endl; - throw 0; - } - return atof(tokens[2].c_str()); -} - -bool values_are_one_percent_close(double a, double b) { - double maxval = std::max(fabs(a), fabs(b)); - if (maxval < 0.000001) { - return true; - } - - double one_percent = maxval / 100; - return fabs(a - b) <= one_percent; -} - -// returns true if both are optimal -void compare_costs(std::string glpk_out_file_name, - std::string lp_out_file_name, - unsigned & successes, - unsigned & failures) { - double a = get_glpk_cost(glpk_out_file_name); - double b = get_lp_tst_cost(lp_out_file_name); - - if (values_are_one_percent_close(a, b)) { - successes++; - } else { - failures++; - std::cout << "glpsol cost is " << a << " lp_tst cost is " << b << std::endl; - } -} - -void compare_with_glpk(std::string glpk_out_file_name, std::string lp_out_file_name, unsigned & successes, unsigned & failures, std::string /*lp_file_name*/) { -#ifdef CHECK_GLPK_SOLUTION - std::unordered_map * solution_table = get_solution_from_glpsol_output(glpk_out_file_name); - if (solution_is_feasible(lp_file_name, *solution_table)) { - std::cout << "glpk solution is feasible" << std::endl; - } else { - std::cout << "glpk solution is infeasible" << std::endl; - } - delete solution_table; -#endif - if (compare_statuses(glpk_out_file_name, lp_out_file_name, successes, failures)) { - compare_costs(glpk_out_file_name, lp_out_file_name, successes, failures); - } -} -void test_lar_on_file(std::string file_name, argument_parser & args_parser); -void process_test_file(std::string test_dir, std::string test_file_name, argument_parser & args_parser, std::string out_dir, unsigned max_iters, unsigned time_limit, unsigned & successes, unsigned & failures, unsigned & inconclusives) { - bool use_mpq = args_parser.option_is_used("--mpq"); - bool minimize = args_parser.option_is_used("--min"); - std::string full_lp_tst_out_name = out_dir + "/" + create_output_file_name(minimize, test_file_name, use_mpq); - - std::string input_file_name = test_dir + "/" + test_file_name; - if (input_file_name[input_file_name.size() - 1] == '~') { - // std::cout << "ignoring " << input_file_name << std::endl; - return; - } - std::cout <<"processing " << input_file_name << std::endl; - - std::ofstream out(full_lp_tst_out_name); - if (!out.is_open()) { - std::cout << "cannot open file " << full_lp_tst_out_name << std::endl; - throw 0; - } - std::streambuf *coutbuf = std::cout.rdbuf(); // save old buffer - std::cout.rdbuf(out.rdbuf()); // redirect std::cout to dir_entry->d_name! - bool dual = args_parser.option_is_used("--dual"); - try { - if (args_parser.option_is_used("--lar")) - test_lar_on_file(input_file_name, args_parser); - else - solve_mps(input_file_name, minimize, time_limit, use_mpq, dual, false, args_parser); - } - catch(...) { - std::cout << "catching the failure" << std::endl; - failures++; - std::cout.rdbuf(coutbuf); // reset to standard output again - return; - } - std::cout.rdbuf(coutbuf); // reset to standard output again - - if (args_parser.option_is_used("--compare_with_glpk")) { - std::string glpk_out_file_name = out_dir + "/" + create_output_file_name_for_glpsol(minimize, std::string(test_file_name)); - int glpk_exit_code = run_glpk(input_file_name, glpk_out_file_name, minimize, time_limit); - if (glpk_exit_code != 0) { - std::cout << "glpk failed" << std::endl; - inconclusives++; - } else { - compare_with_glpk(glpk_out_file_name, full_lp_tst_out_name, successes, failures, input_file_name); - } - } -} -/* - int my_readdir(DIR *dirp, struct dirent * - #ifndef LEAN_WINDOWS - entry - #endif - , struct dirent **result) { - #ifdef LEAN_WINDOWS - *result = readdir(dirp); // NOLINT - return *result != nullptr? 0 : 1; - #else - return readdir_r(dirp, entry, result); - #endif - } -*/ -/* - vector> get_file_list_of_dir(std::string test_file_dir) { - DIR *dir; - if ((dir = opendir(test_file_dir.c_str())) == nullptr) { - std::cout << "Cannot open directory " << test_file_dir << std::endl; - throw 0; - } - vector> ret; - struct dirent entry; - struct dirent* result; - int return_code; - for (return_code = my_readdir(dir, &entry, &result); - #ifndef LEAN_WINDOWS - result != nullptr && - #endif - return_code == 0; - return_code = my_readdir(dir, &entry, &result)) { - DIR *tmp_dp = opendir(result->d_name); - struct stat file_record; - if (tmp_dp == nullptr) { - std::string s = test_file_dir+ "/" + result->d_name; - int stat_ret = stat(s.c_str(), & file_record); - if (stat_ret!= -1) { - ret.push_back(make_pair(result->d_name, file_record.st_size)); - } else { - perror("stat"); - exit(1); - } - } else { - closedir(tmp_dp); - } - } - closedir(dir); - return ret; - } -*/ -/* - struct file_size_comp { - unordered_map& m_file_sizes; - file_size_comp(unordered_map& fs) :m_file_sizes(fs) {} - int operator()(std::string a, std::string b) { - std::cout << m_file_sizes.size() << std::endl; - std::cout << a << std::endl; - std::cout << b << std::endl; - - auto ls = m_file_sizes.find(a); - std::cout << "fa" << std::endl; - auto rs = m_file_sizes.find(b); - std::cout << "fb" << std::endl; - if (ls != m_file_sizes.end() && rs != m_file_sizes.end()) { - std::cout << "fc " << std::endl; - int r = (*ls < *rs? -1: (*ls > *rs)? 1 : 0); - std::cout << "calc r " << std::endl; - return r; - } else { - std::cout << "sc " << std::endl; - return 0; - } - } - }; - -*/ struct sort_pred { bool operator()(const std::pair &left, const std::pair &right) { return left.second < right.second; @@ -2598,121 +2008,11 @@ struct sort_pred { }; -void test_files_from_directory(std::string test_file_dir, argument_parser & args_parser) { - /* - std::cout << "loading files from directory \"" << test_file_dir << "\"" << std::endl; - std::string out_dir = args_parser.get_option_value("--out_dir"); - if (out_dir.size() == 0) { - out_dir = "/tmp/test"; - } - DIR *out_dir_p = opendir(out_dir.c_str()); - if (out_dir_p == nullptr) { - std::cout << "Cannot open output directory \"" << out_dir << "\"" << std::endl; - return; - } - closedir(out_dir_p); - vector> files = get_file_list_of_dir(test_file_dir); - std::sort(files.begin(), files.end(), sort_pred()); - unsigned max_iters, time_limit; - get_time_limit_and_max_iters_from_parser(args_parser, time_limit); - unsigned successes = 0, failures = 0, inconclusives = 0; - for (auto & t : files) { - process_test_file(test_file_dir, t.first, args_parser, out_dir, max_iters, time_limit, successes, failures, inconclusives); - } - std::cout << "comparing with glpk: successes " << successes << ", failures " << failures << ", inconclusives " << inconclusives << std::endl; - */ -} -std::unordered_map get_solution_map(lp_solver * lps, mps_reader & reader) { - std::unordered_map ret; - for (const auto & it : reader.column_names()) { - ret[it] = lps->get_column_value_by_name(it); - } - return ret; -} -void run_lar_solver(argument_parser & args_parser, lar_solver * solver, mps_reader * reader) { - std::string maxng = args_parser.get_option_value("--maxng"); - if (!maxng.empty()) { - solver->settings().max_number_of_iterations_with_no_improvements = atoi(maxng.c_str()); - } - if (args_parser.option_is_used("-pd")){ - solver->settings().presolve_with_double_solver_for_lar = true; - } - - if (args_parser.option_is_used("--compare_with_primal")){ - if (reader == nullptr) { - std::cout << "cannot compare with primal, the reader is null " << std::endl; - return; - } - auto * lps = reader->create_solver(false); - lps->find_maximal_solution(); - std::unordered_map sol = get_solution_map(lps, *reader); - std::cout << "status = " << lp_status_to_string(solver->get_status()) << std::endl; - return; - } - stopwatch sw; - sw.start(); - lp_status status = solver->solve(); - std::cout << "status is " << lp_status_to_string(status) << ", processed for " << sw.get_current_seconds() <<" seconds, and " << solver->get_total_iterations() << " iterations" << std::endl; - if (solver->get_status() == lp_status::INFEASIBLE) { - explanation evidence; - solver->get_infeasibility_explanation(evidence); - } - if (args_parser.option_is_used("--randomize_lar")) { - if (solver->get_status() != lp_status::OPTIMAL) { - std::cout << "cannot check randomize on an infeazible problem" << std::endl; - return; - } - std::cout << "checking randomize" << std::endl; - vector all_vars; - for (unsigned j = 0; j < solver->number_of_vars(); j++) - all_vars.push_back(j); - - unsigned m = all_vars.size(); - if (m > 100) - m = 100; - - var_index *vars = new var_index[m]; - for (unsigned i = 0; i < m; i++) - vars[i]=all_vars[i]; - - solver->random_update(m, vars); - delete []vars; - } -} -lar_solver * create_lar_solver_from_file(std::string file_name, argument_parser & args_parser) { - if (args_parser.option_is_used("--smt")) { - smt_reader reader(file_name); - reader.read(); - if (!reader.is_ok()){ - std::cout << "cannot process " << file_name << std::endl; - return nullptr; - } - return reader.create_lar_solver(); - } - mps_reader reader(file_name); - reader.read(); - if (!reader.is_ok()) { - std::cout << "cannot process " << file_name << std::endl; - return nullptr; - } - return reader.create_lar_solver(); -} -void test_lar_on_file(std::string file_name, argument_parser & args_parser) { - lar_solver * solver = create_lar_solver_from_file(file_name, args_parser); - mps_reader reader(file_name); - mps_reader * mps_reader = nullptr; - reader.read(); - if (reader.is_ok()) { - mps_reader = & reader; - run_lar_solver(args_parser, solver, mps_reader); - } - delete solver; -} vector get_file_names_from_file_list(std::string filelist) { std::ifstream file(filelist); @@ -2733,23 +2033,6 @@ vector get_file_names_from_file_list(std::string filelist) { return ret; } -void test_lar_solver(argument_parser & args_parser) { - - std::string file_name = args_parser.get_option_value("--file"); - if (!file_name.empty()) { - test_lar_on_file(file_name, args_parser); - return; - } - - std::string file_list = args_parser.get_option_value("--filelist"); - if (!file_list.empty()) { - for (const std::string & fn : get_file_names_from_file_list(file_list)) - test_lar_on_file(fn, args_parser); - return; - } - - std::cout << "give option --file or --filelist to test_lar_solver\n"; -} void test_numeric_pair() { numeric_pair a; @@ -3934,22 +3217,6 @@ void test_lp_local(int argn, char**argv) { return finalize(0); } - if (args_parser.option_is_used("--test_mpq")) { - test_rationals(); - return finalize(0); - } - - if (args_parser.option_is_used("--test_mpq_np")) { - test_rationals_no_numeric_pairs(); - return finalize(0); - } - - if (args_parser.option_is_used("--test_mpq_np_plus")) { - test_rationals_no_numeric_pairs_plus(); - return finalize(0); - } - - if (args_parser.option_is_used("--test_int_set")) { test_int_set(); @@ -3967,29 +3234,8 @@ void test_lp_local(int argn, char**argv) { return finalize(0); } -#ifdef Z3DEBUG - if (args_parser.option_is_used("--test_swaps")) { - square_sparse_matrix m(10, 0); - fill_matrix(m); - test_swap_rows_with_permutation(m); - test_swap_cols_with_permutation(m); - return finalize(0); - } -#endif - if (args_parser.option_is_used("--test_perm")) { - test_permutations(); - return finalize(0); - } - if (args_parser.option_is_used("--test_file_directory")) { - test_files_from_directory(args_parser.get_option_value("--test_file_directory"), args_parser); - return finalize(0); - } - std::string file_list = args_parser.get_option_value("--filelist"); - if (!file_list.empty()) { - for (const std::string & fn : get_file_names_from_file_list(file_list)) - solve_mps(fn, args_parser); - return finalize(0); - } + + if (args_parser.option_is_used("-tbq")) { test_binary_priority_queue(); @@ -3997,100 +3243,6 @@ void test_lp_local(int argn, char**argv) { return finalize(ret); } -#ifdef Z3DEBUG - lp_settings settings; - update_settings(args_parser, settings); - if (args_parser.option_is_used("--test_lu")) { - test_lu(settings); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--test_small_lu")) { - test_small_lu(settings); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--lar")){ - std::cout <<"calling test_lar_solver" << std::endl; - test_lar_solver(args_parser); - return finalize(0); - } - - - - if (args_parser.option_is_used("--test_larger_lu")) { - test_larger_lu(settings); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--test_larger_lu_with_holes")) { - test_larger_lu_with_holes(settings); - ret = 0; - return finalize(ret); - } -#endif - if (args_parser.option_is_used("--eti")) { - test_evidence_for_total_inf_simple(args_parser); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--maximize_term")) { - test_maximize_term(); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--test_lp_0")) { - test_lp_0(); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--smap")) { - test_stacked(); - ret = 0; - return finalize(ret); - } - if (args_parser.option_is_used("--term")) { - test_term(); - ret = 0; - return finalize(ret); - } - unsigned time_limit; - get_time_limit_and_max_iters_from_parser(args_parser, time_limit); - bool dual = args_parser.option_is_used("--dual"); - bool solve_for_rational = args_parser.option_is_used("--mpq"); - std::string file_name = args_parser.get_option_value("--file"); - if (!file_name.empty()) { - solve_mps(file_name, args_parser.option_is_used("--min"), time_limit, solve_for_rational, dual, args_parser.option_is_used("--compare_with_primal"), args_parser); - ret = 0; - return finalize(ret); - } - - if (args_parser.option_is_used("--solve_some_mps")) { -#ifndef _WINDOWS - solve_some_mps(args_parser); -#endif - ret = 0; - return finalize(ret); - } - // lp::ccc = 0; - return finalize(0); - test_init_U(); - test_replace_column(); -#ifdef Z3DEBUG - square_sparse_matrix_with_permutations_test(); - test_dense_matrix(); - test_swap_operations(); - test_permutations(); - test_pivot_like_swaps_and_pivot(); -#endif - tst1(); - std::cout << "done with LP tests\n"; return finalize(0); // has_violations() ? 1 : 0); } } diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 2ab0c1ea69a..75edb23b987 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -20,18 +20,14 @@ Revision History: #pragma once -// reads an MPS file representing a Mixed Integer Program #include #include #include -#include "math/lp/lp_primal_simplex.h" -#include "math/lp/lp_dual_simplex.h" #include "math/lp/lar_solver.h" #include #include #include #include -#include "math/lp/mps_reader.h" #include "math/lp/ul_pair.h" #include "math/lp/lar_constraints.h" #include diff --git a/src/test/lp/test_file_reader.h b/src/test/lp/test_file_reader.h index 8f461ea1c26..36b27374023 100644 --- a/src/test/lp/test_file_reader.h +++ b/src/test/lp/test_file_reader.h @@ -27,7 +27,6 @@ Revision History: #include #include #include "math/lp/lp_utils.h" -#include "math/lp/lp_solver.h" namespace lp { From 60a5c39604445b325d8025ad5d944be6c2e4cc30 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 11:56:23 -0800 Subject: [PATCH 02/36] rm get_column_in_lu_mode --- src/math/lp/lar_solver.h | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index f13231610bd..20556deab75 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -267,13 +267,7 @@ class lar_solver : public column_namer { void shrink_explanation_to_minimum(vector> & explanation) const; inline bool column_value_is_integer(unsigned j) const { return get_column_value(j).is_int(); } bool model_is_int_feasible() const; - inline - indexed_vector & get_column_in_lu_mode(unsigned j) { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - return m_column_buffer; - } + bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const; inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; } void catch_up_in_updating_int_solver(); From 69c804353b80e709308ce47478f49e2f4ce8dd0e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 12:15:48 -0800 Subject: [PATCH 03/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lar_core_solver.h | 2 +- src/math/lp/lar_solver.cpp | 19 ++++---------- src/math/lp/lp_core_solver_base_def.h | 20 ++------------- src/math/lp/lp_settings.h | 8 +++--- src/test/lp/lp.cpp | 36 --------------------------- 5 files changed, 11 insertions(+), 74 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index de8fe68adb5..b6c97513919 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -229,7 +229,7 @@ class lar_core_solver { } bool need_to_presolve_with_double_solver() const { - return settings().simplex_strategy() == simplex_strategy_enum::lu; + return false; } template diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 86ecb02b964..c2a332ad31a 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -45,7 +45,7 @@ namespace lp { delete t; } - bool lar_solver::use_lu() const { return m_settings.simplex_strategy() == simplex_strategy_enum::lu; } + bool lar_solver::use_lu() const { return false; } bool lar_solver::sizes_are_correct() const { lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); @@ -478,10 +478,7 @@ namespace lp { m_mpq_lar_core_solver.m_r_solver.set_status(lp_status::OPTIMAL); return ret; - case simplex_strategy_enum::lu: - lp_assert(false); // not implemented - return false; - + default: lp_unreachable(); // wrong mode } @@ -1999,20 +1996,14 @@ namespace lp { void lar_solver::decide_on_strategy_and_adjust_initial_state() { lp_assert(strategy_is_undecided()); - if (m_columns_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) { - m_settings.set_simplex_strategy(simplex_strategy_enum::lu); - } - else { - m_settings.set_simplex_strategy(simplex_strategy_enum::tableau_rows); // todo: when to switch to tableau_costs? - } + + m_settings.set_simplex_strategy(simplex_strategy_enum::tableau_rows); // todo: when to switch to tableau_costs? + adjust_initial_state(); } void lar_solver::adjust_initial_state() { switch (m_settings.simplex_strategy()) { - case simplex_strategy_enum::lu: - adjust_initial_state_for_lu(); - break; case simplex_strategy_enum::tableau_rows: adjust_initial_state_for_tableau_rows(); break; diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 4d29234a815..40e0a527d41 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -894,27 +894,11 @@ template bool lp_core_solver_base::pivot_column_g lp_assert(m_basis_heading[j] < 0); lp_assert(m_basis_heading[j_basic] >= 0); unsigned row_index = m_basis_heading[j_basic]; - if (m_settings.m_simplex_strategy == simplex_strategy_enum::lu) { - if (m_factorization->need_to_refactor()) { - init_lu(); - } - else { - m_factorization->prepare_entering(j, w); // to init vector w - m_factorization->replace_column(zero_of_type(), w, row_index); - } - if (m_factorization->get_status() != LU_status::OK) { - init_lu(); - return false; - } - else { - change_basis(j, j_basic); - } - } - else { // the tableau case + // the tableau case if (pivot_column_tableau(j, row_index)) change_basis(j, j_basic); else return false; - } + return true; } diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 2245f6f4ed1..790354e5586 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -55,8 +55,7 @@ inline std::ostream& operator<<(std::ostream& out, column_type const& t) { enum class simplex_strategy_enum { undecided = 3, tableau_rows = 0, - tableau_costs = 1, - lu = 2 + tableau_costs = 1 }; std::string column_type_to_string(column_type t); @@ -341,12 +340,11 @@ struct lp_settings { } bool use_lu() const { - return m_simplex_strategy == simplex_strategy_enum::lu; + return false; } bool use_tableau() const { - return m_simplex_strategy == simplex_strategy_enum::tableau_rows || - m_simplex_strategy == simplex_strategy_enum::tableau_costs; + return true; } bool use_tableau_rows() const { diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 78abf1a6f4d..fe589835d48 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -1422,42 +1422,6 @@ bool get_double_from_args_parser(const char * option, argument_parser & args_par } -void update_settings(argument_parser & args_parser, lp_settings& settings) { - unsigned n; - settings.m_simplex_strategy = simplex_strategy_enum::lu; - if (get_int_from_args_parser("--rep_frq", args_parser, n)) - settings.report_frequency = n; - else - settings.report_frequency = args_parser.option_is_used("--mpq")? 80: 1000; - - settings.print_statistics = true; - - if (get_int_from_args_parser("--percent_for_enter", args_parser, n)) - settings.percent_of_entering_to_check = n; - if (get_int_from_args_parser("--partial_pivot", args_parser, n)) { - std::cout << "setting partial pivot constant to " << n << std::endl; - settings.c_partial_pivoting = n; - } - if (get_int_from_args_parser("--density", args_parser, n)) { - double density = static_cast(n) / 100.0; - std::cout << "setting density to " << density << std::endl; - settings.density_threshold = density; - } - if (get_int_from_args_parser("--maxng", args_parser, n)) - settings.max_number_of_iterations_with_no_improvements = n; - double d; - if (get_double_from_args_parser("--harris_toler", args_parser, d)) { - std::cout << "setting harris_feasibility_tolerance to " << d << std::endl; - settings.harris_feasibility_tolerance = d; - } - if (get_int_from_args_parser("--random_seed", args_parser, n)) { - settings.set_random_seed(n); - } - if (get_int_from_args_parser("--simplex_strategy", args_parser, n)) { - settings.set_simplex_strategy(static_cast(n)); - } -} - bool values_are_one_percent_close(double a, double b); From 1e8bf7669c1cfeefb4be123c15991517e4786e52 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 12:34:15 -0800 Subject: [PATCH 04/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lar_solver.cpp | 13 +++---------- src/math/lp/lar_solver.h | 1 - src/math/lp/lp_core_solver_base_def.h | 3 +-- src/math/lp/lp_settings.h | 5 +---- 4 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index c2a332ad31a..3339b55a5b7 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -45,8 +45,7 @@ namespace lp { delete t; } - bool lar_solver::use_lu() const { return false; } - + bool lar_solver::sizes_are_correct() const { lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); @@ -1622,8 +1621,7 @@ namespace lp { m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); increase_by_one_columns_with_changed_bounds(); add_new_var_to_core_fields_for_mpq(false); // false for not adding a row - if (use_lu()) - add_new_var_to_core_fields_for_doubles(false); + } void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { @@ -1785,8 +1783,6 @@ namespace lp { fill_last_row_of_A_r(A_r(), term); } m_mpq_lar_core_solver.m_r_solver.update_x(j, get_basic_var_value_from_row(A_r().row_count() - 1)); - if (use_lu()) - fill_last_row_of_A_d(A_d(), term); for (lar_term::ival c : *term) { unsigned j = c.column(); while (m_usage_in_terms.size() <= j) { @@ -1798,15 +1794,12 @@ namespace lp { } void lar_solver::add_basic_var_to_core_fields() { - bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver(); - lp_assert(!use_lu || A_r().column_count() == A_d().column_count()); m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column); increase_by_one_columns_with_changed_bounds(); m_incorrect_columns.increase_size_by_one(); m_rows_with_changed_bounds.increase_size_by_one(); add_new_var_to_core_fields_for_mpq(true); - if (use_lu) - add_new_var_to_core_fields_for_doubles(true); + } bool lar_solver::bound_is_integer_for_integer_column(unsigned j, const mpq& right_side) const { diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 20556deab75..c1deb2fb1c8 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -166,7 +166,6 @@ class lar_solver : public column_namer { void adjust_initial_state_for_lu(); void adjust_initial_state_for_tableau_rows(); void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls); - bool use_lu() const; bool sizes_are_correct() const; bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const; diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 40e0a527d41..93d5f430239 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -82,8 +82,7 @@ allocate_basis_heading() { // the rest of initialization will be handled by the template void lp_core_solver_base:: init() { allocate_basis_heading(); - if (m_settings.use_lu()) - init_factorization(m_factorization, m_A, m_basis, m_settings); + } // i is the pivot row, and j is the pivot column diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 790354e5586..d6a78564d8f 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -339,10 +339,7 @@ struct lp_settings { m_simplex_strategy = s; } - bool use_lu() const { - return false; - } - + bool use_tableau() const { return true; } From 1bbb35972b49ad107264d325873a8a02c40f2ac2 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 14:58:49 -0800 Subject: [PATCH 05/36] rm_lp Signed-off-by: Lev Nachmanson --- src/math/lp/core_solver_pretty_printer.h | 1 - src/math/lp/core_solver_pretty_printer_def.h | 67 +---- src/math/lp/int_solver.cpp | 1 - src/math/lp/lar_core_solver.h | 68 +---- src/math/lp/lar_core_solver_def.h | 37 +-- src/math/lp/lar_solver.cpp | 57 ++-- src/math/lp/lar_solver.h | 22 +- src/math/lp/lp_core_solver_base.cpp | 14 +- src/math/lp/lp_core_solver_base.h | 12 +- src/math/lp/lp_core_solver_base_def.h | 68 +---- src/math/lp/lp_dual_core_solver_def.h | 22 +- src/math/lp/lp_primal_core_solver.h | 3 +- src/math/lp/lp_primal_core_solver_def.h | 244 +----------------- .../lp/lp_primal_core_solver_tableau_def.h | 34 +-- src/math/lp/lp_settings.h | 6 +- src/math/lp/lu.cpp | 3 - src/math/lp/lu.h | 2 - src/math/lp/lu_def.h | 15 +- src/test/lp/lp.cpp | 30 +-- 19 files changed, 65 insertions(+), 641 deletions(-) diff --git a/src/math/lp/core_solver_pretty_printer.h b/src/math/lp/core_solver_pretty_printer.h index 3c0563c32bb..353212dcd1a 100644 --- a/src/math/lp/core_solver_pretty_printer.h +++ b/src/math/lp/core_solver_pretty_printer.h @@ -110,7 +110,6 @@ class core_solver_pretty_printer { return T_to_string(m_exact_column_norms[col]); } - void print_exact_norms(); void print_approx_norms(); diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index 23417b691b6..6971061832b 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -59,22 +59,13 @@ core_solver_pretty_printer::core_solver_pretty_printer(const lp_core_solve } template void core_solver_pretty_printer::init_costs() { - if (!m_core_solver.use_tableau()) { - vector local_y(m_core_solver.m_m()); - m_core_solver.solve_yB(local_y); - for (unsigned i = 0; i < ncols(); i++) { - if (m_core_solver.m_basis_heading[i] < 0) { - T t = m_core_solver.m_costs[i] - m_core_solver.m_A.dot_product_with_column(local_y, i); - set_coeff(m_costs, m_cost_signs, i, t, m_core_solver.column_name(i)); - } - } - } else { + for (unsigned i = 0; i < ncols(); i++) { if (m_core_solver.m_basis_heading[i] < 0) { set_coeff(m_costs, m_cost_signs, i, m_core_solver.m_d[i], m_core_solver.column_name(i)); } } - } + } template core_solver_pretty_printer::~core_solver_pretty_printer() { @@ -97,7 +88,7 @@ template T core_solver_pretty_printer::current_co } template void core_solver_pretty_printer::init_m_A_and_signs() { - if (numeric_traits::precise() && m_core_solver.m_settings.use_tableau()) { + if (numeric_traits::precise() ) { for (unsigned column = 0; column < ncols(); column++) { vector t(nrows(), zero_of_type()); for (const auto & c : m_core_solver.m_A.m_columns[column]){ @@ -125,23 +116,7 @@ template void core_solver_pretty_printer::init_m_ m_rs[row] += t[row] * m_core_solver.m_x[column]; } } - } else { - for (unsigned column = 0; column < ncols(); column++) { - m_core_solver.solve_Bd(column, m_ed_buff, m_w_buff); // puts the result into m_core_solver.m_ed - string name = m_core_solver.column_name(column); - for (unsigned row = 0; row < nrows(); row ++) { - set_coeff( - m_A[row], - m_signs[row], - column, - m_ed_buff[row], - name); - m_rs[row] += m_ed_buff[row] * m_core_solver.m_x[column]; - } - if (!m_core_solver.use_tableau()) - m_exact_column_norms.push_back(current_column_norm() + T(1)); // a conversion missing 1 -> T - } - } + } } template void core_solver_pretty_printer::init_column_widths() { @@ -190,11 +165,7 @@ template unsigned core_solver_pretty_printer:: ge w = cellw; } } - if (!m_core_solver.use_tableau()) { - w = std::max(w, (unsigned)T_to_string(m_exact_column_norms[column]).size()); - if (!m_core_solver.m_column_norms.empty()) - w = std::max(w, (unsigned)T_to_string(m_core_solver.m_column_norms[column]).size()); - } + return w; } @@ -315,41 +286,15 @@ template void core_solver_pretty_printer::print_u m_out << std::endl; } -template void core_solver_pretty_printer::print_exact_norms() { - if (m_core_solver.use_tableau()) return; - int blanks = m_title_width + 1 - static_cast(m_exact_norm_title.size()); - m_out << m_exact_norm_title; - print_blanks_local(blanks, m_out); - for (unsigned i = 0; i < ncols(); i++) { - string s = get_exact_column_norm_string(i); - int blanks = m_column_widths[i] - static_cast(s.size()); - print_blanks_local(blanks, m_out); - m_out << s << " "; - } - m_out << std::endl; -} template void core_solver_pretty_printer::print_approx_norms() { - if (m_core_solver.use_tableau()) return; - int blanks = m_title_width + 1 - static_cast(m_approx_norm_title.size()); - m_out << m_approx_norm_title; - print_blanks_local(blanks, m_out); - for (unsigned i = 0; i < ncols(); i++) { - string s = T_to_string(m_core_solver.m_column_norms[i]); - int blanks = m_column_widths[i] - static_cast(s.size()); - print_blanks_local(blanks, m_out); - m_out << s << " "; - } - m_out << std::endl; + return; } template void core_solver_pretty_printer::print() { for (unsigned i = 0; i < nrows(); i++) { print_row(i); } - print_exact_norms(); - if (!m_core_solver.m_column_norms.empty()) - print_approx_norms(); m_out << std::endl; if (m_core_solver.inf_set().size()) { m_out << "inf columns: "; diff --git a/src/math/lp/int_solver.cpp b/src/math/lp/int_solver.cpp index 3aaf8f29eb7..e338e222a27 100644 --- a/src/math/lp/int_solver.cpp +++ b/src/math/lp/int_solver.cpp @@ -344,7 +344,6 @@ bool int_solver::get_freedom_interval_for_column(unsigned j, bool & inf_l, impq set_upper(u, inf_u, upper_bound(j) - xj); - lp_assert(settings().use_tableau()); const auto & A = lra.A_r(); TRACE("random_update", tout << "m = " << m << "\n";); diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index b6c97513919..9678edd6bed 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -80,8 +80,7 @@ class lar_core_solver { column_type get_column_type(unsigned j) { return m_column_types[j];} - void calculate_pivot_row(unsigned i); - + void print_pivot_row(std::ostream & out, unsigned row_index) const { for (unsigned j : m_r_solver.m_pivot_row.m_index) { if (numeric_traits::is_pos(m_r_solver.m_pivot_row.m_data[j])) @@ -138,18 +137,11 @@ class lar_core_solver { void fill_not_improvable_zero_sum(); void pop_basis(unsigned k) { - if (!settings().use_tableau()) { - m_r_pushed_basis.pop(k); - m_r_basis = m_r_pushed_basis(); - m_r_solver.init_basis_heading_and_non_basic_columns_vector(); - m_d_pushed_basis.pop(k); - m_d_basis = m_d_pushed_basis(); - m_d_solver.init_basis_heading_and_non_basic_columns_vector(); - } else { + m_d_basis = m_r_basis; m_d_nbasis = m_r_nbasis; m_d_heading = m_r_heading; - } + } void push() { @@ -160,19 +152,11 @@ class lar_core_solver { m_stacked_simplex_strategy.push(); m_column_types.push(); // rational - if (!settings().use_tableau()) - m_r_A.push(); m_r_lower_bounds.push(); m_r_upper_bounds.push(); - if (!settings().use_tableau()) { - push_vector(m_r_pushed_basis, m_r_basis); - push_vector(m_r_columns_nz, m_r_solver.m_columns_nz); - push_vector(m_r_rows_nz, m_r_solver.m_rows_nz); - } m_d_A.push(); - if (!settings().use_tableau()) - push_vector(m_d_pushed_basis, m_d_basis); + } template @@ -202,8 +186,6 @@ class lar_core_solver { void pop(unsigned k) { // rationals - if (!settings().use_tableau()) - m_r_A.pop(k); m_r_lower_bounds.pop(k); m_r_upper_bounds.pop(k); m_column_types.pop(k); @@ -213,8 +195,7 @@ class lar_core_solver { m_r_x.resize(m_r_A.column_count()); m_r_solver.m_costs.resize(m_r_A.column_count()); m_r_solver.m_d.resize(m_r_A.column_count()); - if(!settings().use_tableau()) - pop_markowitz_counts(k); + m_d_A.pop(k); // doubles delete m_d_solver.m_factorization; @@ -454,7 +435,6 @@ class lar_core_solver { void solve_on_signature_tableau(const lar_solution_signature & signature, const vector & changes_of_basis) { r_basis_is_OK(); - lp_assert(settings().use_tableau()); bool r = catch_up_in_lu_tableau(changes_of_basis, m_d_solver.m_basis_heading); if (!r) { // it is the case where m_d_solver gives a degenerated basis @@ -553,8 +533,7 @@ class lar_core_solver { bool r_basis_is_OK() const { #ifdef Z3DEBUG - if (!m_r_solver.m_settings.use_tableau()) - return true; + for (unsigned j : m_r_solver.m_basis) { lp_assert(m_r_solver.m_A.m_columns[j].size() == 1); } @@ -568,40 +547,7 @@ class lar_core_solver { return true; } - void solve_on_signature(const lar_solution_signature & signature, const vector & changes_of_basis) { - SASSERT(!settings().use_tableau()); - if (m_r_solver.m_factorization == nullptr) { - for (unsigned j = 0; j < changes_of_basis.size(); j+=2) { - unsigned entering = changes_of_basis[j]; - unsigned leaving = changes_of_basis[j + 1]; - m_r_solver.change_basis_unconditionally(entering, leaving); - } - init_factorization(m_r_solver.m_factorization, m_r_A, m_r_basis, settings()); - } else { - catch_up_in_lu(changes_of_basis, m_d_solver.m_basis_heading, m_r_solver); - } - - if (no_r_lu()) { // it is the case where m_d_solver gives a degenerated basis, we need to roll back - catch_up_in_lu_in_reverse(changes_of_basis, m_r_solver); - m_r_solver.find_feasible_solution(); - m_d_basis = m_r_basis; - m_d_heading = m_r_heading; - m_d_nbasis = m_r_nbasis; - delete m_d_solver.m_factorization; - m_d_solver.m_factorization = nullptr; - } else { - prepare_solver_x_with_signature(signature, m_r_solver); - m_r_solver.start_tracing_basis_changes(); - m_r_solver.find_feasible_solution(); - if (settings().get_cancel_flag()) - return; - m_r_solver.stop_tracing_basis_changes(); - // and now catch up in the double solver - lp_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); - catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); - } - } - + void create_double_matrix(static_matrix & A) { for (unsigned i = 0; i < m_r_A.row_count(); i++) { auto & row = m_r_A.m_rows[i]; diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index 75fff64fd71..182029e3e98 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -46,23 +46,9 @@ lar_core_solver::lar_core_solver( column_names) { } -void lar_core_solver::calculate_pivot_row(unsigned i) { - m_r_solver.calculate_pivot_row(i); -} void lar_core_solver::prefix_r() { - if (!m_r_solver.m_settings.use_tableau()) { - m_r_solver.m_copy_of_xB.resize(m_r_solver.m_n()); - m_r_solver.m_ed.resize(m_r_solver.m_m()); - m_r_solver.m_pivot_row.resize(m_r_solver.m_n()); - m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m()); - m_r_solver.m_w.resize(m_r_solver.m_m()); - m_r_solver.m_y.resize(m_r_solver.m_m()); - m_r_solver.m_rows_nz.resize(m_r_solver.m_m(), 0); - m_r_solver.m_columns_nz.resize(m_r_solver.m_n(), 0); - init_column_row_nz_for_r_solver(); - } - + // m_r_solver.m_b.resize(m_r_solver.m_m()); if (m_r_solver.m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) { if(m_r_solver.m_settings.use_breakpoints_in_feasibility_search) @@ -142,7 +128,7 @@ void lar_core_solver::solve() { } ++settings().stats().m_need_to_solve_inf; CASSERT("A_off", !m_r_solver.A_mult_x_is_off()); - lp_assert((!settings().use_tableau()) || r_basis_is_OK()); + lp_assert( r_basis_is_OK()); if (need_to_presolve_with_double_solver()) { TRACE("lar_solver", tout << "presolving\n";); prefix_d(); @@ -152,26 +138,17 @@ void lar_core_solver::solve() { m_r_solver.set_status(lp_status::TIME_EXHAUSTED); return; } - if (settings().use_tableau()) - solve_on_signature_tableau(solution_signature, changes_of_basis); - else - solve_on_signature(solution_signature, changes_of_basis); - - lp_assert(!settings().use_tableau() || r_basis_is_OK()); + solve_on_signature_tableau(solution_signature, changes_of_basis); + + lp_assert( r_basis_is_OK()); } else { - if (!settings().use_tableau()) { - TRACE("lar_solver", tout << "no tablau\n";); - bool snapped = m_r_solver.snap_non_basic_x_to_bound(); - lp_assert(m_r_solver.non_basic_columns_are_set_correctly()); - if (snapped) - m_r_solver.solve_Ax_eq_b(); - } + if (m_r_solver.m_look_for_feasible_solution_only) //todo : should it be set? m_r_solver.find_feasible_solution(); else { m_r_solver.solve(); } - lp_assert(!settings().use_tableau() || r_basis_is_OK()); + lp_assert(r_basis_is_OK()); } switch (m_r_solver.get_status()) { diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 3339b55a5b7..2e9541525d4 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -261,8 +261,7 @@ namespace lp { m_crossed_bounds_column.pop(k); unsigned n = m_columns_to_ul_pairs.peek_size(k); m_var_register.shrink(n); - if (m_settings.use_tableau()) - pop_tableau(); + pop_tableau(); lp_assert(A_r().column_count() == n); TRACE("lar_solver_details", for (unsigned j = 0; j < n; j++) { @@ -284,7 +283,7 @@ namespace lp { clean_popped_elements(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - (!use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + ( m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau())); m_constraints.pop(k); @@ -299,7 +298,7 @@ namespace lp { m_simplex_strategy.pop(k); m_settings.set_simplex_strategy(m_simplex_strategy); lp_assert(sizes_are_correct()); - lp_assert((!m_settings.use_tableau()) || m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); + lp_assert(m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); m_usage_in_terms.pop(k); set_status(lp_status::UNKNOWN); } @@ -630,15 +629,7 @@ namespace lp { } void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - if (A_r().row_count() != m_column_buffer.data_size()) - m_column_buffer.resize(A_r().row_count()); - else - m_column_buffer.clear(); - lp_assert(m_column_buffer.size() == 0 && m_column_buffer.is_OK()); - - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) - insert_row_with_changed_bounds(i); + lp_assert(false); } @@ -648,8 +639,7 @@ namespace lp { insert_row_with_changed_bounds(rc.var()); } - bool lar_solver::use_tableau() const { return m_settings.use_tableau(); } - + bool lar_solver::use_tableau_costs() const { return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; } @@ -692,7 +682,7 @@ namespace lp { } void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair& delta) { - if (use_tableau()) { + { for (const auto& c : A_r().m_columns[j]) { unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; if (tableau_with_costs()) { @@ -705,15 +695,7 @@ namespace lp { } } - else { - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -m_column_buffer[i] * delta); - } - } + } void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { @@ -742,10 +724,8 @@ namespace lp { return; } - if (use_tableau()) - detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); - else - detect_rows_of_bound_change_column_for_nbasic_column(j); + detect_rows_of_bound_change_column_for_nbasic_column_tableau(j); + } void lar_solver::detect_rows_with_changed_bounds() { @@ -773,8 +753,6 @@ namespace lp { void lar_solver::solve_with_core_solver() { - if (!use_tableau()) - add_last_rows_to_lu(m_mpq_lar_core_solver.m_r_solver); if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); } @@ -782,10 +760,7 @@ namespace lp { if (costs_are_used()) { m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); } - if (use_tableau()) - update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); - else - update_x_and_inf_costs_for_columns_with_changed_bounds(); + update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); m_mpq_lar_core_solver.solve(); set_status(m_mpq_lar_core_solver.m_r_solver.get_status()); lp_assert(((stats().m_make_feasible% 100) != 0) || m_status != lp_status::OPTIMAL || all_constraints_hold()); @@ -1753,7 +1728,7 @@ namespace lp { SASSERT(m_terms.size() == m_term_register.size()); unsigned adjusted_term_index = m_terms.size() - 1; var_index ret = tv::mask_term(adjusted_term_index); - if (use_tableau() && !coeffs.empty()) { + if ( !coeffs.empty()) { add_row_from_term_no_constraint(m_terms.back(), ret); if (m_settings.bound_propagation()) insert_row_with_changed_bounds(A_r().row_count() - 1); @@ -1774,14 +1749,12 @@ namespace lp { ul_pair ul(true); // to mark this column as associated_with_row m_columns_to_ul_pairs.push_back(ul); add_basic_var_to_core_fields(); - if (use_tableau()) { - A_r().fill_last_row_with_pivoting(*term, + + A_r().fill_last_row_with_pivoting(*term, j, m_mpq_lar_core_solver.m_r_solver.m_basis_heading); - } - else { - fill_last_row_of_A_r(A_r(), term); - } + + m_mpq_lar_core_solver.m_r_solver.update_x(j, get_basic_var_value_from_row(A_r().row_count() - 1)); for (lar_term::ival c : *term) { unsigned j = c.column(); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index c1deb2fb1c8..51365936819 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -177,7 +177,6 @@ class lar_solver : public column_namer { if (A_r().m_rows[row_index].size() > settings().max_row_length_for_bound_propagation || row_has_a_big_num(row_index)) return; - lp_assert(use_tableau()); bound_analyzer_on_row, lp_bound_propagator>::analyze_row(A_r().m_rows[row_index], null_ci, @@ -190,7 +189,6 @@ class lar_solver : public column_namer { void substitute_basis_var_in_terms_for_row(unsigned i); template void calculate_implied_bounds_for_row(unsigned i, lp_bound_propagator & bp) { - SASSERT(use_tableau()); analyze_new_bounds_on_row_tableau(i, bp); } static void clean_popped_elements(unsigned n, u_set& set); @@ -210,7 +208,6 @@ class lar_solver : public column_namer { vector> &left_side) const; void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j); void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j); - bool use_tableau() const; bool use_tableau_costs() const; void detect_rows_of_column_with_bound_change(unsigned j); void adjust_x_of_column(unsigned j); @@ -376,7 +373,6 @@ class lar_solver : public column_namer { void mark_rows_for_bound_prop(lpvar j); template void propagate_bounds_for_touched_rows(lp_bound_propagator & bp) { - SASSERT(use_tableau()); for (unsigned i : m_rows_with_changed_bounds) { calculate_implied_bounds_for_row(i, bp); if (settings().get_cancel_flag()) @@ -429,8 +425,8 @@ class lar_solver : public column_namer { void change_basic_columns_dependend_on_a_given_nb_column_report(unsigned j, const numeric_pair & delta, const ChangeReport& after) { - if (use_tableau()) { - for (const auto & c : A_r().m_columns[j]) { + + for (const auto & c : A_r().m_columns[j]) { unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; if (tableau_with_costs()) { m_basic_columns_with_changed_cost.insert(bj); @@ -440,20 +436,8 @@ class lar_solver : public column_namer { TRACE("change_x_del", tout << "changed basis column " << bj << ", it is " << ( m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj)? "feas":"inf") << std::endl;); - - - } - } else { - NOT_IMPLEMENTED_YET(); - m_column_buffer.clear(); - m_column_buffer.resize(A_r().row_count()); - m_mpq_lar_core_solver.m_r_solver.solve_Bd(j, m_column_buffer); - for (unsigned i : m_column_buffer.m_index) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[i]; - m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -m_column_buffer[i] * delta); } - } - } + } template void set_value_for_nbasic_column_report(unsigned j, diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index c8b1692d272..5dc8fb9e2c2 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -26,7 +26,6 @@ Revision History: template bool lp::lp_core_solver_base::A_mult_x_is_off() const; template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; template bool lp::lp_core_solver_base::basis_heading_is_correct() const; -template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); @@ -52,16 +51,12 @@ template void lp::lp_core_solver_base::set_non_basic_x_to_correc template void lp::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); -template void lp::lp_core_solver_base::solve_Bd(unsigned int); -template void lp::lp_core_solver_base::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&) const; -template void lp::lp_core_solver_base>::solve_Bd(unsigned int, indexed_vector&); template void lp::lp_core_solver_base::solve_yB(vector&) const; template bool lp::lp_core_solver_base::update_basis_and_x(int, int, double const&); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); template bool lp::lp_core_solver_base::A_mult_x_is_off() const; template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; -template void lp::lp_core_solver_base::calculate_pivot_row_of_B_1(unsigned int); template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); @@ -71,11 +66,9 @@ template bool lp::lp_core_solver_base::print_statistics_with_i template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); -template void lp::lp_core_solver_base::solve_Bd(unsigned int); template void lp::lp_core_solver_base::solve_yB(vector&) const; template bool lp::lp_core_solver_base::update_basis_and_x(int, int, lp::mpq const&); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); -template void lp::lp_core_solver_base >::calculate_pivot_row_of_B_1(unsigned int); template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template void lp::lp_core_solver_base >::init(); template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); @@ -88,7 +81,7 @@ template lp::lp_core_solver_base >::lp_core_s template bool lp::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair, std::ostream&); template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); template void lp::lp_core_solver_base >::solve_Ax_eq_b(); -template void lp::lp_core_solver_base >::solve_Bd(unsigned int); + template bool lp::lp_core_solver_base >::update_basis_and_x(int, int, lp::numeric_pair const&); template void lp::lp_core_solver_base >::add_delta_to_entering(unsigned int, const lp::numeric_pair&); template lp::lp_core_solver_base::lp_core_solver_base( @@ -145,8 +138,7 @@ template bool lp::lp_core_solver_base::inf_set_is_correct() co template bool lp::lp_core_solver_base >::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; -template void lp::lp_core_solver_base >::calculate_pivot_row(unsigned int); template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int); template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int, lp::numeric_pair const&); -template void lp::lp_core_solver_base::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&) const; -template void lp::lp_core_solver_base >::solve_Bd(unsigned int, lp::indexed_vector&, lp::indexed_vector&) const; + + diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index b7010aa54a8..631f687816c 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -156,11 +156,6 @@ class lp_core_solver_base { void solve_yB(vector & y) const; - void solve_Bd(unsigned entering, indexed_vector & d_buff, indexed_vector& w_buff) const; - - void solve_Bd(unsigned entering); - - void solve_Bd(unsigned entering, indexed_vector & column); void pretty_print(std::ostream & out); @@ -184,9 +179,7 @@ class lp_core_solver_base { bool A_mult_x_is_off() const; bool A_mult_x_is_off_on_index(const vector & index) const; - // from page 182 of Istvan Maros's book - void calculate_pivot_row_of_B_1(unsigned pivot_row); - + void calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row); void add_delta_to_entering(unsigned entering, const X & delta); @@ -670,7 +663,6 @@ class lp_core_solver_base { m_settings.simplex_strategy(); } - bool use_tableau() const { return m_settings.use_tableau(); } template static void swap(vector &v, unsigned i, unsigned j) { @@ -760,7 +752,7 @@ class lp_core_solver_base { return m_iters_with_no_cost_growing; } - void calculate_pivot_row(unsigned i); + unsigned get_base_column_in_row(unsigned row_index) const { return m_basis[row_index]; } diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 93d5f430239..0e834243050 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -131,35 +131,9 @@ solve_yB(vector & y) const { // m_index_of_ed.push_back(i); // } // } -template void lp_core_solver_base::solve_Bd(unsigned entering, indexed_vector & column) { - lp_assert(!m_settings.use_tableau()); - if (m_factorization == nullptr) { - init_factorization(m_factorization, m_A, m_basis, m_settings); - } - m_factorization->solve_Bd_faster(entering, column); -} -template void lp_core_solver_base::solve_Bd(unsigned , indexed_vector& , indexed_vector &) const { - NOT_IMPLEMENTED_YET(); -} -template void lp_core_solver_base:: -solve_Bd(unsigned entering) { - lp_assert(m_ed.is_OK()); - m_factorization->solve_Bd(entering, m_ed, m_w); - if (this->precise()) - m_columns_nz[entering] = m_ed.m_index.size(); - lp_assert(m_ed.is_OK()); - lp_assert(m_w.is_OK()); -#ifdef Z3DEBUG - // auto B = get_B(*m_factorization, m_basis); - // vector a(m_m()); - // m_A.copy_column_to_vector(entering, a); - // vector cd(m_ed.m_data); - // B.apply_from_left(cd, m_settings); - // lp_assert(vectors_are_equal(cd , a)); -#endif -} + template void lp_core_solver_base:: pretty_print(std::ostream & out) { @@ -279,17 +253,6 @@ A_mult_x_is_off_on_index(const vector & index) const { return false; } -// from page 182 of Istvan Maros's book -template void lp_core_solver_base:: -calculate_pivot_row_of_B_1(unsigned pivot_row) { - lp_assert(! use_tableau()); - lp_assert(m_pivot_row_of_B_1.is_OK()); - m_pivot_row_of_B_1.clear(); - m_pivot_row_of_B_1.set_value(numeric_traits::one(), pivot_row); - lp_assert(m_pivot_row_of_B_1.is_OK()); - m_factorization->solve_yB_with_error_check_indexed(m_pivot_row_of_B_1, m_basis_heading, m_basis, m_settings); - lp_assert(m_pivot_row_of_B_1.is_OK()); -} template void lp_core_solver_base:: @@ -316,13 +279,7 @@ calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row) { template void lp_core_solver_base:: add_delta_to_entering(unsigned entering, const X& delta) { m_x[entering] += delta; - if (!use_tableau()) - for (unsigned i : m_ed.m_index) { - if (!numeric_traits::precise()) - m_copy_of_xB[i] = m_x[m_basis[i]]; - m_x[m_basis[i]] -= delta * m_ed[i]; - } - else + for (const auto & c : m_A.m_columns[entering]) { unsigned i = c.var(); m_x[m_basis[i]] -= delta * m_A.get_val(c); @@ -1000,26 +957,5 @@ lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) } } -template -void lp_core_solver_base::calculate_pivot_row(unsigned i) { - lp_assert(!use_tableau()); - lp_assert(m_pivot_row.is_OK()); - m_pivot_row_of_B_1.clear(); - m_pivot_row_of_B_1.resize(m_m()); - m_pivot_row.clear(); - m_pivot_row.resize(m_n()); - if (m_settings.use_tableau()) { - unsigned basic_j = m_basis[i]; - for (auto & c : m_A.m_rows[i]) { - if (c.var() != basic_j) - m_pivot_row.set_value(c.coeff(), c.var()); - } - return; - } - - calculate_pivot_row_of_B_1(i); - calculate_pivot_row_when_pivot_row_of_B1_is_ready(i); -} - } diff --git a/src/math/lp/lp_dual_core_solver_def.h b/src/math/lp/lp_dual_core_solver_def.h index b42d644af34..df70e64f1bc 100644 --- a/src/math/lp/lp_dual_core_solver_def.h +++ b/src/math/lp/lp_dual_core_solver_def.h @@ -210,26 +210,8 @@ template void lp_dual_core_solver::DSE_FTran() { } template bool lp_dual_core_solver::advance_on_known_p() { - if (done()) { - return true; - } - this->calculate_pivot_row_of_B_1(m_r); - this->calculate_pivot_row_when_pivot_row_of_B1_is_ready(m_r); - if (!ratio_test()) { - return true; - } - calculate_beta_r_precisely(); - this->solve_Bd(m_q); // FTRAN - int pivot_compare_result = this->pivots_in_column_and_row_are_different(m_q, m_p); - if (!pivot_compare_result){;} - else if (pivot_compare_result == 2) { // the sign is changed, cannot continue - lp_unreachable(); // not implemented yet - } else { - lp_assert(pivot_compare_result == 1); - this->init_lu(); - } - DSE_FTran(); - return basis_change_and_update(); + + return false; } template int lp_dual_core_solver::define_sign_of_alpha_r() { diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index a60395ab014..dc6cb2900e8 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -468,7 +468,6 @@ class lp_primal_core_solver:public lp_core_solver_base { } void update_basis_and_x_tableau_rows(int entering, int leaving, X const & tt) { - lp_assert(this->use_tableau()); lp_assert(entering != leaving); update_x_tableau_rows(entering, leaving, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); @@ -804,7 +803,7 @@ class lp_primal_core_solver:public lp_core_solver_base { return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); } - void init_reduced_costs(); + bool lower_bounds_are_set() const override { return true; } diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 3818b589a5a..0a58b0fdf69 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -33,21 +33,14 @@ namespace lp { template void lp_primal_core_solver::sort_non_basis_rational() { lp_assert(numeric_traits::precise()); - if (this->m_settings.use_tableau()) { + std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { unsigned ca = this->m_A.number_of_non_zeroes_in_column(a); unsigned cb = this->m_A.number_of_non_zeroes_in_column(b); if (ca == 0 && cb != 0) return false; return ca < cb; }); - } else { - std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { - unsigned ca = this->m_columns_nz[a]; - unsigned cb = this->m_columns_nz[b]; - if (ca == 0 && cb != 0) return false; - return ca < cb; - });} - + m_non_basis_list.clear(); // reinit m_basis_heading for (unsigned j = 0; j < this->m_nbasis.size(); j++) { @@ -644,25 +637,7 @@ template void lp_primal_core_solver::backup_an } template void lp_primal_core_solver::init_run() { - this->m_basis_sort_counter = 0; // to initiate the sort of the basis - // this->set_total_iterations(0); - this->iters_with_no_cost_growing() = 0; - init_inf_set(); - if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) - return; - this->set_using_infeas_costs(false); - if (this->m_settings.backup_costs) - backup_and_normalize_costs(); - m_epsilon_of_reduced_cost = numeric_traits::precise()? zero_of_type(): T(1)/T(10000000); - m_breakpoint_indices_queue.resize(this->m_n()); - init_reduced_costs(); - if (!numeric_traits::precise()) { - this->m_column_norm_update_counter = 0; - init_column_norms(); - } else { - if (this->m_columns_nz.size() != this->m_n()) - init_column_row_non_zeroes(); - } + } @@ -676,166 +651,20 @@ template void lp_primal_core_solver::calc_work template void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering, X & t) { - CASSERT("A_off", !this->A_mult_x_is_off() ); - this->add_delta_to_entering(entering, t * m_sign_of_entering_delta); - if (this->A_mult_x_is_off_on_index(this->m_ed.m_index) && !this->find_x_by_solving()) { - this->init_lu(); - if (!this->find_x_by_solving()) { - this->restore_x(entering, t * m_sign_of_entering_delta); - this->iters_with_no_cost_growing()++; - LP_OUT(this->m_settings, "failing in advance_on_entering_equal_leaving for entering = " << entering << std::endl); - return; - } - } - if (this->using_infeas_costs()) { - lp_assert(is_zero(this->m_costs[entering])); - init_infeasibility_costs_for_changed_basis_only(); - } - if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) - return; - if (need_to_switch_costs() ||!this->current_x_is_feasible()) { - init_reduced_costs(); - } - this->iters_with_no_cost_growing() = 0; } template void lp_primal_core_solver::advance_on_entering_and_leaving(int entering, int leaving, X & t) { - lp_assert(entering >= 0 && m_non_basis_list.back() == static_cast(entering)); - lp_assert(this->using_infeas_costs() || t >= zero_of_type()); - lp_assert(leaving >= 0 && entering >= 0); - lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes - if (entering == leaving) { - advance_on_entering_equal_leaving(entering, t); - return; - } - unsigned pivot_row = this->m_basis_heading[leaving]; - this->calculate_pivot_row_of_B_1(pivot_row); - this->calculate_pivot_row_when_pivot_row_of_B1_is_ready(pivot_row); - - int pivot_compare_result = this->pivots_in_column_and_row_are_different(entering, leaving); - if (!pivot_compare_result){;} - else if (pivot_compare_result == 2) { // the sign is changed, cannot continue - this->set_status(lp_status::UNSTABLE); - this->iters_with_no_cost_growing()++; - return; - } else { - lp_assert(pivot_compare_result == 1); - this->init_lu(); - if (this->m_factorization == nullptr || this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::UNSTABLE); - this->iters_with_no_cost_growing()++; - return; - } - } - if (!numeric_traits::precise()) - calc_working_vector_beta_for_column_norms(); - if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search) { - if (m_sign_of_entering_delta == -1) - t = -t; - } - if (!this->update_basis_and_x(entering, leaving, t)) { - if (this->get_status() == lp_status::FLOATING_POINT_ERROR) - return; - if (this->m_look_for_feasible_solution_only) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return; - } - init_reduced_costs(); - return; - } - - if (!is_zero(t)) { - this->iters_with_no_cost_growing() = 0; - init_infeasibility_after_update_x_if_inf(leaving); - } - - if (this->current_x_is_feasible()) { - this->set_status(lp_status::FEASIBLE); - if (this->m_look_for_feasible_solution_only) - return; - } - if (numeric_traits::precise() == false) - update_or_init_column_norms(entering, leaving); - - - if (need_to_switch_costs()) { - init_reduced_costs(); - } else { - update_reduced_costs_from_pivot_row(entering, leaving); - } - lp_assert(!need_to_switch_costs()); - std::list::iterator it = m_non_basis_list.end(); - it--; - * it = static_cast(leaving); + } template void lp_primal_core_solver::advance_on_entering_precise(int entering) { - lp_assert(numeric_traits::precise()); - lp_assert(entering > -1); - this->solve_Bd(entering); - X t; - int leaving = find_leaving_and_t_precise(entering, t); - if (leaving == -1) { - TRACE("lar_solver", tout << "non-leaving\n";); - this->set_status(lp_status::UNBOUNDED); - return; - } - advance_on_entering_and_leaving(entering, leaving, t); + lp_assert(false); } template void lp_primal_core_solver::advance_on_entering(int entering) { - if (numeric_traits::precise()) { - advance_on_entering_precise(entering); - return; - } - lp_assert(entering > -1); - this->solve_Bd(entering); - int refresh_result = refresh_reduced_cost_at_entering_and_check_that_it_is_off(entering); - if (refresh_result) { - if (this->m_look_for_feasible_solution_only) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return; - } - - this->init_lu(); - init_reduced_costs(); - if (refresh_result == 2) { - this->iters_with_no_cost_growing()++; - return; - } - } - X t; - int leaving = find_leaving_and_t(entering, t); - if (leaving == -1){ - if (!this->current_x_is_feasible()) { - lp_assert(!numeric_traits::precise()); // we cannot have unbounded with inf costs - - // if (m_look_for_feasible_solution_only) { - // this->m_status = INFEASIBLE; - // return; - // } - - - if (this->get_status() == lp_status::UNSTABLE) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return; - } - init_infeasibility_costs(); - this->set_status(lp_status::UNSTABLE); - - return; - } - if (this->get_status() == lp_status::TENTATIVE_UNBOUNDED) { - this->set_status(lp_status::UNBOUNDED); - } else { - this->set_status(lp_status::TENTATIVE_UNBOUNDED); - } - TRACE("lar_solver", tout << this->get_status() << "\n";); - return; - } - advance_on_entering_and_leaving(entering, leaving, t); + lp_assert(false); } template void lp_primal_core_solver::push_forward_offset_in_non_basis(unsigned & offset_in_nb) { @@ -867,7 +696,7 @@ template void lp_primal_core_solver::print_column // returns the number of iterations template unsigned lp_primal_core_solver::solve() { TRACE("lar_solver", tout << "solve " << this->get_status() << "\n";); - if (numeric_traits::precise() && this->m_settings.use_tableau()) + if (numeric_traits::precise()) return solve_with_tableau(); init_run(); @@ -893,56 +722,19 @@ template unsigned lp_primal_core_solver::solve() case lp_status::INFEASIBLE: if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) break; - if (!numeric_traits::precise()) { - if(this->m_look_for_feasible_solution_only) - break; - this->init_lu(); + { // precise case - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status (lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); - if (choose_entering_column(1) == -1) { - decide_on_status_when_cannot_find_entering(); - break; - } - this->set_status(lp_status::UNKNOWN); - } else { // precise case - if (this->m_look_for_feasible_solution_only) { // todo: keep the reduced costs correct all the time! - init_reduced_costs(); - if (choose_entering_column(1) == -1) { - decide_on_status_when_cannot_find_entering(); - break; - } - this->set_status(lp_status::UNKNOWN); - } } break; case lp_status::TENTATIVE_UNBOUNDED: - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - - init_reduced_costs(); + lp_assert(false); break; case lp_status::UNBOUNDED: - if (this->current_x_is_infeasible()) { - init_reduced_costs(); - this->set_status(lp_status::UNKNOWN); - } + lp_assert(false); break; case lp_status::UNSTABLE: - lp_assert(! (numeric_traits::precise())); - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); + lp_assert(false); break; default: @@ -1292,20 +1084,6 @@ template void lp_primal_core_solver::print_breakp print_bound_info_and_x(b->m_j, out); } -template -void lp_primal_core_solver::init_reduced_costs() { - lp_assert(!this->use_tableau()); - if (this->current_x_is_infeasible() && !this->using_infeas_costs()) { - init_infeasibility_costs(); - } else if (this->current_x_is_feasible() && this->using_infeas_costs()) { - if (this->m_look_for_feasible_solution_only) - return; - this->m_costs = m_costs_backup; - this->set_using_infeas_costs(false); - } - - this->init_reduced_costs_for_one_iteration(); -} template void lp_primal_core_solver::change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { if (b->m_j == entering) { diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index 46297a63e14..fa25694adc7 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -126,22 +126,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { case lp_status::INFEASIBLE: if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) break; - if (!numeric_traits::precise()) { - if(this->m_look_for_feasible_solution_only) - break; - this->init_lu(); - - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); - if (choose_entering_column(1) == -1) { - decide_on_status_when_cannot_find_entering(); - break; - } - this->set_status(lp_status::UNKNOWN); - } else { // precise case + { // precise case if ((!this->infeasibility_costs_are_correct())) { init_reduced_costs_tableau(); // forcing recalc if (choose_entering_column_tableau() == -1) { @@ -153,13 +138,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { } break; case lp_status::TENTATIVE_UNBOUNDED: - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - - init_reduced_costs(); + lp_assert(false); break; case lp_status::UNBOUNDED: if (this->current_x_is_infeasible()) { @@ -169,13 +148,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { break; case lp_status::UNSTABLE: - lp_assert(! (numeric_traits::precise())); - this->init_lu(); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - break; - } - init_reduced_costs(); + lp_assert(false); break; default: @@ -348,7 +321,6 @@ template void lp_primal_core_solver::init_run_tab template bool lp_primal_core_solver:: update_basis_and_x_tableau(int entering, int leaving, X const & tt) { - lp_assert(this->use_tableau()); lp_assert(entering != leaving); update_x_tableau(entering, tt); this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index d6a78564d8f..360ef99bf1d 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -339,11 +339,7 @@ struct lp_settings { m_simplex_strategy = s; } - - bool use_tableau() const { - return true; - } - + bool use_tableau_rows() const { return m_simplex_strategy == simplex_strategy_enum::tableau_rows; } diff --git a/src/math/lp/lu.cpp b/src/math/lp/lu.cpp index 6c9bcc5f65f..313fa990151 100644 --- a/src/math/lp/lu.cpp +++ b/src/math/lp/lu.cpp @@ -28,13 +28,10 @@ template double dot_product(vector const&, vector>::lu(static_matrix const&, vector&, lp_settings&); template void lu>::push_matrix_to_tail(tail_matrix*); template void lu>::replace_column(double, indexed_vector&, unsigned); -template void lu>::solve_Bd(unsigned int, indexed_vector&, indexed_vector&); template lu>::~lu(); template void lu>::push_matrix_to_tail(tail_matrix*); -template void lu>::solve_Bd(unsigned int, indexed_vector&, indexed_vector&); template lu>::~lu(); template void lu>::push_matrix_to_tail(tail_matrix*); -template void lu>::solve_Bd(unsigned int, indexed_vector&, indexed_vector&); template lu>::~lu(); template mpq dot_product(vector const&, vector const&); template void init_factorization> diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h index aca59065d4b..191018100f8 100644 --- a/src/math/lp/lu.h +++ b/src/math/lp/lu.h @@ -171,8 +171,6 @@ class lu { void print_matrix_compact(std::ostream & f); void print(indexed_vector & w, const vector& basis); - void solve_Bd(unsigned a_column, vector & d, indexed_vector & w); - void solve_Bd(unsigned a_column, indexed_vector & d, indexed_vector & w); void solve_Bd_faster(unsigned a_column, indexed_vector & d); // d is the right side on the input and the solution at the exit void solve_yB(vector& y); diff --git a/src/math/lp/lu_def.h b/src/math/lp/lu_def.h index 80c9cdf0ed4..059a430124c 100644 --- a/src/math/lp/lu_def.h +++ b/src/math/lp/lu_def.h @@ -117,7 +117,7 @@ lu::lu(const M& A, m_failure(false), m_row_eta_work_vector(A.row_count()), m_refactor_counter(0) { - lp_assert(!(numeric_traits::precise() && settings.use_tableau())); + lp_assert(!(numeric_traits::precise() )); #ifdef Z3DEBUG debug_test_of_basis(A, basis); #endif @@ -256,19 +256,6 @@ void lu< M>::print(indexed_vector & w, const vector& basis) { print_indexed_vector(w, f); f.close(); } -template -void lu< M>::solve_Bd(unsigned a_column, indexed_vector & d, indexed_vector & w) { - init_vector_w(a_column, w); - - if (w.m_index.size() * ratio_of_index_size_to_all_size() < d.m_data.size()) { // this const might need some tuning - d = w; - solve_By_for_T_indexed_only(d, m_settings); - } else { - d.m_data = w.m_data; - d.m_index.clear(); - solve_By_when_y_is_ready_for_T(d.m_data, d.m_index); - } -} template void lu< M>::solve_Bd_faster(unsigned a_column, indexed_vector & d) { // puts the a_column into d diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index fe589835d48..189bd604b92 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -2095,35 +2095,7 @@ void read_indexed_vector(indexed_vector & v, std::ifstream & f) { } void check_lu_from_file(std::string lufile_name) { - std::ifstream f(lufile_name); - if (!f.is_open()) { - std::cout << "cannot open file " << lufile_name << std::endl; - } - unsigned m, n; - get_matrix_dimensions(f, m, n); - std::cout << "init matrix " << m << " by " << n << std::endl; - static_matrix A(m, n); - read_rows(A, f); - vector basis; - read_basis(basis, f); - indexed_vector v(m); - // read_indexed_vector(v, f); - f.close(); - vector basis_heading; - lp_settings settings; - vector non_basic_columns; - lu> lsuhl(A, basis, settings); - indexed_vector d(A.row_count()); - unsigned entering = 26; - lsuhl.solve_Bd(entering, d, v); -#ifdef Z3DEBUG - auto B = get_B(lsuhl, basis); - vector a(m); - A.copy_column_to_vector(entering, a); - indexed_vector cd(d); - B.apply_from_left(cd.m_data, settings); - lp_assert(vectors_are_equal(cd.m_data , a)); -#endif + lp_assert(false); } void test_square_dense_submatrix() { From a2a12085e4e958367538b7cbeb6d22c8731c3de9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 15:15:08 -0800 Subject: [PATCH 06/36] rm_lu --- src/math/lp/lar_solver.cpp | 19 +----- src/math/lp/lp_primal_core_solver.h | 2 +- src/math/lp/lu.h | 59 ++---------------- src/test/lp/lp.cpp | 92 +---------------------------- 4 files changed, 9 insertions(+), 163 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 2e9541525d4..d9961eaa8ab 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -795,24 +795,7 @@ namespace lp { template void lar_solver::add_last_rows_to_lu(lp_primal_core_solver& s) { - auto& f = s.m_factorization; - if (f != nullptr) { - auto columns_to_replace = f->get_set_of_columns_to_replace_for_add_last_rows(s.m_basis_heading); - if (f->m_refactor_counter + columns_to_replace.size() >= 200 || f->has_dense_submatrix()) { - delete f; - f = nullptr; - } - else { - f->add_last_rows_to_B(s.m_basis_heading, columns_to_replace); - } - } - if (f == nullptr) { - init_factorization(f, s.m_A, s.m_basis, m_settings); - if (f->get_status() != LU_status::OK) { - delete f; - f = nullptr; - } - } + lp_assert(false); } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index dc6cb2900e8..5332b4001da 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -418,7 +418,7 @@ class lp_primal_core_solver:public lp_core_solver_base { // returns the number of iterations unsigned solve(); - lu> * factorization() {return this->m_factorization;} + lu> * factorization() {return nullptr;} void delete_factorization(); diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h index 191018100f8..bcbb850434d 100644 --- a/src/math/lp/lu.h +++ b/src/math/lp/lu.h @@ -305,66 +305,19 @@ class lu { void calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element); void prepare_entering(unsigned entering, indexed_vector & w) { - init_vector_w(entering, w); + lp_assert(false); } - bool need_to_refactor() { return m_refactor_counter >= 200; } + bool need_to_refactor() { lp_assert(false); + return m_refactor_counter >= 200; } void adjust_dimension_with_matrix_A() { - lp_assert(m_A.row_count() >= m_dim); - m_dim = m_A.row_count(); - m_U.resize(m_dim); - m_Q.resize(m_dim); - m_R.resize(m_dim); - m_row_eta_work_vector.resize(m_dim); + lp_assert(false); } - std::unordered_set get_set_of_columns_to_replace_for_add_last_rows(const vector & heading) const { - std::unordered_set columns_to_replace; - unsigned m = m_A.row_count(); - unsigned m_prev = m_U.dimension(); - - lp_assert(m_A.column_count() == heading.size()); - - for (unsigned i = m_prev; i < m; i++) { - for (const row_cell & c : m_A.m_rows[i]) { - int h = heading[c.var()]; - if (h < 0) { - continue; - } - columns_to_replace.insert(c.var()); - } - } - return columns_to_replace; - } - void add_last_rows_to_B(const vector & heading, const std::unordered_set & columns_to_replace) { - unsigned m = m_A.row_count(); - lp_assert(m_A.column_count() == heading.size()); - adjust_dimension_with_matrix_A(); - m_w_for_extension.resize(m); - // At this moment the LU is correct - // for B extended by only by ones at the diagonal in the lower right corner - - for (unsigned j :columns_to_replace) { - lp_assert(heading[j] >= 0); - replace_column_with_only_change_at_last_rows(j, heading[j]); - if (get_status() == LU_status::Degenerated) - break; - } - } - // column j is a basis column, and there is a change in the last rows - void replace_column_with_only_change_at_last_rows(unsigned j, unsigned column_to_change_in_U) { - init_vector_w(j, m_w_for_extension); - replace_column(zero_of_type(), m_w_for_extension, column_to_change_in_U); - } - - bool has_dense_submatrix() const { - for (auto m : m_tail) - if (m->is_dense()) - return true; - return false; - } + + }; // end of lu diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 189bd604b92..ceca92b4ecc 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -551,90 +551,7 @@ void change_basis(unsigned entering, unsigned leaving, vector& basis, #ifdef Z3DEBUG void test_small_lu(lp_settings & settings) { - std::cout << " test_small_lu" << std::endl; - static_matrix m(3, 6); - vector basis(3); - basis[0] = 0; - basis[1] = 1; - basis[2] = 3; - - m(0, 0) = 1; m(0, 2)= 3.9; m(2, 3) = 11; m(0, 5) = -3; - m(1, 1) = 4; m(1, 4) = 7; - m(2, 0) = 1.8; m(2, 2) = 5; m(2, 4) = 2; m(2, 5) = 8; - -#ifdef Z3DEBUG - print_matrix(m, std::cout); -#endif - vector heading = allocate_basis_heading(m.column_count()); - vector non_basic_columns; - init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); - lu> l(m, basis, settings); - lp_assert(l.is_correct(basis)); - indexed_vector w(m.row_count()); - std::cout << "entering 2, leaving 0" << std::endl; - l.prepare_entering(2, w); // to init vector w - l.replace_column(0, w, heading[0]); - change_basis(2, 0, basis, non_basic_columns, heading); - // #ifdef Z3DEBUG - // std::cout << "we were factoring " << std::endl; - // print_matrix(get_B(l)); - // #endif - lp_assert(l.is_correct(basis)); - std::cout << "entering 4, leaving 3" << std::endl; - l.prepare_entering(4, w); // to init vector w - l.replace_column(0, w, heading[3]); - change_basis(4, 3, basis, non_basic_columns, heading); - std::cout << "we were factoring " << std::endl; -#ifdef Z3DEBUG - { - auto bl = get_B(l, basis); - print_matrix(&bl, std::cout); - } -#endif - lp_assert(l.is_correct(basis)); - - std::cout << "entering 5, leaving 1" << std::endl; - l.prepare_entering(5, w); // to init vector w - l.replace_column(0, w, heading[1]); - change_basis(5, 1, basis, non_basic_columns, heading); - std::cout << "we were factoring " << std::endl; -#ifdef Z3DEBUG - { - auto bl = get_B(l, basis); - print_matrix(&bl, std::cout); - } -#endif - lp_assert(l.is_correct(basis)); - std::cout << "entering 3, leaving 2" << std::endl; - l.prepare_entering(3, w); // to init vector w - l.replace_column(0, w, heading[2]); - change_basis(3, 2, basis, non_basic_columns, heading); - std::cout << "we were factoring " << std::endl; -#ifdef Z3DEBUG - { - auto bl = get_B(l, basis); - print_matrix(&bl, std::cout); - } -#endif - lp_assert(l.is_correct(basis)); - - m.add_row(); - m.add_column(); - m.add_row(); - m.add_column(); - for (unsigned i = 0; i < m.column_count(); i++) { - m(3, i) = i; - m(4, i) = i * i; // to make the rows linearly independent - } - unsigned j = m.column_count() ; - basis.push_back(j-2); - heading.push_back(basis.size() - 1); - basis.push_back(j-1); - heading.push_back(basis.size() - 1); - auto columns_to_replace = l.get_set_of_columns_to_replace_for_add_last_rows(heading); - l.add_last_rows_to_B(heading, columns_to_replace); - lp_assert(l.is_correct(basis)); } #endif @@ -827,10 +744,7 @@ void test_larger_lu(lp_settings& settings) { void test_lu(lp_settings & settings) { - test_small_lu(settings); - test_larger_lu(settings); - test_larger_lu_with_holes(settings); - test_larger_lu_exp(settings); + } #endif @@ -1785,10 +1699,6 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_after_string_with_help("--time_limit", "time limit in seconds"); parser.add_option_with_help_string("--mpq", "solve for rational numbers"); parser.add_option_with_after_string_with_help("--simplex_strategy", "sets simplex strategy for rational number"); - parser.add_option_with_help_string("--test_lu", "test the work of the factorization"); - parser.add_option_with_help_string("--test_small_lu", "test the work of the factorization on a smallish matrix"); - parser.add_option_with_help_string("--test_larger_lu", "test the work of the factorization"); - parser.add_option_with_help_string("--test_larger_lu_with_holes", "test the work of the factorization"); parser.add_option_with_help_string("--test_lp_0", "solve a small lp"); parser.add_option_with_help_string("--solve_some_mps", "solves a list of mps problems"); parser.add_option_with_after_string_with_help("--test_file_directory", "loads files from the directory for testing"); From 832b80471adbcd91fa48466dc31578918dedf7a9 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 15:26:55 -0800 Subject: [PATCH 07/36] rm lu --- src/math/lp/lu.h | 10 +- src/math/lp/lu_def.h | 235 +++---------------------------------------- src/test/lp/lp.cpp | 136 ------------------------- 3 files changed, 16 insertions(+), 365 deletions(-) diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h index bcbb850434d..b3e2f0c2221 100644 --- a/src/math/lp/lu.h +++ b/src/math/lp/lu.h @@ -266,13 +266,6 @@ class lu { bool is_correct(); -#ifdef Z3DEBUG - dense_matrix tail_product(); - dense_matrix get_left_side(const vector& basis); - dense_matrix get_left_side(); - - dense_matrix get_right_side(); -#endif // needed for debugging purposes void copy_w(T *buffer, indexed_vector & w); @@ -296,8 +289,7 @@ class lu { void pivot_and_solve_the_system(unsigned replaced_column, unsigned lowest_row_of_the_bump); // see Achim Koberstein's thesis page 58, but here we solve the system and pivot to the last // row at the same time - row_eta_matrix *get_row_eta_matrix_and_set_row_vector(unsigned replaced_column, unsigned lowest_row_of_the_bump, const T & pivot_elem_for_checking); - + void replace_column(T pivot_elem, indexed_vector & w, unsigned leaving_column_of_U); void calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump); diff --git a/src/math/lp/lu_def.h b/src/math/lp/lu_def.h index 059a430124c..d7c0c0c3a07 100644 --- a/src/math/lp/lu_def.h +++ b/src/math/lp/lu_def.h @@ -626,161 +626,41 @@ void lu::process_column(int j) { } template bool lu::is_correct(const vector& basis) { -#ifdef Z3DEBUG - if (get_status() != LU_status::OK) { - return false; - } - dense_matrix left_side = get_left_side(basis); - dense_matrix right_side = get_right_side(); - return left_side == right_side; -#else - return true; -#endif +return true; } template bool lu::is_correct() { -#ifdef Z3DEBUG - if (get_status() != LU_status::OK) { - return false; - } - dense_matrix left_side = get_left_side(); - dense_matrix right_side = get_right_side(); - return left_side == right_side; -#else return true; -#endif } -#ifdef Z3DEBUG -template -dense_matrix lu::tail_product() { - lp_assert(tail_size() > 0); - dense_matrix left_side = permutation_matrix(m_dim); - for (unsigned i = 0; i < tail_size(); i++) { - matrix* lp = get_lp_matrix(i); - lp->set_number_of_rows(m_dim); - lp->set_number_of_columns(m_dim); - left_side = ((*lp) * left_side); - } - return left_side; -} -template -dense_matrix lu::get_left_side(const vector& basis) { - dense_matrix left_side = get_B(*this, basis); - for (unsigned i = 0; i < tail_size(); i++) { - matrix* lp = get_lp_matrix(i); - lp->set_number_of_rows(m_dim); - lp->set_number_of_columns(m_dim); - left_side = ((*lp) * left_side); - } - return left_side; -} -template -dense_matrix lu::get_left_side() { - dense_matrix left_side = get_B(*this); - for (unsigned i = 0; i < tail_size(); i++) { - matrix* lp = get_lp_matrix(i); - lp->set_number_of_rows(m_dim); - lp->set_number_of_columns(m_dim); - left_side = ((*lp) * left_side); - } - return left_side; -} -template -dense_matrix lu::get_right_side() { - auto ret = U() * R(); - ret = Q() * ret; - return ret; -} -#endif - // needed for debugging purposes template void lu::copy_w(T *buffer, indexed_vector & w) { - unsigned i = m_dim; - while (i--) { - buffer[i] = w[i]; - } + } // needed for debugging purposes template void lu::restore_w(T *buffer, indexed_vector & w) { - unsigned i = m_dim; - while (i--) { - w[i] = buffer[i]; - } + } template bool lu::all_columns_and_rows_are_active() { - unsigned i = m_dim; - while (i--) { - lp_assert(m_U.col_is_active(i)); - lp_assert(m_U.row_is_active(i)); - } return true; } template bool lu::too_dense(unsigned j) const { - unsigned r = m_dim - j; - if (r < 5) - return false; - // if (j * 5 < m_dim * 4) // start looking for dense only at the bottom of the rows - // return false; - // return r * r * m_settings.density_threshold <= m_U.get_number_of_nonzeroes_below_row(j); - return r * r * m_settings.density_threshold <= m_U.get_n_of_active_elems(); + return false; } template void lu::pivot_in_dense_mode(unsigned i) { - int j = m_dense_LU->find_pivot_column_in_row(i); - if (j == -1) { - m_failure = true; - return; - } - if (i != static_cast(j)) { - swap_columns(i, j); - m_dense_LU->swap_columns(i, j); - } - m_dense_LU->pivot(i, m_settings); + } template void lu::create_initial_factorization(){ - m_U.prepare_for_factorization(); - unsigned j; - for (j = 0; j < m_dim; j++) { - process_column(j); - if (m_failure) { - set_status(LU_status::Degenerated); - return; - } - if (too_dense(j)) { - break; - } - } - if (j == m_dim) { - // TBD does not compile: lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lp_assert(is_correct()); - // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - return; - } - j++; - m_dense_LU = new square_dense_submatrix(&m_U, j); - for (; j < m_dim; j++) { - pivot_in_dense_mode(j); - if (m_failure) { - set_status(LU_status::Degenerated); - return; - } - } - m_dense_LU->update_parent_matrix(m_settings); - lp_assert(m_dense_LU->is_L_matrix()); - m_dense_LU->conjugate_by_permutation(m_Q); - push_matrix_to_tail(m_dense_LU); - m_refactor_counter = 0; - // lp_assert(is_correct()); - // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + } template @@ -856,123 +736,38 @@ void lu::pivot_and_solve_the_system(unsigned replaced_column, unsigned lowest } } } -// see Achim Koberstein's thesis page 58, but here we solve the system and pivot to the last -// row at the same time -template -row_eta_matrix *lu::get_row_eta_matrix_and_set_row_vector(unsigned replaced_column, unsigned lowest_row_of_the_bump, const T & pivot_elem_for_checking) { - if (replaced_column == lowest_row_of_the_bump) return nullptr; - scan_last_row_to_work_vector(lowest_row_of_the_bump); - pivot_and_solve_the_system(replaced_column, lowest_row_of_the_bump); - if (numeric_traits::precise() == false && !is_zero(pivot_elem_for_checking)) { - T denom = std::max(T(1), abs(pivot_elem_for_checking)); - if ( - !m_settings.abs_val_is_smaller_than_pivot_tolerance((m_row_eta_work_vector[lowest_row_of_the_bump] - pivot_elem_for_checking) / denom)) { - set_status(LU_status::Degenerated); - // LP_OUT(m_settings, "diagonal element is off" << std::endl); - return nullptr; - } - } -#ifdef Z3DEBUG - auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump, m_dim); -#else - auto ret = new row_eta_matrix(replaced_column, lowest_row_of_the_bump); -#endif - - for (auto j : m_row_eta_work_vector.m_index) { - if (j < lowest_row_of_the_bump) { - auto & v = m_row_eta_work_vector[j]; - if (!is_zero(v)) { - if (!m_settings.abs_val_is_smaller_than_drop_tolerance(v)){ - ret->push_back(j, v); - } - v = numeric_traits::zero(); - } - } - } // now the lowest_row_of_the_bump contains the rest of the row to the right of the bump with correct values - return ret; -} template void lu::replace_column(T pivot_elem_for_checking, indexed_vector & w, unsigned leaving_column_of_U){ - m_refactor_counter++; - unsigned replaced_column = transform_U_to_V_by_replacing_column( w, leaving_column_of_U); - unsigned lowest_row_of_the_bump = m_U.lowest_row_in_column(replaced_column); - m_r_wave.init(m_dim); - calculate_r_wave_and_update_U(replaced_column, lowest_row_of_the_bump, m_r_wave); - auto row_eta = get_row_eta_matrix_and_set_row_vector(replaced_column, lowest_row_of_the_bump, pivot_elem_for_checking); - - if (get_status() == LU_status::Degenerated) { - m_row_eta_work_vector.clear_all(); - return; - } - m_Q.multiply_by_permutation_from_right(m_r_wave); - m_R.multiply_by_permutation_reverse_from_left(m_r_wave); - if (row_eta != nullptr) { - row_eta->conjugate_by_permutation(m_Q); - push_matrix_to_tail(row_eta); - } - calculate_Lwave_Pwave_for_bump(replaced_column, lowest_row_of_the_bump); - // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); - // lp_assert(w.is_OK() && m_row_eta_work_vector.is_OK()); + lp_assert(false); } template void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump){ - T diagonal_elem; - if (replaced_column < lowest_row_of_the_bump) { - diagonal_elem = m_row_eta_work_vector[lowest_row_of_the_bump]; - // lp_assert(m_row_eta_work_vector.is_OK()); - m_U.set_row_from_work_vector_and_clean_work_vector_not_adjusted(m_U.adjust_row(lowest_row_of_the_bump), m_row_eta_work_vector, m_settings); - } else { - diagonal_elem = m_U(lowest_row_of_the_bump, lowest_row_of_the_bump); // todo - get it more efficiently - } - if (m_settings.abs_val_is_smaller_than_pivot_tolerance(diagonal_elem)) { - set_status(LU_status::Degenerated); - return; - } - - calculate_Lwave_Pwave_for_last_row(lowest_row_of_the_bump, diagonal_elem); - // lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); + lp_assert(false);// lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); } template void lu::calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element) { - auto l = new one_elem_on_diag(lowest_row_of_the_bump, diagonal_element); -#ifdef Z3DEBUG - l->set_number_of_columns(m_dim); -#endif - push_matrix_to_tail(l); - m_U.divide_row_by_constant(lowest_row_of_the_bump, diagonal_element, m_settings); - l->conjugate_by_permutation(m_Q); + lp_assert(false); } template void init_factorization(lu* & factorization, M & m_A, vector & m_basis, lp_settings &m_settings) { - if (factorization != nullptr) - delete factorization; - factorization = new lu(m_A, m_basis, m_settings); - // if (factorization->get_status() != LU_status::OK) - // LP_OUT(m_settings, "failing in init_factorization" << std::endl); + lp_assert(false); } #ifdef Z3DEBUG template dense_matrix get_B(lu& f, const vector& basis) { - lp_assert(basis.size() == f.dimension()); - lp_assert(basis.size() == f.m_U.dimension()); - dense_matrix B(f.dimension(), f.dimension()); - for (unsigned i = 0; i < f.dimension(); i++) - for (unsigned j = 0; j < f.dimension(); j++) - B.set_elem(i, j, f.B_(i, j, basis)); - + lp_assert(false); + + dense_matrix B(0, 0); return B; } template dense_matrix get_B(lu& f) { - dense_matrix B(f.dimension(), f.dimension()); - for (unsigned i = 0; i < f.dimension(); i++) - for (unsigned j = 0; j < f.dimension(); j++) - B.set_elem(i, j, f.m_A[i][j]); - + lp_assert(false); + dense_matrix B(0,0); return B; } #endif diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index ceca92b4ecc..1a2ee2338b6 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -611,142 +611,6 @@ void fill_larger_square_sparse_matrix(static_matrix & m){ int perm_id = 0; -#ifdef Z3DEBUG -void test_larger_lu_exp(lp_settings & settings) { - std::cout << " test_larger_lu_exp" << std::endl; - static_matrix m(6, 12); - vector basis(6); - basis[0] = 1; - basis[1] = 3; - basis[2] = 0; - basis[3] = 4; - basis[4] = 5; - basis[5] = 6; - - - fill_larger_square_sparse_matrix_exp(m); - // print_matrix(m); - vector heading = allocate_basis_heading(m.column_count()); - vector non_basic_columns; - init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); - lu> l(m, basis, settings); - - dense_matrix left_side = l.get_left_side(basis); - dense_matrix right_side = l.get_right_side(); - lp_assert(left_side == right_side); - int leaving = 3; - int entering = 8; - for (unsigned i = 0; i < m.row_count(); i++) { - std::cout << static_cast(m(i, entering)) << std::endl; - } - - indexed_vector w(m.row_count()); - - l.prepare_entering(entering, w); - l.replace_column(0, w, heading[leaving]); - change_basis(entering, leaving, basis, non_basic_columns, heading); - lp_assert(l.is_correct(basis)); - - l.prepare_entering(11, w); // to init vector w - l.replace_column(0, w, heading[0]); - change_basis(11, 0, basis, non_basic_columns, heading); - lp_assert(l.is_correct(basis)); -} - -void test_larger_lu_with_holes(lp_settings & settings) { - std::cout << " test_larger_lu_with_holes" << std::endl; - static_matrix m(8, 9); - vector basis(8); - for (unsigned i = 0; i < m.row_count(); i++) { - basis[i] = i; - } - m(0, 0) = 1; m(0, 1) = 2; m(0, 2) = 3; m(0, 3) = 4; m(0, 4) = 5; m(0, 8) = 99; - /* */ m(1, 1) =- 6; m(1, 2) = 7; m(1, 3) = 8; m(1, 4) = 9; - /* */ m(2, 2) = 10; - /* */ m(3, 2) = 11; m(3, 3) = -12; - /* */ m(4, 2) = 13; m(4, 3) = 14; m(4, 4) = 15; - // the rest of the matrix is denser - m(5, 4) = 28; m(5, 5) = -18; m(5, 6) = 19; m(5, 7) = 25; - /* */ m(6, 5) = 20; m(6, 6) = -21; - /* */ m(7, 5) = 22; m(7, 6) = 23; m(7, 7) = 24; m(7, 8) = 88; - print_matrix(m, std::cout); - vector heading = allocate_basis_heading(m.column_count()); - vector non_basic_columns; - init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); - lu> l(m, basis, settings); - std::cout << "printing factorization" << std::endl; - for (int i = l.tail_size() - 1; i >=0; i--) { - auto lp = l.get_lp_matrix(i); - lp->set_number_of_columns(m.row_count()); - lp->set_number_of_rows(m.row_count()); - print_matrix( *lp, std::cout); - } - - dense_matrix left_side = l.get_left_side(basis); - dense_matrix right_side = l.get_right_side(); - if (!(left_side == right_side)) { - std::cout << "different sides" << std::endl; - } - - indexed_vector w(m.row_count()); - l.prepare_entering(8, w); // to init vector w - l.replace_column(0, w, heading[0]); - change_basis(8, 0, basis, non_basic_columns, heading); - lp_assert(l.is_correct(basis)); -} - - -void test_larger_lu(lp_settings& settings) { - std::cout << " test_larger_lu" << std::endl; - static_matrix m(6, 12); - vector basis(6); - basis[0] = 1; - basis[1] = 3; - basis[2] = 0; - basis[3] = 4; - basis[4] = 5; - basis[5] = 6; - - - fill_larger_square_sparse_matrix(m); - print_matrix(m, std::cout); - - vector heading = allocate_basis_heading(m.column_count()); - vector non_basic_columns; - init_basis_heading_and_non_basic_columns_vector(basis, heading, non_basic_columns); - auto l = lu> (m, basis, settings); - // std::cout << "printing factorization" << std::endl; - // for (int i = lu.tail_size() - 1; i >=0; i--) { - // auto lp = lu.get_lp_matrix(i); - // lp->set_number_of_columns(m.row_count()); - // lp->set_number_of_rows(m.row_count()); - // print_matrix(* lp); - // } - - dense_matrix left_side = l.get_left_side(basis); - dense_matrix right_side = l.get_right_side(); - if (!(left_side == right_side)) { - std::cout << "left side" << std::endl; - print_matrix(&left_side, std::cout); - std::cout << "right side" << std::endl; - print_matrix(&right_side, std::cout); - - std::cout << "different sides" << std::endl; - std::cout << "initial factorization is incorrect" << std::endl; - exit(1); - } - indexed_vector w(m.row_count()); - l.prepare_entering(9, w); // to init vector w - l.replace_column(0, w, heading[0]); - change_basis(9, 0, basis, non_basic_columns, heading); - lp_assert(l.is_correct(basis)); -} - - -void test_lu(lp_settings & settings) { - -} -#endif From 9c1128393acfef74bec81b8955cf1d47ffb2a75a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Sat, 4 Mar 2023 16:02:46 -0800 Subject: [PATCH 08/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lp_core_solver_base.cpp | 3 -- src/math/lp/lp_core_solver_base.h | 3 +- src/math/lp/lp_core_solver_base_def.h | 60 ------------------------- src/math/lp/lp_dual_core_solver_def.h | 28 +----------- src/math/lp/lp_primal_core_solver.h | 4 +- src/math/lp/lp_primal_core_solver_def.h | 6 --- 6 files changed, 4 insertions(+), 100 deletions(-) diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 5dc8fb9e2c2..9f6f2534f6c 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -52,7 +52,6 @@ template void lp::lp_core_solver_base::snap_xN_to_bounds_and_fre template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::solve_yB(vector&) const; -template bool lp::lp_core_solver_base::update_basis_and_x(int, int, double const&); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); template bool lp::lp_core_solver_base::A_mult_x_is_off() const; template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; @@ -67,7 +66,6 @@ template void lp::lp_core_solver_base::restore_x(unsigned int, template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::solve_yB(vector&) const; -template bool lp::lp_core_solver_base::update_basis_and_x(int, int, lp::mpq const&); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template void lp::lp_core_solver_base >::init(); @@ -82,7 +80,6 @@ template bool lp::lp_core_solver_base >::prin template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); template void lp::lp_core_solver_base >::solve_Ax_eq_b(); -template bool lp::lp_core_solver_base >::update_basis_and_x(int, int, lp::numeric_pair const&); template void lp::lp_core_solver_base >::add_delta_to_entering(unsigned int, const lp::numeric_pair&); template lp::lp_core_solver_base::lp_core_solver_base( lp::static_matrix&, diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 631f687816c..dce805b62ee 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -307,8 +307,7 @@ class lp_core_solver_base { bool find_x_by_solving(); - bool update_basis_and_x(int entering, int leaving, X const & tt); - + bool basis_has_no_doubles() const; bool non_basis_has_no_doubles() const; diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 0e834243050..51b24128fef 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -457,66 +457,6 @@ template bool lp_core_solver_base::inf_set_is_cor return true; } -template bool lp_core_solver_base:: -update_basis_and_x(int entering, int leaving, X const & tt) { - - if (!is_zero(tt)) { - add_delta_to_entering(entering, tt); - if ((!numeric_traits::precise()) && A_mult_x_is_off_on_index(m_ed.m_index) && !find_x_by_solving()) { - init_factorization(m_factorization, m_A, m_basis, m_settings); - if (!find_x_by_solving()) { - restore_x(entering, tt); - if(A_mult_x_is_off()) { - m_status = lp_status::FLOATING_POINT_ERROR; - m_iters_with_no_cost_growing++; - return false; - } - - init_factorization(m_factorization, m_A, m_basis, m_settings); - m_iters_with_no_cost_growing++; - if (m_factorization->get_status() != LU_status::OK) { - std::stringstream s; - // s << "failing refactor on off_result for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations(); - m_status = lp_status::FLOATING_POINT_ERROR; - return false; - } - return false; - } - } - } - - bool refactor = m_factorization->need_to_refactor(); - if (!refactor) { - const T & pivot = this->m_pivot_row[entering]; // m_ed[m_factorization->basis_heading(leaving)] is the same but the one that we are using is more precise - m_factorization->replace_column(pivot, m_w, m_basis_heading[leaving]); - if (m_factorization->get_status() == LU_status::OK) { - change_basis(entering, leaving); - return true; - } - } - // need to refactor == true - change_basis(entering, leaving); - init_lu(); - if (m_factorization->get_status() != LU_status::OK) { - if (m_look_for_feasible_solution_only && !precise()) { - m_status = lp_status::UNSTABLE; - delete m_factorization; - m_factorization = nullptr; - return false; - } - // LP_OUT(m_settings, "failing refactor for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << total_iterations() << std::endl); - restore_x_and_refactor(entering, leaving, tt); - if (m_status == lp_status::FLOATING_POINT_ERROR) - return false; - CASSERT("A_off", !A_mult_x_is_off()); - m_iters_with_no_cost_growing++; - // LP_OUT(m_settings, "rolled back after failing of init_factorization()" << std::endl); - m_status = lp_status::UNSTABLE; - return false; - } - return true; -} - template bool lp_core_solver_base:: divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { diff --git a/src/math/lp/lp_dual_core_solver_def.h b/src/math/lp/lp_dual_core_solver_def.h index df70e64f1bc..fd8fc80718f 100644 --- a/src/math/lp/lp_dual_core_solver_def.h +++ b/src/math/lp/lp_dual_core_solver_def.h @@ -411,33 +411,7 @@ template void lp_dual_core_solver::init_betas_pre // step 7 of the algorithm from Progress template bool lp_dual_core_solver::basis_change_and_update() { - update_betas(); - update_d_and_xB(); - // m_theta_P = m_delta / this->m_ed[m_r]; - m_theta_P = m_delta / this->m_pivot_row[m_q]; - // xb_minus_delta_p_pivot_column(); - apply_flips(); - if (!this->update_basis_and_x(m_q, m_p, m_theta_P)) { - init_betas_precisely(); - return false; - } - - if (snap_runaway_nonbasic_column(m_p)) { - if (!this->find_x_by_solving()) { - revert_to_previous_basis(); - this->iters_with_no_cost_growing()++; - return false; - } - } - - if (!problem_is_dual_feasible()) { - // todo : shift the costs!!!! - revert_to_previous_basis(); - this->iters_with_no_cost_growing()++; - return false; - } - - lp_assert(d_is_correct()); + return true; } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 5332b4001da..abee0cc6efd 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -552,9 +552,9 @@ class lp_primal_core_solver:public lp_core_solver_base { void clear_breakpoints(); void change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering); - void advance_on_sorted_breakpoints(unsigned entering); + - void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta); + void decide_on_status_when_cannot_find_entering() { lp_assert(!need_to_switch_costs()); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 0a58b0fdf69..7d522f9331d 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -855,12 +855,6 @@ template void lp_primal_core_solver::one_iteratio } } -template void lp_primal_core_solver::update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta) { - if (entering != leaving) - this->update_basis_and_x(entering, leaving, delta); - else - this->update_x(entering, delta); -} template void lp_primal_core_solver::clear_breakpoints() { From 0a9516dd5be927a4b1d86d249eafa995f61e0cb7 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 07:35:10 -0800 Subject: [PATCH 09/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lar_core_solver.h | 241 +----------------- src/math/lp/lar_core_solver_def.h | 28 +- src/math/lp/lp_core_solver_base.cpp | 11 - src/math/lp/lp_core_solver_base.h | 13 +- src/math/lp/lp_core_solver_base_def.h | 97 +------ src/math/lp/lp_dual_core_solver.h | 2 +- src/math/lp/lp_dual_core_solver_def.h | 14 +- src/math/lp/lp_primal_core_solver_def.h | 5 +- .../lp/lp_primal_core_solver_tableau_def.h | 9 - src/math/lp/lu.h | 3 +- src/math/lp/lu_def.h | 60 +---- 11 files changed, 22 insertions(+), 461 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 9678edd6bed..999eef13bc8 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -190,16 +190,12 @@ class lar_core_solver { m_r_upper_bounds.pop(k); m_column_types.pop(k); - delete m_r_solver.m_factorization; - m_r_solver.m_factorization = nullptr; m_r_x.resize(m_r_A.column_count()); m_r_solver.m_costs.resize(m_r_A.column_count()); m_r_solver.m_d.resize(m_r_A.column_count()); m_d_A.pop(k); // doubles - delete m_d_solver.m_factorization; - m_d_solver.m_factorization = nullptr; m_d_x.resize(m_d_A.column_count()); pop_basis(k); @@ -294,172 +290,13 @@ class lar_core_solver { unsigned jb = m_r_solver.m_basis[i]; m_r_solver.add_delta_to_x_and_track_feasibility(jb, - delta * m_r_solver.m_A.get_val(cc)); } - CASSERT("A_off", m_r_solver.A_mult_x_is_off() == false); + } lp_assert(m_r_solver.inf_set_is_correct()); } - template - void prepare_solver_x_with_signature(const lar_solution_signature & signature, lp_primal_core_solver & s) { - for (auto &t : signature) { - unsigned j = t.first; - lp_assert(m_r_heading[j] < 0); - auto pos_type = t.second; - switch (pos_type) { - case at_lower_bound: - s.m_x[j] = s.m_lower_bounds[j]; - break; - case at_fixed: - case at_upper_bound: - s.m_x[j] = s.m_upper_bounds[j]; - break; - case free_of_bounds: { - s.m_x[j] = zero_of_type(); - continue; - } - case not_at_bound: - switch (m_column_types[j]) { - case column_type::free_column: - lp_assert(false); // unreachable - break; - case column_type::upper_bound: - s.m_x[j] = s.m_upper_bounds[j]; - break; - case column_type::lower_bound: - s.m_x[j] = s.m_lower_bounds[j]; - break; - case column_type::boxed: - if (settings().random_next() % 2) { - s.m_x[j] = s.m_lower_bounds[j]; - } else { - s.m_x[j] = s.m_upper_bounds[j]; - } - break; - case column_type::fixed: - s.m_x[j] = s.m_lower_bounds[j]; - break; - default: - lp_assert(false); - } - break; - default: - lp_unreachable(); - } - } - - // lp_assert(is_zero_vector(s.m_b)); - s.solve_Ax_eq_b(); - } - - template - void catch_up_in_lu_in_reverse(const vector & trace_of_basis_change, lp_primal_core_solver & cs) { - // recover the previous working basis - for (unsigned i = trace_of_basis_change.size(); i > 0; i-= 2) { - unsigned entering = trace_of_basis_change[i-1]; - unsigned leaving = trace_of_basis_change[i-2]; - cs.change_basis_unconditionally(entering, leaving); - } - cs.init_lu(); - } - - //basis_heading is the basis heading of the solver owning trace_of_basis_change - // here we compact the trace as we go to avoid unnecessary column changes - template - void catch_up_in_lu(const vector & trace_of_basis_change, const vector & basis_heading, lp_primal_core_solver & cs) { - if (cs.m_factorization == nullptr || cs.m_factorization->m_refactor_counter + trace_of_basis_change.size()/2 >= 200) { - for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { - unsigned entering = trace_of_basis_change[i]; - unsigned leaving = trace_of_basis_change[i+1]; - cs.change_basis_unconditionally(entering, leaving); - } - if (cs.m_factorization != nullptr) { - delete cs.m_factorization; - cs.m_factorization = nullptr; - } - } else { - indexed_vector w(cs.m_A.row_count()); - // the queues of delayed indices - std::queue entr_q, leav_q; - auto * l = cs.m_factorization; - lp_assert(l->get_status() == LU_status::OK); - for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { - unsigned entering = trace_of_basis_change[i]; - unsigned leaving = trace_of_basis_change[i+1]; - bool good_e = basis_heading[entering] >= 0 && cs.m_basis_heading[entering] < 0; - bool good_l = basis_heading[leaving] < 0 && cs.m_basis_heading[leaving] >= 0; - if (!good_e && !good_l) continue; - if (good_e && !good_l) { - while (!leav_q.empty() && cs.m_basis_heading[leav_q.front()] < 0) - leav_q.pop(); - if (!leav_q.empty()) { - leaving = leav_q.front(); - leav_q.pop(); - } else { - entr_q.push(entering); - continue; - } - } else if (!good_e && good_l) { - while (!entr_q.empty() && cs.m_basis_heading[entr_q.front()] >= 0) - entr_q.pop(); - if (!entr_q.empty()) { - entering = entr_q.front(); - entr_q.pop(); - } else { - leav_q.push(leaving); - continue; - } - } - lp_assert(cs.m_basis_heading[entering] < 0); - lp_assert(cs.m_basis_heading[leaving] >= 0); - if (l->get_status() == LU_status::OK) { - l->prepare_entering(entering, w); // to init vector w - l->replace_column(zero_of_type(), w, cs.m_basis_heading[leaving]); - } - cs.change_basis_unconditionally(entering, leaving); - } - if (l->get_status() != LU_status::OK) { - delete l; - cs.m_factorization = nullptr; - } - } - if (cs.m_factorization == nullptr) { - if (numeric_traits::precise()) - init_factorization(cs.m_factorization, cs.m_A, cs.m_basis, settings()); - } - } - - bool no_r_lu() const { - return m_r_solver.m_factorization == nullptr || m_r_solver.m_factorization->get_status() == LU_status::Degenerated; - } - - void solve_on_signature_tableau(const lar_solution_signature & signature, const vector & changes_of_basis) { - r_basis_is_OK(); - bool r = catch_up_in_lu_tableau(changes_of_basis, m_d_solver.m_basis_heading); - - if (!r) { // it is the case where m_d_solver gives a degenerated basis - prepare_solver_x_with_signature_tableau(signature); // still are going to use the signature partially - m_r_solver.find_feasible_solution(); - m_d_basis = m_r_basis; - m_d_heading = m_r_heading; - m_d_nbasis = m_r_nbasis; - delete m_d_solver.m_factorization; - m_d_solver.m_factorization = nullptr; - } - else { - prepare_solver_x_with_signature_tableau(signature); - m_r_solver.start_tracing_basis_changes(); - m_r_solver.find_feasible_solution(); - if (settings().get_cancel_flag()) - return; - m_r_solver.stop_tracing_basis_changes(); - // and now catch up in the double solver - lp_assert(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2); - catch_up_in_lu(m_r_solver.m_trace_of_basis_change_vector, m_r_solver.m_basis_heading, m_d_solver); - } - lp_assert(r_basis_is_OK()); - } - + bool adjust_x_of_column(unsigned j) { /* if (m_r_solver.m_basis_heading[j] >= 0) { @@ -478,58 +315,6 @@ class lar_core_solver { return true; } - - bool catch_up_in_lu_tableau(const vector & trace_of_basis_change, const vector & basis_heading) { - lp_assert(r_basis_is_OK()); - // the queues of delayed indices - std::queue entr_q, leav_q; - for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) { - unsigned entering = trace_of_basis_change[i]; - unsigned leaving = trace_of_basis_change[i+1]; - bool good_e = basis_heading[entering] >= 0 && m_r_solver.m_basis_heading[entering] < 0; - bool good_l = basis_heading[leaving] < 0 && m_r_solver.m_basis_heading[leaving] >= 0; - if (!good_e && !good_l) continue; - if (good_e && !good_l) { - while (!leav_q.empty() && m_r_solver.m_basis_heading[leav_q.front()] < 0) - leav_q.pop(); - if (!leav_q.empty()) { - leaving = leav_q.front(); - leav_q.pop(); - } else { - entr_q.push(entering); - continue; - } - } else if (!good_e && good_l) { - while (!entr_q.empty() && m_r_solver.m_basis_heading[entr_q.front()] >= 0) - entr_q.pop(); - if (!entr_q.empty()) { - entering = entr_q.front(); - entr_q.pop(); - } else { - leav_q.push(leaving); - continue; - } - } - lp_assert(m_r_solver.m_basis_heading[entering] < 0); - lp_assert(m_r_solver.m_basis_heading[leaving] >= 0); - m_r_solver.change_basis_unconditionally(entering, leaving); - if(!m_r_solver.pivot_column_tableau(entering, m_r_solver.m_basis_heading[entering])) { - // unroll the last step - m_r_solver.change_basis_unconditionally(leaving, entering); -#ifdef Z3DEBUG - bool t = -#endif - m_r_solver.pivot_column_tableau(leaving, m_r_solver.m_basis_heading[leaving]); -#ifdef Z3DEBUG - lp_assert(t); -#endif - return false; - } - } - lp_assert(r_basis_is_OK()); - return true; - } - bool r_basis_is_OK() const { #ifdef Z3DEBUG @@ -598,27 +383,7 @@ class lar_core_solver { } - // returns the trace of basis changes - vector find_solution_signature_with_doubles(lar_solution_signature & signature) { - if (m_d_solver.m_factorization == nullptr || m_d_solver.m_factorization->get_status() != LU_status::OK) { - vector ret; - return ret; - } - get_bounds_for_double_solver(); - - extract_signature_from_lp_core_solver(m_r_solver, signature); - prepare_solver_x_with_signature(signature, m_d_solver); - m_d_solver.start_tracing_basis_changes(); - m_d_solver.find_feasible_solution(); - if (settings().get_cancel_flag()) - return vector(); - - m_d_solver.stop_tracing_basis_changes(); - extract_signature_from_lp_core_solver(m_d_solver, signature); - return m_d_solver.m_trace_of_basis_change_vector; - } - - + bool lower_bound_is_set(unsigned j) const { switch (m_column_types[j]) { case column_type::free_column: diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index 182029e3e98..22dc23bd512 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -78,7 +78,6 @@ void lar_core_solver::prefix_d() { } void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { - CASSERT("A_off", m_r_solver.A_mult_x_is_off() == false); unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); m_infeasible_linear_combination.clear(); @@ -127,29 +126,16 @@ void lar_core_solver::solve() { return; } ++settings().stats().m_need_to_solve_inf; - CASSERT("A_off", !m_r_solver.A_mult_x_is_off()); lp_assert( r_basis_is_OK()); - if (need_to_presolve_with_double_solver()) { - TRACE("lar_solver", tout << "presolving\n";); - prefix_d(); - lar_solution_signature solution_signature; - vector changes_of_basis = find_solution_signature_with_doubles(solution_signature); - if (m_d_solver.get_status() == lp_status::TIME_EXHAUSTED) { - m_r_solver.set_status(lp_status::TIME_EXHAUSTED); - return; - } - solve_on_signature_tableau(solution_signature, changes_of_basis); - - lp_assert( r_basis_is_OK()); - } else { + - if (m_r_solver.m_look_for_feasible_solution_only) //todo : should it be set? - m_r_solver.find_feasible_solution(); - else { - m_r_solver.solve(); - } - lp_assert(r_basis_is_OK()); + if (m_r_solver.m_look_for_feasible_solution_only) //todo : should it be set? + m_r_solver.find_feasible_solution(); + else { + m_r_solver.solve(); } + lp_assert(r_basis_is_OK()); + switch (m_r_solver.get_status()) { case lp_status::INFEASIBLE: diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 9f6f2534f6c..508a06d730e 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -23,8 +23,6 @@ Revision History: #include "util/vector.h" #include #include "math/lp/lp_core_solver_base_def.h" -template bool lp::lp_core_solver_base::A_mult_x_is_off() const; -template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; template bool lp::lp_core_solver_base::basis_heading_is_correct() const; template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; @@ -33,7 +31,6 @@ template bool lp::lp_core_solver_base::find_x_by_solving(); template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); template lp::lp_core_solver_base::lp_core_solver_base( lp::static_matrix&, // vector&, vector&, @@ -51,26 +48,20 @@ template void lp::lp_core_solver_base::set_non_basic_x_to_correc template void lp::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); -template void lp::lp_core_solver_base::solve_yB(vector&) const; template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); -template bool lp::lp_core_solver_base::A_mult_x_is_off() const; -template bool lp::lp_core_solver_base::A_mult_x_is_off_on_index(const vector &) const; template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); template bool lp::lp_core_solver_base::find_x_by_solving(); -template void lp::lp_core_solver_base::init_reduced_costs_for_one_iteration(); template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); -template void lp::lp_core_solver_base::solve_yB(vector&) const; template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template void lp::lp_core_solver_base >::init(); template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); -template void lp::lp_core_solver_base >::init_reduced_costs_for_one_iteration(); template lp::lp_core_solver_base >::lp_core_solver_base(lp::static_matrix >&, // vector >&, vector&, vector &, vector &, vector >&, vector&, lp::lp_settings&, const column_namer&, const vector&, @@ -106,7 +97,6 @@ template std::string lp::lp_core_solver_base template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); template void lp::lp_core_solver_base >::restore_state(lp::mpq*, lp::mpq*); template void lp::lp_core_solver_base >::save_state(lp::mpq*, lp::mpq*); -template void lp::lp_core_solver_base >::solve_yB(vector&) const; template void lp::lp_core_solver_base::init_lu(); template void lp::lp_core_solver_base::init_lu(); template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; @@ -122,7 +112,6 @@ template bool lp::lp_core_solver_base::column_is_feasible(unsi template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); template void lp::lp_core_solver_base >::init_lu(); -template bool lp::lp_core_solver_base >::A_mult_x_is_off_on_index(vector const&) const; template bool lp::lp_core_solver_base >::find_x_by_solving(); template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index dce805b62ee..edff349d23d 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -154,9 +154,6 @@ class lp_core_solver_base { void fill_cb(vector & y) const; - void solve_yB(vector & y) const; - - void pretty_print(std::ostream & out); void save_state(T * w_buffer, T * d_buffer); @@ -175,10 +172,6 @@ class lp_core_solver_base { void copy_m_ed(T * buffer); void restore_m_ed(T * buffer); - - bool A_mult_x_is_off() const; - - bool A_mult_x_is_off_on_index(const vector & index) const; void calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row); @@ -317,8 +310,6 @@ class lp_core_solver_base { bool basis_heading_is_correct() const; - void restore_x_and_refactor(int entering, int leaving, X const & t); - void restore_x(unsigned entering, X const & t); void fill_reduced_costs_from_m_y_by_rows(); @@ -435,9 +426,7 @@ class lp_core_solver_base { void snap_xN_to_bounds_and_fill_xB(); void snap_xN_to_bounds_and_free_columns_to_zeroes(); - - void init_reduced_costs_for_one_iteration(); - + non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; void init_lu(); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 51b24128fef..ae04bd5eec6 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -116,11 +116,6 @@ fill_cb(vector & y) const { } } -template void lp_core_solver_base:: -solve_yB(vector & y) const { - fill_cb(y); // now y = cB, that is the projection of costs to basis - m_factorization->solve_yB_with_error_check(y, m_basis); -} // template void lp_core_solver_base:: // update_index_of_ed() { @@ -188,71 +183,6 @@ restore_m_ed(T * buffer) { } } -template bool lp_core_solver_base:: -A_mult_x_is_off() const { - lp_assert(m_x.size() == m_A.column_count()); - if (numeric_traits::precise()) { - for (unsigned i = 0; i < m_m(); i++) { - X delta = /*m_b[i] */- m_A.dot_product_with_row(i, m_x); - if (delta != numeric_traits::zero()) { - return true; - } - } - return false; - } - T feps = convert_struct::convert(m_settings.refactor_tolerance); - X one = convert_struct::convert(1.0); - for (unsigned i = 0; i < m_m(); i++) { - X delta = abs(/*m_b[i] -*/ m_A.dot_product_with_row(i, m_x)); - auto eps = feps /* * (one + T(0.1) * abs(m_b[i])) */; - - if (delta > eps) { -#if 0 - LP_OUT(m_settings, "x is off (" - << "m_b[" << i << "] = " << m_b[i] << " " - << "left side = " << m_A.dot_product_with_row(i, m_x) << ' ' - << "delta = " << delta << ' ' - << "iters = " << total_iterations() << ")" << std::endl); -#endif - return true; - } - } - return false; -} -template bool lp_core_solver_base:: -A_mult_x_is_off_on_index(const vector & index) const { - lp_assert(m_x.size() == m_A.column_count()); - if (numeric_traits::precise()) return false; -#if RUN_A_MULT_X_IS_OFF_FOR_PRECESE - for (unsigned i : index) { - X delta = m_b[i] - m_A.dot_product_with_row(i, m_x); - if (delta != numeric_traits::zero()) { - return true; - } - } - return false; -#endif - // todo(levnach) run on m_ed.m_index only !!!!! - T feps = convert_struct::convert(m_settings.refactor_tolerance); - X one = convert_struct::convert(1.0); - for (unsigned i : index) { - X delta = abs(/*m_b[i] -*/ m_A.dot_product_with_row(i, m_x)); - auto eps = feps /* *(one + T(0.1) * abs(m_b[i])) */; - - if (delta > eps) { -#if 0 - LP_OUT(m_settings, "x is off (" - << "m_b[" << i << "] = " << m_b[i] << " " - << "left side = " << m_A.dot_product_with_row(i, m_x) << ' ' - << "delta = " << delta << ' ' - << "iters = " << total_iterations() << ")" << std::endl); -#endif - return true; - } - } - return false; -} - template void lp_core_solver_base:: @@ -292,7 +222,7 @@ print_statistics(char const* str, X cost, std::ostream & out) { if (str!= nullptr) out << str << " "; out << "iterations = " << (total_iterations() - 1) << ", cost = " << T_to_string(cost) - << ", nonzeros = " << (m_factorization != nullptr? m_factorization->get_number_of_nonzeroes() : m_A.number_of_non_zeroes()) << std::endl; + << ", nonzeros = " << m_A.number_of_non_zeroes() << std::endl; } template bool lp_core_solver_base:: @@ -411,7 +341,7 @@ rs_minus_Anx(vector & rs) { template bool lp_core_solver_base:: find_x_by_solving() { solve_Ax_eq_b(); - return !A_mult_x_is_off(); + return true; } template bool lp_core_solver_base::column_is_feasible(unsigned j) const { @@ -591,24 +521,6 @@ template bool lp_core_solver_base:: return true; } -template void lp_core_solver_base:: -restore_x_and_refactor(int entering, int leaving, X const & t) { - this->restore_basis_change(entering, leaving); - restore_x(entering, t); - init_factorization(m_factorization, m_A, m_basis, m_settings); - if (m_factorization->get_status() == LU_status::Degenerated) { - LP_OUT(m_settings, "cannot refactor" << std::endl); - m_status = lp_status::FLOATING_POINT_ERROR; - return; - } - // solve_Ax_eq_b(); - if (A_mult_x_is_off()) { - LP_OUT(m_settings, "cannot restore solution" << std::endl); - m_status = lp_status::FLOATING_POINT_ERROR; - return; - } -} - template void lp_core_solver_base:: restore_x(unsigned entering, X const & t) { if (is_zero(t)) return; @@ -731,11 +643,6 @@ snap_xN_to_bounds_and_free_columns_to_zeroes() { solve_Ax_eq_b(); } -template void lp_core_solver_base:: -init_reduced_costs_for_one_iteration() { - solve_yB(m_y); - fill_reduced_costs_from_m_y_by_rows(); -} template non_basic_column_value_position lp_core_solver_base:: get_non_basic_column_value_position(unsigned j) const { diff --git a/src/math/lp/lp_dual_core_solver.h b/src/math/lp/lp_dual_core_solver.h index 804879c3da2..b78a2214701 100644 --- a/src/math/lp/lp_dual_core_solver.h +++ b/src/math/lp/lp_dual_core_solver.h @@ -76,7 +76,7 @@ class lp_dual_core_solver:public lp_core_solver_base { m_a_wave(this->m_m()), m_betas(this->m_m()) { m_harris_tolerance = numeric_traits::precise()? numeric_traits::zero() : T(this->m_settings.harris_feasibility_tolerance); - this->solve_yB(this->m_y); + lp_assert(false); this->init_basic_part_of_basis_heading(); fill_non_basis_with_only_able_to_enter_columns(); } diff --git a/src/math/lp/lp_dual_core_solver_def.h b/src/math/lp/lp_dual_core_solver_def.h index fd8fc80718f..9c39fe195bf 100644 --- a/src/math/lp/lp_dual_core_solver_def.h +++ b/src/math/lp/lp_dual_core_solver_def.h @@ -74,8 +74,7 @@ template void lp_dual_core_solver::recalculate_xB } template void lp_dual_core_solver::recalculate_d() { - this->solve_yB(this->m_y); - this->fill_reduced_costs_from_m_y_by_rows(); +lp_assert(false) } template void lp_dual_core_solver::init_betas() { @@ -316,15 +315,8 @@ template void lp_dual_core_solver::restore_d() { } template bool lp_dual_core_solver::d_is_correct() { - this->solve_yB(this->m_y); - for (auto j : this->non_basis()) { - T d = this->m_costs[j] - this->m_A.dot_product_with_column(this->m_y, j); - if (numeric_traits::get_double(abs(d - this->m_d[j])) >= 0.001) { - LP_OUT(this->m_settings, "total_iterations = " << this->total_iterations() << std::endl - << "d[" << j << "] = " << this->m_d[j] << " but should be " << d << std::endl); - return false; - } - } + + lp_assert(false); return true; } diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 7d522f9331d..19ffaa1eadc 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -705,10 +705,7 @@ template unsigned lp_primal_core_solver::solve() return 0; } - if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return 0; - } + do { if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->using_infeas_costs()? "inf" : "feas"), * this->m_settings.get_message_ostream())) { return this->total_iterations(); diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index fa25694adc7..736b79db5ad 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -107,10 +107,6 @@ unsigned lp_primal_core_solver::solve_with_tableau() { return 0; } - if ((!numeric_traits::precise()) && this->A_mult_x_is_off()) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return 0; - } do { if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->using_infeas_costs()? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) { return this->total_iterations(); @@ -183,7 +179,6 @@ unsigned lp_primal_core_solver::solve_with_tableau() { } template void lp_primal_core_solver::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) { - CASSERT("A_off", this->A_mult_x_is_off() == false); lp_assert(leaving >= 0 && entering >= 0); lp_assert((this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) || @@ -200,7 +195,6 @@ template void lp_primal_core_solver::advance_on_en t = -t; } this->update_basis_and_x_tableau(entering, leaving, t); - CASSERT("A_off", this->A_mult_x_is_off() == false); this->iters_with_no_cost_growing() = 0; } else { this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); @@ -224,7 +218,6 @@ template void lp_primal_core_solver::advance_on_en template void lp_primal_core_solver::advance_on_entering_equal_leaving_tableau(int entering, X & t) { - CASSERT("A_off", !this->A_mult_x_is_off() ); this->update_x_tableau(entering, t * m_sign_of_entering_delta); if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) return; @@ -296,7 +289,6 @@ template int lp_primal_core_solver::find_leaving_ return m_leaving_candidates[k]; } template void lp_primal_core_solver::init_run_tableau() { - CASSERT("A_off", this->A_mult_x_is_off() == false); lp_assert(basis_columns_are_set_correctly()); this->m_basis_sort_counter = 0; // to initiate the sort of the basis // this->set_total_iterations(0); @@ -350,7 +342,6 @@ update_x_tableau(unsigned entering, const X& delta) { this->insert_column_into_inf_set(j); } } - CASSERT("A_off", this->A_mult_x_is_off() == false); } template void lp_primal_core_solver:: diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h index b3e2f0c2221..18251e3ada5 100644 --- a/src/math/lp/lu.h +++ b/src/math/lp/lu.h @@ -173,8 +173,7 @@ class lu { void print(indexed_vector & w, const vector& basis); void solve_Bd_faster(unsigned a_column, indexed_vector & d); // d is the right side on the input and the solution at the exit - void solve_yB(vector& y); - + void solve_yB_indexed(indexed_vector& y); void add_delta_to_solution_indexed(indexed_vector& y); diff --git a/src/math/lp/lu_def.h b/src/math/lp/lu_def.h index d7c0c0c3a07..ca34481cca8 100644 --- a/src/math/lp/lu_def.h +++ b/src/math/lp/lu_def.h @@ -263,20 +263,6 @@ void lu< M>::solve_Bd_faster(unsigned a_column, indexed_vector & d) { // puts solve_By_for_T_indexed_only(d, m_settings); } -template -void lu< M>::solve_yB(vector& y) { - // first solve yU = cb*R(-1) - m_R.apply_reverse_from_right_to_T(y); // got y = cb*R(-1) - m_U.solve_y_U(y); // got y*U=cb*R(-1) - m_Q.apply_reverse_from_right_to_T(y); // - for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { -#ifdef Z3DEBUG - (*e)->set_number_of_columns(m_dim); -#endif - (*e)->apply_from_right(y); - } -} - template void lu< M>::solve_yB_indexed(indexed_vector& y) { lp_assert(y.is_OK()); @@ -412,55 +398,15 @@ void lu< M>::find_error_of_yB_indexed(const indexed_vector& y, const vector void lu< M>::solve_yB_with_error_check_indexed(indexed_vector & y, const vector& heading, const vector & basis, const lp_settings & settings) { - if (numeric_traits::precise()) { - if (y.m_index.size() * ratio_of_index_size_to_all_size() * 3 < m_A.column_count()) { - solve_yB_indexed(y); - } else { - solve_yB(y.m_data); - y.restore_index_and_clean_from_data(); - } - return; - } - lp_assert(m_y_copy.is_OK()); - lp_assert(y.is_OK()); - if (y.m_index.size() * ratio_of_index_size_to_all_size() < m_A.column_count()) { - m_y_copy = y; - solve_yB_indexed(y); - lp_assert(y.is_OK()); - if (y.m_index.size() * ratio_of_index_size_to_all_size() >= m_A.column_count()) { - find_error_of_yB(m_y_copy.m_data, y.m_data, basis); - solve_yB(m_y_copy.m_data); - add_delta_to_solution(m_y_copy.m_data, y.m_data); - y.restore_index_and_clean_from_data(); - m_y_copy.clear_all(); - } else { - find_error_of_yB_indexed(y, heading, settings); // this works with m_y_copy - solve_yB_indexed(m_y_copy); - add_delta_to_solution_indexed(y); - } - lp_assert(m_y_copy.is_OK()); - } else { - solve_yB_with_error_check(y.m_data, basis); - y.restore_index_and_clean_from_data(); - } -} + lp_assert(false); + } // solves y*B = y // y is the input template void lu< M>::solve_yB_with_error_check(vector & y, const vector& basis) { - if (numeric_traits::precise()) { - solve_yB(y); - return; - } - auto & yc = m_y_copy.m_data; - yc =y; // copy y aside - solve_yB(y); - find_error_of_yB(yc, y, basis); - solve_yB(yc); - add_delta_to_solution(yc, y); - m_y_copy.clear_all(); + lp_assert(false); } template void lu< M>::apply_Q_R_to_U(permutation_matrix & r_wave) { From 5c69cc65103c7fd0c8bc23f5038f91896d14db88 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 07:44:22 -0800 Subject: [PATCH 10/36] rm lu --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/lp_core_solver_base.cpp | 3 - src/math/lp/lp_core_solver_base.h | 3 - src/math/lp/lp_core_solver_base_def.h | 6 - src/math/lp/lp_dual_core_solver.cpp | 44 -- src/math/lp/lp_dual_core_solver.h | 212 -------- src/math/lp/lp_dual_core_solver_def.h | 699 -------------------------- src/math/lp/static_matrix.cpp | 1 - 8 files changed, 969 deletions(-) delete mode 100644 src/math/lp/lp_dual_core_solver.cpp delete mode 100644 src/math/lp/lp_dual_core_solver.h delete mode 100644 src/math/lp/lp_dual_core_solver_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 5719de44fae..cc58c9610fc 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -19,7 +19,6 @@ z3_add_component(lp lar_solver.cpp lar_core_solver.cpp lp_core_solver_base.cpp - lp_dual_core_solver.cpp lp_primal_core_solver.cpp lp_settings.cpp lu.cpp diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 508a06d730e..0d9f4297419 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -27,7 +27,6 @@ template bool lp::lp_core_solver_base::basis_heading_is_correct( template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lp::lp_core_solver_base::find_x_by_solving(); template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; @@ -53,7 +52,6 @@ template bool lp::lp_core_solver_base::basis_heading_is_correc template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template bool lp::lp_core_solver_base::find_x_by_solving(); template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); @@ -112,7 +110,6 @@ template bool lp::lp_core_solver_base::column_is_feasible(unsi template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); template void lp::lp_core_solver_base >::init_lu(); -template bool lp::lp_core_solver_base >::find_x_by_solving(); template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index edff349d23d..729792c1266 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -298,9 +298,6 @@ class lp_core_solver_base { void rs_minus_Anx(vector & rs); - bool find_x_by_solving(); - - bool basis_has_no_doubles() const; bool non_basis_has_no_doubles() const; diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index ae04bd5eec6..e470072e04c 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -338,12 +338,6 @@ rs_minus_Anx(vector & rs) { } } -template bool lp_core_solver_base:: -find_x_by_solving() { - solve_Ax_eq_b(); - return true; -} - template bool lp_core_solver_base::column_is_feasible(unsigned j) const { const X& x = this->m_x[j]; switch (this->m_column_types[j]) { diff --git a/src/math/lp/lp_dual_core_solver.cpp b/src/math/lp/lp_dual_core_solver.cpp deleted file mode 100644 index 8cf45f7c6cd..00000000000 --- a/src/math/lp/lp_dual_core_solver.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include -#include -#include "util/vector.h" -#include -#include "math/lp/lp_dual_core_solver_def.h" -template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lp::lp_dual_core_solver::solve(); -template lp::lp_dual_core_solver::lp_dual_core_solver(lp::static_matrix&, vector&, - vector&, - vector&, - vector&, - vector &, - vector &, - vector&, - vector&, - vector&, - vector&, - lp::lp_settings&, const lp::column_namer&); -template void lp::lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible(); -template void lp::lp_dual_core_solver::solve(); -template void lp::lp_dual_core_solver::restore_non_basis(); -template void lp::lp_dual_core_solver::restore_non_basis(); -template void lp::lp_dual_core_solver::revert_to_previous_basis(); -template void lp::lp_dual_core_solver::revert_to_previous_basis(); diff --git a/src/math/lp/lp_dual_core_solver.h b/src/math/lp/lp_dual_core_solver.h deleted file mode 100644 index b78a2214701..00000000000 --- a/src/math/lp/lp_dual_core_solver.h +++ /dev/null @@ -1,212 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once -#include "math/lp/static_matrix.h" -#include "math/lp/lp_core_solver_base.h" -#include -#include -#include -#include -#include "util/vector.h" - -namespace lp { -template -class lp_dual_core_solver:public lp_core_solver_base { -public: - vector & m_can_enter_basis; - int m_r; // the row of the leaving column - int m_p; // leaving column; that is m_p = m_basis[m_r] - T m_delta; // the offset of the leaving basis variable - int m_sign_of_alpha_r; // see page 27 - T m_theta_D; - T m_theta_P; - int m_q; - // todo : replace by a vector later - std::set m_breakpoint_set; // it is F in "Progress in the dual simplex method ..." - std::set m_flipped_boxed; - std::set m_tight_set; // it is the set of all breakpoints that become tight when m_q becomes tight - vector m_a_wave; - vector m_betas; // m_betas[i] is approximately a square of the norm of the i-th row of the reverse of B - T m_harris_tolerance; - std::set m_forbidden_rows; - - lp_dual_core_solver(static_matrix & A, - vector & can_enter_basis, - vector & b, // the right side vector - vector & x, // the number of elements in x needs to be at least as large as the number of columns in A - vector & basis, - vector & nbasis, - vector & heading, - vector & costs, - vector & column_type_array, - vector & lower_bound_values, - vector & upper_bound_values, - lp_settings & settings, - const column_namer & column_names): - lp_core_solver_base(A, - // b, - basis, - nbasis, - heading, - x, - costs, - settings, - column_names, - column_type_array, - lower_bound_values, - upper_bound_values), - m_can_enter_basis(can_enter_basis), - m_a_wave(this->m_m()), - m_betas(this->m_m()) { - m_harris_tolerance = numeric_traits::precise()? numeric_traits::zero() : T(this->m_settings.harris_feasibility_tolerance); - lp_assert(false); - this->init_basic_part_of_basis_heading(); - fill_non_basis_with_only_able_to_enter_columns(); - } - - void init_a_wave_by_zeros(); - - void fill_non_basis_with_only_able_to_enter_columns() { - auto & nb = this->m_nbasis; - nb.reset(); - unsigned j = this->m_n(); - while (j--) { - if (this->m_basis_heading[j] >= 0 || !m_can_enter_basis[j]) continue; - nb.push_back(j); - this->m_basis_heading[j] = - static_cast(nb.size()); - } - } - - void restore_non_basis(); - - bool update_basis(int entering, int leaving); - - void recalculate_xB_and_d(); - - void recalculate_d(); - - void init_betas(); - - void adjust_xb_for_changed_xn_and_init_betas(); - - void start_with_initial_basis_and_make_it_dual_feasible(); - - bool done(); - - T get_edge_steepness_for_lower_bound(unsigned p); - - T get_edge_steepness_for_upper_bound(unsigned p); - - T pricing_for_row(unsigned i); - - void pricing_loop(unsigned number_of_rows_to_try, unsigned offset_in_rows); - - bool advance_on_known_p(); - - int define_sign_of_alpha_r(); - - bool can_be_breakpoint(unsigned j); - - void fill_breakpoint_set(); - - void DSE_FTran(); - T get_delta(); - - void restore_d(); - - bool d_is_correct(); - - void xb_minus_delta_p_pivot_column(); - - void update_betas(); - - void apply_flips(); - - void snap_xN_column_to_bounds(unsigned j); - - void snap_xN_to_bounds(); - - void init_beta_precisely(unsigned i); - - void init_betas_precisely(); - - // step 7 of the algorithm from Progress - bool basis_change_and_update(); - - void revert_to_previous_basis(); - - non_basic_column_value_position m_entering_boundary_position; - bool update_basis_and_x_local(int entering, int leaving, X const & tt); - void recover_leaving(); - - bool problem_is_dual_feasible() const; - - bool snap_runaway_nonbasic_column(unsigned); - - bool snap_runaway_nonbasic_columns(); - - unsigned get_number_of_rows_to_try_for_leaving(); - - void update_a_wave(const T & del, unsigned j) { - this->m_A.add_column_to_vector(del, j, & m_a_wave[0]); - } - - bool delta_keeps_the_sign(int initial_delta_sign, const T & delta); - - void set_status_to_tentative_dual_unbounded_or_dual_unbounded(); - - // it is positive if going from low bound to upper bound and negative if going from upper bound to low bound - T signed_span_of_boxed(unsigned j) { - return this->x_is_at_lower_bound(j)? this->bound_span(j): - this->bound_span(j); - } - - void add_tight_breakpoints_and_q_to_flipped_set(); - - T delta_lost_on_flips_of_tight_breakpoints(); - - bool tight_breakpoinst_are_all_boxed(); - - T calculate_harris_delta_on_breakpoint_set(); - - void fill_tight_set_on_harris_delta(const T & harris_delta ); - - void find_q_on_tight_set(); - - void find_q_and_tight_set(); - - void erase_tight_breakpoints_and_q_from_breakpoint_set(); - - bool ratio_test(); - - void process_flipped(); - void update_d_and_xB(); - - void calculate_beta_r_precisely(); - // see "Progress in the dual simplex method for large scale LP problems: practical dual phase 1 algorithms" - - void update_xb_after_bound_flips(); - - void one_iteration(); - - void solve(); - - bool lower_bounds_are_set() const override { return true; } -}; -} diff --git a/src/math/lp/lp_dual_core_solver_def.h b/src/math/lp/lp_dual_core_solver_def.h deleted file mode 100644 index 9c39fe195bf..00000000000 --- a/src/math/lp/lp_dual_core_solver_def.h +++ /dev/null @@ -1,699 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include -#include "util/vector.h" -#include "math/lp/lp_dual_core_solver.h" - -namespace lp { - -template void lp_dual_core_solver::init_a_wave_by_zeros() { - unsigned j = this->m_m(); - while (j--) { - m_a_wave[j] = numeric_traits::zero(); - } -} - -template void lp_dual_core_solver::restore_non_basis() { - auto & nb = this->m_nbasis; - nb.reset(); - unsigned j = this->m_n(); - while (j--) { - if (this->m_basis_heading[j] >= 0 ) continue; - if (m_can_enter_basis[j]) { - lp_assert(std::find(nb.begin(), nb.end(), j) == nb.end()); - nb.push_back(j); - this->m_basis_heading[j] = - static_cast(nb.size()); - } - } -} - -template bool lp_dual_core_solver::update_basis(int entering, int leaving) { - // the second argument is the element of the entering column from the pivot row - its value should be equal to the low diagonal element of the bump after all pivoting is done - if (this->m_refactor_counter++ < 200) { - this->m_factorization->replace_column(this->m_ed[this->m_factorization->basis_heading(leaving)], this->m_w); - if (this->m_factorization->get_status() == LU_status::OK) { - this->m_factorization->change_basis(entering, leaving); - return true; - } - } - // need to refactor - this->m_factorization->change_basis(entering, leaving); - init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_basis_heading, this->m_settings); - this->m_refactor_counter = 0; - if (this->m_factorization->get_status() != LU_status::OK) { - LP_OUT(this->m_settings, "failing refactor for entering = " << entering << ", leaving = " << leaving << " total_iterations = " << this->total_iterations() << std::endl); - this->m_iters_with_no_cost_growing++; - return false; - } - return true; -} - -template void lp_dual_core_solver::recalculate_xB_and_d() { - this->solve_Ax_eq_b(); - recalculate_d(); -} - -template void lp_dual_core_solver::recalculate_d() { -lp_assert(false) -} - -template void lp_dual_core_solver::init_betas() { - // todo : look at page 194 of Progress in the dual simplex algorithm for solving large scale LP problems : techniques for a fast and stable implementation - // the current implementation is not good enough: todo - unsigned i = this->m_m(); - while (i--) { - m_betas[i] = 1; - } -} - -template void lp_dual_core_solver::adjust_xb_for_changed_xn_and_init_betas() { - this->solve_Ax_eq_b(); - init_betas(); -} - -template void lp_dual_core_solver::start_with_initial_basis_and_make_it_dual_feasible() { - this->set_non_basic_x_to_correct_bounds(); // It is not an efficient version, see 3.29, - // however this version does not require that m_x is the solution of Ax = 0 beforehand - adjust_xb_for_changed_xn_and_init_betas(); -} - -template bool lp_dual_core_solver::done() { - if (this->get_status() == lp_status::OPTIMAL) { - return true; - } - - return false; // todo, need to be more cases -} - -template T lp_dual_core_solver::get_edge_steepness_for_lower_bound(unsigned p) { - lp_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); - T del = this->m_x[p] - this->m_lower_bounds[p]; - del *= del; - return del / this->m_betas[this->m_basis_heading[p]]; -} - -template T lp_dual_core_solver::get_edge_steepness_for_upper_bound(unsigned p) { - lp_assert(this->m_basis_heading[p] >= 0 && static_cast(this->m_basis_heading[p]) < this->m_m()); - T del = this->m_x[p] - this->m_upper_bounds[p]; - del *= del; - return del / this->m_betas[this->m_basis_heading[p]]; -} - -template T lp_dual_core_solver::pricing_for_row(unsigned i) { - unsigned p = this->m_basis[i]; - switch (this->m_column_types[p]) { - case column_type::fixed: - case column_type::boxed: - if (this->x_below_low_bound(p)) { - T del = get_edge_steepness_for_lower_bound(p); - return del; - } - if (this->x_above_upper_bound(p)) { - T del = get_edge_steepness_for_upper_bound(p); - return del; - } - return numeric_traits::zero(); - case column_type::lower_bound: - if (this->x_below_low_bound(p)) { - T del = get_edge_steepness_for_lower_bound(p); - return del; - } - return numeric_traits::zero(); - break; - case column_type::upper_bound: - if (this->x_above_upper_bound(p)) { - T del = get_edge_steepness_for_upper_bound(p); - return del; - } - return numeric_traits::zero(); - break; - case column_type::free_column: - lp_assert(numeric_traits::is_zero(this->m_d[p])); - return numeric_traits::zero(); - default: - lp_unreachable(); - } - lp_unreachable(); - return numeric_traits::zero(); -} - -template void lp_dual_core_solver::pricing_loop(unsigned number_of_rows_to_try, unsigned offset_in_rows) { - m_r = -1; - T steepest_edge_max = numeric_traits::zero(); - unsigned initial_offset_in_rows = offset_in_rows; - unsigned i = offset_in_rows; - unsigned rows_left = number_of_rows_to_try; - do { - if (m_forbidden_rows.find(i) != m_forbidden_rows.end()) { - if (++i == this->m_m()) { - i = 0; - } - continue; - } - T se = pricing_for_row(i); - if (se > steepest_edge_max) { - steepest_edge_max = se; - m_r = i; - if (rows_left > 0) { - rows_left--; - } - } - if (++i == this->m_m()) { - i = 0; - } - } while (i != initial_offset_in_rows && rows_left); - if (m_r == -1) { - if (this->get_status() != lp_status::UNSTABLE) { - this->set_status(lp_status::OPTIMAL); - } - } else { - m_p = this->m_basis[m_r]; - m_delta = get_delta(); - if (advance_on_known_p()){ - m_forbidden_rows.clear(); - return; - } - // failure in advance_on_known_p - if (this->get_status() == lp_status::FLOATING_POINT_ERROR) { - return; - } - this->set_status(lp_status::UNSTABLE); - m_forbidden_rows.insert(m_r); - } -} - - // this calculation is needed for the steepest edge update, - // it hijackes m_pivot_row_of_B_1 for this purpose since we will need it anymore to the end of the cycle -template void lp_dual_core_solver::DSE_FTran() { // todo, see algorithm 7 from page 35 - this->m_factorization->solve_By_for_T_indexed_only(this->m_pivot_row_of_B_1, this->m_settings); -} - -template bool lp_dual_core_solver::advance_on_known_p() { - - return false; -} - -template int lp_dual_core_solver::define_sign_of_alpha_r() { - switch (this->m_column_types[m_p]) { - case column_type::boxed: - case column_type::fixed: - if (this->x_below_low_bound(m_p)) { - return -1; - } - if (this->x_above_upper_bound(m_p)) { - return 1; - } - lp_unreachable(); - case column_type::lower_bound: - if (this->x_below_low_bound(m_p)) { - return -1; - } - lp_unreachable(); - case column_type::upper_bound: - if (this->x_above_upper_bound(m_p)) { - return 1; - } - lp_unreachable(); - default: - lp_unreachable(); - } - lp_unreachable(); - return 0; -} - -template bool lp_dual_core_solver::can_be_breakpoint(unsigned j) { - if (this->pivot_row_element_is_too_small_for_ratio_test(j)) return false; - switch (this->m_column_types[j]) { - case column_type::lower_bound: - lp_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_lower_bounds[j])); - return m_sign_of_alpha_r * this->m_pivot_row[j] > 0; - case column_type::upper_bound: - lp_assert(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j])); - return m_sign_of_alpha_r * this->m_pivot_row[j] < 0; - case column_type::boxed: - { - bool lower_bound = this->x_is_at_lower_bound(j); - bool grawing = m_sign_of_alpha_r * this->m_pivot_row[j] > 0; - return lower_bound == grawing; - } - case column_type::fixed: // is always dual feasible so we ignore it - return false; - case column_type::free_column: - return true; - default: - return false; - } -} - -template void lp_dual_core_solver::fill_breakpoint_set() { - m_breakpoint_set.clear(); - for (unsigned j : this->non_basis()) { - if (can_be_breakpoint(j)) { - m_breakpoint_set.insert(j); - } - } -} - -// template void lp_dual_core_solver::FTran() { -// this->solve_Bd(m_q); -// } - -template T lp_dual_core_solver::get_delta() { - switch (this->m_column_types[m_p]) { - case column_type::boxed: - if (this->x_below_low_bound(m_p)) { - return this->m_x[m_p] - this->m_lower_bounds[m_p]; - } - if (this->x_above_upper_bound(m_p)) { - return this->m_x[m_p] - this->m_upper_bounds[m_p]; - } - lp_unreachable(); - case column_type::lower_bound: - if (this->x_below_low_bound(m_p)) { - return this->m_x[m_p] - this->m_lower_bounds[m_p]; - } - lp_unreachable(); - case column_type::upper_bound: - if (this->x_above_upper_bound(m_p)) { - return get_edge_steepness_for_upper_bound(m_p); - } - lp_unreachable(); - case column_type::fixed: - return this->m_x[m_p] - this->m_upper_bounds[m_p]; - default: - lp_unreachable(); - } - lp_unreachable(); - return zero_of_type(); -} - -template void lp_dual_core_solver::restore_d() { - this->m_d[m_p] = numeric_traits::zero(); - for (auto j : this->non_basis()) { - this->m_d[j] += m_theta_D * this->m_pivot_row[j]; - } -} - -template bool lp_dual_core_solver::d_is_correct() { - - lp_assert(false); - return true; -} - -template void lp_dual_core_solver::xb_minus_delta_p_pivot_column() { - unsigned i = this->m_m(); - while (i--) { - this->m_x[this->m_basis[i]] -= m_theta_P * this->m_ed[i]; - } -} - -template void lp_dual_core_solver::update_betas() { // page 194 of Progress ... todo - once in a while betas have to be reinitialized - T one_over_arq = numeric_traits::one() / this->m_pivot_row[m_q]; - T beta_r = this->m_betas[m_r] = std::max(T(0.0001), (m_betas[m_r] * one_over_arq) * one_over_arq); - T k = -2 * one_over_arq; - unsigned i = this->m_m(); - while (i--) { - if (static_cast(i) == m_r) continue; - T a = this->m_ed[i]; - m_betas[i] += a * (a * beta_r + k * this->m_pivot_row_of_B_1[i]); - if (m_betas[i] < T(0.0001)) - m_betas[i] = T(0.0001); - } -} - -template void lp_dual_core_solver::apply_flips() { - for (unsigned j : m_flipped_boxed) { - lp_assert(this->x_is_at_bound(j)); - if (this->x_is_at_lower_bound(j)) { - this->m_x[j] = this->m_upper_bounds[j]; - } else { - this->m_x[j] = this->m_lower_bounds[j]; - } - } -} - -template void lp_dual_core_solver::snap_xN_column_to_bounds(unsigned j) { - switch (this->m_column_type[j]) { - case column_type::fixed: - this->m_x[j] = this->m_lower_bounds[j]; - break; - case column_type::boxed: - if (this->x_is_at_lower_bound(j)) { - this->m_x[j] = this->m_lower_bounds[j]; - } else { - this->m_x[j] = this->m_upper_bounds[j]; - } - break; - case column_type::lower_bound: - this->m_x[j] = this->m_lower_bounds[j]; - break; - case column_type::upper_bound: - this->m_x[j] = this->m_upper_bounds[j]; - break; - case column_type::free_column: - break; - default: - lp_unreachable(); - } -} - -template void lp_dual_core_solver::snap_xN_to_bounds() { - for (auto j : this->non_basis()) { - snap_xN_column_to_bounds(j); - } -} - -template void lp_dual_core_solver::init_beta_precisely(unsigned i) { - vector vec(this->m_m(), numeric_traits::zero()); - vec[i] = numeric_traits::one(); - this->m_factorization->solve_yB_with_error_check(vec, this->m_basis); - T beta = numeric_traits::zero(); - for (T & v : vec) { - beta += v * v; - } - this->m_betas[i] =beta; -} - -template void lp_dual_core_solver::init_betas_precisely() { - unsigned i = this->m_m(); - while (i--) { - init_beta_precisely(i); - } -} - -// step 7 of the algorithm from Progress -template bool lp_dual_core_solver::basis_change_and_update() { - - return true; -} - -template void lp_dual_core_solver::recover_leaving() { - switch (m_entering_boundary_position) { - case at_lower_bound: - case at_fixed: - this->m_x[m_q] = this->m_lower_bounds[m_q]; - break; - case at_upper_bound: - this->m_x[m_q] = this->m_upper_bounds[m_q]; - break; - case free_of_bounds: - this->m_x[m_q] = zero_of_type(); - default: - lp_unreachable(); - } -} - -template void lp_dual_core_solver::revert_to_previous_basis() { - LP_OUT(this->m_settings, "revert to previous basis on ( " << m_p << ", " << m_q << ")" << std::endl); - this->change_basis_unconditionally(m_p, m_q); - init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_settings); - if (this->m_factorization->get_status() != LU_status::OK) { - this->set_status(lp_status::FLOATING_POINT_ERROR); // complete failure - return; - } - recover_leaving(); - if (!this->find_x_by_solving()) { - this->set_status(lp_status::FLOATING_POINT_ERROR); - return; - } - recalculate_xB_and_d(); - init_betas_precisely(); -} - -// returns true if the column has been snapped -template bool lp_dual_core_solver::snap_runaway_nonbasic_column(unsigned j) { - switch (this->m_column_types[j]) { - case column_type::fixed: - case column_type::lower_bound: - if (!this->x_is_at_lower_bound(j)) { - this->m_x[j] = this->m_lower_bounds[j]; - return true; - } - break; - case column_type::boxed: - { - bool closer_to_lower_bound = abs(this->m_lower_bounds[j] - this->m_x[j]) < abs(this->m_upper_bounds[j] - this->m_x[j]); - if (closer_to_lower_bound) { - if (!this->x_is_at_lower_bound(j)) { - this->m_x[j] = this->m_lower_bounds[j]; - return true; - } - } else { - if (!this->x_is_at_upper_bound(j)) { - this->m_x[j] = this->m_lower_bounds[j]; - return true; - } - } - } - break; - case column_type::upper_bound: - if (!this->x_is_at_upper_bound(j)) { - this->m_x[j] = this->m_upper_bounds[j]; - return true; - } - break; - default: - break; - } - return false; -} - - -template bool lp_dual_core_solver::problem_is_dual_feasible() const { - for (unsigned j : this->non_basis()){ - if (!this->column_is_dual_feasible(j)) { - return false; - } - } - return true; -} - -template unsigned lp_dual_core_solver::get_number_of_rows_to_try_for_leaving() { - unsigned s = this->m_m(); - if (this->m_m() > 300) { - s = (unsigned)((s / 100.0) * this->m_settings.percent_of_entering_to_check); - } - return this->m_settings.random_next() % s + 1; -} - -template bool lp_dual_core_solver::delta_keeps_the_sign(int initial_delta_sign, const T & delta) { - if (numeric_traits::precise()) - return ((delta > numeric_traits::zero()) && (initial_delta_sign == 1)) || - ((delta < numeric_traits::zero()) && (initial_delta_sign == -1)); - - double del = numeric_traits::get_double(delta); - return ( (del > this->m_settings.zero_tolerance) && (initial_delta_sign == 1)) || - ((del < - this->m_settings.zero_tolerance) && (initial_delta_sign == -1)); -} - -template void lp_dual_core_solver::set_status_to_tentative_dual_unbounded_or_dual_unbounded() { - if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) { - this->set_status(lp_status::DUAL_UNBOUNDED); - } else { - this->set_status(lp_status::TENTATIVE_DUAL_UNBOUNDED); - } -} - -template void lp_dual_core_solver::add_tight_breakpoints_and_q_to_flipped_set() { - m_flipped_boxed.insert(m_q); - for (auto j : m_tight_set) { - m_flipped_boxed.insert(j); - } -} - -template T lp_dual_core_solver::delta_lost_on_flips_of_tight_breakpoints() { - T ret = abs(this->bound_span(m_q) * this->m_pivot_row[m_q]); - for (auto j : m_tight_set) { - ret += abs(this->bound_span(j) * this->m_pivot_row[j]); - } - return ret; -} - -template bool lp_dual_core_solver::tight_breakpoinst_are_all_boxed() { - if (this->m_column_types[m_q] != column_type::boxed) return false; - for (auto j : m_tight_set) { - if (this->m_column_types[j] != column_type::boxed) return false; - } - return true; -} - -template T lp_dual_core_solver::calculate_harris_delta_on_breakpoint_set() { - bool first_time = true; - T ret = zero_of_type(); - lp_assert(m_breakpoint_set.size() > 0); - for (auto j : m_breakpoint_set) { - T t; - if (this->x_is_at_lower_bound(j)) { - t = abs((std::max(this->m_d[j], numeric_traits::zero()) + m_harris_tolerance) / this->m_pivot_row[j]); - } else { - t = abs((std::min(this->m_d[j], numeric_traits::zero()) - m_harris_tolerance) / this->m_pivot_row[j]); - } - if (first_time) { - ret = t; - first_time = false; - } else if (t < ret) { - ret = t; - } - } - return ret; -} - -template void lp_dual_core_solver::fill_tight_set_on_harris_delta(const T & harris_delta ){ - m_tight_set.clear(); - for (auto j : m_breakpoint_set) { - if (this->x_is_at_lower_bound(j)) { - if (abs(std::max(this->m_d[j], numeric_traits::zero()) / this->m_pivot_row[j]) <= harris_delta){ - m_tight_set.insert(j); - } - } else { - if (abs(std::min(this->m_d[j], numeric_traits::zero() ) / this->m_pivot_row[j]) <= harris_delta){ - m_tight_set.insert(j); - } - } - } -} - -template void lp_dual_core_solver::find_q_on_tight_set() { - m_q = -1; - T max_pivot; - for (auto j : m_tight_set) { - T r = abs(this->m_pivot_row[j]); - if (m_q != -1) { - if (r > max_pivot) { - max_pivot = r; - m_q = j; - } - } else { - max_pivot = r; - m_q = j; - } - } - m_tight_set.erase(m_q); - lp_assert(m_q != -1); -} - -template void lp_dual_core_solver::find_q_and_tight_set() { - T harris_del = calculate_harris_delta_on_breakpoint_set(); - fill_tight_set_on_harris_delta(harris_del); - find_q_on_tight_set(); - m_entering_boundary_position = this->get_non_basic_column_value_position(m_q); -} - -template void lp_dual_core_solver::erase_tight_breakpoints_and_q_from_breakpoint_set() { - m_breakpoint_set.erase(m_q); - for (auto j : m_tight_set) { - m_breakpoint_set.erase(j); - } -} - -template bool lp_dual_core_solver::ratio_test() { - m_sign_of_alpha_r = define_sign_of_alpha_r(); - fill_breakpoint_set(); - m_flipped_boxed.clear(); - int initial_delta_sign = m_delta >= numeric_traits::zero()? 1: -1; - do { - if (m_breakpoint_set.empty()) { - set_status_to_tentative_dual_unbounded_or_dual_unbounded(); - return false; - } - this->set_status(lp_status::FEASIBLE); - find_q_and_tight_set(); - if (!tight_breakpoinst_are_all_boxed()) break; - T del = m_delta - delta_lost_on_flips_of_tight_breakpoints() * initial_delta_sign; - if (!delta_keeps_the_sign(initial_delta_sign, del)) break; - if (m_tight_set.size() + 1 == m_breakpoint_set.size()) { - break; // deciding not to flip since we might get stuck without finding m_q, the column entering the basis - } - // we can flip m_q together with the tight set and look for another breakpoint candidate for m_q and another tight set - add_tight_breakpoints_and_q_to_flipped_set(); - m_delta = del; - erase_tight_breakpoints_and_q_from_breakpoint_set(); - } while (true); - m_theta_D = this->m_d[m_q] / this->m_pivot_row[m_q]; - return true; -} - -template void lp_dual_core_solver::process_flipped() { - init_a_wave_by_zeros(); - for (auto j : m_flipped_boxed) { - update_a_wave(signed_span_of_boxed(j), j); - } -} -template void lp_dual_core_solver::update_d_and_xB() { - for (auto j : this->non_basis()) { - this->m_d[j] -= m_theta_D * this->m_pivot_row[j]; - } - this->m_d[m_p] = - m_theta_D; - if (!m_flipped_boxed.empty()) { - process_flipped(); - update_xb_after_bound_flips(); - } -} - -template void lp_dual_core_solver::calculate_beta_r_precisely() { - T t = numeric_traits::zero(); - unsigned i = this->m_m(); - while (i--) { - T b = this->m_pivot_row_of_B_1[i]; - t += b * b; - } - m_betas[m_r] = t; -} -// see "Progress in the dual simplex method for large scale LP problems: practical dual phase 1 algorithms" - -template void lp_dual_core_solver::update_xb_after_bound_flips() { - this->m_factorization->solve_By(m_a_wave); - unsigned i = this->m_m(); - while (i--) { - this->m_x[this->m_basis[i]] -= m_a_wave[i]; - } -} - -template void lp_dual_core_solver::one_iteration() { - unsigned number_of_rows_to_try = get_number_of_rows_to_try_for_leaving(); - unsigned offset_in_rows = this->m_settings.random_next() % this->m_m(); - if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) { - number_of_rows_to_try = this->m_m(); - } else { - this->set_status(lp_status::FEASIBLE); - } - pricing_loop(number_of_rows_to_try, offset_in_rows); - lp_assert(problem_is_dual_feasible()); -} - -template void lp_dual_core_solver::solve() { // see the page 35 - lp_assert(d_is_correct()); - lp_assert(problem_is_dual_feasible()); - lp_assert(this->basis_heading_is_correct()); - //this->set_total_iterations(0); - this->iters_with_no_cost_growing() = 0; - do { - if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over("", *this->m_settings.get_message_ostream())){ - return; - } - one_iteration(); - } while (this->get_status() != lp_status::FLOATING_POINT_ERROR && this->get_status() != lp_status::DUAL_UNBOUNDED && this->get_status() != lp_status::OPTIMAL && - this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements - ); -} -} diff --git a/src/math/lp/static_matrix.cpp b/src/math/lp/static_matrix.cpp index cde96277b5e..93360b9140f 100644 --- a/src/math/lp/static_matrix.cpp +++ b/src/math/lp/static_matrix.cpp @@ -23,7 +23,6 @@ Revision History: #include #include "math/lp/static_matrix_def.h" #include "math/lp/lp_core_solver_base.h" -#include "math/lp/lp_dual_core_solver.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/scaler.h" #include "math/lp/lar_solver.h" From 15f41d7e9128f674cc0c7011480af3688862b781 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 07:56:04 -0800 Subject: [PATCH 11/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lar_core_solver.h | 41 --------------------------- src/math/lp/lar_solver.cpp | 5 ---- src/math/lp/lar_solver.h | 1 - src/math/lp/lp_core_solver_base.cpp | 14 --------- src/math/lp/lp_core_solver_base.h | 10 +------ src/math/lp/lp_core_solver_base_def.h | 40 -------------------------- 6 files changed, 1 insertion(+), 110 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 999eef13bc8..9168862c651 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -274,47 +274,6 @@ class lar_core_solver { } - - void prepare_solver_x_with_signature_tableau(const lar_solution_signature & signature) { - lp_assert(m_r_solver.inf_set_is_correct()); - for (auto &t : signature) { - unsigned j = t.first; - if (m_r_heading[j] >= 0) - continue; - auto pos_type = t.second; - numeric_pair delta; - if (!update_xj_and_get_delta(j, pos_type, delta)) - continue; - for (const auto & cc : m_r_solver.m_A.m_columns[j]){ - unsigned i = cc.var(); - unsigned jb = m_r_solver.m_basis[i]; - m_r_solver.add_delta_to_x_and_track_feasibility(jb, - delta * m_r_solver.m_A.get_val(cc)); - } - - } - lp_assert(m_r_solver.inf_set_is_correct()); - } - - - - bool adjust_x_of_column(unsigned j) { - /* - if (m_r_solver.m_basis_heading[j] >= 0) { - return false; - } - - if (m_r_solver.column_is_feasible(j)) { - return false; - } - - m_r_solver.snap_column_to_bound_tableau(j); - lp_assert(m_r_solver.column_is_feasible(j)); - m_r_solver.m_inf_set.erase(j); - */ - lp_assert(false); - return true; - } - bool r_basis_is_OK() const { #ifdef Z3DEBUG diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index d9961eaa8ab..48c575184ba 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -643,11 +643,6 @@ namespace lp { bool lar_solver::use_tableau_costs() const { return m_settings.simplex_strategy() == simplex_strategy_enum::tableau_costs; } - - void lar_solver::adjust_x_of_column(unsigned j) { - lp_assert(false); - } - bool lar_solver::row_is_correct(unsigned i) const { numeric_pair r = zero_of_type>(); for (const auto& c : A_r().m_rows[i]) { diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 51365936819..09612d905e4 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -210,7 +210,6 @@ class lar_solver : public column_namer { void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j); bool use_tableau_costs() const; void detect_rows_of_column_with_bound_change(unsigned j); - void adjust_x_of_column(unsigned j); bool tableau_with_costs() const; bool costs_are_used() const; void change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta); diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 0d9f4297419..90101e998f5 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -24,7 +24,6 @@ Revision History: #include #include "math/lp/lp_core_solver_base_def.h" template bool lp::lp_core_solver_base::basis_heading_is_correct() const; -template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; @@ -44,12 +43,9 @@ template bool lp::lp_core_solver_base::print_statistics_with_ite template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template void lp::lp_core_solver_base::restore_x(unsigned int, double const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lp::lp_core_solver_base::snap_xN_to_bounds_and_free_columns_to_zeroes(); -template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_free_columns_to_zeroes(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; -template void lp::lp_core_solver_base::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); @@ -57,7 +53,6 @@ template void lp::lp_core_solver_base::restore_x(unsigned int, template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); -template void lp::lp_core_solver_base >::calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned); template void lp::lp_core_solver_base >::init(); template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); template lp::lp_core_solver_base >::lp_core_solver_base(lp::static_matrix >&, @@ -85,18 +80,10 @@ template lp::lp_core_solver_base::lp_core_solver_base( template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); template std::string lp::lp_core_solver_base::column_name(unsigned int) const; template void lp::lp_core_solver_base::pretty_print(std::ostream & out); -template void lp::lp_core_solver_base::restore_state(double*, double*); -template void lp::lp_core_solver_base::save_state(double*, double*); template std::string lp::lp_core_solver_base::column_name(unsigned int) const; template void lp::lp_core_solver_base::pretty_print(std::ostream & out); -template void lp::lp_core_solver_base::restore_state(lp::mpq*, lp::mpq*); -template void lp::lp_core_solver_base::save_state(lp::mpq*, lp::mpq*); template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); -template void lp::lp_core_solver_base >::restore_state(lp::mpq*, lp::mpq*); -template void lp::lp_core_solver_base >::save_state(lp::mpq*, lp::mpq*); -template void lp::lp_core_solver_base::init_lu(); -template void lp::lp_core_solver_base::init_lu(); template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; @@ -109,7 +96,6 @@ template bool lp::lp_core_solver_base::column_is_feasible(unsi // template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); -template void lp::lp_core_solver_base >::init_lu(); template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 729792c1266..e54c884891b 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -156,10 +156,6 @@ class lp_core_solver_base { void pretty_print(std::ostream & out); - void save_state(T * w_buffer, T * d_buffer); - - void restore_state(T * w_buffer, T * d_buffer); - X get_cost() const { return dot_product(m_costs, m_x); } @@ -173,8 +169,6 @@ class lp_core_solver_base { void restore_m_ed(T * buffer); - void calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row); - void add_delta_to_entering(unsigned entering, const X & delta); const X & get_var_value(unsigned j) const { @@ -422,11 +416,9 @@ class lp_core_solver_base { void snap_non_basic_x_to_bound_and_free_to_zeroes(); void snap_xN_to_bounds_and_fill_xB(); - void snap_xN_to_bounds_and_free_columns_to_zeroes(); - + non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; - void init_lu(); int pivots_in_column_and_row_are_different(int entering, int leaving) const; void pivot_fixed_vars_from_basis(); bool remove_from_basis(unsigned j); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index e470072e04c..bc902e8b052 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -136,17 +136,6 @@ pretty_print(std::ostream & out) { pp.print(); } -template void lp_core_solver_base:: -save_state(T * w_buffer, T * d_buffer) { - copy_m_w(w_buffer); - copy_m_ed(d_buffer); -} - -template void lp_core_solver_base:: -restore_state(T * w_buffer, T * d_buffer) { - restore_m_w(w_buffer); - restore_m_ed(d_buffer); -} template void lp_core_solver_base:: copy_m_w(T * buffer) { @@ -185,26 +174,6 @@ restore_m_ed(T * buffer) { -template void lp_core_solver_base:: -calculate_pivot_row_when_pivot_row_of_B1_is_ready(unsigned pivot_row) { - m_pivot_row.clear(); - - for (unsigned i : m_pivot_row_of_B_1.m_index) { - const T & pi_1 = m_pivot_row_of_B_1[i]; - if (numeric_traits::is_zero(pi_1)) { - continue; - } - for (auto & c : m_A.m_rows[i]) { - unsigned j = c.var(); - if (m_basis_heading[j] < 0) { - m_pivot_row.add_value_at_index_with_drop_tolerance(j, c.coeff() * pi_1); - } - } - } - if (precise()) { - m_rows_nz[pivot_row] = m_pivot_row.m_index.size(); - } -} template void lp_core_solver_base:: add_delta_to_entering(unsigned entering, const X& delta) { @@ -631,11 +600,6 @@ snap_xN_to_bounds_and_fill_xB() { solve_Ax_eq_b(); } -template void lp_core_solver_base:: -snap_xN_to_bounds_and_free_columns_to_zeroes() { - snap_non_basic_x_to_bound_and_free_to_zeroes(); - solve_Ax_eq_b(); -} template non_basic_column_value_position lp_core_solver_base:: @@ -661,10 +625,6 @@ get_non_basic_column_value_position(unsigned j) const { return at_lower_bound; } -template void lp_core_solver_base::init_lu() { - init_factorization(this->m_factorization, this->m_A, this->m_basis, this->m_settings); -} - template int lp_core_solver_base::pivots_in_column_and_row_are_different(int entering, int leaving) const { const T & column_p = this->m_ed[this->m_basis_heading[leaving]]; const T & row_p = this->m_pivot_row[entering]; From 6c78d2556c38c41e8e870197faa18fdc032233a1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 09:11:04 -0800 Subject: [PATCH 12/36] rm lu Signed-off-by: Lev Nachmanson --- src/math/lp/lp_core_solver_base.cpp | 1 - src/math/lp/lp_core_solver_base.h | 7 ++-- src/math/lp/lp_core_solver_base_def.h | 46 +------------------------ src/math/lp/lp_primal_core_solver_def.h | 21 ++--------- 4 files changed, 6 insertions(+), 69 deletions(-) diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 90101e998f5..b76976d371c 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -61,7 +61,6 @@ template lp::lp_core_solver_base >::lp_core_s const vector >&, const vector >&); template bool lp::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair, std::ostream&); -template void lp::lp_core_solver_base >::snap_xN_to_bounds_and_fill_xB(); template void lp::lp_core_solver_base >::solve_Ax_eq_b(); template void lp::lp_core_solver_base >::add_delta_to_entering(unsigned int, const lp::numeric_pair&); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index e54c884891b..c9b42f28be0 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -74,7 +74,7 @@ class lp_core_solver_base { vector & m_x; // a feasible solution, the fist time set in the constructor vector & m_costs; lp_settings & m_settings; - lu> * m_factorization = nullptr; + vector m_y; // the buffer for yB = cb // a device that is able to solve Bx=c, xB=d, and change the basis const column_namer & m_column_names; @@ -134,7 +134,7 @@ class lp_core_solver_base { void init(); virtual ~lp_core_solver_base() { - delete m_factorization; + } vector & non_basis() { @@ -413,9 +413,6 @@ class lp_core_solver_base { } - void snap_non_basic_x_to_bound_and_free_to_zeroes(); - void snap_xN_to_bounds_and_fill_xB(); - non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index bc902e8b052..01aa9802e8c 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -554,52 +554,8 @@ find_error_in_BxB(vector& rs){ // recalculates the projection of x to B, such that Ax = b template void lp_core_solver_base:: solve_Ax_eq_b() { - if (numeric_traits::precise()) { - vector rs(m_m()); - rs_minus_Anx(rs); - m_factorization->solve_By(rs); - copy_rs_to_xB(rs); - } - else { - vector rs(m_m()); - rs_minus_Anx(rs); - vector rrs = rs; // another copy of rs - m_factorization->solve_By(rs); - copy_rs_to_xB(rs); - find_error_in_BxB(rrs); - m_factorization->solve_By(rrs); - add_delta_to_xB(rrs); - } -} - - - - -template void lp_core_solver_base:: -snap_non_basic_x_to_bound_and_free_to_zeroes() { - for (unsigned j : non_basis()) { - lp_assert(j < m_x.size()); - switch (m_column_types[j]) { - case column_type::fixed: - case column_type::boxed: - case column_type::lower_bound: - m_x[j] = m_lower_bounds[j]; - break; - case column_type::upper_bound: - m_x[j] = m_upper_bounds[j]; - break; - default: - m_x[j] = zero_of_type(); - break; - } - } + lp_assert(false); } -template void lp_core_solver_base:: -snap_xN_to_bounds_and_fill_xB() { - snap_non_basic_x_to_bound(); - solve_Ax_eq_b(); -} - template non_basic_column_value_position lp_core_solver_base:: diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 19ffaa1eadc..7764ce6d2d9 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -642,11 +642,7 @@ template void lp_primal_core_solver::init_run( template void lp_primal_core_solver::calc_working_vector_beta_for_column_norms(){ - lp_assert(numeric_traits::precise() == false); - lp_assert(this->m_ed.is_OK()); - lp_assert(m_beta.is_OK()); - m_beta = this->m_ed; - this->m_factorization->solve_yB_with_error_check_indexed(m_beta, this->m_basis_heading, this->m_basis, this->m_settings); + lp_assert(false); } template @@ -758,10 +754,7 @@ template unsigned lp_primal_core_solver::solve() } template void lp_primal_core_solver::delete_factorization() { - if (this->m_factorization != nullptr) { - delete this->m_factorization; - this->m_factorization = nullptr; - } + lp_assert(false); } // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" @@ -776,15 +769,7 @@ template void lp_primal_core_solver::init_column_ // debug only template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { - lp_assert(numeric_traits::precise() == false); - indexed_vector w(this->m_m()); - this->m_A.copy_column_to_vector(j, w); - vector d(this->m_m()); - this->m_factorization->solve_Bd_when_w_is_ready(d, w); - T ret = zero_of_type(); - for (auto v : d) - ret += v*v; - return ret+1; + lp_assert(false); } template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { From 1bf416df27083e56d5692161f31b2b8db2cfe8b5 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 09:33:53 -0800 Subject: [PATCH 13/36] rm lu --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/lp_core_solver_base.h | 14 +- src/math/lp/lp_primal_core_solver.h | 4 - src/math/lp/lp_primal_core_solver_def.h | 13 +- .../lp/lp_primal_core_solver_tableau_def.h | 6 +- src/math/lp/lp_settings.h | 1 - src/math/lp/lp_settings_def.h | 2 - src/math/lp/lu.cpp | 81 -- src/math/lp/lu.h | 325 -------- src/math/lp/lu_def.h | 720 ------------------ src/math/lp/row_eta_matrix.cpp | 1 - src/math/lp/square_sparse_matrix.cpp | 1 - src/math/lp/square_sparse_matrix_def.h | 2 + src/smt/theory_lra.cpp | 2 +- 14 files changed, 22 insertions(+), 1151 deletions(-) delete mode 100644 src/math/lp/lu.cpp delete mode 100644 src/math/lp/lu.h delete mode 100644 src/math/lp/lu_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index cc58c9610fc..97073736717 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -21,7 +21,6 @@ z3_add_component(lp lp_core_solver_base.cpp lp_primal_core_solver.cpp lp_settings.cpp - lu.cpp lp_utils.cpp matrix.cpp mon_eq.cpp diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index c9b42f28be0..0e8a2abdf3a 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -25,11 +25,21 @@ Revision History: #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/numeric_pair.h" #include "math/lp/static_matrix.h" -#include "math/lp/lu.h" #include "math/lp/permutation_matrix.h" #include "math/lp/column_namer.h" +#include "math/lp/u_set.h" + namespace lp { +template +X dot_product(const vector & a, const vector & b) { + lp_assert(a.size() == b.size()); + auto r = zero_of_type(); + for (unsigned i = 0; i < a.size(); i++) { + r += a[i] * b[i]; + } + return r; +} template // X represents the type of the x variable and the bounds class lp_core_solver_base { @@ -156,6 +166,8 @@ class lp_core_solver_base { void pretty_print(std::ostream & out); + + X get_cost() const { return dot_product(m_costs, m_x); } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index abee0cc6efd..38a2aa5f5e0 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -29,7 +29,6 @@ Revision History: #include #include #include -#include "math/lp/lu.h" #include "math/lp/static_matrix.h" #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/lp_core_solver_base.h" @@ -418,9 +417,6 @@ class lp_primal_core_solver:public lp_core_solver_base { // returns the number of iterations unsigned solve(); - lu> * factorization() {return nullptr;} - - void delete_factorization(); // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" void init_column_norms(); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 7764ce6d2d9..3967b6e6698 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -26,6 +26,7 @@ Revision History: #include #include #include "math/lp/lp_primal_core_solver.h" +#include "math/lp/dense_matrix.h" namespace lp { // This core solver solves (Ax=b, lower_bound_values \leq x \leq upper_bound_values, maximize costs*x ) // The right side b is given implicitly by x and the basis @@ -733,8 +734,7 @@ template unsigned lp_primal_core_solver::solve() default: break; // do nothing } - } while (this->get_status() != lp_status::FLOATING_POINT_ERROR - && + } while ( this->get_status() != lp_status::UNBOUNDED && this->get_status() != lp_status::OPTIMAL @@ -745,18 +745,13 @@ template unsigned lp_primal_core_solver::solve() && !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR - || + lp_assert( this->current_x_is_feasible() == false || this->calc_current_x_is_feasible_include_non_basis()); return this->total_iterations(); } -template void lp_primal_core_solver::delete_factorization() { - lp_assert(false); -} - // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" template void lp_primal_core_solver::init_column_norms() { lp_assert(numeric_traits::precise() == false); @@ -860,7 +855,7 @@ template void lp_primal_core_solver::fill_breakpo template bool lp_primal_core_solver::done() { - if (this->get_status() == lp_status::OPTIMAL || this->get_status() == lp_status::FLOATING_POINT_ERROR) return true; + if (this->get_status() == lp_status::OPTIMAL) return true; if (this->get_status() == lp_status::INFEASIBLE) { return true; } diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index 736b79db5ad..e742b0cd01a 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -157,8 +157,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { this->set_status(lp_status::CANCELLED); break; // from the loop } - } while (this->get_status() != lp_status::FLOATING_POINT_ERROR - && + } while ( this->get_status() != lp_status::UNBOUNDED && this->get_status() != lp_status::OPTIMAL @@ -168,8 +167,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) ); - lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR - || + lp_assert( this->get_status() == lp_status::CANCELLED || this->current_x_is_feasible() == false diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 360ef99bf1d..cb60eebc9c5 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -69,7 +69,6 @@ enum class lp_status { DUAL_UNBOUNDED, OPTIMAL, FEASIBLE, - FLOATING_POINT_ERROR, TIME_EXHAUSTED, EMPTY, UNSTABLE, diff --git a/src/math/lp/lp_settings_def.h b/src/math/lp/lp_settings_def.h index 58b37a19dcf..bb87109f6fb 100644 --- a/src/math/lp/lp_settings_def.h +++ b/src/math/lp/lp_settings_def.h @@ -45,7 +45,6 @@ const char* lp_status_to_string(lp_status status) { case lp_status::DUAL_UNBOUNDED: return "DUAL_UNBOUNDED"; case lp_status::OPTIMAL: return "OPTIMAL"; case lp_status::FEASIBLE: return "FEASIBLE"; - case lp_status::FLOATING_POINT_ERROR: return "FLOATING_POINT_ERROR"; case lp_status::TIME_EXHAUSTED: return "TIME_EXHAUSTED"; case lp_status::EMPTY: return "EMPTY"; case lp_status::UNSTABLE: return "UNSTABLE"; @@ -62,7 +61,6 @@ lp_status lp_status_from_string(std::string status) { if (status == "UNBOUNDED") return lp_status::UNBOUNDED; if (status == "OPTIMAL") return lp_status::OPTIMAL; if (status == "FEASIBLE") return lp_status::FEASIBLE; - if (status == "FLOATING_POINT_ERROR") return lp_status::FLOATING_POINT_ERROR; if (status == "TIME_EXHAUSTED") return lp_status::TIME_EXHAUSTED; if (status == "EMPTY") return lp_status::EMPTY; lp_unreachable(); diff --git a/src/math/lp/lu.cpp b/src/math/lp/lu.cpp deleted file mode 100644 index 313fa990151..00000000000 --- a/src/math/lp/lu.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include -#include -#include "util/vector.h" -#include "util/debug.h" -#include "math/lp/lu_def.h" -namespace lp { -template double dot_product(vector const&, vector const&); -template lu>::lu(static_matrix const&, vector&, lp_settings&); -template void lu>::push_matrix_to_tail(tail_matrix*); -template void lu>::replace_column(double, indexed_vector&, unsigned); -template lu>::~lu(); -template void lu>::push_matrix_to_tail(tail_matrix*); -template lu>::~lu(); -template void lu>::push_matrix_to_tail(tail_matrix*); -template lu>::~lu(); -template mpq dot_product(vector const&, vector const&); -template void init_factorization> - (lu>*&, static_matrix&, vector&, lp_settings&); -template void init_factorization> - (lu>*&, static_matrix&, vector&, lp_settings&); -template void init_factorization>(lu >*&, static_matrix&, vector&, lp_settings&); -template void print_matrix>(square_sparse_matrix&, std::ostream & out); -template void print_matrix>(static_matrix&, std::ostream&); -template void print_matrix >(static_matrix&, std::ostream&); -template void print_matrix>(static_matrix&, std::ostream & out); -#ifdef Z3DEBUG -template bool lu>::is_correct(const vector& basis); -template bool lu>::is_correct( vector const &); -template dense_matrix get_B>(lu>&, const vector& basis); -template dense_matrix get_B>(lu>&, vector const&); - -#endif - -template bool lu>::pivot_the_row(int); // NOLINT -template void lu>::init_vector_w(unsigned int, indexed_vector&); -template void lu>::solve_By(vector&); -template void lu>::solve_By_when_y_is_ready_for_X(vector&); -template void lu>::solve_yB_with_error_check(vector&, const vector& basis); -template void lu>::solve_yB_with_error_check_indexed(indexed_vector&, vector const&, const vector & basis, const lp_settings&); -template void lu>::replace_column(mpq, indexed_vector&, unsigned); -template void lu>::solve_By(vector&); -template void lu>::solve_By_when_y_is_ready_for_X(vector&); -template void lu>::solve_yB_with_error_check(vector&, const vector& basis); -template void lu>::solve_yB_with_error_check_indexed(indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lu >::solve_yB_with_error_check_indexed(indexed_vector&, vector< int > const&, const vector & basis, const lp_settings&); -template void lu >::init_vector_w(unsigned int, indexed_vector&); -template void lu >::replace_column(mpq, indexed_vector&, unsigned); -template void lu >::solve_Bd_faster(unsigned int, indexed_vector&); -template void lu >::solve_By(vector&); -template void lu >::solve_By_when_y_is_ready_for_X(vector&); -template void lu >::solve_yB_with_error_check(vector&, const vector& basis); -template void lu>::solve_By(indexed_vector&); -template void lu>::solve_By(indexed_vector&); -template void lu>::solve_yB_indexed(indexed_vector&); -template void lu >::solve_yB_indexed(indexed_vector&); -template void lu>::solve_By_for_T_indexed_only(indexed_vector&, lp_settings const&); -template void lu>::solve_By_for_T_indexed_only(indexed_vector&, lp_settings const&); -#ifdef Z3DEBUG -template void print_matrix>(tail_matrix&, std::ostream&); -#endif -} diff --git a/src/math/lp/lu.h b/src/math/lp/lu.h deleted file mode 100644 index 18251e3ada5..00000000000 --- a/src/math/lp/lu.h +++ /dev/null @@ -1,325 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - for matrix B we have - t0*...*tn-1*B = Q*U*R - here ti are matrices corresponding to pivot operations, - including columns and rows swaps, - or a multiplication matrix row by a number - Q, R - permutations and U is an upper triangular matrix -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once - -#include "util/vector.h" -#include "util/debug.h" -#include -#include -#include "math/lp/square_sparse_matrix.h" -#include "math/lp/static_matrix.h" -#include -#include "math/lp/numeric_pair.h" -#include -#include -#include "math/lp/row_eta_matrix.h" -#include "math/lp/square_dense_submatrix.h" -#include "math/lp/dense_matrix.h" -namespace lp { -template // print the nr x nc submatrix at the top left corner -void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc); - -template -void print_matrix(M &m, std::ostream & out); - -template -X dot_product(const vector & a, const vector & b) { - lp_assert(a.size() == b.size()); - auto r = zero_of_type(); - for (unsigned i = 0; i < a.size(); i++) { - r += a[i] * b[i]; - } - return r; -} - - -template -class one_elem_on_diag: public tail_matrix { - unsigned m_i; - T m_val; -public: - one_elem_on_diag(unsigned i, T val) : m_i(i), m_val(val) { -#ifdef Z3DEBUG - m_one_over_val = numeric_traits::one() / m_val; -#endif - } - - bool is_dense() const override { return false; } - - one_elem_on_diag(const one_elem_on_diag & o); - -#ifdef Z3DEBUG - unsigned m_m; - unsigned m_n; - void set_number_of_rows(unsigned m) override { m_m = m; m_n = m; } - void set_number_of_columns(unsigned n) override { m_m = n; m_n = n; } - T m_one_over_val; - - T get_elem (unsigned i, unsigned j) const override; - - unsigned row_count() const override { return m_m; } // not defined } - unsigned column_count() const override { return m_m; } // not defined } -#endif - void apply_from_left(vector & w, lp_settings &) override { - w[m_i] /= m_val; - } - - void apply_from_right(vector & w) override { - w[m_i] /= m_val; - } - - void apply_from_right(indexed_vector & w) override { - if (is_zero(w.m_data[m_i])) - return; - auto & v = w.m_data[m_i] /= m_val; - if (lp_settings::is_eps_small_general(v, 1e-14)) { - w.erase_from_index(m_i); - v = zero_of_type(); - } - } - - - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override; - - void conjugate_by_permutation(permutation_matrix & p) { - // this = p * this * p(-1) -#ifdef Z3DEBUG - // auto rev = p.get_reverse(); - // auto deb = ((*this) * rev); - // deb = p * deb; -#endif - m_i = p.apply_reverse(m_i); - -#ifdef Z3DEBUG - // lp_assert(*this == deb); -#endif - } -}; // end of one_elem_on_diag - -enum class LU_status { OK, Degenerated}; - -// This class supports updates of the columns of B, and solves systems Bx=b,and yB=c -// Using Suhl-Suhl method described in the dissertation of Achim Koberstein, Chapter 5 -template -class lu { - LU_status m_status; -public: - typedef typename M::coefftype T; - typedef typename M::argtype X; - - // the fields - unsigned m_dim; - const M & m_A; - permutation_matrix m_Q; - permutation_matrix m_R; - permutation_matrix m_r_wave; - square_sparse_matrix m_U; - square_dense_submatrix* m_dense_LU; - - vector *> m_tail; - lp_settings & m_settings; - bool m_failure; - indexed_vector m_row_eta_work_vector; - indexed_vector m_w_for_extension; - indexed_vector m_y_copy; - indexed_vector m_ii; //to optimize the work with the m_index fields - unsigned m_refactor_counter; - // constructor - // if A is an m by n matrix then basis has length m and values in [0,n); the values are all different - // they represent the set of m columns - lu(const M & A, - vector& basis, - lp_settings & settings); - lu(const M & A, lp_settings&); - void debug_test_of_basis(const M & A, vector & basis); - void solve_Bd_when_w_is_ready(vector & d, indexed_vector& w ); - void solve_By(indexed_vector & y); - - void solve_By(vector & y); - - void solve_By_for_T_indexed_only(indexed_vector& y, const lp_settings &); - - template - void solve_By_when_y_is_ready(indexed_vector & y); - void solve_By_when_y_is_ready_for_X(vector & y); - void solve_By_when_y_is_ready_for_T(vector & y, vector & index); - void print_indexed_vector(indexed_vector & w, std::ofstream & f); - - void print_matrix_compact(std::ostream & f); - - void print(indexed_vector & w, const vector& basis); - void solve_Bd_faster(unsigned a_column, indexed_vector & d); // d is the right side on the input and the solution at the exit - - - void solve_yB_indexed(indexed_vector& y); - - void add_delta_to_solution_indexed(indexed_vector& y); - - void add_delta_to_solution(const vector& yc, vector& y); - - - void find_error_of_yB(vector& yc, const vector& y, - const vector& basis); - - void find_error_of_yB_indexed(const indexed_vector& y, - const vector& heading, const lp_settings& settings); - - - void solve_yB_with_error_check(vector & y, const vector& basis); - - void solve_yB_with_error_check_indexed(indexed_vector & y, const vector& heading, const vector & basis, const lp_settings &); - - void apply_Q_R_to_U(permutation_matrix & r_wave); - - - LU_status get_status() { return m_status; } - - void set_status(LU_status status) { - m_status = status; - } - - ~lu(); - - void init_vector_y(vector & y); - - void perform_transformations_on_w(indexed_vector& w); - - void init_vector_w(unsigned entering, indexed_vector & w); - void apply_lp_list_to_w(indexed_vector & w); - void apply_lp_list_to_y(vector& y); - - void swap_rows(int j, int k); - - void swap_columns(int j, int pivot_column); - - void push_matrix_to_tail(tail_matrix* tm) { - m_tail.push_back(tm); - } - - bool pivot_the_row(int row); - - eta_matrix * get_eta_matrix_for_pivot(unsigned j); - // we're processing the column j now - eta_matrix * get_eta_matrix_for_pivot(unsigned j, square_sparse_matrix& copy_of_U); - - // see page 407 of Chvatal - unsigned transform_U_to_V_by_replacing_column(indexed_vector & w, unsigned leaving_column_of_U); - -#ifdef Z3DEBUG - void check_vector_w(unsigned entering); - - void check_apply_matrix_to_vector(matrix *lp, T *w); - - void check_apply_lp_lists_to_w(T * w); - - // provide some access operators for testing - permutation_matrix & Q() { return m_Q; } - permutation_matrix & R() { return m_R; } - matrix & U() { return m_U; } - unsigned tail_size() { return m_tail.size(); } - - tail_matrix * get_lp_matrix(unsigned i) { - return m_tail[i]; - } - - T B_(unsigned i, unsigned j, const vector& basis) { - return m_A[i][basis[j]]; - } - - unsigned dimension() { return m_dim; } - -#endif - - - unsigned get_number_of_nonzeroes() { - return m_U.get_number_of_nonzeroes(); - } - - - void process_column(int j); - - bool is_correct(const vector& basis); - bool is_correct(); - - - - // needed for debugging purposes - void copy_w(T *buffer, indexed_vector & w); - - // needed for debugging purposes - void restore_w(T *buffer, indexed_vector & w); - bool all_columns_and_rows_are_active(); - - bool too_dense(unsigned j) const; - - void pivot_in_dense_mode(unsigned i); - - void create_initial_factorization(); - - void calculate_r_wave_and_update_U(unsigned bump_start, unsigned bump_end, permutation_matrix & r_wave); - - void scan_last_row_to_work_vector(unsigned lowest_row_of_the_bump); - - bool diagonal_element_is_off(T /* diag_element */) { return false; } - - void pivot_and_solve_the_system(unsigned replaced_column, unsigned lowest_row_of_the_bump); - // see Achim Koberstein's thesis page 58, but here we solve the system and pivot to the last - // row at the same time - - void replace_column(T pivot_elem, indexed_vector & w, unsigned leaving_column_of_U); - - void calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump); - - void calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element); - - void prepare_entering(unsigned entering, indexed_vector & w) { - lp_assert(false); - } - bool need_to_refactor() { lp_assert(false); - return m_refactor_counter >= 200; } - - void adjust_dimension_with_matrix_A() { - lp_assert(false); - } - - - - - - -}; // end of lu - -template -void init_factorization(lu* & factorization, M & m_A, vector & m_basis, lp_settings &m_settings); - -#ifdef Z3DEBUG -template -dense_matrix get_B(lu& f, const vector& basis); - -template -dense_matrix get_B(lu& f); -#endif -} diff --git a/src/math/lp/lu_def.h b/src/math/lp/lu_def.h deleted file mode 100644 index ca34481cca8..00000000000 --- a/src/math/lp/lu_def.h +++ /dev/null @@ -1,720 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include -#include -#include "util/vector.h" -#include -#include "util/debug.h" -#include "math/lp/lu.h" -namespace lp { -template // print the nr x nc submatrix at the top left corner -void print_submatrix(square_sparse_matrix & m, unsigned mr, unsigned nc, std::ostream & out) { - vector> A; - vector widths; - for (unsigned i = 0; i < m.row_count() && i < mr ; i++) { - A.push_back(vector()); - for (unsigned j = 0; j < m.column_count() && j < nc; j++) { - A[i].push_back(T_to_string(static_cast(m(i, j)))); - } - } - - for (unsigned j = 0; j < m.column_count() && j < nc; j++) { - widths.push_back(get_width_of_column(j, A)); - } - - print_matrix_with_widths(A, widths, out); -} - -template -void print_matrix(M &m, std::ostream & out) { - vector> A; - vector widths; - for (unsigned i = 0; i < m.row_count(); i++) { - A.push_back(vector()); - for (unsigned j = 0; j < m.column_count(); j++) { - A[i].push_back(T_to_string(m[i][j])); - } - } - - for (unsigned j = 0; j < m.column_count(); j++) { - widths.push_back(get_width_of_column(j, A)); - } - - print_matrix_with_widths(A, widths, out); -} - -template -one_elem_on_diag::one_elem_on_diag(const one_elem_on_diag & o) { - m_i = o.m_i; - m_val = o.m_val; -#ifdef Z3DEBUG - m_m = m_n = o.m_m; - m_one_over_val = numeric_traits::one() / o.m_val; -#endif -} - -#ifdef Z3DEBUG -template -T one_elem_on_diag::get_elem(unsigned i, unsigned j) const { - if (i == j){ - if (j == m_i) { - return m_one_over_val; - } - return numeric_traits::one(); - } - - return numeric_traits::zero(); -} -#endif -template -void one_elem_on_diag::apply_from_left_to_T(indexed_vector & w, lp_settings & settings) { - T & t = w[m_i]; - if (numeric_traits::is_zero(t)) { - return; - } - t /= m_val; - if (numeric_traits::precise()) return; - if (settings.abs_val_is_smaller_than_drop_tolerance(t)) { - w.erase_from_index(m_i); - t = numeric_traits::zero(); - } -} - -// This class supports updates of the columns of B, and solves systems Bx=b,and yB=c -// Using Suhl-Suhl method described in the dissertation of Achim Koberstein, Chapter 5 -template -lu::lu(const M& A, - vector& basis, - lp_settings & settings): - m_status(LU_status::OK), - m_dim(A.row_count()), - m_A(A), - m_Q(m_dim), - m_R(m_dim), - m_r_wave(m_dim), - m_U(A, basis), // create the square matrix that eventually will be factorized - m_settings(settings), - m_failure(false), - m_row_eta_work_vector(A.row_count()), - m_refactor_counter(0) { - lp_assert(!(numeric_traits::precise() )); -#ifdef Z3DEBUG - debug_test_of_basis(A, basis); -#endif - ++m_settings.stats().m_num_factorizations; - create_initial_factorization(); -#ifdef Z3DEBUG - // lp_assert(check_correctness()); -#endif -} -template -lu::lu(const M& A, - lp_settings & settings): - m_status(LU_status::OK), - m_dim(A.row_count()), - m_A(A), - m_Q(m_dim), - m_R(m_dim), - m_r_wave(m_dim), - m_U(A), // create the square matrix that eventually will be factorized - m_settings(settings), - m_failure(false), - m_row_eta_work_vector(A.row_count()), - m_refactor_counter(0) { - lp_assert(A.row_count() == A.column_count()); - create_initial_factorization(); -#ifdef Z3DEBUG - lp_assert(is_correct()); -#endif -} -template -void lu::debug_test_of_basis( M const & A, vector & basis) { - std::set set; - for (unsigned i = 0; i < A.row_count(); i++) { - lp_assert(basis[i]< A.column_count()); - set.insert(basis[i]); - } - lp_assert(set.size() == A.row_count()); -} - -template -void lu::solve_By(indexed_vector & y) { - lp_assert(false); // not implemented - // init_vector_y(y); - // solve_By_when_y_is_ready(y); - } - - -template -void lu::solve_By(vector & y) { - init_vector_y(y); - solve_By_when_y_is_ready_for_X(y); -} - -template -void lu::solve_By_when_y_is_ready_for_X(vector & y) { - if (numeric_traits::precise()) { - m_U.solve_U_y(y); - m_R.apply_reverse_from_left_to_X(y); // see 24.3 from Chvatal - return; - } - m_U.double_solve_U_y(y); - m_R.apply_reverse_from_left_to_X(y); // see 24.3 from Chvatal - unsigned i = m_dim; - while (i--) { - if (is_zero(y[i])) continue; - if (m_settings.abs_val_is_smaller_than_drop_tolerance(y[i])){ - y[i] = zero_of_type(); - } - } -} - -template -void lu::solve_By_when_y_is_ready_for_T(vector & y, vector & index) { - if (numeric_traits::precise()) { - m_U.solve_U_y(y); - m_R.apply_reverse_from_left_to_T(y); // see 24.3 from Chvatal - unsigned j = m_dim; - while (j--) { - if (!is_zero(y[j])) - index.push_back(j); - } - return; - } - m_U.double_solve_U_y(y); - m_R.apply_reverse_from_left_to_T(y); // see 24.3 from Chvatal - unsigned i = m_dim; - while (i--) { - if (is_zero(y[i])) continue; - if (m_settings.abs_val_is_smaller_than_drop_tolerance(y[i])){ - y[i] = zero_of_type(); - } else { - index.push_back(i); - } - } -} - -template -void lu::solve_By_for_T_indexed_only(indexed_vector & y, const lp_settings & settings) { - if (numeric_traits::precise()) { - vector active_rows; - m_U.solve_U_y_indexed_only(y, settings, active_rows); - m_R.apply_reverse_from_left(y); // see 24.3 from Chvatal - return; - } - m_U.double_solve_U_y(y, m_settings); - m_R.apply_reverse_from_left(y); // see 24.3 from Chvatal -} - -template -void lu::print_matrix_compact(std::ostream & f) { - f << "matrix_start" << std::endl; - f << "nrows " << m_A.row_count() << std::endl; - f << "ncolumns " << m_A.column_count() << std::endl; - for (unsigned i = 0; i < m_A.row_count(); i++) { - auto & row = m_A.m_rows[i]; - f << "row " << i << std::endl; - for (auto & t : row) { - f << "column " << t.m_j << " value " << t.m_value << std::endl; - } - f << "row_end" << std::endl; - } - f << "matrix_end" << std::endl; -} -template -void lu< M>::print(indexed_vector & w, const vector& basis) { - std::string dump_file_name("/tmp/lu"); - remove(dump_file_name.c_str()); - std::ofstream f(dump_file_name); - if (!f.is_open()) { - LP_OUT(m_settings, "cannot open file " << dump_file_name << std::endl); - return; - } - LP_OUT(m_settings, "writing lu dump to " << dump_file_name << std::endl); - print_matrix_compact(f); - print_vector(basis, f); - print_indexed_vector(w, f); - f.close(); -} - -template -void lu< M>::solve_Bd_faster(unsigned a_column, indexed_vector & d) { // puts the a_column into d - init_vector_w(a_column, d); - solve_By_for_T_indexed_only(d, m_settings); -} - -template -void lu< M>::solve_yB_indexed(indexed_vector& y) { - lp_assert(y.is_OK()); - // first solve yU = cb*R(-1) - m_R.apply_reverse_from_right_to_T(y); // got y = cb*R(-1) - lp_assert(y.is_OK()); - m_U.solve_y_U_indexed(y, m_settings); // got y*U=cb*R(-1) - lp_assert(y.is_OK()); - m_Q.apply_reverse_from_right_to_T(y); - lp_assert(y.is_OK()); - for (auto e = m_tail.rbegin(); e != m_tail.rend(); ++e) { -#ifdef Z3DEBUG - (*e)->set_number_of_columns(m_dim); -#endif - (*e)->apply_from_right(y); - lp_assert(y.is_OK()); - } -} - -template -void lu< M>::add_delta_to_solution(const vector& yc, vector& y){ - unsigned i = static_cast(y.size()); - while (i--) - y[i]+=yc[i]; -} - -template -void lu< M>::add_delta_to_solution_indexed(indexed_vector& y) { - // the delta sits in m_y_copy, put result into y - lp_assert(y.is_OK()); - lp_assert(m_y_copy.is_OK()); - m_ii.clear(); - m_ii.resize(y.data_size()); - for (unsigned i : y.m_index) - m_ii.set_value(1, i); - for (unsigned i : m_y_copy.m_index) { - y.m_data[i] += m_y_copy[i]; - if (m_ii[i] == 0) - m_ii.set_value(1, i); - } - lp_assert(m_ii.is_OK()); - y.m_index.clear(); - - for (unsigned i : m_ii.m_index) { - T & v = y.m_data[i]; - if (!lp_settings::is_eps_small_general(v, 1e-14)) - y.m_index.push_back(i); - else if (!numeric_traits::is_zero(v)) - v = zero_of_type(); - } - - lp_assert(y.is_OK()); -} - -template -void lu< M>::find_error_of_yB(vector& yc, const vector& y, const vector& m_basis) { - unsigned i = m_dim; - while (i--) { - yc[i] -= m_A.dot_product_with_column(y, m_basis[i]); - } -} - -template -void lu< M>::find_error_of_yB_indexed(const indexed_vector& y, const vector& heading, const lp_settings& settings) { -#if 0 == 1 - // it is a non efficient version - indexed_vector yc = m_y_copy; - yc.m_index.clear(); - lp_assert(!numeric_traits::precise()); - { - - vector d_basis(y.m_data.size()); - for (unsigned j = 0; j < heading.size(); j++) { - if (heading[j] >= 0) { - d_basis[heading[j]] = j; - } - } - - - unsigned i = m_dim; - while (i--) { - T & v = yc.m_data[i] -= m_A.dot_product_with_column(y.m_data, d_basis[i]); - if (settings.abs_val_is_smaller_than_drop_tolerance(v)) - v = zero_of_type(); - else - yc.m_index.push_back(i); - } - } -#endif - lp_assert(m_ii.is_OK()); - m_ii.clear(); - m_ii.resize(y.data_size()); - lp_assert(m_y_copy.is_OK()); - // put the error into m_y_copy - for (auto k : y.m_index) { - auto & row = m_A.m_rows[k]; - const T & y_k = y.m_data[k]; - for (auto & c : row) { - unsigned j = c.var(); - int hj = heading[j]; - if (hj < 0) continue; - if (m_ii.m_data[hj] == 0) - m_ii.set_value(1, hj); - m_y_copy.m_data[hj] -= c.coeff() * y_k; - } - } - // add the index of m_y_copy to m_ii - for (unsigned i : m_y_copy.m_index) { - if (m_ii.m_data[i] == 0) - m_ii.set_value(1, i); - } - - // there is no guarantee that m_y_copy is OK here, but its index - // is contained in m_ii index - m_y_copy.m_index.clear(); - // setup the index of m_y_copy - for (auto k : m_ii.m_index) { - T& v = m_y_copy.m_data[k]; - if (settings.abs_val_is_smaller_than_drop_tolerance(v)) - v = zero_of_type(); - else { - m_y_copy.set_value(v, k); - } - } - lp_assert(m_y_copy.is_OK()); - -} - - - - -// solves y*B = y -// y is the input -template -void lu< M>::solve_yB_with_error_check_indexed(indexed_vector & y, const vector& heading, const vector & basis, const lp_settings & settings) { - lp_assert(false); - } - - -// solves y*B = y -// y is the input -template -void lu< M>::solve_yB_with_error_check(vector & y, const vector& basis) { - lp_assert(false); -} -template -void lu< M>::apply_Q_R_to_U(permutation_matrix & r_wave) { - m_U.multiply_from_right(r_wave); - m_U.multiply_from_left_with_reverse(r_wave); -} - - -// Solving yB = cb to find the entering variable, -// where cb is the cost vector projected to B. -// The result is stored in cb. - -// solving Bd = a ( to find the column d of B^{-1} A_N corresponding to the entering -// variable -template -lu< M>::~lu(){ - for (auto t : m_tail) { - delete t; - } -} -template -void lu< M>::init_vector_y(vector & y) { - apply_lp_list_to_y(y); - m_Q.apply_reverse_from_left_to_X(y); -} - -template -void lu< M>::perform_transformations_on_w(indexed_vector& w) { - apply_lp_list_to_w(w); - m_Q.apply_reverse_from_left(w); - // TBD does not compile: lp_assert(numeric_traits::precise() || check_vector_for_small_values(w, m_settings)); -} - -// see Chvatal 24.3 -template -void lu< M>::init_vector_w(unsigned entering, indexed_vector & w) { - w.clear(); - m_A.copy_column_to_indexed_vector(entering, w); // w = a, the column - perform_transformations_on_w(w); -} -template -void lu< M>::apply_lp_list_to_w(indexed_vector & w) { - for (unsigned i = 0; i < m_tail.size(); i++) { - m_tail[i]->apply_from_left_to_T(w, m_settings); - // TBD does not compile: lp_assert(check_vector_for_small_values(w, m_settings)); - } -} -template -void lu< M>::apply_lp_list_to_y(vector& y) { - for (unsigned i = 0; i < m_tail.size(); i++) { - m_tail[i]->apply_from_left(y, m_settings); - } -} -template -void lu< M>::swap_rows(int j, int k) { - if (j != k) { - m_Q.transpose_from_left(j, k); - m_U.swap_rows(j, k); - } -} - -template -void lu< M>::swap_columns(int j, int pivot_column) { - if (j == pivot_column) - return; - m_R.transpose_from_right(j, pivot_column); - m_U.swap_columns(j, pivot_column); -} -template -bool lu< M>::pivot_the_row(int row) { - eta_matrix * eta_matrix = get_eta_matrix_for_pivot(row); - if (get_status() != LU_status::OK) { - return false; - } - - if (eta_matrix == nullptr) { - m_U.shorten_active_matrix(row, nullptr); - return true; - } - if (!m_U.pivot_with_eta(row, eta_matrix, m_settings)) - return false; - eta_matrix->conjugate_by_permutation(m_Q); - push_matrix_to_tail(eta_matrix); - return true; -} -// we're processing the column j now -template -eta_matrix * lu< M>::get_eta_matrix_for_pivot(unsigned j) { - eta_matrix *ret; - if(!m_U.fill_eta_matrix(j, &ret)) { - set_status(LU_status::Degenerated); - } - return ret; -} -// we're processing the column j now -template -eta_matrix * lu::get_eta_matrix_for_pivot(unsigned j, square_sparse_matrix& copy_of_U) { - eta_matrix *ret; - copy_of_U.fill_eta_matrix(j, &ret); - return ret; -} - -// see page 407 of Chvatal -template -unsigned lu::transform_U_to_V_by_replacing_column(indexed_vector & w, - unsigned leaving_column) { - unsigned column_to_replace = m_R.apply_reverse(leaving_column); - m_U.replace_column(column_to_replace, w, m_settings); - return column_to_replace; -} - -#ifdef Z3DEBUG -template -void lu::check_vector_w(unsigned entering) { - T * w = new T[m_dim]; - m_A.copy_column_to_vector(entering, w); - check_apply_lp_lists_to_w(w); - delete [] w; -} -template -void lu::check_apply_matrix_to_vector(matrix *lp, T *w) { - if (lp != nullptr) { - lp -> set_number_of_rows(m_dim); - lp -> set_number_of_columns(m_dim); - apply_to_vector(*lp, w); - } -} - -template -void lu::check_apply_lp_lists_to_w(T * w) { - for (unsigned i = 0; i < m_tail.size(); i++) { - check_apply_matrix_to_vector(m_tail[i], w); - } - permutation_matrix qr = m_Q.get_reverse(); - apply_to_vector(qr, w); - for (int i = m_dim - 1; i >= 0; i--) { - lp_assert(abs(w[i] - w[i]) < 0.0000001); - } -} - -#endif -template -void lu::process_column(int j) { - unsigned pi, pj; - bool success = m_U.get_pivot_for_column(pi, pj, m_settings.c_partial_pivoting, j); - if (!success) { - // LP_OUT(m_settings, "get_pivot returned false: cannot find the pivot for column " << j << std::endl); - m_failure = true; - return; - } - - if (static_cast(pi) == -1) { - // LP_OUT(m_settings, "cannot find the pivot for column " << j << std::endl); - m_failure = true; - return; - } - swap_columns(j, pj); - swap_rows(j, pi); - if (!pivot_the_row(j)) { - // LP_OUT(m_settings, "pivot_the_row(" << j << ") failed" << std::endl); - m_failure = true; - } -} -template -bool lu::is_correct(const vector& basis) { -return true; -} - -template -bool lu::is_correct() { - return true; -} - - -// needed for debugging purposes -template -void lu::copy_w(T *buffer, indexed_vector & w) { - -} - -// needed for debugging purposes -template -void lu::restore_w(T *buffer, indexed_vector & w) { - -} -template -bool lu::all_columns_and_rows_are_active() { - return true; -} -template -bool lu::too_dense(unsigned j) const { - return false; -} -template -void lu::pivot_in_dense_mode(unsigned i) { - -} -template -void lu::create_initial_factorization(){ - -} - -template -void lu::calculate_r_wave_and_update_U(unsigned bump_start, unsigned bump_end, permutation_matrix & r_wave) { - if (bump_start > bump_end) { - set_status(LU_status::Degenerated); - return; - } - if (bump_start == bump_end) { - return; - } - - r_wave[bump_start] = bump_end; // sending the offensive column to the end of the bump - - for ( unsigned i = bump_start + 1 ; i <= bump_end; i++ ) { - r_wave[i] = i - 1; - } - - m_U.multiply_from_right(r_wave); - m_U.multiply_from_left_with_reverse(r_wave); -} -template -void lu::scan_last_row_to_work_vector(unsigned lowest_row_of_the_bump) { - vector> & last_row_vec = m_U.get_row_values(m_U.adjust_row(lowest_row_of_the_bump)); - for (auto & iv : last_row_vec) { - if (is_zero(iv.m_value)) continue; - lp_assert(!m_settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value)); - unsigned adjusted_col = m_U.adjust_column_inverse(iv.m_index); - if (adjusted_col < lowest_row_of_the_bump) { - m_row_eta_work_vector.set_value(-iv.m_value, adjusted_col); - } else { - m_row_eta_work_vector.set_value(iv.m_value, adjusted_col); // preparing to calculate the real value in the matrix - } - } -} - -template -void lu::pivot_and_solve_the_system(unsigned replaced_column, unsigned lowest_row_of_the_bump) { - // we have the system right side at m_row_eta_work_vector now - // solve the system column wise - for (unsigned j = replaced_column; j < lowest_row_of_the_bump; j++) { - T v = m_row_eta_work_vector[j]; - if (numeric_traits::is_zero(v)) continue; // this column does not contribute to the solution - unsigned aj = m_U.adjust_row(j); - vector> & row = m_U.get_row_values(aj); - for (auto & iv : row) { - unsigned col = m_U.adjust_column_inverse(iv.m_index); - lp_assert(col >= j || numeric_traits::is_zero(iv.m_value)); - if (col == j) continue; - if (numeric_traits::is_zero(iv.m_value)) { - continue; - } - // the -v is for solving the system ( to zero the last row), and +v is for pivoting - T delta = col < lowest_row_of_the_bump? -v * iv.m_value: v * iv.m_value; - lp_assert(numeric_traits::is_zero(delta) == false); - - - - // m_row_eta_work_vector.add_value_at_index_with_drop_tolerance(col, delta); - if (numeric_traits::is_zero(m_row_eta_work_vector[col])) { - if (!m_settings.abs_val_is_smaller_than_drop_tolerance(delta)){ - m_row_eta_work_vector.set_value(delta, col); - } - } else { - T t = (m_row_eta_work_vector[col] += delta); - if (m_settings.abs_val_is_smaller_than_drop_tolerance(t)){ - m_row_eta_work_vector[col] = numeric_traits::zero(); - auto it = std::find(m_row_eta_work_vector.m_index.begin(), m_row_eta_work_vector.m_index.end(), col); - if (it != m_row_eta_work_vector.m_index.end()) - m_row_eta_work_vector.m_index.erase(it); - } - } - } - } -} - -template -void lu::replace_column(T pivot_elem_for_checking, indexed_vector & w, unsigned leaving_column_of_U){ - lp_assert(false); -} -template -void lu::calculate_Lwave_Pwave_for_bump(unsigned replaced_column, unsigned lowest_row_of_the_bump){ - lp_assert(false);// lp_assert(m_U.is_upper_triangular_and_maximums_are_set_correctly_in_rows(m_settings)); -} - -template -void lu::calculate_Lwave_Pwave_for_last_row(unsigned lowest_row_of_the_bump, T diagonal_element) { - lp_assert(false); -} - -template -void init_factorization(lu* & factorization, M & m_A, vector & m_basis, lp_settings &m_settings) { - lp_assert(false); -} - -#ifdef Z3DEBUG -template -dense_matrix get_B(lu& f, const vector& basis) { - lp_assert(false); - - dense_matrix B(0, 0); - return B; -} -template -dense_matrix get_B(lu& f) { - lp_assert(false); - dense_matrix B(0,0); - return B; -} -#endif -} diff --git a/src/math/lp/row_eta_matrix.cpp b/src/math/lp/row_eta_matrix.cpp index 6fafb83ed6a..356f80b3c01 100644 --- a/src/math/lp/row_eta_matrix.cpp +++ b/src/math/lp/row_eta_matrix.cpp @@ -20,7 +20,6 @@ Revision History: #include #include "util/vector.h" #include "math/lp/row_eta_matrix_def.h" -#include "math/lp/lu.h" namespace lp { template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); template void row_eta_matrix >::conjugate_by_permutation(permutation_matrix >&); diff --git a/src/math/lp/square_sparse_matrix.cpp b/src/math/lp/square_sparse_matrix.cpp index 35d38e52944..3ec88f47d85 100644 --- a/src/math/lp/square_sparse_matrix.cpp +++ b/src/math/lp/square_sparse_matrix.cpp @@ -20,7 +20,6 @@ Revision History: #include #include "util/vector.h" #include "math/lp/lp_settings.h" -#include "math/lp/lu.h" #include "math/lp/square_sparse_matrix_def.h" #include "math/lp/dense_matrix.h" namespace lp { diff --git a/src/math/lp/square_sparse_matrix_def.h b/src/math/lp/square_sparse_matrix_def.h index 3533ba066b5..19263462717 100644 --- a/src/math/lp/square_sparse_matrix_def.h +++ b/src/math/lp/square_sparse_matrix_def.h @@ -21,6 +21,8 @@ Revision History: #include "util/vector.h" #include "math/lp/square_sparse_matrix.h" +#include "math/lp/dense_matrix.h" + #include #include namespace lp { diff --git a/src/smt/theory_lra.cpp b/src/smt/theory_lra.cpp index 2aa988282d2..3eda1ddff43 100644 --- a/src/smt/theory_lra.cpp +++ b/src/smt/theory_lra.cpp @@ -3126,7 +3126,7 @@ class theory_lra::imp { return l_false; TRACE("arith", tout << "status treated as inconclusive: " << status << "\n";); // TENTATIVE_UNBOUNDED, UNBOUNDED, TENTATIVE_DUAL_UNBOUNDED, DUAL_UNBOUNDED, - // FLOATING_POINT_ERROR, TIME_EXAUSTED, EMPTY, UNSTABLE + // TIME_EXAUSTED, EMPTY, UNSTABLE return l_undef; } From 0784243efd729aaef9763467cbfb23dd0c21cc44 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 09:51:10 -0800 Subject: [PATCH 14/36] cleanup --- src/math/lp/lar_core_solver_def.h | 5 +- src/math/lp/lp_core_solver_base.h | 12 ---- src/math/lp/lp_core_solver_base_def.h | 34 +---------- src/math/lp/lp_primal_core_solver.cpp | 1 - src/math/lp/lp_primal_core_solver.h | 4 -- src/math/lp/lp_primal_core_solver_def.h | 58 ++----------------- .../lp/lp_primal_core_solver_tableau_def.h | 6 +- src/math/lp/lp_settings.h | 1 - 8 files changed, 9 insertions(+), 112 deletions(-) diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index 22dc23bd512..fe99a202f71 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -51,8 +51,6 @@ void lar_core_solver::prefix_r() { // m_r_solver.m_b.resize(m_r_solver.m_m()); if (m_r_solver.m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows) { - if(m_r_solver.m_settings.use_breakpoints_in_feasibility_search) - m_r_solver.m_breakpoint_indices_queue.resize(m_r_solver.m_n()); m_r_solver.m_costs.resize(m_r_solver.m_n()); m_r_solver.m_d.resize(m_r_solver.m_n()); m_r_solver.set_using_infeas_costs(true); @@ -61,7 +59,6 @@ void lar_core_solver::prefix_r() { void lar_core_solver::prefix_d() { // m_d_solver.m_b.resize(m_d_solver.m_m()); - m_d_solver.m_breakpoint_indices_queue.resize(m_d_solver.m_n()); m_d_solver.m_copy_of_xB.resize(m_d_solver.m_n()); m_d_solver.m_costs.resize(m_d_solver.m_n()); m_d_solver.m_d.resize(m_d_solver.m_n()); @@ -91,7 +88,7 @@ void lar_core_solver::fill_not_improvable_zero_sum() { return; } // reusing the existing mechanism for row_feasibility_loop - m_infeasible_sum_sign = m_r_solver.m_settings.use_breakpoints_in_feasibility_search? -1 : 1; + m_infeasible_sum_sign = 1; m_infeasible_linear_combination.clear(); for (auto j : m_r_solver.m_basis) { const mpq & cost_j = m_r_solver.m_costs[j]; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 0e8a2abdf3a..5f723c1185f 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -159,15 +159,8 @@ class lp_core_solver_base { lp_status get_status() const{ return m_status; } - - void fill_cb(T * y) const; - - void fill_cb(vector & y) const; - void pretty_print(std::ostream & out); - - X get_cost() const { return dot_product(m_costs, m_x); } @@ -176,11 +169,6 @@ class lp_core_solver_base { void restore_m_w(T * buffer); - // needed for debugging - void copy_m_ed(T * buffer); - - void restore_m_ed(T * buffer); - void add_delta_to_entering(unsigned entering, const X & delta); const X & get_var_value(unsigned j) const { diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 01aa9802e8c..8b87728e090 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -101,20 +101,7 @@ pivot_to_reduced_costs_tableau(unsigned i, unsigned j) { } -template void lp_core_solver_base:: -fill_cb(T * y) const { - for (unsigned i = 0; i < m_m(); i++) { - y[i] = m_costs[m_basis[i]]; - } -} - -template void lp_core_solver_base:: -fill_cb(vector & y) const { - for (unsigned i = 0; i < m_m(); i++) { - y[i] = m_costs[m_basis[i]]; - } -} // template void lp_core_solver_base:: @@ -155,25 +142,6 @@ restore_m_w(T * buffer) { } } -// needed for debugging -template void lp_core_solver_base:: -copy_m_ed(T * buffer) { - unsigned i = m_m(); - while (i --) { - buffer[i] = m_ed[i]; - } -} - -template void lp_core_solver_base:: -restore_m_ed(T * buffer) { - unsigned i = m_m(); - while (i --) { - m_ed[i] = buffer[i]; - } -} - - - template void lp_core_solver_base:: add_delta_to_entering(unsigned entering, const X& delta) { @@ -682,7 +650,7 @@ lp_core_solver_base::infeasibility_costs_are_correct() const { template bool lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) const { - T r = (!this->m_settings.use_breakpoints_in_feasibility_search)? -one_of_type(): one_of_type(); + T r = -one_of_type(); switch (this->m_column_types[j]) { case column_type::fixed: diff --git a/src/math/lp/lp_primal_core_solver.cpp b/src/math/lp/lp_primal_core_solver.cpp index 8a4359806a3..f4597da762c 100644 --- a/src/math/lp/lp_primal_core_solver.cpp +++ b/src/math/lp/lp_primal_core_solver.cpp @@ -34,7 +34,6 @@ template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver::solve_with_tableau(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver >::solve(); -template void lp::lp_primal_core_solver::clear_breakpoints(); template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lp::mpq const&); template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); template bool lp::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lp::numeric_pair const&); diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 38a2aa5f5e0..0a182ad9175 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -47,8 +47,6 @@ class lp_primal_core_solver:public lp_core_solver_base { unsigned m_column_norm_update_counter; T m_enter_price_eps; int m_sign_of_entering_delta; - vector> m_breakpoints; - binary_heap_priority_queue m_breakpoint_indices_queue; indexed_vector m_beta; // see Swietanowski working vector beta for column norms T m_epsilon_of_reduced_cost; vector m_costs_backup; @@ -545,8 +543,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void try_add_breakpoint_in_row(unsigned i); - void clear_breakpoints(); - void change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 3967b6e6698..5d4a662cff7 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -112,8 +112,6 @@ template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsigned j) const { if (numeric_traits::precise()) return column_is_benefitial_for_entering_basis_precise(j); - if (this->using_infeas_costs() && this->m_settings.use_breakpoints_in_feasibility_search) - return column_is_benefitial_for_entering_on_breakpoints(j); const T& dj = this->m_d[j]; switch (this->m_column_types[j]) { case column_type::fixed: break; @@ -146,8 +144,6 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsign template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { lp_assert (numeric_traits::precise()); - if (this->using_infeas_costs() && this->m_settings.use_breakpoints_in_feasibility_search) - return column_is_benefitial_for_entering_on_breakpoints(j); const T& dj = this->m_d[j]; TRACE("lar_solver", tout << "dj=" << dj << "\n";); switch (this->m_column_types[j]) { @@ -219,8 +215,6 @@ int lp_primal_core_solver::choose_entering_column_presize(unsigned number_ return -1; unsigned entering = *entering_iter; m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1; - if (this->using_infeas_costs() && this->m_settings.use_breakpoints_in_feasibility_search) - m_sign_of_entering_delta = -m_sign_of_entering_delta; m_non_basis_list.erase(entering_iter); m_non_basis_list.push_back(entering); return entering; @@ -259,8 +253,6 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef if (entering_iter != m_non_basis_list.end()) { unsigned entering = *entering_iter; m_sign_of_entering_delta = this->m_d[entering] > 0? 1 : -1; - if (this->using_infeas_costs() && this->m_settings.use_breakpoints_in_feasibility_search) - m_sign_of_entering_delta = - m_sign_of_entering_delta; m_non_basis_list.erase(entering_iter); m_non_basis_list.push_back(entering); return entering; @@ -268,28 +260,6 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef return -1; } -template int lp_primal_core_solver::advance_on_sorted_breakpoints(unsigned entering, X &t) { - T slope_at_entering = this->m_d[entering]; - breakpoint * last_bp = nullptr; - lp_assert(m_breakpoint_indices_queue.is_empty()==false); - while (m_breakpoint_indices_queue.is_empty() == false) { - unsigned bi = m_breakpoint_indices_queue.dequeue(); - breakpoint *b = &m_breakpoints[bi]; - change_slope_on_breakpoint(entering, b, slope_at_entering); - last_bp = b; - if (slope_at_entering * m_sign_of_entering_delta > - m_epsilon_of_reduced_cost) { // the slope started to increase infeasibility - break; - } else { - if ((numeric_traits::precise() == false) || ( numeric_traits::is_zero(slope_at_entering) && this->m_settings.random_next() % 2 == 0)) { - // it is not cost beneficial to advance the delta more, so just break to increase the randomness - break; - } - } - } - lp_assert (last_bp != nullptr); - t = last_bp->m_delta; - return last_bp->m_j; -} template int @@ -406,8 +376,6 @@ try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t ) { } template int lp_primal_core_solver::find_leaving_and_t_precise(unsigned entering, X & t) { - if (this->m_settings.use_breakpoints_in_feasibility_search && !this->current_x_is_feasible()) - return find_leaving_and_t_with_breakpoints(entering, t); bool unlimited = true; unsigned steps = this->m_ed.m_index.size(); unsigned k = this->m_settings.random_next() % steps; @@ -472,8 +440,6 @@ template int lp_primal_core_solver::find_leaving_ template int lp_primal_core_solver::find_leaving_and_t(unsigned entering, X & t) { - if (this->m_settings.use_breakpoints_in_feasibility_search && !this->current_x_is_feasible()) - return find_leaving_and_t_with_breakpoints(entering, t); X theta = zero_of_type(); bool unlimited = get_harris_theta(theta); lp_assert(unlimited || theta >= zero_of_type()); @@ -584,7 +550,7 @@ void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned e this->m_d[j] -= dq * this->m_pivot_row[j]; } this->m_d[leaving] = -dq; - if (this->current_x_is_infeasible() && !this->m_settings.use_breakpoints_in_feasibility_search) { + if (this->current_x_is_infeasible()) { this->m_d[leaving] -= this->m_costs[leaving]; this->m_costs[leaving] = zero_of_type(); } @@ -833,14 +799,7 @@ template void lp_primal_core_solver::one_iteratio } - -template void lp_primal_core_solver::clear_breakpoints() { - m_breakpoints.clear(); - m_breakpoint_indices_queue.clear(); -} - template void lp_primal_core_solver::fill_breakpoints_array(unsigned entering) { - clear_breakpoints(); for (unsigned i : this->m_ed.m_index) try_add_breakpoint_in_row(i); @@ -924,9 +883,8 @@ lp_primal_core_solver::get_infeasibility_cost_for_column(unsigned j) const break; } - if (!this->m_settings.use_breakpoints_in_feasibility_search) { - ret = - ret; - } + ret = - ret; + return ret; } @@ -982,9 +940,8 @@ lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { } else { this->insert_column_into_inf_set(j); } - if (!this->m_settings.use_breakpoints_in_feasibility_search) { - this->m_costs[j] = - this->m_costs[j]; - } + this->m_costs[j] = - this->m_costs[j]; + } @@ -1009,10 +966,7 @@ template void lp_primal_core_solver::print_column } } -template void lp_primal_core_solver::add_breakpoint(unsigned j, X delta, breakpoint_type type) { - m_breakpoints.push_back(breakpoint(j, delta, type)); - m_breakpoint_indices_queue.enqueue(m_breakpoint_indices_queue.size(), abs(delta)); -} + // j is the basic column, x is the value at x[j] // d is the coefficient before m_entering in the row with j as the basis column diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index e742b0cd01a..b63c54bfd10 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -88,8 +88,6 @@ template int lp_primal_core_solver::choose_enteri return -1; unsigned entering = *entering_iter; m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1; - if (this->using_infeas_costs() && this->m_settings.use_breakpoints_in_feasibility_search) - m_sign_of_entering_delta = -m_sign_of_entering_delta; m_non_basis_list.erase(entering_iter); m_non_basis_list.push_back(entering); return entering; @@ -188,7 +186,7 @@ template void lp_primal_core_solver::advance_on_en return; } if (!is_zero(t)) { - if (this->current_x_is_feasible() || !this->m_settings.use_breakpoints_in_feasibility_search ) { + if (this->current_x_is_feasible() ) { if (m_sign_of_entering_delta == -1) t = -t; } @@ -297,8 +295,6 @@ template void lp_primal_core_solver::init_run_tab if (this->m_settings.backup_costs) backup_and_normalize_costs(); m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); - if (this->m_settings.use_breakpoints_in_feasibility_search) - m_breakpoint_indices_queue.resize(this->m_n()); if (!numeric_traits::precise()) { this->m_column_norm_update_counter = 0; init_column_norms(); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index cb60eebc9c5..38270230e7e 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -223,7 +223,6 @@ struct lp_settings { unsigned column_norms_update_frequency { 12000 }; bool scale_with_ratio { true }; double density_threshold { 0.7 }; - bool use_breakpoints_in_feasibility_search { false }; unsigned max_row_length_for_bound_propagation { 300 }; bool backup_costs { true }; unsigned column_number_threshold_for_using_lu_in_lar_solver { 4000 }; From 5379fb820c5ac808b3690baafb7b526858184ae0 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 09:59:32 -0800 Subject: [PATCH 15/36] rm breakpoints --- src/math/lp/breakpoint.h | 35 ------ src/math/lp/lar_core_solver.h | 6 - src/math/lp/lp_primal_core_solver.h | 66 +--------- src/math/lp/lp_primal_core_solver_def.h | 161 ------------------------ 4 files changed, 1 insertion(+), 267 deletions(-) delete mode 100644 src/math/lp/breakpoint.h diff --git a/src/math/lp/breakpoint.h b/src/math/lp/breakpoint.h deleted file mode 100644 index 40fab293f88..00000000000 --- a/src/math/lp/breakpoint.h +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once - -namespace lp { -enum breakpoint_type { - low_break, upper_break, fixed_break -}; -template -struct breakpoint { - unsigned m_j; // the basic column - breakpoint_type m_type; - X m_delta; - breakpoint(){} - breakpoint(unsigned j, X delta, breakpoint_type type):m_j(j), m_type(type), m_delta(delta) {} -}; -} diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 9168862c651..d9379cb9d3f 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -13,7 +13,6 @@ Copyright (c) 2017 Microsoft Corporation #include #include "math/lp/indexed_vector.h" #include "math/lp/binary_heap_priority_queue.h" -#include "math/lp/breakpoint.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/stacked_vector.h" #include "math/lp/lar_solution_signature.h" @@ -96,11 +95,6 @@ class lar_core_solver { m_r_solver.print_column_bound_info(m_r_solver.m_basis[row_index], out); } - - void advance_on_sorted_breakpoints(unsigned entering); - - void change_slope_on_breakpoint(unsigned entering, breakpoint> * b, mpq & slope_at_entering); - bool row_is_infeasible(unsigned row); bool row_is_evidence(unsigned row); diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 0a182ad9175..2c7360712d6 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -32,7 +32,6 @@ Revision History: #include "math/lp/static_matrix.h" #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/lp_core_solver_base.h" -#include "math/lp/breakpoint.h" #include "math/lp/binary_heap_priority_queue.h" #include "math/lp/u_set.h" namespace lp { @@ -64,47 +63,7 @@ class lp_primal_core_solver:public lp_core_solver_base { int choose_entering_column(unsigned number_of_benefitial_columns_to_go_over); int choose_entering_column_tableau(); int choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over); - int find_leaving_and_t_with_breakpoints(unsigned entering, X & t); - // int find_inf_row() { - // // mimicing CLP : todo : use a heap - // int j = -1; - // for (unsigned k : this->m_inf_set.m_index) { - // if (k < static_cast(j)) - // j = static_cast(k); - // } - // if (j == -1) - // return -1; - // return this->m_basis_heading[j]; - // #if 0 - // vector choices; - // unsigned len = 100000000; - // for (unsigned j : this->m_inf_set.m_index) { - // int i = this->m_basis_heading[j]; - // lp_assert(i >= 0); - // unsigned row_len = this->m_A.m_rows[i].size(); - // if (row_len < len) { - // choices.clear(); - // choices.push_back(i); - // len = row_len; - // if (m_settings.random_next() % 10) break; - // } else if (row_len == len) { - // choices.push_back(i); - // if (m_settings.random_next() % 10) break; - // } - // } - - // if (choices.size() == 0) - // return -1; - - // if (choices.size() == 1) - // return choices[0]; - - // unsigned k = this->m_settings.random_next() % choices.size(); - // return choices[k]; - // #endif - // } - - + bool column_is_benefitial_for_entering_basis_on_sign_row_strategy(unsigned j, int sign) const { // sign = 1 means the x of the basis column of the row has to grow to become feasible, when the coeff before j is neg, or x - has to diminish when the coeff is pos // we have xbj = -aj * xj @@ -538,16 +497,7 @@ class lp_primal_core_solver:public lp_core_solver_base { if (this->current_x_is_feasible()) this->set_status(lp_status::OPTIMAL); } - - void fill_breakpoints_array(unsigned entering); - - void try_add_breakpoint_in_row(unsigned i); - - void change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering); - - - void decide_on_status_when_cannot_find_entering() { lp_assert(!need_to_switch_costs()); this->set_status(this->current_x_is_feasible()? lp_status::OPTIMAL: lp_status::INFEASIBLE); @@ -772,10 +722,6 @@ class lp_primal_core_solver:public lp_core_solver_base { bool column_is_benefitial_for_entering_basis(unsigned j) const; bool column_is_benefitial_for_entering_basis_precise(unsigned j) const; - - bool column_is_benefitial_for_entering_on_breakpoints(unsigned j) const; - - bool can_enter_basis(unsigned j); bool done(); void init_infeasibility_costs(); @@ -785,26 +731,16 @@ class lp_primal_core_solver:public lp_core_solver_base { void init_infeasibility_costs_for_changed_basis_only(); void print_column(unsigned j, std::ostream & out); - void add_breakpoint(unsigned j, X delta, breakpoint_type type); - // j is the basic column, x is the value at x[j] // d is the coefficient before m_entering in the row with j as the basis column - void try_add_breakpoint(unsigned j, const X & x, const T & d, breakpoint_type break_type, const X & break_value); template bool same_sign_with_entering_delta(const L & a) { return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); } - bool lower_bounds_are_set() const override { return true; } - int advance_on_sorted_breakpoints(unsigned entering, X & t); - - std::string break_type_to_string(breakpoint_type type); - - void print_breakpoint(const breakpoint * b, std::ostream & out); - void print_bound_info_and_x(unsigned j, std::ostream & out); void init_infeasibility_after_update_x_if_inf(unsigned leaving) { diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 5d4a662cff7..7a027f8d38c 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -75,39 +75,6 @@ void lp_primal_core_solver::sort_non_basis() { } } -template -bool lp_primal_core_solver::column_is_benefitial_for_entering_on_breakpoints(unsigned j) const { - bool ret; - const T & d = this->m_d[j]; - switch (this->m_column_types[j]) { - case column_type::lower_bound: - lp_assert(this->x_is_at_lower_bound(j)); - ret = d < -m_epsilon_of_reduced_cost; - break; - case column_type::upper_bound: - lp_assert(this->x_is_at_upper_bound(j)); - ret = d > m_epsilon_of_reduced_cost; - break; - case column_type::fixed: - ret = false; - break; - case column_type::boxed: - { - bool lower_bound = this->x_is_at_lower_bound(j); - lp_assert(lower_bound || this->x_is_at_upper_bound(j)); - ret = (lower_bound && d < -m_epsilon_of_reduced_cost) || ((!lower_bound) && d > m_epsilon_of_reduced_cost); - } - break; - case column_type::free_column: - ret = d > m_epsilon_of_reduced_cost || d < - m_epsilon_of_reduced_cost; - break; - default: - lp_unreachable(); - ret = false; - break; - } - return ret; -} template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsigned j) const { if (numeric_traits::precise()) @@ -261,14 +228,6 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef } - -template int -lp_primal_core_solver::find_leaving_and_t_with_breakpoints(unsigned entering, X & t){ - lp_assert(this->precise() == false); - fill_breakpoints_array(entering); - return advance_on_sorted_breakpoints(entering, t); -} - template bool lp_primal_core_solver::get_harris_theta(X & theta) { lp_assert(this->m_ed.is_OK()); bool unlimited = true; @@ -799,19 +758,6 @@ template void lp_primal_core_solver::one_iteratio } -template void lp_primal_core_solver::fill_breakpoints_array(unsigned entering) { - for (unsigned i : this->m_ed.m_index) - try_add_breakpoint_in_row(i); - - if (this->m_column_types[entering] == column_type::boxed) { - if (m_sign_of_entering_delta < 0) - add_breakpoint(entering, - this->bound_span(entering), low_break); - else - add_breakpoint(entering, this->bound_span(entering), upper_break); - } -} - - template bool lp_primal_core_solver::done() { if (this->get_status() == lp_status::OPTIMAL) return true; @@ -893,9 +839,6 @@ lp_primal_core_solver::get_infeasibility_cost_for_column(unsigned j) const template void lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { - // If j is a breakpoint column, then we set the cost zero. - // When anylyzing an entering column candidate we update the cost of the breakpoints columns to get the left or the right derivative if the infeasibility function - // set zero cost for each non-basis column if (this->m_basis_heading[j] < 0) { this->m_costs[j] = numeric_traits::zero(); this->remove_column_from_inf_set(j); @@ -966,110 +909,6 @@ template void lp_primal_core_solver::print_column } } - - -// j is the basic column, x is the value at x[j] -// d is the coefficient before m_entering in the row with j as the basis column -template void lp_primal_core_solver::try_add_breakpoint(unsigned j, const X & x, const T & d, breakpoint_type break_type, const X & break_value) { - X diff = x - break_value; - if (is_zero(diff)) { - switch (break_type) { - case low_break: - if (!same_sign_with_entering_delta(d)) - return; // no breakpoint - break; - case upper_break: - if (same_sign_with_entering_delta(d)) - return; // no breakpoint - break; - default: break; - } - add_breakpoint(j, zero_of_type(), break_type); - return; - } - auto delta_j = diff / d; - if (same_sign_with_entering_delta(delta_j)) - add_breakpoint(j, delta_j, break_type); -} - -template std::string lp_primal_core_solver::break_type_to_string(breakpoint_type type) { - switch (type){ - case low_break: return "low_break"; - case upper_break: return "upper_break"; - case fixed_break: return "fixed_break"; - default: - lp_assert(false); - break; - } - return "type is not found"; -} - -template void lp_primal_core_solver::print_breakpoint(const breakpoint * b, std::ostream & out) { - out << "(" << this->column_name(b->m_j) << "," << break_type_to_string(b->m_type) << "," << T_to_string(b->m_delta) << ")" << std::endl; - print_bound_info_and_x(b->m_j, out); -} - - -template void lp_primal_core_solver::change_slope_on_breakpoint(unsigned entering, breakpoint * b, T & slope_at_entering) { - if (b->m_j == entering) { - lp_assert(b->m_type != fixed_break && (!is_zero(b->m_delta))); - slope_at_entering += m_sign_of_entering_delta; - return; - } - - lp_assert(this->m_basis_heading[b->m_j] >= 0); - unsigned i_row = this->m_basis_heading[b->m_j]; - const T & d = - this->m_ed[i_row]; - if (numeric_traits::is_zero(d)) return; - - T delta = m_sign_of_entering_delta * abs(d); - switch (b->m_type) { - case fixed_break: - if (is_zero(b->m_delta)) { - slope_at_entering += delta; - } else { - slope_at_entering += 2 * delta; - } - break; - case low_break: - case upper_break: - slope_at_entering += delta; - break; - default: - lp_assert(false); - } -} - - -template void lp_primal_core_solver::try_add_breakpoint_in_row(unsigned i) { - lp_assert(i < this->m_m()); - const T & d = this->m_ed[i]; // the coefficient before m_entering in the i-th row - if (d == 0) return; // the change of x[m_entering] will not change the corresponding basis x - unsigned j = this->m_basis[i]; - const X & x = this->m_x[j]; - switch (this->m_column_types[j]) { - case column_type::fixed: - try_add_breakpoint(j, x, d, fixed_break, this->m_lower_bounds[j]); - break; - case column_type::boxed: - try_add_breakpoint(j, x, d, low_break, this->m_lower_bounds[j]); - try_add_breakpoint(j, x, d, upper_break, this->m_upper_bounds[j]); - break; - case column_type::lower_bound: - try_add_breakpoint(j, x, d, low_break, this->m_lower_bounds[j]); - break; - case column_type::upper_bound: - try_add_breakpoint(j, x, d, upper_break, this->m_upper_bounds[j]); - break; - case column_type::free_column: - break; - default: - lp_assert(false); - break; - } -} - - template void lp_primal_core_solver::print_bound_info_and_x(unsigned j, std::ostream & out) { out << "type of " << this->column_name(j) << " is " << column_type_to_string(this->m_column_types[j]) << std::endl; out << "x[" << this->column_name(j) << "] = " << this->m_x[j] << std::endl; From 547254abe786c80231ca78bcd245e6ddb5a15c47 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 10:23:52 -0800 Subject: [PATCH 16/36] rm dealing with doubles --- src/math/lp/lp_core_solver_base.cpp | 3 - src/math/lp/lp_core_solver_base.h | 1 - src/math/lp/lp_core_solver_base_def.h | 17 --- src/math/lp/lp_primal_core_solver.h | 137 +++--------------- src/math/lp/lp_primal_core_solver_def.h | 103 +------------ .../lp/lp_primal_core_solver_tableau_def.h | 5 +- 6 files changed, 21 insertions(+), 245 deletions(-) diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index b76976d371c..e87dc5dd2f6 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -83,9 +83,6 @@ template std::string lp::lp_core_solver_base::column_name(unsi template void lp::lp_core_solver_base::pretty_print(std::ostream & out); template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); -template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; -template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 5f723c1185f..fff50090591 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -416,7 +416,6 @@ class lp_core_solver_base { non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; - int pivots_in_column_and_row_are_different(int entering, int leaving) const; void pivot_fixed_vars_from_basis(); bool remove_from_basis(unsigned j); bool remove_from_basis(unsigned j, const impq&); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 8b87728e090..c5910f4274c 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -549,23 +549,6 @@ get_non_basic_column_value_position(unsigned j) const { return at_lower_bound; } -template int lp_core_solver_base::pivots_in_column_and_row_are_different(int entering, int leaving) const { - const T & column_p = this->m_ed[this->m_basis_heading[leaving]]; - const T & row_p = this->m_pivot_row[entering]; - if (is_zero(column_p) || is_zero(row_p)) return true; // pivots cannot be zero - // the pivots have to have the same sign - if (column_p < 0) { - if (row_p > 0) - return 2; - } else { // column_p > 0 - if (row_p < 0) - return 2; - } - T diff_normalized = abs((column_p - row_p) / (numeric_traits::one() + abs(row_p))); - if ( !this->m_settings.abs_val_is_smaller_than_harris_tolerance(diff_normalized / T(10))) - return 1; - return 0; -} template void lp_core_solver_base::transpose_rows_tableau(unsigned i, unsigned j) { transpose_basis(i, j); m_A.transpose_rows(i, j); diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 2c7360712d6..568eefa9829 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -43,20 +43,16 @@ class lp_primal_core_solver:public lp_core_solver_base { public: // m_sign_of_entering is set to 1 if the entering variable needs // to grow and is set to -1 otherwise - unsigned m_column_norm_update_counter; T m_enter_price_eps; int m_sign_of_entering_delta; - indexed_vector m_beta; // see Swietanowski working vector beta for column norms T m_epsilon_of_reduced_cost; vector m_costs_backup; - T m_converted_harris_eps; unsigned m_inf_row_index_for_tableau; bool m_bland_mode_tableau; u_set m_left_basis_tableau; unsigned m_bland_mode_threshold; unsigned m_left_basis_repeated; vector m_leaving_candidates; - // T m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); std::list m_non_basis_list; void sort_non_basis(); void sort_non_basis_rational(); @@ -277,14 +273,9 @@ class lp_primal_core_solver:public lp_core_solver_base { return convert_struct::convert(std::numeric_limits::max()); } - bool get_harris_theta(X & theta); - - void restore_harris_eps() { m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); } - void zero_harris_eps() { m_converted_harris_eps = zero_of_type(); } - int find_leaving_on_harris_theta(X const & harris_theta, X & t); + bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); - int find_leaving_and_t(unsigned entering, X & t); int find_leaving_and_t_precise(unsigned entering, X & t); int find_leaving_and_t_tableau(unsigned entering, X & t); @@ -318,10 +309,7 @@ class lp_primal_core_solver:public lp_core_solver_base { lp_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); }; - - X harris_eps_for_bound(const X & bound) const { return ( convert_struct::convert(1) + abs(bound)/10) * m_converted_harris_eps/3; - } - + void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector & leavings, T m, X & t, T & abs_of_d_of_leaving); vector m_lower_bounds_dummy; // needed for the base class only @@ -514,10 +502,7 @@ class lp_primal_core_solver:public lp_core_solver_base { // } void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m < 0); - const X& eps = harris_eps_for_bound(this->m_lower_bounds[j]); - limit_theta((this->m_lower_bounds[j] - this->m_x[j] - eps) / m, theta, unlimited); - if (theta < zero_of_type()) theta = zero_of_type(); + lp_assert(false); } bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { @@ -531,16 +516,7 @@ class lp_primal_core_solver:public lp_core_solver_base { theta = zero_of_type(); unlimited = false; } - } else { - const X& eps = harris_eps_for_bound(bound); - if (this->below_bound(x, bound)) return false; - if (this->above_bound(x, bound)) { - limit_theta((bound - x - eps) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } - } + } return true; } @@ -555,16 +531,7 @@ class lp_primal_core_solver:public lp_core_solver_base { theta = zero_of_type(); unlimited = false; } - } else { - const X& eps = harris_eps_for_bound(bound); - if (this->above_bound(x, bound)) return false; - if (this->below_bound(x, bound)) { - limit_theta((bound - x + eps) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } - } + } return true; } @@ -576,82 +543,32 @@ class lp_primal_core_solver:public lp_core_solver_base { limit_theta((bound - x) / m, theta, unlimited); } } - else { - // x gets larger - lp_assert(m > 0); - const X& eps = harris_eps_for_bound(bound); - if (this->below_bound(x, bound)) { - limit_theta((bound - x + eps) / m, theta, unlimited); - } - } + } void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lp_assert(m < 0); - const X& eps = harris_eps_for_bound(bound); - if (this->above_bound(x, bound)) { - limit_theta((bound - x - eps) / m, theta, unlimited); - } + lp_assert(false); + } void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lp_assert(m > 0 && this->m_column_type[j] == column_type::boxed); - const X & x = this->m_x[j]; - const X & lbound = this->m_lower_bounds[j]; - - if (this->below_bound(x, lbound)) { - const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); - limit_theta((lbound - x + eps) / m, theta, unlimited); - } else { - const X & ubound = this->m_upper_bounds[j]; - if (this->below_bound(x, ubound)){ - const X& eps = harris_eps_for_bound(ubound); - limit_theta((ubound - x + eps) / m, theta, unlimited); - } else if (!this->above_bound(x, ubound)) { - theta = zero_of_type(); - unlimited = false; - } - } + lp_assert(false); + } void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lp_assert(m < 0 && this->m_column_type[j] == column_type::boxed); - const X & x = this->m_x[j]; - const X & ubound = this->m_upper_bounds[j]; - if (this->above_bound(x, ubound)) { - const X& eps = harris_eps_for_bound(ubound); - limit_theta((ubound - x - eps) / m, theta, unlimited); - } else { - const X & lbound = this->m_lower_bounds[j]; - if (this->above_bound(x, lbound)){ - const X& eps = harris_eps_for_bound(lbound); - limit_theta((lbound - x - eps) / m, theta, unlimited); - } else if (!this->below_bound(x, lbound)) { - theta = zero_of_type(); - unlimited = false; - } - } + lp_assert(false); + } void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m > 0); - const T& eps = harris_eps_for_bound(this->m_upper_bounds[j]); - if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { - limit_theta((this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); - if (theta < zero_of_type()) { - theta = zero_of_type(); - unlimited = false; - } - } + lp_assert(false); + } void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { - lp_assert(m > 0); - const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); - limit_theta( (this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); - if (theta < zero_of_type()) { - theta = zero_of_type(); - } + lp_assert(false); + } // j is a basic column or the entering, in any case x[j] has to stay feasible. @@ -722,14 +639,12 @@ class lp_primal_core_solver:public lp_core_solver_base { bool column_is_benefitial_for_entering_basis(unsigned j) const; bool column_is_benefitial_for_entering_basis_precise(unsigned j) const; - bool can_enter_basis(unsigned j); bool done(); void init_infeasibility_costs(); void init_infeasibility_cost_for_column(unsigned j); T get_infeasibility_cost_for_column(unsigned j) const; - void init_infeasibility_costs_for_changed_basis_only(); - + void print_column(unsigned j, std::ostream & out); // j is the basic column, x is the value at x[j] // d is the coefficient before m_entering in the row with j as the basis column @@ -743,13 +658,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void print_bound_info_and_x(unsigned j, std::ostream & out); - void init_infeasibility_after_update_x_if_inf(unsigned leaving) { - if (this->using_infeas_costs()) { - init_infeasibility_costs_for_changed_basis_only(); - this->m_costs[leaving] = zero_of_type(); - this->remove_column_from_inf_set(leaving); - } - } void init_inf_set() { this->clear_inf_set(); @@ -885,15 +793,10 @@ class lp_primal_core_solver:public lp_core_solver_base { column_type_array, lower_bound_values, upper_bound_values), - m_beta(A.row_count()), m_epsilon_of_reduced_cost(T(1)/T(10000000)), m_bland_mode_threshold(1000) { - if (!(numeric_traits::precise())) { - m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); - } else { - m_converted_harris_eps = zero_of_type(); - } + this->set_status(lp_status::UNKNOWN); } @@ -919,9 +822,7 @@ class lp_primal_core_solver:public lp_core_solver_base { column_names, column_type_array, m_lower_bounds_dummy, - upper_bound_values), - m_beta(A.row_count()), - m_converted_harris_eps(convert_struct::convert(this->m_settings.harris_feasibility_tolerance)) { + upper_bound_values) { lp_assert(initial_x_is_correct()); m_lower_bounds_dummy.resize(A.column_count(), zero_of_type()); m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 7a027f8d38c..22bd4db52e1 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -228,54 +228,8 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef } -template bool lp_primal_core_solver::get_harris_theta(X & theta) { - lp_assert(this->m_ed.is_OK()); - bool unlimited = true; - for (unsigned i : this->m_ed.m_index) { - if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; - limit_theta_on_basis_column(this->m_basis[i], - this->m_ed[i] * m_sign_of_entering_delta, theta, unlimited); - if (!unlimited && is_zero(theta)) break; - } - return unlimited; -} -template int lp_primal_core_solver:: -find_leaving_on_harris_theta(X const & harris_theta, X & t) { - int leaving = -1; - T pivot_abs_max = zero_of_type(); - // we know already that there is no bound flip on entering - // we also know that harris_theta is limited, so we will find a leaving - zero_harris_eps(); - unsigned steps = this->m_ed.m_index.size(); - unsigned k = this->m_settings.random_next() % steps; - unsigned initial_k = k; - do { - unsigned i = this->m_ed.m_index[k]; - const T & ed = this->m_ed[i]; - if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(ed)) { - if (++k == steps) - k = 0; - continue; - } - X ratio; - unsigned j = this->m_basis[i]; - bool unlimited = true; - limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, ratio, unlimited); - if ((!unlimited) && ratio <= harris_theta) { - if (leaving == -1 || abs(ed) > pivot_abs_max) { - t = ratio; - leaving = j; - pivot_abs_max = abs(ed); - } - } - if (++k == steps) k = 0; - } while (k != initial_k); - if (!this->precise()) - restore_harris_eps(); - return leaving; -} - template bool lp_primal_core_solver::try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, @@ -398,17 +352,6 @@ template int lp_primal_core_solver::find_leaving_ } -template int lp_primal_core_solver::find_leaving_and_t(unsigned entering, X & t) { - X theta = zero_of_type(); - bool unlimited = get_harris_theta(theta); - lp_assert(unlimited || theta >= zero_of_type()); - if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering; - if (unlimited) - return -1; - return find_leaving_on_harris_theta(theta, t); -} - - // m is the multiplier. updating t in a way that holds the following // x[j] + t * m >= m_lower_bounds[j] ( if m < 0 ) @@ -687,47 +630,10 @@ template void lp_primal_core_solver::init_column_ } } -// debug only -template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { - lp_assert(false); -} -template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { - lp_assert(numeric_traits::precise() == false); - lp_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); - if (m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { - m_column_norm_update_counter = 0; - init_column_norms(); - } else { - m_column_norm_update_counter++; - update_column_norms(entering, leaving); - } -} -// following Swietanowski - A new steepest ... -template void lp_primal_core_solver::update_column_norms(unsigned entering, unsigned leaving) { - lp_assert(numeric_traits::precise() == false); - T pivot = this->m_pivot_row[entering]; - T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot; - if (!numeric_traits::precise()) { - if (g_ent < T(0.000001)) - g_ent = T(0.000001); - } - this->m_column_norms[leaving] = g_ent; - for (unsigned j : this->m_pivot_row.m_index) { - if (j == leaving) - continue; - const T & t = this->m_pivot_row[j]; - T s = this->m_A.dot_product_with_column(m_beta.m_data, j); - T k = -2 / pivot; - T tp = t/pivot; - if (this->m_column_types[j] != column_type::fixed) { // a fixed columns do not enter the basis, we don't use the norm of a fixed column - this->m_column_norms[j] = std::max(this->m_column_norms[j] + t * (t * g_ent + k * s), // see Istvan Maros, page 196 - 1 + tp * tp); - } - } -} +// following Swietanowski - A new steepest ... template T lp_primal_core_solver::calculate_norm_of_entering_exactly() { T r = numeric_traits::one(); @@ -771,13 +677,6 @@ template bool lp_primal_core_solver::done() { return false; } -template -void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_only() { - for (unsigned i : this->m_ed.m_index) - init_infeasibility_cost_for_column(this->m_basis[i]); - this->set_using_infeas_costs(true); -} - template void lp_primal_core_solver::init_infeasibility_costs() { diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index b63c54bfd10..a63a6be17ad 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -295,10 +295,7 @@ template void lp_primal_core_solver::init_run_tab if (this->m_settings.backup_costs) backup_and_normalize_costs(); m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); - if (!numeric_traits::precise()) { - this->m_column_norm_update_counter = 0; - init_column_norms(); - } + if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); lp_assert(this->reduced_costs_are_correct_tableau()); From 4e948cebac76194cb6017df0f14ba24f08dc5074 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 10:56:44 -0800 Subject: [PATCH 17/36] Revert "rm dealing with doubles" This reverts commit 547254abe786c80231ca78bcd245e6ddb5a15c47. --- src/math/lp/lp_core_solver_base.cpp | 3 + src/math/lp/lp_core_solver_base.h | 1 + src/math/lp/lp_core_solver_base_def.h | 17 +++ src/math/lp/lp_primal_core_solver.h | 137 +++++++++++++++--- src/math/lp/lp_primal_core_solver_def.h | 103 ++++++++++++- .../lp/lp_primal_core_solver_tableau_def.h | 5 +- 6 files changed, 245 insertions(+), 21 deletions(-) diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index e87dc5dd2f6..b76976d371c 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -83,6 +83,9 @@ template std::string lp::lp_core_solver_base::column_name(unsi template void lp::lp_core_solver_base::pretty_print(std::ostream & out); template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; +template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index fff50090591..5f723c1185f 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -416,6 +416,7 @@ class lp_core_solver_base { non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; + int pivots_in_column_and_row_are_different(int entering, int leaving) const; void pivot_fixed_vars_from_basis(); bool remove_from_basis(unsigned j); bool remove_from_basis(unsigned j, const impq&); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index c5910f4274c..8b87728e090 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -549,6 +549,23 @@ get_non_basic_column_value_position(unsigned j) const { return at_lower_bound; } +template int lp_core_solver_base::pivots_in_column_and_row_are_different(int entering, int leaving) const { + const T & column_p = this->m_ed[this->m_basis_heading[leaving]]; + const T & row_p = this->m_pivot_row[entering]; + if (is_zero(column_p) || is_zero(row_p)) return true; // pivots cannot be zero + // the pivots have to have the same sign + if (column_p < 0) { + if (row_p > 0) + return 2; + } else { // column_p > 0 + if (row_p < 0) + return 2; + } + T diff_normalized = abs((column_p - row_p) / (numeric_traits::one() + abs(row_p))); + if ( !this->m_settings.abs_val_is_smaller_than_harris_tolerance(diff_normalized / T(10))) + return 1; + return 0; +} template void lp_core_solver_base::transpose_rows_tableau(unsigned i, unsigned j) { transpose_basis(i, j); m_A.transpose_rows(i, j); diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 568eefa9829..2c7360712d6 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -43,16 +43,20 @@ class lp_primal_core_solver:public lp_core_solver_base { public: // m_sign_of_entering is set to 1 if the entering variable needs // to grow and is set to -1 otherwise + unsigned m_column_norm_update_counter; T m_enter_price_eps; int m_sign_of_entering_delta; + indexed_vector m_beta; // see Swietanowski working vector beta for column norms T m_epsilon_of_reduced_cost; vector m_costs_backup; + T m_converted_harris_eps; unsigned m_inf_row_index_for_tableau; bool m_bland_mode_tableau; u_set m_left_basis_tableau; unsigned m_bland_mode_threshold; unsigned m_left_basis_repeated; vector m_leaving_candidates; + // T m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); std::list m_non_basis_list; void sort_non_basis(); void sort_non_basis_rational(); @@ -273,9 +277,14 @@ class lp_primal_core_solver:public lp_core_solver_base { return convert_struct::convert(std::numeric_limits::max()); } - + bool get_harris_theta(X & theta); + + void restore_harris_eps() { m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); } + void zero_harris_eps() { m_converted_harris_eps = zero_of_type(); } + int find_leaving_on_harris_theta(X const & harris_theta, X & t); bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); + int find_leaving_and_t(unsigned entering, X & t); int find_leaving_and_t_precise(unsigned entering, X & t); int find_leaving_and_t_tableau(unsigned entering, X & t); @@ -309,7 +318,10 @@ class lp_primal_core_solver:public lp_core_solver_base { lp_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); }; - + + X harris_eps_for_bound(const X & bound) const { return ( convert_struct::convert(1) + abs(bound)/10) * m_converted_harris_eps/3; + } + void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector & leavings, T m, X & t, T & abs_of_d_of_leaving); vector m_lower_bounds_dummy; // needed for the base class only @@ -502,7 +514,10 @@ class lp_primal_core_solver:public lp_core_solver_base { // } void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(false); + lp_assert(m < 0); + const X& eps = harris_eps_for_bound(this->m_lower_bounds[j]); + limit_theta((this->m_lower_bounds[j] - this->m_x[j] - eps) / m, theta, unlimited); + if (theta < zero_of_type()) theta = zero_of_type(); } bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { @@ -516,7 +531,16 @@ class lp_primal_core_solver:public lp_core_solver_base { theta = zero_of_type(); unlimited = false; } - } + } else { + const X& eps = harris_eps_for_bound(bound); + if (this->below_bound(x, bound)) return false; + if (this->above_bound(x, bound)) { + limit_theta((bound - x - eps) / m, theta, unlimited); + } else { + theta = zero_of_type(); + unlimited = false; + } + } return true; } @@ -531,7 +555,16 @@ class lp_primal_core_solver:public lp_core_solver_base { theta = zero_of_type(); unlimited = false; } - } + } else { + const X& eps = harris_eps_for_bound(bound); + if (this->above_bound(x, bound)) return false; + if (this->below_bound(x, bound)) { + limit_theta((bound - x + eps) / m, theta, unlimited); + } else { + theta = zero_of_type(); + unlimited = false; + } + } return true; } @@ -543,32 +576,82 @@ class lp_primal_core_solver:public lp_core_solver_base { limit_theta((bound - x) / m, theta, unlimited); } } - + else { + // x gets larger + lp_assert(m > 0); + const X& eps = harris_eps_for_bound(bound); + if (this->below_bound(x, bound)) { + limit_theta((bound - x + eps) / m, theta, unlimited); + } + } } void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller - lp_assert(false); - + lp_assert(m < 0); + const X& eps = harris_eps_for_bound(bound); + if (this->above_bound(x, bound)) { + limit_theta((bound - x - eps) / m, theta, unlimited); + } } void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(false); - + // lp_assert(m > 0 && this->m_column_type[j] == column_type::boxed); + const X & x = this->m_x[j]; + const X & lbound = this->m_lower_bounds[j]; + + if (this->below_bound(x, lbound)) { + const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); + limit_theta((lbound - x + eps) / m, theta, unlimited); + } else { + const X & ubound = this->m_upper_bounds[j]; + if (this->below_bound(x, ubound)){ + const X& eps = harris_eps_for_bound(ubound); + limit_theta((ubound - x + eps) / m, theta, unlimited); + } else if (!this->above_bound(x, ubound)) { + theta = zero_of_type(); + unlimited = false; + } + } } void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(false); - + // lp_assert(m < 0 && this->m_column_type[j] == column_type::boxed); + const X & x = this->m_x[j]; + const X & ubound = this->m_upper_bounds[j]; + if (this->above_bound(x, ubound)) { + const X& eps = harris_eps_for_bound(ubound); + limit_theta((ubound - x - eps) / m, theta, unlimited); + } else { + const X & lbound = this->m_lower_bounds[j]; + if (this->above_bound(x, lbound)){ + const X& eps = harris_eps_for_bound(lbound); + limit_theta((lbound - x - eps) / m, theta, unlimited); + } else if (!this->below_bound(x, lbound)) { + theta = zero_of_type(); + unlimited = false; + } + } } void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(false); - + lp_assert(m > 0); + const T& eps = harris_eps_for_bound(this->m_upper_bounds[j]); + if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { + limit_theta((this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); + if (theta < zero_of_type()) { + theta = zero_of_type(); + unlimited = false; + } + } } void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { - lp_assert(false); - + lp_assert(m > 0); + const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); + limit_theta( (this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); + if (theta < zero_of_type()) { + theta = zero_of_type(); + } } // j is a basic column or the entering, in any case x[j] has to stay feasible. @@ -639,12 +722,14 @@ class lp_primal_core_solver:public lp_core_solver_base { bool column_is_benefitial_for_entering_basis(unsigned j) const; bool column_is_benefitial_for_entering_basis_precise(unsigned j) const; + bool can_enter_basis(unsigned j); bool done(); void init_infeasibility_costs(); void init_infeasibility_cost_for_column(unsigned j); T get_infeasibility_cost_for_column(unsigned j) const; - + void init_infeasibility_costs_for_changed_basis_only(); + void print_column(unsigned j, std::ostream & out); // j is the basic column, x is the value at x[j] // d is the coefficient before m_entering in the row with j as the basis column @@ -658,6 +743,13 @@ class lp_primal_core_solver:public lp_core_solver_base { void print_bound_info_and_x(unsigned j, std::ostream & out); + void init_infeasibility_after_update_x_if_inf(unsigned leaving) { + if (this->using_infeas_costs()) { + init_infeasibility_costs_for_changed_basis_only(); + this->m_costs[leaving] = zero_of_type(); + this->remove_column_from_inf_set(leaving); + } + } void init_inf_set() { this->clear_inf_set(); @@ -793,10 +885,15 @@ class lp_primal_core_solver:public lp_core_solver_base { column_type_array, lower_bound_values, upper_bound_values), + m_beta(A.row_count()), m_epsilon_of_reduced_cost(T(1)/T(10000000)), m_bland_mode_threshold(1000) { - + if (!(numeric_traits::precise())) { + m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); + } else { + m_converted_harris_eps = zero_of_type(); + } this->set_status(lp_status::UNKNOWN); } @@ -822,7 +919,9 @@ class lp_primal_core_solver:public lp_core_solver_base { column_names, column_type_array, m_lower_bounds_dummy, - upper_bound_values) { + upper_bound_values), + m_beta(A.row_count()), + m_converted_harris_eps(convert_struct::convert(this->m_settings.harris_feasibility_tolerance)) { lp_assert(initial_x_is_correct()); m_lower_bounds_dummy.resize(A.column_count(), zero_of_type()); m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 22bd4db52e1..7a027f8d38c 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -228,8 +228,54 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef } +template bool lp_primal_core_solver::get_harris_theta(X & theta) { + lp_assert(this->m_ed.is_OK()); + bool unlimited = true; + for (unsigned i : this->m_ed.m_index) { + if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; + limit_theta_on_basis_column(this->m_basis[i], - this->m_ed[i] * m_sign_of_entering_delta, theta, unlimited); + if (!unlimited && is_zero(theta)) break; + } + return unlimited; +} +template int lp_primal_core_solver:: +find_leaving_on_harris_theta(X const & harris_theta, X & t) { + int leaving = -1; + T pivot_abs_max = zero_of_type(); + // we know already that there is no bound flip on entering + // we also know that harris_theta is limited, so we will find a leaving + zero_harris_eps(); + unsigned steps = this->m_ed.m_index.size(); + unsigned k = this->m_settings.random_next() % steps; + unsigned initial_k = k; + do { + unsigned i = this->m_ed.m_index[k]; + const T & ed = this->m_ed[i]; + if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(ed)) { + if (++k == steps) + k = 0; + continue; + } + X ratio; + unsigned j = this->m_basis[i]; + bool unlimited = true; + limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, ratio, unlimited); + if ((!unlimited) && ratio <= harris_theta) { + if (leaving == -1 || abs(ed) > pivot_abs_max) { + t = ratio; + leaving = j; + pivot_abs_max = abs(ed); + } + } + if (++k == steps) k = 0; + } while (k != initial_k); + if (!this->precise()) + restore_harris_eps(); + return leaving; +} + template bool lp_primal_core_solver::try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, @@ -352,6 +398,17 @@ template int lp_primal_core_solver::find_leaving_ } +template int lp_primal_core_solver::find_leaving_and_t(unsigned entering, X & t) { + X theta = zero_of_type(); + bool unlimited = get_harris_theta(theta); + lp_assert(unlimited || theta >= zero_of_type()); + if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering; + if (unlimited) + return -1; + return find_leaving_on_harris_theta(theta, t); +} + + // m is the multiplier. updating t in a way that holds the following // x[j] + t * m >= m_lower_bounds[j] ( if m < 0 ) @@ -630,10 +687,47 @@ template void lp_primal_core_solver::init_column_ } } +// debug only +template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { + lp_assert(false); +} - +template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { + lp_assert(numeric_traits::precise() == false); + lp_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); + if (m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { + m_column_norm_update_counter = 0; + init_column_norms(); + } else { + m_column_norm_update_counter++; + update_column_norms(entering, leaving); + } +} // following Swietanowski - A new steepest ... +template void lp_primal_core_solver::update_column_norms(unsigned entering, unsigned leaving) { + lp_assert(numeric_traits::precise() == false); + T pivot = this->m_pivot_row[entering]; + T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot; + if (!numeric_traits::precise()) { + if (g_ent < T(0.000001)) + g_ent = T(0.000001); + } + this->m_column_norms[leaving] = g_ent; + + for (unsigned j : this->m_pivot_row.m_index) { + if (j == leaving) + continue; + const T & t = this->m_pivot_row[j]; + T s = this->m_A.dot_product_with_column(m_beta.m_data, j); + T k = -2 / pivot; + T tp = t/pivot; + if (this->m_column_types[j] != column_type::fixed) { // a fixed columns do not enter the basis, we don't use the norm of a fixed column + this->m_column_norms[j] = std::max(this->m_column_norms[j] + t * (t * g_ent + k * s), // see Istvan Maros, page 196 + 1 + tp * tp); + } + } +} template T lp_primal_core_solver::calculate_norm_of_entering_exactly() { T r = numeric_traits::one(); @@ -677,6 +771,13 @@ template bool lp_primal_core_solver::done() { return false; } +template +void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_only() { + for (unsigned i : this->m_ed.m_index) + init_infeasibility_cost_for_column(this->m_basis[i]); + this->set_using_infeas_costs(true); +} + template void lp_primal_core_solver::init_infeasibility_costs() { diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index a63a6be17ad..b63c54bfd10 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -295,7 +295,10 @@ template void lp_primal_core_solver::init_run_tab if (this->m_settings.backup_costs) backup_and_normalize_costs(); m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); - + if (!numeric_traits::precise()) { + this->m_column_norm_update_counter = 0; + init_column_norms(); + } if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); lp_assert(this->reduced_costs_are_correct_tableau()); From 1c2c108fdcf7eea2960029590d36df5e7902e93a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 11:01:39 -0800 Subject: [PATCH 18/36] rm lu Signed-off-by: Lev Nachmanson --- src/test/lp/lp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 1a2ee2338b6..c386cf002d9 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -49,7 +49,6 @@ #include "math/lp/matrix.h" #include "math/lp/hnf.h" #include "math/lp/square_sparse_matrix_def.h" -#include "math/lp/lu_def.h" #include "math/lp/general_matrix.h" #include "math/lp/lp_bound_propagator.h" #include "math/lp/nla_solver.h" From 5495b2b50057a94ab534be1b751dcdd7fbd0e3a1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 11:38:45 -0800 Subject: [PATCH 19/36] rm lu --- src/math/lp/lar_core_solver.h | 9 +-------- src/math/lp/lar_core_solver_def.h | 29 +---------------------------- src/math/lp/lar_solver.cpp | 4 ---- 3 files changed, 2 insertions(+), 40 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index d9379cb9d3f..d40572b9e24 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -56,8 +56,6 @@ class lar_core_solver { lp_primal_core_solver> m_r_solver; // solver in rational numbers - - lp_primal_core_solver m_d_solver; // solver in doubles lar_core_solver( lp_settings & settings, @@ -140,7 +138,6 @@ class lar_core_solver { void push() { lp_assert(m_r_solver.basis_heading_is_correct()); - lp_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); lp_assert(m_column_types.size() == m_r_A.column_count()); m_stacked_simplex_strategy = settings().simplex_strategy(); m_stacked_simplex_strategy.push(); @@ -196,13 +193,9 @@ class lar_core_solver { m_stacked_simplex_strategy.pop(k); settings().set_simplex_strategy(m_stacked_simplex_strategy); lp_assert(m_r_solver.basis_heading_is_correct()); - lp_assert(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct()); - } - - bool need_to_presolve_with_double_solver() const { - return false; } + template bool is_zero_vector(const vector & b) { for (const L & m: b) diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index fe99a202f71..419345f0ca0 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -31,18 +31,6 @@ lar_core_solver::lar_core_solver( m_r_lower_bounds(), m_r_upper_bounds(), settings, - column_names), - m_d_solver(m_d_A, - m_d_right_sides_dummy, - m_d_x, - m_d_basis, - m_d_nbasis, - m_d_heading, - m_d_costs_dummy, - m_column_types(), - m_d_lower_bounds, - m_d_upper_bounds, - settings, column_names) { } @@ -57,22 +45,7 @@ void lar_core_solver::prefix_r() { } } -void lar_core_solver::prefix_d() { - // m_d_solver.m_b.resize(m_d_solver.m_m()); - m_d_solver.m_copy_of_xB.resize(m_d_solver.m_n()); - m_d_solver.m_costs.resize(m_d_solver.m_n()); - m_d_solver.m_d.resize(m_d_solver.m_n()); - m_d_solver.m_ed.resize(m_d_solver.m_m()); - m_d_solver.m_pivot_row.resize(m_d_solver.m_n()); - m_d_solver.m_pivot_row_of_B_1.resize(m_d_solver.m_m()); - m_d_solver.m_w.resize(m_d_solver.m_m()); - m_d_solver.m_y.resize(m_d_solver.m_m()); - m_d_solver.m_steepest_edge_coefficients.resize(m_d_solver.m_n()); - m_d_solver.m_column_norms.clear(); - m_d_solver.m_column_norms.resize(m_d_solver.m_n(), 2); - m_d_solver.clear_inf_set(); - m_d_solver.resize_inf_set(m_d_solver.m_n()); -} + void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 48c575184ba..f890b27fa43 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -47,7 +47,6 @@ namespace lp { bool lar_solver::sizes_are_correct() const { - lp_assert(strategy_is_undecided() || !m_mpq_lar_core_solver.need_to_presolve_with_double_solver() || A_r().column_count() == A_d().column_count()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_column_types.size()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size()); lp_assert(A_r().column_count() == m_mpq_lar_core_solver.m_r_x.size()); @@ -748,9 +747,6 @@ namespace lp { void lar_solver::solve_with_core_solver() { - if (m_mpq_lar_core_solver.need_to_presolve_with_double_solver()) { - add_last_rows_to_lu(m_mpq_lar_core_solver.m_d_solver); - } m_mpq_lar_core_solver.prefix_r(); if (costs_are_used()) { m_basic_columns_with_changed_cost.resize(m_mpq_lar_core_solver.m_r_x.size()); From e9b902e6393d3bf95c4499806b3d261621e03e15 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 13:40:21 -0800 Subject: [PATCH 20/36] rm lu --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/square_dense_submatrix.cpp | 48 -- src/math/lp/square_dense_submatrix.h | 225 --------- src/math/lp/square_dense_submatrix_def.h | 370 -------------- src/test/lp/lp.cpp | 592 +---------------------- 5 files changed, 4 insertions(+), 1232 deletions(-) delete mode 100644 src/math/lp/square_dense_submatrix.cpp delete mode 100644 src/math/lp/square_dense_submatrix.h delete mode 100644 src/math/lp/square_dense_submatrix_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 97073736717..5d21bba70ba 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -42,7 +42,6 @@ z3_add_component(lp random_updater.cpp row_eta_matrix.cpp scaler.cpp - square_dense_submatrix.cpp square_sparse_matrix.cpp static_matrix.cpp COMPONENT_DEPENDENCIES diff --git a/src/math/lp/square_dense_submatrix.cpp b/src/math/lp/square_dense_submatrix.cpp deleted file mode 100644 index 4d9fcec131e..00000000000 --- a/src/math/lp/square_dense_submatrix.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include "util/vector.h" -#include "math/lp/square_dense_submatrix_def.h" -template void lp::square_dense_submatrix::init(lp::square_sparse_matrix*, unsigned int); -template lp::square_dense_submatrix::square_dense_submatrix(lp::square_sparse_matrix*, unsigned int); -template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); -template bool lp::square_dense_submatrix::is_L_matrix() const; -template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); -template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); -template lp::square_dense_submatrix >::square_dense_submatrix(lp::square_sparse_matrix >*, unsigned int); -template void lp::square_dense_submatrix >::update_parent_matrix(lp::lp_settings&); -template bool lp::square_dense_submatrix >::is_L_matrix() const; -template void lp::square_dense_submatrix >::conjugate_by_permutation(lp::permutation_matrix >&); -template int lp::square_dense_submatrix >::find_pivot_column_in_row(unsigned int) const; -template void lp::square_dense_submatrix >::pivot(unsigned int, lp::lp_settings&); -#ifdef Z3DEBUG -template double lp::square_dense_submatrix::get_elem(unsigned int, unsigned int) const; -#endif -template void lp::square_dense_submatrix::apply_from_right(vector&); - -template void lp::square_dense_submatrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); -template void lp::square_dense_submatrix::apply_from_left_to_vector(vector&); -template lp::square_dense_submatrix::square_dense_submatrix(lp::square_sparse_matrix*, unsigned int); -template void lp::square_dense_submatrix::update_parent_matrix(lp::lp_settings&); -template bool lp::square_dense_submatrix::is_L_matrix() const; -template void lp::square_dense_submatrix::conjugate_by_permutation(lp::permutation_matrix&); -template int lp::square_dense_submatrix::find_pivot_column_in_row(unsigned int) const; -template void lp::square_dense_submatrix::pivot(unsigned int, lp::lp_settings&); diff --git a/src/math/lp/square_dense_submatrix.h b/src/math/lp/square_dense_submatrix.h deleted file mode 100644 index 308f9eadc63..00000000000 --- a/src/math/lp/square_dense_submatrix.h +++ /dev/null @@ -1,225 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "math/lp/permutation_matrix.h" -#include -#include "math/lp/static_matrix.h" -#include -#include -#include -#include -#include -#include "math/lp/indexed_value.h" -#include "math/lp/indexed_vector.h" -#include -#include "math/lp/lp_settings.h" -#include "math/lp/eta_matrix.h" -#include "math/lp/binary_heap_upair_queue.h" -#include "math/lp/square_sparse_matrix.h" -namespace lp { -template -class square_dense_submatrix : public tail_matrix { - // the submatrix uses the permutations of the parent matrix to access the elements - struct ref { - unsigned m_i_offset; - square_dense_submatrix & m_s; - ref(unsigned i, square_dense_submatrix & s) : - m_i_offset((i - s.m_index_start) * s.m_dim), m_s(s){} - T & operator[] (unsigned j) { - lp_assert(j >= m_s.m_index_start); - return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; - } - const T & operator[] (unsigned j) const { - lp_assert(j >= m_s.m_index_start); - return m_s.m_v[m_i_offset + m_s.adjust_column(j) - m_s.m_index_start]; - } - }; -public: - unsigned m_index_start; - unsigned m_dim; - vector m_v; - square_sparse_matrix * m_parent; - permutation_matrix m_row_permutation; - indexed_vector m_work_vector; -public: - permutation_matrix m_column_permutation; - bool is_active() const { return m_parent != nullptr; } - - square_dense_submatrix() {} - - square_dense_submatrix (square_sparse_matrix *parent_matrix, unsigned index_start); - - void init(square_sparse_matrix *parent_matrix, unsigned index_start); - - bool is_dense() const override { return true; } - - ref operator[] (unsigned i) { - lp_assert(i >= m_index_start); - lp_assert(i < m_parent->dimension()); - return ref(i, *this); - } - - int find_pivot_column_in_row(unsigned i) const; - - void swap_columns(unsigned i, unsigned j) { - if (i != j) - m_column_permutation.transpose_from_left(i, j); - } - - unsigned adjust_column(unsigned col) const{ - if (col >= m_column_permutation.size()) - return col; - return m_column_permutation.apply_reverse(col); - } - - unsigned adjust_column_inverse(unsigned col) const{ - if (col >= m_column_permutation.size()) - return col; - return m_column_permutation[col]; - } - unsigned adjust_row(unsigned row) const{ - if (row >= m_row_permutation.size()) - return row; - return m_row_permutation[row]; - } - - unsigned adjust_row_inverse(unsigned row) const{ - if (row >= m_row_permutation.size()) - return row; - return m_row_permutation.apply_reverse(row); - } - - void pivot(unsigned i, lp_settings & settings); - - void pivot_row_to_row(unsigned i, unsigned row, lp_settings & settings);; - - void divide_row_by_pivot(unsigned i); - - void update_parent_matrix(lp_settings & settings); - - void update_existing_or_delete_in_parent_matrix_for_row(unsigned i, lp_settings & settings); - - void push_new_elements_to_parent_matrix(lp_settings & settings); - - template - L row_by_vector_product(unsigned i, const vector & v); - - template - L column_by_vector_product(unsigned j, const vector & v); - - template - L row_by_indexed_vector_product(unsigned i, const indexed_vector & v); - - template - void apply_from_left_local(indexed_vector & w, lp_settings & settings); - - template - void apply_from_left_to_vector(vector & w); - - bool is_L_matrix() const; - - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { - apply_from_left_local(w, settings); - } - - - - void apply_from_right(indexed_vector & w) override { -#if 1==0 - indexed_vector wcopy = w; - apply_from_right(wcopy.m_data); - wcopy.m_index.clear(); - if (numeric_traits::precise()) { - for (unsigned i = 0; i < m_parent->dimension(); i++) { - if (!is_zero(wcopy.m_data[i])) - wcopy.m_index.push_back(i); - } - } else { - for (unsigned i = 0; i < m_parent->dimension(); i++) { - T & v = wcopy.m_data[i]; - if (!lp_settings::is_eps_small_general(v, 1e-14)){ - wcopy.m_index.push_back(i); - } else { - v = zero_of_type(); - } - } - } - lp_assert(wcopy.is_OK()); - apply_from_right(w.m_data); - w.m_index.clear(); - if (numeric_traits::precise()) { - for (unsigned i = 0; i < m_parent->dimension(); i++) { - if (!is_zero(w.m_data[i])) - w.m_index.push_back(i); - } - } else { - for (unsigned i = 0; i < m_parent->dimension(); i++) { - T & v = w.m_data[i]; - if (!lp_settings::is_eps_small_general(v, 1e-14)){ - w.m_index.push_back(i); - } else { - v = zero_of_type(); - } - } - } -#else - lp_assert(w.is_OK()); - lp_assert(m_work_vector.is_OK()); - m_work_vector.resize(w.data_size()); - m_work_vector.clear(); - lp_assert(m_work_vector.is_OK()); - unsigned end = m_index_start + m_dim; - for (unsigned k : w.m_index) { - // find j such that k = adjust_row_inverse(j) - unsigned j = adjust_row(k); - if (j < m_index_start || j >= end) { - m_work_vector.set_value(w[k], adjust_column_inverse(j)); - } else { // j >= m_index_start and j < end - unsigned offset = (j - m_index_start) * m_dim; // this is the row start - const T& wv = w[k]; - for (unsigned col = m_index_start; col < end; col++, offset ++) { - unsigned adj_col = adjust_column_inverse(col); - m_work_vector.add_value_at_index(adj_col, m_v[offset] * wv); - } - } - } - m_work_vector.clean_up(); - lp_assert(m_work_vector.is_OK()); - w = m_work_vector; -#endif - } - void apply_from_left(vector & w, lp_settings & /*settings*/) override { - apply_from_left_to_vector(w);// , settings); - } - - void apply_from_right(vector & w) override; - -#ifdef Z3DEBUG - T get_elem (unsigned i, unsigned j) const override; - unsigned row_count() const override { return m_parent->row_count();} - unsigned column_count() const override { return row_count();} - void set_number_of_rows(unsigned) override {} - void set_number_of_columns(unsigned) override {} -#endif - void conjugate_by_permutation(permutation_matrix & q); -}; -} diff --git a/src/math/lp/square_dense_submatrix_def.h b/src/math/lp/square_dense_submatrix_def.h deleted file mode 100644 index 3a9006b4d9e..00000000000 --- a/src/math/lp/square_dense_submatrix_def.h +++ /dev/null @@ -1,370 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include "util/vector.h" -#include "math/lp/square_dense_submatrix.h" -namespace lp { -template -square_dense_submatrix::square_dense_submatrix (square_sparse_matrix *parent_matrix, unsigned index_start) : - m_index_start(index_start), - m_dim(parent_matrix->dimension() - index_start), - m_v(m_dim * m_dim), - m_parent(parent_matrix), - m_row_permutation(m_parent->dimension()), - m_column_permutation(m_parent->dimension()) { - int row_offset = - static_cast(m_index_start); - for (unsigned i = index_start; i < parent_matrix->dimension(); i++) { - unsigned row = parent_matrix->adjust_row(i); - for (auto & iv : parent_matrix->get_row_values(row)) { - unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); - lp_assert(j>= m_index_start); - m_v[row_offset + j] = iv.m_value; - } - row_offset += m_dim; - } -} - -template void square_dense_submatrix::init(square_sparse_matrix *parent_matrix, unsigned index_start) { - m_index_start = index_start; - m_dim = parent_matrix->dimension() - index_start; - m_v.resize(m_dim * m_dim); - m_parent = parent_matrix; - m_column_permutation.init(m_parent->dimension()); - for (unsigned i = index_start; i < parent_matrix->dimension(); i++) { - unsigned row = parent_matrix->adjust_row(i); - for (auto & iv : parent_matrix->get_row_values(row)) { - unsigned j = parent_matrix->adjust_column_inverse(iv.m_index); - (*this)[i][j] = iv.m_value; - } - } -} - -template int square_dense_submatrix::find_pivot_column_in_row(unsigned i) const { - int j = -1; - T max = zero_of_type(); - lp_assert(i >= m_index_start); - unsigned row_start = (i - m_index_start) * m_dim; - for (unsigned k = i; k < m_parent->dimension(); k++) { - unsigned col = adjust_column(k); // this is where the column is in the row - unsigned offs = row_start + col - m_index_start; - T t = abs(m_v[offs]); - if (t > max) { - j = k; - max = t; - } - } - return j; -} - -template void square_dense_submatrix::pivot(unsigned i, lp_settings & settings) { - divide_row_by_pivot(i); - for (unsigned k = i + 1; k < m_parent->dimension(); k++) - pivot_row_to_row(i, k, settings); -} - -template void square_dense_submatrix::pivot_row_to_row(unsigned i, unsigned row, lp_settings & settings) { - lp_assert(i < row); - unsigned pj = adjust_column(i); // the pivot column - unsigned pjd = pj - m_index_start; - unsigned pivot_row_offset = (i-m_index_start)*m_dim; - T pivot = m_v[pivot_row_offset + pjd]; - unsigned row_offset= (row-m_index_start)*m_dim; - T m = m_v[row_offset + pjd]; - lp_assert(!is_zero(pivot)); - m_v[row_offset + pjd] = -m * pivot; // creating L matrix - for (unsigned j = m_index_start; j < m_parent->dimension(); j++) { - if (j == pj) { - pivot_row_offset++; - row_offset++; - continue; - } - auto t = m_v[row_offset] - m_v[pivot_row_offset] * m; - if (settings.abs_val_is_smaller_than_drop_tolerance(t)) { - m_v[row_offset] = zero_of_type(); - } else { - m_v[row_offset] = t; - } - row_offset++; pivot_row_offset++; - // at the same time we pivot the L too - } -} - -template void square_dense_submatrix::divide_row_by_pivot(unsigned i) { - unsigned pj = adjust_column(i); // the pivot column - unsigned irow_offset = (i - m_index_start) * m_dim; - T pivot = m_v[irow_offset + pj - m_index_start]; - lp_assert(!is_zero(pivot)); - for (unsigned k = m_index_start; k < m_parent->dimension(); k++) { - if (k == pj){ - m_v[irow_offset++] = one_of_type() / pivot; // creating the L matrix diagonal - continue; - } - m_v[irow_offset++] /= pivot; - } -} - -template void square_dense_submatrix::update_parent_matrix(lp_settings & settings) { - for (unsigned i = m_index_start; i < m_parent->dimension(); i++) - update_existing_or_delete_in_parent_matrix_for_row(i, settings); - push_new_elements_to_parent_matrix(settings); - for (unsigned i = m_index_start; i < m_parent->dimension(); i++) - m_parent->set_max_in_row(m_parent->adjust_row(i)); -} - -template void square_dense_submatrix::update_existing_or_delete_in_parent_matrix_for_row(unsigned i, lp_settings & settings) { - bool diag_updated = false; - unsigned ai = m_parent->adjust_row(i); - auto & row_vals = m_parent->get_row_values(ai); - for (unsigned k = 0; k < row_vals.size(); k++) { - auto & iv = row_vals[k]; - unsigned j = m_parent->adjust_column_inverse(iv.m_index); - if (j < i) { - m_parent->remove_element(row_vals, iv); - k--; - } else if (i == j) { - m_parent->m_columns[iv.m_index].m_values[iv.m_other].set_value(iv.m_value = one_of_type()); - diag_updated = true; - } else { // j > i - T & v = (*this)[i][j]; - if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { - m_parent->remove_element(row_vals, iv); - k--; - } else { - m_parent->m_columns[iv.m_index].m_values[iv.m_other].set_value(iv.m_value = v); - v = zero_of_type(); // only new elements are left above the diagonal - } - } - } - if (!diag_updated) { - unsigned aj = m_parent->adjust_column(i); - m_parent->add_new_element(ai, aj, one_of_type()); - } -} - -template void square_dense_submatrix::push_new_elements_to_parent_matrix(lp_settings & settings) { - for (unsigned i = m_index_start; i < m_parent->dimension() - 1; i++) { - unsigned ai = m_parent->adjust_row(i); - for (unsigned j = i + 1; j < m_parent->dimension(); j++) { - T & v = (*this)[i][j]; - if (!settings.abs_val_is_smaller_than_drop_tolerance(v)) { - unsigned aj = m_parent->adjust_column(j); - m_parent->add_new_element(ai, aj, v); - } - v = zero_of_type(); // leave only L elements now - } - } -} -template -template -L square_dense_submatrix::row_by_vector_product(unsigned i, const vector & v) { - lp_assert(i >= m_index_start); - - unsigned row_in_subm = i - m_index_start; - unsigned row_offset = row_in_subm * m_dim; - L r = zero_of_type(); - for (unsigned j = 0; j < m_dim; j++) - r += m_v[row_offset + j] * v[adjust_column_inverse(m_index_start + j)]; - return r; -} - -template -template -L square_dense_submatrix::column_by_vector_product(unsigned j, const vector & v) { - lp_assert(j >= m_index_start); - - unsigned offset = j - m_index_start; - L r = zero_of_type(); - for (unsigned i = 0; i < m_dim; i++, offset += m_dim) - r += m_v[offset] * v[adjust_row_inverse(m_index_start + i)]; - return r; -} -template -template -L square_dense_submatrix::row_by_indexed_vector_product(unsigned i, const indexed_vector & v) { - lp_assert(i >= m_index_start); - - unsigned row_in_subm = i - m_index_start; - unsigned row_offset = row_in_subm * m_dim; - L r = zero_of_type(); - for (unsigned j = 0; j < m_dim; j++) - r += m_v[row_offset + j] * v[adjust_column_inverse(m_index_start + j)]; - return r; -} -template -template -void square_dense_submatrix::apply_from_left_local(indexed_vector & w, lp_settings & settings) { -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // vector deb_w(w.m_data.size()); - // for (unsigned i = 0; i < w.m_data.size(); i++) - // deb_w[i] = w[i]; - - // deb.apply_from_left(deb_w); -#endif // use indexed vector here - -#ifndef DO_NOT_USE_INDEX - vector t(m_parent->dimension(), zero_of_type()); - for (auto k : w.m_index) { - unsigned j = adjust_column(k); // k-th element will contribute only to column j - if (j < m_index_start || j >= this->m_index_start + this->m_dim) { // it is a unit matrix outside - t[adjust_row_inverse(j)] = w[k]; - } else { - const L & v = w[k]; - for (unsigned i = 0; i < m_dim; i++) { - unsigned row = adjust_row_inverse(m_index_start + i); - unsigned offs = i * m_dim + j - m_index_start; - t[row] += m_v[offs] * v; - } - } - } - w.m_index.clear(); - for (unsigned i = 0; i < m_parent->dimension(); i++) { - const L & v = t[i]; - if (!settings.abs_val_is_smaller_than_drop_tolerance(v)){ - w.m_index.push_back(i); - w.m_data[i] = v; - } else { - w.m_data[i] = zero_of_type(); - } - } -#else - vector t(m_parent->dimension()); - for (unsigned i = 0; i < m_index_start; i++) { - t[adjust_row_inverse(i)] = w[adjust_column_inverse(i)]; - } - for (unsigned i = m_index_start; i < m_parent->dimension(); i++){ - t[adjust_row_inverse(i)] = row_by_indexed_vector_product(i, w); - } - for (unsigned i = 0; i < m_parent->dimension(); i++) { - w.set_value(t[i], i); - } - for (unsigned i = 0; i < m_parent->dimension(); i++) { - const L & v = t[i]; - if (!is_zero(v)) - w.m_index.push_back(i); - w.m_data[i] = v; - } -#endif -#ifdef Z3DEBUG - // cout << "w final" << endl; - // print_vector(w.m_data); - // lp_assert(vectors_are_equal(deb_w, w.m_data)); - // lp_assert(w.is_OK()); -#endif -} - -template -template -void square_dense_submatrix::apply_from_left_to_vector(vector & w) { - // lp_settings & settings) { - // dense_matrix deb(*this); - // vector deb_w(w); - // deb.apply_from_left_to_X(deb_w, settings); - // // cout << "deb" << endl; - // // print_matrix(deb); - // // cout << "w" << endl; - // // print_vector(w.m_data); - // // cout << "deb_w" << endl; - // // print_vector(deb_w); - vector t(m_parent->dimension()); - for (unsigned i = 0; i < m_index_start; i++) { - t[adjust_row_inverse(i)] = w[adjust_column_inverse(i)]; - } - for (unsigned i = m_index_start; i < m_parent->dimension(); i++){ - t[adjust_row_inverse(i)] = row_by_vector_product(i, w); - } - for (unsigned i = 0; i < m_parent->dimension(); i++) { - w[i] = t[i]; - } -#ifdef Z3DEBUG - // cout << "w final" << endl; - // print_vector(w.m_data); - // lp_assert(vectors_are_equal(deb_w, w)); -#endif -} - -template bool square_dense_submatrix::is_L_matrix() const { -#ifdef Z3DEBUG - lp_assert(m_row_permutation.is_identity()); - for (unsigned i = 0; i < m_parent->dimension(); i++) { - if (i < m_index_start) { - lp_assert(m_column_permutation[i] == i); - continue; - } - unsigned row_offs = (i-m_index_start)*m_dim; - for (unsigned k = 0; k < m_dim; k++) { - unsigned j = m_index_start + k; - unsigned jex = adjust_column_inverse(j); - if (jex > i) { - lp_assert(is_zero(m_v[row_offs + k])); - } else if (jex == i) { - lp_assert(!is_zero(m_v[row_offs + k])); - } - } - } -#endif - return true; -} - -template void square_dense_submatrix::apply_from_right(vector & w) { -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // vector deb_w(w); - // deb.apply_from_right(deb_w); -#endif - vector t(w.size()); - - for (unsigned j = 0; j < m_index_start; j++) { - t[adjust_column_inverse(j)] = w[adjust_row_inverse(j)]; - } - unsigned end = m_index_start + m_dim; - for (unsigned j = end; j < m_parent->dimension(); j++) { - t[adjust_column_inverse(j)] = w[adjust_row_inverse(j)]; - } - for (unsigned j = m_index_start; j < end; j++) { - t[adjust_column_inverse(j)] = column_by_vector_product(j, w); - } - w = t; -#ifdef Z3DEBUG - // lp_assert(vector_are_equal(deb_w, w)); -#endif -} - - - - -#ifdef Z3DEBUG - -template T square_dense_submatrix::get_elem (unsigned i, unsigned j) const { - i = adjust_row(i); - j = adjust_column(j); - if (i < m_index_start || j < m_index_start) - return i == j? one_of_type() : zero_of_type(); - unsigned offs = (i - m_index_start)* m_dim + j - m_index_start; - return m_v[offs]; -} - -#endif -template void square_dense_submatrix::conjugate_by_permutation(permutation_matrix & q) { - m_row_permutation.multiply_by_permutation_from_left(q); - m_column_permutation.multiply_by_reverse_from_right(q); -} -} diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index c386cf002d9..2e8faeaedc5 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -48,7 +48,6 @@ #include "test/lp/gomory_test.h" #include "math/lp/matrix.h" #include "math/lp/hnf.h" -#include "math/lp/square_sparse_matrix_def.h" #include "math/lp/general_matrix.h" #include "math/lp/lp_bound_propagator.h" #include "math/lp/nla_solver.h" @@ -56,6 +55,8 @@ #include "math/lp/cross_nested.h" #include "math/lp/int_cube.h" #include "math/lp/emonics.h" +#include "math/lp/static_matrix.h" +#include "math/lp/dense_matrix.h" bool my_white_space(const char & a) { return a == ' ' || a == '\t'; @@ -388,122 +389,6 @@ struct simple_column_namer:public column_namer }; -template -void test_matrix(square_sparse_matrix & a) { - auto m = a.dimension(); - - // copy a to b in the reversed order - square_sparse_matrix b(m, m); - std::cout << "copy b to a"<< std::endl; - for (int row = m - 1; row >= 0; row--) - for (int col = m - 1; col >= 0; col --) { - b(row, col) = (T const&) a(row, col); - } - - - std::cout << "zeroing b in the reverse order"<< std::endl; - for (int row = m - 1; row >= 0; row--) - for (int col = m - 1; col >= 0; col --) - b.set(row, col, T(0)); - - - - for (unsigned row = 0; row < m; row ++) - for (unsigned col = 0; col < m; col ++) - a.set(row, col, T(0)); - - - unsigned i = my_random() % m; - unsigned j = my_random() % m; - - auto t = T(1); - - a.set(i, j, t); - - lp_assert(a.get(i, j) == t); - - unsigned j1; - if (j < m - 1) { - j1 = m - 1; - a.set(i, j1, T(2)); - } -} - -void tst1() { - std::cout << "testing the minimal matrix with 1 row and 1 column" << std::endl; - square_sparse_matrix m0(1, 1); - m0.set(0, 0, 1); - // print_matrix(m0); - m0.set(0, 0, 0); - // print_matrix(m0); - test_matrix(m0); - - unsigned rows = 2; - square_sparse_matrix m(rows, rows); - std::cout << "setting m(0,1)=" << std::endl; - - m.set(0, 1, 11); - m.set(0, 0, 12); - - // print_matrix(m); - - test_matrix(m); - - square_sparse_matrix m1(2, 2); - m1.set(0, 0, 2); - m1.set(1, 0, 3); - // print_matrix(m1); - std::cout << " zeroing matrix 2 by 2" << std::endl; - m1.set(0, 0, 0); - m1.set(1, 0, 0); - // print_matrix(m1); - - test_matrix(m1); - - - std::cout << "printing zero matrix 3 by 1" << std::endl; - square_sparse_matrix m2(3, 3); - // print_matrix(m2); - - m2.set(0, 0, 1); - m2.set(2, 0, 2); - std::cout << "printing matrix 3 by 1 with a gap" << std::endl; - // print_matrix(m2); - - test_matrix(m2); - - square_sparse_matrix m10by9(10, 10); - m10by9.set(0, 1, 1); - - m10by9(0, 1) = 4; - - double test = m10by9(0, 1); - - std::cout << "got " << test << std::endl; - - - m10by9.set(0, 8, 8); - m10by9.set(3, 4, 7); - m10by9.set(3, 2, 5); - m10by9.set(3, 8, 99); - m10by9.set(3, 2, 6); - m10by9.set(1, 8, 9); - m10by9.set(4, 0, 40); - m10by9.set(0, 0, 10); - - std::cout << "printing matrix 10 by 9" << std::endl; - // print_matrix(m10by9); - - - test_matrix(m10by9); - std::cout <<"zeroing m10by9\n"; -#ifdef Z3DEBUG - for (unsigned int i = 0; i < m10by9.dimension(); i++) - for (unsigned int j = 0; j < m10by9.column_count(); j++) - m10by9.set(i, j, 0); -#endif - // print_matrix(m10by9); -} vector allocate_basis_heading(unsigned count) { // the rest of initialization will be handled by lu_QR vector basis_heading(count, -1); @@ -555,12 +440,6 @@ void test_small_lu(lp_settings & settings) { #endif -void fill_long_row(square_sparse_matrix &m, int i) { - int n = m.dimension(); - for (int j = 0; j < n; j ++) { - m (i, (j + i) % n) = j * j; - } -} void fill_long_row(static_matrix &m, int i) { int n = m.column_count(); @@ -570,13 +449,6 @@ void fill_long_row(static_matrix &m, int i) { } -void fill_long_row_exp(square_sparse_matrix &m, int i) { - int n = m.dimension(); - - for (int j = 0; j < n; j ++) { - m(i, j) = my_random() % 20; - } -} void fill_long_row_exp(static_matrix &m, int i) { int n = m.column_count(); @@ -586,26 +458,9 @@ void fill_long_row_exp(static_matrix &m, int i) { } } -void fill_larger_square_sparse_matrix_exp(square_sparse_matrix & m){ - for ( unsigned i = 0; i < m.dimension(); i++ ) - fill_long_row_exp(m, i); -} - -void fill_larger_square_sparse_matrix_exp(static_matrix & m){ - for ( unsigned i = 0; i < m.row_count(); i++ ) - fill_long_row_exp(m, i); -} -void fill_larger_square_sparse_matrix(square_sparse_matrix & m){ - for ( unsigned i = 0; i < m.dimension(); i++ ) - fill_long_row(m, i); -} -void fill_larger_square_sparse_matrix(static_matrix & m){ - for ( unsigned i = 0; i < m.row_count(); i++ ) - fill_long_row(m, i); -} int perm_id = 0; @@ -616,11 +471,6 @@ int perm_id = 0; -void init_b(vector & b, square_sparse_matrix & m, vector& x) { - for (unsigned i = 0; i < m.dimension(); i++) { - b.push_back(m.dot_product_with_row(i, x)); - } -} void init_b(vector & b, static_matrix & m, vector & x) { for (unsigned i = 0; i < m.row_count(); i++) { @@ -671,7 +521,7 @@ void test_lp_1() { m(2, 0) = 2; m(2, 1) = -1; m(2, 2) = 2; m(2, 5) = 1; m(3, 0) = 2; m(3, 1) = 3; m(3, 2) = -1; m(3, 6) = 1; #ifdef Z3DEBUG - print_matrix(m, std::cout); + //print_matrix(m, std::cout); #endif vector x_star(7); x_star[0] = 0; x_star[1] = 0; x_star[2] = 0; @@ -724,213 +574,9 @@ void test_lp_primal_core_solver() { } -#ifdef Z3DEBUG -template -void test_swap_rows_with_permutation(square_sparse_matrix& m){ - std::cout << "testing swaps" << std::endl; - unsigned dim = m.row_count(); - dense_matrix original(&m); - permutation_matrix q(dim); - print_matrix(m, std::cout); - lp_assert(original == q * m); - for (int i = 0; i < 100; i++) { - unsigned row1 = my_random() % dim; - unsigned row2 = my_random() % dim; - if (row1 == row2) continue; - std::cout << "swap " << row1 << " " << row2 << std::endl; - m.swap_rows(row1, row2); - q.transpose_from_left(row1, row2); - lp_assert(original == q * m); - print_matrix(m, std::cout); - std::cout << std::endl; - } -} -#endif -template -void fill_matrix(square_sparse_matrix& m); // forward definition -#ifdef Z3DEBUG -template -void test_swap_cols_with_permutation(square_sparse_matrix& m){ - std::cout << "testing swaps" << std::endl; - unsigned dim = m.row_count(); - dense_matrix original(&m); - permutation_matrix q(dim); - print_matrix(m, std::cout); - lp_assert(original == q * m); - for (int i = 0; i < 100; i++) { - unsigned row1 = my_random() % dim; - unsigned row2 = my_random() % dim; - if (row1 == row2) continue; - std::cout << "swap " << row1 << " " << row2 << std::endl; - m.swap_rows(row1, row2); - q.transpose_from_right(row1, row2); - lp_assert(original == q * m); - print_matrix(m, std::cout); - std::cout << std::endl; - } -} - - -template -void test_swap_rows(square_sparse_matrix& m, unsigned i0, unsigned i1){ - std::cout << "test_swap_rows(" << i0 << "," << i1 << ")" << std::endl; - square_sparse_matrix mcopy(m.dimension(), 0); - for (unsigned i = 0; i < m.dimension(); i++) - for (unsigned j = 0; j < m.dimension(); j++) { - mcopy(i, j)= m(i, j); - } - std::cout << "swapping rows "<< i0 << "," << i1 << std::endl; - m.swap_rows(i0, i1); - - for (unsigned j = 0; j < m.dimension(); j++) { - lp_assert(mcopy(i0, j) == m(i1, j)); - lp_assert(mcopy(i1, j) == m(i0, j)); - } -} -template -void test_swap_columns(square_sparse_matrix& m, unsigned i0, unsigned i1){ - std::cout << "test_swap_columns(" << i0 << "," << i1 << ")" << std::endl; - square_sparse_matrix mcopy(m.dimension(), 0); // the second argument does not matter - for (unsigned i = 0; i < m.dimension(); i++) - for (unsigned j = 0; j < m.dimension(); j++) { - mcopy(i, j)= m(i, j); - } - m.swap_columns(i0, i1); - - for (unsigned j = 0; j < m.dimension(); j++) { - lp_assert(mcopy(j, i0) == m(j, i1)); - lp_assert(mcopy(j, i1) == m(j, i0)); - } - - for (unsigned i = 0; i < m.dimension(); i++) { - if (i == i0 || i == i1) - continue; - for (unsigned j = 0; j < m.dimension(); j++) { - lp_assert(mcopy(j, i)== m(j, i)); - } - } -} -#endif - -template -void fill_matrix(square_sparse_matrix& m){ - int v = 0; - for (int i = m.dimension() - 1; i >= 0; i--) { - for (int j = m.dimension() - 1; j >=0; j--){ - m(i, j) = v++; - } - } -} - -void test_pivot_like_swaps_and_pivot(){ - square_sparse_matrix m(10, 10); - fill_matrix(m); - // print_matrix(m); - // pivot at 2,7 - m.swap_columns(0, 7); - // print_matrix(m); - m.swap_rows(2, 0); - // print_matrix(m); - for (unsigned i = 1; i < m.dimension(); i++) { - m(i, 0) = 0; - } - // print_matrix(m); - - // say pivot at 3,4 - m.swap_columns(1, 4); - // print_matrix(m); - m.swap_rows(1, 3); - // print_matrix(m); - - vector row; - double alpha = 2.33; - unsigned pivot_row = 1; - unsigned target_row = 2; - unsigned pivot_row_0 = 3; - double beta = 3.1; - m(target_row, 3) = 0; - m(target_row, 5) = 0; - m(pivot_row, 6) = 0; -#ifdef Z3DEBUG - print_matrix(m, std::cout); -#endif - - for (unsigned j = 0; j < m.dimension(); j++) { - row.push_back(m(target_row, j) + alpha * m(pivot_row, j) + beta * m(pivot_row_0, j)); - } - - for (auto & t : row) { - std::cout << t << ","; - } - std::cout << std::endl; - lp_settings settings; - m.pivot_row_to_row(pivot_row, alpha, target_row, settings); - m.pivot_row_to_row(pivot_row_0, beta, target_row, settings); - // print_matrix(m); - for (unsigned j = 0; j < m.dimension(); j++) { - lp_assert(abs(row[j] - m(target_row, j)) < 0.00000001); - } -} - -#ifdef Z3DEBUG -void test_swap_rows() { - square_sparse_matrix m(10, 10); - fill_matrix(m); - // print_matrix(m); - test_swap_rows(m, 3, 5); - - test_swap_rows(m, 1, 3); - - - test_swap_rows(m, 1, 3); - - test_swap_rows(m, 1, 7); - - test_swap_rows(m, 3, 7); - test_swap_rows(m, 0, 7); - m(0, 4) = 1; - // print_matrix(m); - test_swap_rows(m, 0, 7); - // go over some corner cases - square_sparse_matrix m0(2, 2); - test_swap_rows(m0, 0, 1); - m0(0, 0) = 3; - test_swap_rows(m0, 0, 1); - m0(1, 0) = 3; - test_swap_rows(m0, 0, 1); - - - square_sparse_matrix m1(10, 10); - test_swap_rows(m1, 0, 1); - m1(0, 0) = 3; - test_swap_rows(m1, 0, 1); - m1(1, 0) = 3; - m1(0, 3) = 5; - m1(1, 3) = 4; - m1(1, 8) = 8; - m1(1, 9) = 8; - - test_swap_rows(m1, 0, 1); - - square_sparse_matrix m2(3, 3); - test_swap_rows(m2, 0, 1); - m2(0, 0) = 3; - test_swap_rows(m2, 0, 1); - m2(2, 0) = 3; - test_swap_rows(m2, 0, 2); -} - -void fill_uniformly(square_sparse_matrix & m, unsigned dim) { - int v = 0; - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - m(i, j) = v++; - } - } -} void fill_uniformly(dense_matrix & m, unsigned dim) { int v = 0; @@ -941,146 +587,8 @@ void fill_uniformly(dense_matrix & m, unsigned dim) { } } -void square_sparse_matrix_with_permutations_test() { - unsigned dim = 4; - square_sparse_matrix m(dim, dim); - fill_uniformly(m, dim); - dense_matrix dm(dim, dim); - fill_uniformly(dm, dim); - dense_matrix dm0(dim, dim); - fill_uniformly(dm0, dim); - permutation_matrix q0(dim); - q0[0] = 1; - q0[1] = 0; - q0[2] = 3; - q0[3] = 2; - permutation_matrix q1(dim); - q1[0] = 1; - q1[1] = 2; - q1[2] = 3; - q1[3] = 0; - permutation_matrix p0(dim); - p0[0] = 1; - p0[1] = 0; - p0[2] = 3; - p0[3] = 2; - permutation_matrix p1(dim); - p1[0] = 1; - p1[1] = 2; - p1[2] = 3; - p1[3] = 0; - - m.multiply_from_left(q0); - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - lp_assert(m(i, j) == dm0.get_elem(q0[i], j)); - } - } - - auto q0_dm = q0 * dm; - lp_assert(m == q0_dm); - - m.multiply_from_left(q1); - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], j)); - } - } - - - auto q1_q0_dm = q1 * q0_dm; - - lp_assert(m == q1_q0_dm); - - m.multiply_from_right(p0); - - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p0[j])); - } - } - - auto q1_q0_dm_p0 = q1_q0_dm * p0; - - lp_assert(m == q1_q0_dm_p0); - - m.multiply_from_right(p1); - - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p0[j]])); - } - } - - auto q1_q0_dm_p0_p1 = q1_q0_dm_p0 * p1; - lp_assert(m == q1_q0_dm_p0_p1); - - m.multiply_from_right(p1); - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - lp_assert(m(i, j) == dm0.get_elem(q0[q1[i]], p1[p1[p0[j]]])); - } - } - auto q1_q0_dm_p0_p1_p1 = q1_q0_dm_p0_p1 * p1; - - lp_assert(m == q1_q0_dm_p0_p1_p1); -} - -void test_swap_columns() { - square_sparse_matrix m(10, 10); - fill_matrix(m); - // print_matrix(m); - - test_swap_columns(m, 3, 5); - - test_swap_columns(m, 1, 3); - - test_swap_columns(m, 1, 3); - - // print_matrix(m); - test_swap_columns(m, 1, 7); - - test_swap_columns(m, 3, 7); - - test_swap_columns(m, 0, 7); - - test_swap_columns(m, 0, 7); - - // go over some corner cases - square_sparse_matrix m0(2, 2); - test_swap_columns(m0, 0, 1); - m0(0, 0) = 3; - test_swap_columns(m0, 0, 1); - m0(0, 1) = 3; - test_swap_columns(m0, 0, 1); - - - square_sparse_matrix m1(10, 10); - test_swap_columns(m1, 0, 1); - m1(0, 0) = 3; - test_swap_columns(m1, 0, 1); - m1(0, 1) = 3; - m1(3, 0) = 5; - m1(3, 1) = 4; - m1(8, 1) = 8; - m1(9, 1) = 8; - - test_swap_columns(m1, 0, 1); - - square_sparse_matrix m2(3, 3); - test_swap_columns(m2, 0, 1); - m2(0, 0) = 3; - test_swap_columns(m2, 0, 1); - m2(0, 2) = 3; - test_swap_columns(m2, 0, 2); -} - -void test_swap_operations() { - test_swap_rows(); - test_swap_columns(); -} void test_dense_matrix() { dense_matrix d(3, 2); @@ -1110,7 +618,7 @@ void test_dense_matrix() { p2.set_elem(1, 0, 1); auto c2 = d * p2; } -#endif + @@ -1471,59 +979,6 @@ bool contains(std::string const & s, char const * pattern) { - -void test_init_U() { - static_matrix m(3, 7); - m(0, 0) = 10; m(0, 1) = 11; m(0, 2) = 12; m(0, 3) = 13; m(0, 4) = 14; - m(1, 0) = 20; m(1, 1) = 21; m(1, 2) = 22; m(1, 3) = 23; m(1, 5) = 24; - m(2, 0) = 30; m(2, 1) = 31; m(2, 2) = 32; m(2, 3) = 33; m(2, 6) = 34; -#ifdef Z3DEBUG - print_matrix(m, std::cout); -#endif - vector basis(3); - basis[0] = 1; - basis[1] = 2; - basis[2] = 4; - - square_sparse_matrix u(m, basis); - - for (unsigned i = 0; i < 3; i++) { - for (unsigned j = 0; j < 3; j ++) { - lp_assert(m(i, basis[j]) == u(i, j)); - } - } - - // print_matrix(m); - // print_matrix(u); -} - -void test_replace_column() { - square_sparse_matrix m(10, 10); - fill_matrix(m); - m.swap_columns(0, 7); - m.swap_columns(6, 3); - m.swap_rows(2, 0); - for (unsigned i = 1; i < m.dimension(); i++) { - m(i, 0) = 0; - } - - indexed_vector w(m.dimension()); - for (unsigned i = 0; i < m.dimension(); i++) { - w.set_value(i % 3, i); - } - - lp_settings settings; - - for (unsigned column_to_replace = 0; column_to_replace < m.dimension(); column_to_replace ++) { - m.replace_column(column_to_replace, w, settings); - for (unsigned i = 0; i < m.dimension(); i++) { - lp_assert(abs(w[i] - m(i, column_to_replace)) < 0.00000001); - } - } -} - - - void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("-monics", "test emonics"); parser.add_option_with_help_string("-nex_order", "test nex order"); @@ -1544,8 +999,6 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("-xyz_sample", "run a small interactive scenario"); parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense"); parser.add_option_with_after_string_with_help("--harris_toler", "harris tolerance"); - parser.add_option_with_help_string("--test_swaps", "test row swaps with a permutation"); - parser.add_option_with_help_string("--test_perm", "test permutations"); parser.add_option_with_after_string_with_help("--checklu", "the file name for lu checking"); parser.add_option_with_after_string_with_help("--partial_pivot", "the partial pivot constant, a number somewhere between 10 and 100"); parser.add_option_with_after_string_with_help("--percent_for_enter", "which percent of columns check for entering column"); @@ -1871,38 +1324,6 @@ void check_lu_from_file(std::string lufile_name) { lp_assert(false); } -void test_square_dense_submatrix() { - std::cout << "testing square_dense_submatrix" << std::endl; - unsigned parent_dim = 7; - square_sparse_matrix parent(parent_dim, 0); - fill_matrix(parent); - unsigned index_start = 3; - square_dense_submatrix d; - d.init(&parent, index_start); - for (unsigned i = index_start; i < parent_dim; i++) - for (unsigned j = index_start; j < parent_dim; j++) - d[i][j] = i*3+j*2; -#ifdef Z3DEBUG - unsigned dim = parent_dim - index_start; - dense_matrix m(dim, dim); - for (unsigned i = index_start; i < parent_dim; i++) - for (unsigned j = index_start; j < parent_dim; j++) - m[i-index_start][j-index_start] = d[i][j]; - print_matrix(&m, std::cout); -#endif - for (unsigned i = index_start; i < parent_dim; i++) - for (unsigned j = index_start; j < parent_dim; j++) - d[i][j] = d[j][i]; -#ifdef Z3DEBUG - for (unsigned i = index_start; i < parent_dim; i++) - for (unsigned j = index_start; j < parent_dim; j++) - m[i-index_start][j-index_start] = d[i][j]; - - print_matrix(&m, std::cout); - std::cout << std::endl; -#endif -} - void print_st(lp_status status) { @@ -2958,8 +2379,3 @@ void test_lp_local(int argn, char**argv) { void tst_lp(char ** argv, int argc, int& i) { lp::test_lp_local(argc - 2, argv + 2); } -#ifdef Z3DEBUG -namespace lp { -template void print_matrix(general_matrix&, std::ostream&); -} -#endif From 4dfc708b0bc0f2406c71bd262dc1987d43ad65e0 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 13:56:04 -0800 Subject: [PATCH 21/36] rm scaler --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/lar_solver.h | 1 - src/math/lp/scaler.cpp | 22 --- src/math/lp/scaler.h | 94 ------------ src/math/lp/scaler_def.h | 270 ---------------------------------- src/math/lp/static_matrix.cpp | 1 - 6 files changed, 389 deletions(-) delete mode 100644 src/math/lp/scaler.cpp delete mode 100644 src/math/lp/scaler.h delete mode 100644 src/math/lp/scaler_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 5d21bba70ba..5ccc023ab4c 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -41,7 +41,6 @@ z3_add_component(lp permutation_matrix.cpp random_updater.cpp row_eta_matrix.cpp - scaler.cpp square_sparse_matrix.cpp static_matrix.cpp COMPONENT_DEPENDENCIES diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 09612d905e4..be255dd65d3 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -31,7 +31,6 @@ #include "math/lp/lar_constraints.h" #include "math/lp/lar_core_solver.h" #include "math/lp/numeric_pair.h" -#include "math/lp/scaler.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/random_updater.h" #include "util/stacked_value.h" diff --git a/src/math/lp/scaler.cpp b/src/math/lp/scaler.cpp deleted file mode 100644 index 46330e2a1ee..00000000000 --- a/src/math/lp/scaler.cpp +++ /dev/null @@ -1,22 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include "math/lp/scaler_def.h" -template bool lp::scaler::scale(); -template bool lp::scaler::scale(); diff --git a/src/math/lp/scaler.h b/src/math/lp/scaler.h deleted file mode 100644 index dd21b5c2895..00000000000 --- a/src/math/lp/scaler.h +++ /dev/null @@ -1,94 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include -#include -#include /* printf, fopen */ -#include /* exit, EXIT_FAILURE */ -#include "math/lp/lp_utils.h" -#include "math/lp/static_matrix.h" -namespace lp { -// for scaling an LP -template -class scaler { - vector & m_b; // right side - static_matrix &m_A; // the constraint matrix - const T & m_scaling_minimum; - const T & m_scaling_maximum; - vector& m_column_scale; - lp_settings & m_settings; -public: - // constructor - scaler(vector & b, static_matrix &A, const T & scaling_minimum, const T & scaling_maximum, vector & column_scale, - lp_settings & settings): - m_b(b), - m_A(A), - m_scaling_minimum(scaling_minimum), - m_scaling_maximum(scaling_maximum), - m_column_scale(column_scale), - m_settings(settings) { - lp_assert(m_column_scale.size() == 0); - m_column_scale.resize(m_A.column_count(), numeric_traits::one()); - } - - T right_side_balance(); - - T get_balance() { return m_A.get_balance(); } - - T A_min() const; - - T A_max() const; - - T get_A_ratio() const; - - T get_max_ratio_on_rows() const; - - T get_max_ratio_on_columns() const; - - void scale_rows_with_geometric_mean(); - - void scale_columns_with_geometric_mean(); - - void scale_once_for_ratio(); - - bool scale_with_ratio(); - - void bring_row_maximums_to_one(); - - void bring_column_maximums_to_one(); - - void bring_rows_and_columns_maximums_to_one(); - - bool scale_with_log_balance(); - // Returns true if and only if the scaling was successful. - // It is the caller responsibility to restore the matrix - bool scale(); - - void scale_rows(); - - void scale_row(unsigned i); - - void scale_column(unsigned i); - - void scale_columns(); -}; -} diff --git a/src/math/lp/scaler_def.h b/src/math/lp/scaler_def.h deleted file mode 100644 index 8604a67a131..00000000000 --- a/src/math/lp/scaler_def.h +++ /dev/null @@ -1,270 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include "math/lp/scaler.h" -#include "math/lp/numeric_pair.h" -namespace lp { -// for scaling an LP -template T scaler::right_side_balance() { - T ret = zero_of_type(); - unsigned i = m_A.row_count(); - while (i--) { - T rs = abs(convert_struct::convert(m_b[i])); - if (!is_zero(rs)) { - numeric_traits::log(rs); - ret += rs * rs; - } - } - return ret; -} - -template T scaler::A_min() const { - T min = zero_of_type(); - for (unsigned i = 0; i < m_A.row_count(); i++) { - T t = m_A.get_min_abs_in_row(i); - min = i == 0 ? t : std::min(t, min); - } - return min; -} - -template T scaler::A_max() const { - T max = zero_of_type(); - for (unsigned i = 0; i < m_A.row_count(); i++) { - T t = m_A.get_max_abs_in_row(i); - max = i == 0? t : std::max(t, max); - } - return max; -} - -template T scaler::get_A_ratio() const { - T min = A_min(); - T max = A_max(); - lp_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(min)); - T ratio = max / min; - return ratio; -} - -template T scaler::get_max_ratio_on_rows() const { - T ret = T(1); - unsigned i = m_A.row_count(); - while (i--) { - T den = m_A.get_min_abs_in_row(i); - lp_assert(!m_settings.abs_val_is_smaller_than_zero_tolerance(den)); - T t = m_A.get_max_abs_in_row(i)/ den; - if (t > ret) - ret = t; - } - return ret; -} - -template T scaler::get_max_ratio_on_columns() const { - T ret = T(1); - unsigned i = m_A.column_count(); - while (i--) { - T den = m_A.get_min_abs_in_column(i); - if (m_settings.abs_val_is_smaller_than_zero_tolerance(den)) - continue; // got a zero column - T t = m_A.get_max_abs_in_column(i)/den; - if (t > ret) - ret = t; - } - return ret; -} - -template void scaler::scale_rows_with_geometric_mean() { - unsigned i = m_A.row_count(); - while (i--) { - T max = m_A.get_max_abs_in_row(i); - T min = m_A.get_min_abs_in_row(i); - lp_assert(max > zero_of_type() && min > zero_of_type()); - if (is_zero(max) || is_zero(min)) - continue; - T gm = T(sqrt(numeric_traits::get_double(max*min))); - if (m_settings.is_eps_small_general(gm, 0.01)) { - continue; - } - m_A.multiply_row(i, one_of_type() / gm); - m_b[i] /= gm; - } -} - -template void scaler::scale_columns_with_geometric_mean() { - unsigned i = m_A.column_count(); - while (i--) { - T max = m_A.get_max_abs_in_column(i); - T min = m_A.get_min_abs_in_column(i); - T den = T(sqrt(numeric_traits::get_double(max*min))); - if (m_settings.is_eps_small_general(den, 0.01)) - continue; // got a zero column - T gm = T(1)/ den; - T cs = m_column_scale[i] * gm; - if (m_settings.is_eps_small_general(cs, 0.1)) - continue; - m_A.multiply_column(i, gm); - m_column_scale[i] = cs; - } -} - -template void scaler::scale_once_for_ratio() { - T max_ratio_on_rows = get_max_ratio_on_rows(); - T max_ratio_on_columns = get_max_ratio_on_columns(); - bool scale_rows_first = max_ratio_on_rows > max_ratio_on_columns; - // if max_ratio_on_columns is the largest then the rows are in worse shape than columns - if (scale_rows_first) { - scale_rows_with_geometric_mean(); - scale_columns_with_geometric_mean(); - } else { - scale_columns_with_geometric_mean(); - scale_rows_with_geometric_mean(); - } -} - -template bool scaler::scale_with_ratio() { - T ratio = get_A_ratio(); - // The ratio is greater than or equal to one. We would like to diminish it and bring it as close to 1 as possible - unsigned reps = m_settings.reps_in_scaler; - do { - scale_once_for_ratio(); - T new_r = get_A_ratio(); - if (new_r >= T(0.9) * ratio) - break; - } while (reps--); - - bring_rows_and_columns_maximums_to_one(); - return true; -} - -template void scaler::bring_row_maximums_to_one() { - unsigned i = m_A.row_count(); - while (i--) { - T t = m_A.get_max_abs_in_row(i); - if (m_settings.abs_val_is_smaller_than_zero_tolerance(t)) continue; - m_A.multiply_row(i, one_of_type() / t); - m_b[i] /= t; - } -} - -template void scaler::bring_column_maximums_to_one() { - unsigned i = m_A.column_count(); - while (i--) { - T max = m_A.get_max_abs_in_column(i); - if (m_settings.abs_val_is_smaller_than_zero_tolerance(max)) continue; - T t = T(1) / max; - m_A.multiply_column(i, t); - m_column_scale[i] *= t; - } -} - -template void scaler::bring_rows_and_columns_maximums_to_one() { - if (get_max_ratio_on_rows() > get_max_ratio_on_columns()) { - bring_row_maximums_to_one(); - bring_column_maximums_to_one(); - } else { - bring_column_maximums_to_one(); - bring_row_maximums_to_one(); - } -} - -template bool scaler::scale_with_log_balance() { - T balance = get_balance(); - T balance_before_scaling = balance; - // todo : analyze the scale order : rows-columns, or columns-rows. Iterate if needed - for (int i = 0; i < 10; i++) { - scale_rows(); - scale_columns(); - T nb = get_balance(); - if (nb < T(0.9) * balance) { - balance = nb; - } else { - balance = nb; - break; - } - } - return balance <= balance_before_scaling; -} -// Returns true if and only if the scaling was successful. -// It is the caller responsibility to restore the matrix -template bool scaler::scale() { - if (numeric_traits::precise()) return true; - if (m_settings.scale_with_ratio) - return scale_with_ratio(); - return scale_with_log_balance(); -} - -template void scaler::scale_rows() { - for (unsigned i = 0; i < m_A.row_count(); i++) - scale_row(i); -} - -template void scaler::scale_row(unsigned i) { - T row_max = std::max(m_A.get_max_abs_in_row(i), abs(convert_struct::convert(m_b[i]))); - T alpha = numeric_traits::one(); - if (numeric_traits::is_zero(row_max)) { - return; - } - if (row_max < m_scaling_minimum) { - do { - alpha *= T(2); - row_max *= T(2); - } while (row_max < m_scaling_minimum); - m_A.multiply_row(i, alpha); - m_b[i] *= alpha; - } else if (row_max > m_scaling_maximum) { - do { - alpha /= T(2); - row_max /= T(2); - } while (row_max > m_scaling_maximum); - m_A.multiply_row(i, alpha); - m_b[i] *= alpha; - } -} - -template void scaler::scale_column(unsigned i) { - T column_max = m_A.get_max_abs_in_column(i); - T alpha = numeric_traits::one(); - - if (numeric_traits::is_zero(column_max)){ - return; // the column has zeros only - } - if (column_max < m_scaling_minimum) { - do { - alpha *= T(2); - column_max *= T(2); - } while (column_max < m_scaling_minimum); - } else if (column_max > m_scaling_maximum) { - do { - alpha /= T(2); - column_max /= T(2); - } while (column_max > m_scaling_maximum); - } else { - return; - } - m_A.multiply_column(i, alpha); - m_column_scale[i] = alpha; -} - -template void scaler::scale_columns() { - for (unsigned i = 0; i < m_A.column_count(); i++) { - scale_column(i); - } -} -} diff --git a/src/math/lp/static_matrix.cpp b/src/math/lp/static_matrix.cpp index 93360b9140f..12d2f9f0df3 100644 --- a/src/math/lp/static_matrix.cpp +++ b/src/math/lp/static_matrix.cpp @@ -24,7 +24,6 @@ Revision History: #include "math/lp/static_matrix_def.h" #include "math/lp/lp_core_solver_base.h" #include "math/lp/lp_primal_core_solver.h" -#include "math/lp/scaler.h" #include "math/lp/lar_solver.h" namespace lp { template void static_matrix::add_columns_at_the_end(unsigned int); From a37fd877a8c77dc1c6c58bce3312dac7ef62dbbb Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 14:17:04 -0800 Subject: [PATCH 22/36] rm square_sparse_matrix --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/lar_solver.cpp | 7 - src/math/lp/lar_solver.h | 2 - src/math/lp/lp_primal_core_solver.h | 2 +- src/math/lp/square_sparse_matrix.cpp | 118 --- src/math/lp/square_sparse_matrix.h | 433 -------- src/math/lp/square_sparse_matrix_def.h | 1303 ------------------------ src/test/lp/lp.cpp | 4 +- 8 files changed, 3 insertions(+), 1867 deletions(-) delete mode 100644 src/math/lp/square_sparse_matrix.cpp delete mode 100644 src/math/lp/square_sparse_matrix.h delete mode 100644 src/math/lp/square_sparse_matrix_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 5ccc023ab4c..ef363509fcb 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -41,7 +41,6 @@ z3_add_component(lp permutation_matrix.cpp random_updater.cpp row_eta_matrix.cpp - square_sparse_matrix.cpp static_matrix.cpp COMPONENT_DEPENDENCIES util diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index f890b27fa43..9bc850848e5 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -783,13 +783,6 @@ namespace lp { return r; } - - template - void lar_solver::add_last_rows_to_lu(lp_primal_core_solver& s) { - lp_assert(false); - - } - bool lar_solver::x_is_correct() const { if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { return false; diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index be255dd65d3..b925b5ef039 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -222,8 +222,6 @@ class lar_solver : public column_namer { void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); void solve_with_core_solver(); numeric_pair get_basic_var_value_from_row(unsigned i); - template - void add_last_rows_to_lu(lp_primal_core_solver & s); bool x_is_correct() const; void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls); template diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 2c7360712d6..10de624f55a 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -926,7 +926,7 @@ class lp_primal_core_solver:public lp_core_solver_base { m_lower_bounds_dummy.resize(A.column_count(), zero_of_type()); m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); #ifdef Z3DEBUG - // check_correctness(); + lp_assert(false); #endif } diff --git a/src/math/lp/square_sparse_matrix.cpp b/src/math/lp/square_sparse_matrix.cpp deleted file mode 100644 index 3ec88f47d85..00000000000 --- a/src/math/lp/square_sparse_matrix.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include "util/vector.h" -#include "math/lp/lp_settings.h" -#include "math/lp/square_sparse_matrix_def.h" -#include "math/lp/dense_matrix.h" -namespace lp { -template double square_sparse_matrix::dot_product_with_row(unsigned int, vector const&) const; -template void square_sparse_matrix::add_new_element(unsigned int, unsigned int, const double&); -template void square_sparse_matrix::divide_row_by_constant(unsigned int, const double&, lp_settings&); -template bool square_sparse_matrix::fill_eta_matrix(unsigned int, eta_matrix**); -template const double & square_sparse_matrix::get(unsigned int, unsigned int) const; -template unsigned square_sparse_matrix::get_number_of_nonzeroes() const; -template bool square_sparse_matrix::get_pivot_for_column(unsigned int&, unsigned int&, int, unsigned int); -template unsigned square_sparse_matrix::lowest_row_in_column(unsigned int); -template bool square_sparse_matrix::pivot_row_to_row(unsigned int, const double&, unsigned int, lp_settings&); -template bool square_sparse_matrix::pivot_with_eta(unsigned int, eta_matrix*, lp_settings&); -template void square_sparse_matrix::prepare_for_factorization(); -template void square_sparse_matrix::remove_element(vector >&, indexed_value&); -template void square_sparse_matrix::replace_column(unsigned int, indexed_vector&, lp_settings&); -template void square_sparse_matrix::set(unsigned int, unsigned int, double); -template void square_sparse_matrix::set_max_in_row(vector >&); -template bool square_sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); -template bool square_sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); -template void square_sparse_matrix::solve_y_U(vector&) const; -template square_sparse_matrix::square_sparse_matrix(unsigned int, unsigned); -template void square_sparse_matrix::add_new_element(unsigned int, unsigned int, const mpq&); -template void square_sparse_matrix::divide_row_by_constant(unsigned int, const mpq&, lp_settings&); -template bool square_sparse_matrix::fill_eta_matrix(unsigned int, eta_matrix**); -template mpq const & square_sparse_matrix::get(unsigned int, unsigned int) const; -template unsigned square_sparse_matrix::get_number_of_nonzeroes() const; -template bool square_sparse_matrix::get_pivot_for_column(unsigned int&, unsigned int&, int, unsigned int); -template unsigned square_sparse_matrix::lowest_row_in_column(unsigned int); -template bool square_sparse_matrix::pivot_with_eta(unsigned int, eta_matrix*, lp_settings&); -template void square_sparse_matrix::prepare_for_factorization(); -template void square_sparse_matrix::remove_element(vector> &, indexed_value&); -template void square_sparse_matrix::replace_column(unsigned int, indexed_vector&, lp_settings&); -template void square_sparse_matrix::set_max_in_row(vector>&); -template bool square_sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); -template bool square_sparse_matrix::shorten_active_matrix(unsigned int, eta_matrix*); -template void square_sparse_matrix::solve_y_U(vector&) const; -template void square_sparse_matrix>::add_new_element(unsigned int, unsigned int, const mpq&); -template void square_sparse_matrix>::divide_row_by_constant(unsigned int, const mpq&, lp_settings&); -template bool square_sparse_matrix>::fill_eta_matrix(unsigned int, eta_matrix >**); -template const mpq & square_sparse_matrix>::get(unsigned int, unsigned int) const; -template unsigned square_sparse_matrix>::get_number_of_nonzeroes() const; -template bool square_sparse_matrix>::get_pivot_for_column(unsigned int&, unsigned int&, int, unsigned int); -template unsigned square_sparse_matrix>::lowest_row_in_column(unsigned int); -template bool square_sparse_matrix>::pivot_with_eta(unsigned int, eta_matrix >*, lp_settings&); -template void square_sparse_matrix>::prepare_for_factorization(); -template void square_sparse_matrix>::remove_element(vector>&, indexed_value&); -template void square_sparse_matrix>::replace_column(unsigned int, indexed_vector&, lp_settings&); -template void square_sparse_matrix>::set_max_in_row(vector>&); -template bool square_sparse_matrix>::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned int, indexed_vector&, lp_settings&); -template bool square_sparse_matrix>::shorten_active_matrix(unsigned int, eta_matrix >*); -template void square_sparse_matrix>::solve_y_U(vector&) const; -template void square_sparse_matrix::double_solve_U_y(indexed_vector&, const lp_settings &); -template void square_sparse_matrix::double_solve_U_y(indexed_vector&, const lp_settings&); -template void square_sparse_matrix>::double_solve_U_y(indexed_vector&, const lp_settings&); -template void square_sparse_matrix >::double_solve_U_y >(indexed_vector>&, const lp_settings&); -template void square_sparse_matrix::solve_U_y_indexed_only(indexed_vector&, const lp_settings&, vector &); -template void square_sparse_matrix::solve_U_y_indexed_only(indexed_vector&, const lp_settings &, vector &); -#ifdef Z3DEBUG -template bool square_sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; -template bool square_sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; -template bool square_sparse_matrix >::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings&) const; -#endif - -template void square_sparse_matrix >::solve_U_y_indexed_only(indexed_vector&, const lp_settings &, vector &); -template void square_sparse_matrix::solve_U_y(vector&); -template void square_sparse_matrix::double_solve_U_y(vector&); -template void square_sparse_matrix::solve_U_y(vector&); -template void square_sparse_matrix::double_solve_U_y(vector&); -template void square_sparse_matrix >::solve_U_y >(vector >&); -template void square_sparse_matrix >::double_solve_U_y >(vector >&); -template void square_sparse_matrix::find_error_in_solution_U_y_indexed(indexed_vector&, indexed_vector&, const vector &); -template double square_sparse_matrix::dot_product_with_row(unsigned int, indexed_vector const&) const; -template void square_sparse_matrix::find_error_in_solution_U_y_indexed(indexed_vector&, indexed_vector&, const vector &); -template mpq square_sparse_matrix::dot_product_with_row(unsigned int, indexed_vector const&) const; -template void square_sparse_matrix >::find_error_in_solution_U_y_indexed(indexed_vector&, indexed_vector&, const vector &); -template mpq square_sparse_matrix >::dot_product_with_row(unsigned int, indexed_vector const&) const; -template void square_sparse_matrix >::find_error_in_solution_U_y_indexed >(indexed_vector >&, indexed_vector >&, const vector &); -template numeric_pair square_sparse_matrix >::dot_product_with_row >(unsigned int, indexed_vector > const&) const; -template void square_sparse_matrix::extend_and_sort_active_rows(vector const&, vector&); - -template void square_sparse_matrix >::extend_and_sort_active_rows(vector const&, vector&); - -template void square_sparse_matrix >::solve_U_y(vector&); -template void square_sparse_matrix >::double_solve_U_y(vector&); -template void square_sparse_matrix< mpq,numeric_pair< mpq> >::set(unsigned int,unsigned int, mpq); -template void square_sparse_matrix::solve_y_U_indexed(indexed_vector&, const lp_settings & ); -template void square_sparse_matrix::solve_y_U_indexed(indexed_vector&, const lp_settings &); -template void square_sparse_matrix >::solve_y_U_indexed(indexed_vector&, const lp_settings &); - -template square_sparse_matrix::square_sparse_matrix(static_matrix const&, vector&); -template square_sparse_matrix::square_sparse_matrix (static_matrix const&, vector&); -template square_sparse_matrix >::square_sparse_matrix(static_matrix > const&, vector&); -} -template void lp::square_sparse_matrix::copy_from_input_on_basis >(lp::static_matrix const&, vector&); -template void lp::square_sparse_matrix::copy_from_input_on_basis >(lp::static_matrix const&, vector&); diff --git a/src/math/lp/square_sparse_matrix.h b/src/math/lp/square_sparse_matrix.h deleted file mode 100644 index 5637af99f37..00000000000 --- a/src/math/lp/square_sparse_matrix.h +++ /dev/null @@ -1,433 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "math/lp/permutation_matrix.h" -#include "math/lp/static_matrix.h" -#include -#include -#include -#include -#include -#include "math/lp/indexed_value.h" -#include "math/lp/indexed_vector.h" -#include -#include "math/lp/lp_settings.h" -#include "math/lp/eta_matrix.h" -#include "math/lp/binary_heap_upair_queue.h" -#include "math/lp/numeric_pair.h" -#include "math/lp/u_set.h" -namespace lp { -// it is a square matrix -template -class square_sparse_matrix - : public matrix -{ - struct col_header { - unsigned m_shortened_markovitz; - vector> m_values; // the actual column values - - col_header(): m_shortened_markovitz(0) {} - - void shorten_markovich_by_one() { - m_shortened_markovitz++; - } - - void zero_shortened_markovitz() { - m_shortened_markovitz = 0; - } - }; - - unsigned m_n_of_active_elems; - binary_heap_upair_queue m_pivot_queue; -public: - vector>> m_rows; - vector m_columns; - permutation_matrix m_row_permutation; - permutation_matrix m_column_permutation; - // m_work_pivot_vector[j] = offset of elementh of j-th column in the row we are pivoting to - // if the column is not present then m_work_pivot_vector[j] is -1 - vector m_work_pivot_vector; - vector m_processed; - unsigned get_n_of_active_elems() const { return m_n_of_active_elems; } - -#ifdef Z3DEBUG - // dense_matrix m_dense; -#endif - /* - the rule is: row i is mapped to m_row_permutation[i] and - column j is mapped to m_column_permutation.apply_reverse(j) - */ - - unsigned adjust_row(unsigned row) const{ - return m_row_permutation[row]; - } - - unsigned adjust_column(unsigned col) const{ - return m_column_permutation.apply_reverse(col); - } - - unsigned adjust_row_inverse(unsigned row) const{ - return m_row_permutation.apply_reverse(row); - } - - unsigned adjust_column_inverse(unsigned col) const{ - return m_column_permutation[col]; - } - - template - void copy_column_from_input(unsigned input_column, const M& A, unsigned j); - template - void copy_column_from_input_with_possible_zeros(const M& A, unsigned j); - - template - void copy_from_input(const M& A); - template - void copy_from_input_on_basis(const M& A, vector & basis); - -public: - - // constructors - template - square_sparse_matrix(const M &A, vector& basis); - - template - square_sparse_matrix(const M &A); - - square_sparse_matrix(unsigned dim, unsigned); // the second parameter is needed to distinguish this - // constructor from the one above - - - - class ref_matrix_element { - square_sparse_matrix & m_matrix; - unsigned m_row; - unsigned m_col; - public: - ref_matrix_element(square_sparse_matrix & m, unsigned row, unsigned col):m_matrix(m), m_row(row), m_col(col) {} - ref_matrix_element & operator=(T const & v) { m_matrix.set( m_row, m_col, v); return *this; } - ref_matrix_element & operator=(ref_matrix_element const & v) { m_matrix.set(m_row, m_col, v.m_matrix.get(v.m_row, v.m_col)); return *this; } - operator T () const { return m_matrix.get(m_row, m_col); } - }; - - class ref_row { - square_sparse_matrix & m_matrix; - unsigned m_row; - public: - ref_row(square_sparse_matrix & m, unsigned row) : m_matrix(m), m_row(row) {} - ref_matrix_element operator[](unsigned col) const { return ref_matrix_element(m_matrix, m_row, col); } - }; - - void set_with_no_adjusting_for_row(unsigned row, unsigned col, T val); - void set_with_no_adjusting_for_col(unsigned row, unsigned col, T val); - - void set_with_no_adjusting(unsigned row, unsigned col, T val); - - void set(unsigned row, unsigned col, T val); - - T const & get_not_adjusted(unsigned row, unsigned col) const; - T const & get(unsigned row, unsigned col) const; - - ref_row operator[](unsigned row) { return ref_row(*this, row); } - - ref_matrix_element operator()(unsigned row, unsigned col) { return ref_matrix_element(*this, row, col); } - - T operator() (unsigned row, unsigned col) const { return get(row, col); } - - vector> & get_row_values(unsigned row) { - return m_rows[row]; - } - - vector> const & get_row_values(unsigned row) const { - return m_rows[row]; - } - - vector> & get_column_values(unsigned col) { - return m_columns[col].m_values; - } - - vector> const & get_column_values(unsigned col) const { - return m_columns[col].m_values; - } - - unsigned dimension() const {return static_cast(m_row_permutation.size());} - - unsigned row_count() const override {return dimension();} - unsigned column_count() const override {return dimension();} - - void init_row_headers(); - - void init_column_headers(); - - unsigned lowest_row_in_column(unsigned j); - - indexed_value & column_iv_other(indexed_value & iv) { - return m_rows[iv.m_index][iv.m_other]; - } - - indexed_value & row_iv_other(indexed_value & iv) { - return m_columns[iv.m_index].m_values[iv.m_other]; - } - - void remove_element(vector> & row_vals, unsigned row_offset, vector> & column_vals, unsigned column_offset); - - void remove_element(vector> & row_chunk, indexed_value & row_el_iv); - - void put_max_index_to_0(vector> & row_vals, unsigned max_index); - - void set_max_in_row(unsigned row) { - set_max_in_row(m_rows[row]); - } - - - void set_max_in_row(vector> & row_vals); - - bool pivot_with_eta(unsigned i, eta_matrix *eta_matrix, lp_settings & settings); - - void scan_row_to_work_vector_and_remove_pivot_column(unsigned row, unsigned pivot_column); - - // This method pivots row i to row i0 by muliplying row i by - // alpha and adding it to row i0. - // After pivoting the row i0 has a max abs value set correctly at the beginning of m_start, - // Returns false if the resulting row is all zeroes, and true otherwise - bool pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, lp_settings & settings ); - - // set the max val as well - // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, - lp_settings & settings); - - - // set the max val as well - // returns false if the resulting row is all zeroes, and true otherwise - bool set_row_from_work_vector_and_clean_work_vector(unsigned i0); - - void remove_zero_elements_and_set_data_on_existing_elements(unsigned row); - - // work_vec here has not adjusted column indices - void remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(unsigned row, indexed_vector & work_vec, lp_settings & settings); - - void multiply_from_right(permutation_matrix& p) { - // m_dense = m_dense * p; - m_column_permutation.multiply_by_permutation_from_right(p); - // lp_assert(*this == m_dense); - } - - void multiply_from_left(permutation_matrix& p) { - // m_dense = p * m_dense; - m_row_permutation.multiply_by_permutation_from_left(p); - // lp_assert(*this == m_dense); - } - - void multiply_from_left_with_reverse(permutation_matrix& p) { - // m_dense = p * m_dense; - m_row_permutation.multiply_by_permutation_reverse_from_left(p); - // lp_assert(*this == m_dense); - } - - // adding delta columns at the end of the matrix - void add_columns_at_the_end(unsigned delta); - - void delete_column(int i); - - void swap_columns(unsigned a, unsigned b) { - m_column_permutation.transpose_from_left(a, b); - } - - void swap_rows(unsigned a, unsigned b) { - m_row_permutation.transpose_from_right(a, b); - // m_dense.swap_rows(a, b); - // lp_assert(*this == m_dense); - } - - void divide_row_by_constant(unsigned i, const T & t, lp_settings & settings); - - bool close(T a, T b) { - return // (numeric_traits::precise() && numeric_traits::is_zero(a - b)) - // || - fabs(numeric_traits::get_double(a - b)) < 0.0000001; - } - - // solving x * this = y, and putting the answer into y - // the matrix here has to be upper triangular - void solve_y_U(vector & y) const; - - // solving x * this = y, and putting the answer into y - // the matrix here has to be upper triangular - void solve_y_U_indexed(indexed_vector & y, const lp_settings &); - - // fills the indices for such that y[i] can be not a zero - // sort them so the smaller indices come first - void fill_reachable_indices(std::set & rset, T *y); - - template - void find_error_in_solution_U_y(vector& y_orig, vector & y); - - template - void find_error_in_solution_U_y_indexed(indexed_vector& y_orig, indexed_vector & y, const vector& sorted_active_rows); - - template - void add_delta_to_solution(const vector& del, vector & y); - - template - void add_delta_to_solution(const indexed_vector& del, indexed_vector & y); - - template - void double_solve_U_y(indexed_vector& y, const lp_settings & settings); - - template - void double_solve_U_y(vector& y); - // solving this * x = y, and putting the answer into y - // the matrix here has to be upper triangular - template - void solve_U_y(vector & y); - // solving this * x = y, and putting the answer into y - // the matrix here has to be upper triangular - template - void solve_U_y_indexed_only(indexed_vector & y, const lp_settings&, vector & sorted_active_rows ); - - T get_elem(unsigned i, unsigned j) const override { return get(i, j); } - unsigned get_number_of_rows() const { return dimension(); } - unsigned get_number_of_columns() const { return dimension(); } - void set_number_of_rows(unsigned /*m*/) override { } - void set_number_of_columns(unsigned /*n*/) override { } - template - L dot_product_with_row (unsigned row, const vector & y) const; - - template - L dot_product_with_row (unsigned row, const indexed_vector & y) const; - - unsigned get_number_of_nonzeroes() const; - - bool get_non_zero_column_in_row(unsigned i, unsigned *j) const; - - void remove_element_that_is_not_in_w(vector> & column_vals, indexed_value & col_el_iv); - - - // w contains the new column - // the old column inside of the matrix has not been changed yet - void remove_elements_that_are_not_in_w_and_update_common_elements(unsigned column_to_replace, indexed_vector & w); - - void add_new_element(unsigned row, unsigned col, const T& val); - - // w contains the "rest" of the new column; all common elements of w and the old column has been zeroed - // the old column inside of the matrix has not been changed yet - void add_new_elements_of_w_and_clear_w(unsigned column_to_replace, indexed_vector & w, lp_settings & settings); - - void replace_column(unsigned column_to_replace, indexed_vector & w, lp_settings &settings); - - unsigned pivot_score(unsigned i, unsigned j); - - void enqueue_domain_into_pivot_queue(); - - void set_max_in_rows(); - - void zero_shortened_markovitz_numbers(); - - void prepare_for_factorization(); - - void recover_pivot_queue(vector & rejected_pivots); - - int elem_is_too_small(unsigned i, unsigned j, int c_partial_pivoting); - - bool remove_row_from_active_pivots_and_shorten_columns(unsigned row); - - void remove_pivot_column(unsigned row); - - void update_active_pivots(unsigned row); - - bool shorten_active_matrix(unsigned row, eta_matrix *eta_matrix); - - unsigned pivot_score_without_shortened_counters(unsigned i, unsigned j, unsigned k); -#ifdef Z3DEBUG - bool can_improve_score_for_row(unsigned row, unsigned score, T const & c_partial_pivoting, unsigned k); - bool really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k); - void print_active_matrix(unsigned k, std::ostream & out); -#endif - bool pivot_queue_is_correct_for_row(unsigned i, unsigned k); - - bool pivot_queue_is_correct_after_pivoting(int k); - - bool get_pivot_for_column(unsigned &i, unsigned &j, int c_partial_pivoting, unsigned k); - - bool elem_is_too_small(vector> & row_chunk, indexed_value & iv, int c_partial_pivoting); - - unsigned number_of_non_zeroes_in_row(unsigned row) const { - return static_cast(m_rows[row].size()); - } - - unsigned number_of_non_zeroes_in_column(unsigned col) const { - return m_columns[col].m_values.size(); - } - - bool shorten_columns_by_pivot_row(unsigned i, unsigned pivot_column); - - bool col_is_active(unsigned j, unsigned pivot) { - return adjust_column_inverse(j) > pivot; - } - - bool row_is_active(unsigned i, unsigned pivot) { - return adjust_row_inverse(i) > pivot; - } - - bool fill_eta_matrix(unsigned j, eta_matrix ** eta); -#ifdef Z3DEBUG - bool is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const; - - bool is_upper_triangular_until(unsigned k) const; - void check_column_vs_rows(unsigned col); - - void check_row_vs_columns(unsigned row); - - void check_rows_vs_columns(); - - void check_columns_vs_rows(); - - void check_matrix(); -#endif - void create_graph_G(const vector & active_rows, vector & sorted_active_rows); - void process_column_recursively(unsigned i, vector & sorted_rows); - void extend_and_sort_active_rows(const vector & active_rows, vector & sorted_active_rows); - void process_index_recursively_for_y_U(unsigned j, vector & sorted_rows); - void resize(unsigned new_dim) { - unsigned old_dim = dimension(); - lp_assert(new_dim >= old_dim); - for (unsigned j = old_dim; j < new_dim; j++) { - m_rows.push_back(vector>()); - m_columns.push_back(col_header()); - } - m_pivot_queue.resize(new_dim); - m_row_permutation.resize(new_dim); - m_column_permutation.resize(new_dim); - m_work_pivot_vector.resize(new_dim); - m_processed.resize(new_dim); - for (unsigned j = old_dim; j < new_dim; j++) { - add_new_element(j, j, numeric_traits::one()); - } - } -#ifdef Z3DEBUG -vector get_full_row(unsigned i) const; -#endif - unsigned pivot_queue_size() const { return m_pivot_queue.size(); } -}; -}; - - diff --git a/src/math/lp/square_sparse_matrix_def.h b/src/math/lp/square_sparse_matrix_def.h deleted file mode 100644 index 19263462717..00000000000 --- a/src/math/lp/square_sparse_matrix_def.h +++ /dev/null @@ -1,1303 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include "util/vector.h" -#include "math/lp/square_sparse_matrix.h" -#include "math/lp/dense_matrix.h" - -#include -#include -namespace lp { -template -template -void square_sparse_matrix::copy_column_from_input(unsigned input_column, const M& A, unsigned j) { - vector> & new_column_vector = m_columns[j].m_values; - for (auto c : A.column(input_column)) { - unsigned col_offset = static_cast(new_column_vector.size()); - vector> & row_vector = m_rows[c.var()]; - unsigned row_offset = static_cast(row_vector.size()); - new_column_vector.push_back(indexed_value(c.coeff(), c.var(), row_offset)); - row_vector.push_back(indexed_value(c.coeff(), j, col_offset)); - m_n_of_active_elems++; - } -} - -template -template -void square_sparse_matrix::copy_column_from_input_with_possible_zeros(const M& A, unsigned j) { - vector> & new_column_vector = m_columns[j].m_values; - for (auto c : A.column(j)) { - if (is_zero(c.coeff())) - continue; - unsigned col_offset = static_cast(new_column_vector.size()); - vector> & row_vector = m_rows[c.var()]; - unsigned row_offset = static_cast(row_vector.size()); - new_column_vector.push_back(indexed_value(c.coeff(), c.var(), row_offset)); - row_vector.push_back(indexed_value(c.coeff(), j, col_offset)); - m_n_of_active_elems++; - } -} - -template -template -void square_sparse_matrix::copy_from_input_on_basis(const M & A, vector & basis) { - unsigned m = A.row_count(); - for (unsigned j = m; j-- > 0;) { - copy_column_from_input(basis[j], A, j); - } -} -template -template -void square_sparse_matrix::copy_from_input(const M & A) { - unsigned m = A.row_count(); - for (unsigned j = m; j-- > 0;) { - copy_column_from_input_with_possible_zeros(A, j); - } -} - -// constructor that copies columns of the basis from A -template -template -square_sparse_matrix::square_sparse_matrix(const M &A, vector & basis) : - m_n_of_active_elems(0), - m_pivot_queue(A.row_count()), - m_row_permutation(A.row_count()), - m_column_permutation(A.row_count()), - m_work_pivot_vector(A.row_count(), -1), - m_processed(A.row_count()) { - init_row_headers(); - init_column_headers(); - copy_from_input_on_basis(A, basis); -} - -template -template -square_sparse_matrix::square_sparse_matrix(const M &A) : - m_n_of_active_elems(0), - m_pivot_queue(A.row_count()), - m_row_permutation(A.row_count()), - m_column_permutation(A.row_count()), - m_work_pivot_vector(A.row_count(), -1), - m_processed(A.row_count()) { - init_row_headers(); - init_column_headers(); - copy_from_input(A); -} - - -template -void square_sparse_matrix::set_with_no_adjusting_for_row(unsigned row, unsigned col, T val) { // should not be used in efficient code - vector> & row_vec = m_rows[row]; - for (auto & iv : row_vec) { - if (iv.m_index == col) { - iv.set_value(val); - return; - } - } - // have not found the column between the indices - row_vec.push_back(indexed_value(val, col, -1)); -} - -template -void square_sparse_matrix::set_with_no_adjusting_for_col(unsigned row, unsigned col, T val) { // should not be used in efficient code - vector> & col_vec = m_columns[col].m_values; - for (auto & iv : col_vec) { - if (iv.m_index == row) { - iv.set_value(val); - return; - } - } - // have not found the column between the indices - col_vec.push_back(indexed_value(val, row, -1)); -} - - -template -void square_sparse_matrix::set_with_no_adjusting(unsigned row, unsigned col, T val) { // should not be used in efficient code - set_with_no_adjusting_for_row(row, col, val); - set_with_no_adjusting_for_col(row, col, val); -} - -template -void square_sparse_matrix::set(unsigned row, unsigned col, T val) { // should not be used in efficient code - lp_assert(row < dimension() && col < dimension()); - // m_dense.set_elem(row, col, val); - row = adjust_row(row); - col = adjust_column(col); - set_with_no_adjusting(row, col, val); - // lp_assert(*this == m_dense); -} - -template -T const & square_sparse_matrix::get_not_adjusted(unsigned row, unsigned col) const { - for (indexed_value const & iv : m_rows[row]) { - if (iv.m_index == col) { - return iv.m_value; - } - } - return numeric_traits::zero(); -} - -template -T const & square_sparse_matrix::get(unsigned row, unsigned col) const { // should not be used in efficient code - row = adjust_row(row); - auto & row_chunk = m_rows[row]; - col = adjust_column(col); - for (indexed_value const & iv : row_chunk) { - if (iv.m_index == col) { - return iv.m_value; - } - } - return numeric_traits::zero(); -} - -// constructor creating a zero matrix of dim*dim -template -square_sparse_matrix::square_sparse_matrix(unsigned dim, unsigned ) : - m_pivot_queue(dim), // dim will be the initial size of the queue - m_row_permutation(dim), - m_column_permutation(dim), - m_work_pivot_vector(dim, -1), - m_processed(dim) { - init_row_headers(); - init_column_headers(); - } - -template -void square_sparse_matrix::init_row_headers() { - for (unsigned l = 0; l < m_row_permutation.size(); l++) { - m_rows.push_back(vector>()); - } -} - -template -void square_sparse_matrix::init_column_headers() { // we always have only square square_sparse_matrix - for (unsigned l = 0; l < m_row_permutation.size(); l++) { - m_columns.push_back(col_header()); - } -} - -template -unsigned square_sparse_matrix::lowest_row_in_column(unsigned j) { - auto & mc = get_column_values(adjust_column(j)); - unsigned ret = 0; - for (auto & iv : mc) { - unsigned row = adjust_row_inverse(iv.m_index); - if (row > ret) { - ret = row; - } - } - return ret; -} - -template -void square_sparse_matrix::remove_element(vector> & row_vals, unsigned row_offset, vector> & column_vals, unsigned column_offset) { - if (column_offset != column_vals.size() - 1) { - auto & column_iv = column_vals[column_offset] = column_vals.back(); // copy from the tail - column_iv_other(column_iv).m_other = column_offset; - if (row_offset != row_vals.size() - 1) { - auto & row_iv = row_vals[row_offset] = row_vals.back(); // copy from the tail - row_iv_other(row_iv).m_other = row_offset; - } - } else if (row_offset != row_vals.size() - 1) { - auto & row_iv = row_vals[row_offset] = row_vals.back(); // copy from the tail - row_iv_other(row_iv).m_other = row_offset; - } - // do nothing - just decrease the sizes - column_vals.pop_back(); - row_vals.pop_back(); - m_n_of_active_elems--; // the value is correct only when refactoring -} - -template -void square_sparse_matrix::remove_element(vector> & row_chunk, indexed_value & row_el_iv) { - auto & column_chunk = get_column_values(row_el_iv.m_index); - indexed_value & col_el_iv = column_chunk[row_el_iv.m_other]; - remove_element(row_chunk, col_el_iv.m_other, column_chunk, row_el_iv.m_other); -} - -template -void square_sparse_matrix::put_max_index_to_0(vector> & row_vals, unsigned max_index) { - if (max_index == 0) return; - indexed_value * max_iv = & row_vals[max_index]; - indexed_value * start_iv = & row_vals[0]; - // update the "other" columns elements which are bound to the start_iv and max_iv - m_columns[max_iv->m_index].m_values[max_iv->m_other].m_other = 0; - m_columns[start_iv->m_index].m_values[start_iv->m_other].m_other = max_index; - - // swap the elements - indexed_value t = * max_iv; - * max_iv = * start_iv; - * start_iv = t; -} - -template -void square_sparse_matrix::set_max_in_row(vector> & row_vals) { - if (row_vals.empty()) - return; - T max_val = abs(row_vals[0].m_value); - unsigned max_index = 0; - for (unsigned i = 1; i < row_vals.size(); i++) { - T iabs = abs(row_vals[i].m_value); - if (iabs > max_val) { - max_val = iabs; - max_index = i; - } - } - put_max_index_to_0(row_vals, max_index); -} - -template -bool square_sparse_matrix::pivot_with_eta(unsigned i, eta_matrix *eta_matrix, lp_settings & settings) { - const T& pivot = eta_matrix->get_diagonal_element(); - for (auto & it : eta_matrix->m_column_vector.m_data) { - if (!pivot_row_to_row(i, it.second, it.first, settings)) { - return false; - } - } - - divide_row_by_constant(i, pivot, settings); - if (!shorten_active_matrix(i, eta_matrix)) { - return false; - } - - return true; -} - -// returns the offset of the pivot column in the row -template -void square_sparse_matrix::scan_row_to_work_vector_and_remove_pivot_column(unsigned row, unsigned pivot_column) { - auto & rvals = m_rows[row]; - unsigned size = rvals.size(); - for (unsigned j = 0; j < size; j++) { - auto & iv = rvals[j]; - if (iv.m_index != pivot_column) { - m_work_pivot_vector[iv.m_index] = j; - } else { - remove_element(rvals, iv); - j--; - size--; - } - } -} - -#ifdef Z3DEBUG -template -vector square_sparse_matrix::get_full_row(unsigned i) const { - vector r; - for (unsigned j = 0; j < column_count(); j++) - r.push_back(get(i, j)); - return r; -} -#endif - - - -// This method pivots row i to row i0 by muliplying row i by -// alpha and adding it to row i0. -// After pivoting the row i0 has a max abs value set correctly at the beginning of m_start, -// Returns false if the resulting row is all zeroes, and true otherwise -template -bool square_sparse_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, lp_settings & settings ) { - lp_assert(i < dimension() && i0 < dimension()); - lp_assert(i != i0); - unsigned pivot_col = adjust_column(i); - i = adjust_row(i); - i0 = adjust_row(i0); - vector became_zeros; - // the offset of element of the pivot column in row i0 - scan_row_to_work_vector_and_remove_pivot_column(i0, pivot_col); - auto & i0_row_vals = m_rows[i0]; - // run over the pivot row and update row i0 - unsigned prev_size_i0 = i0_row_vals.size(); - for (const auto & iv : m_rows[i]) { - unsigned j = iv.m_index; - if (j == pivot_col) continue; - T alv = alpha * iv.m_value; - int j_offs = m_work_pivot_vector[j]; - if (j_offs == -1) { // it is a new element - if (!settings.abs_val_is_smaller_than_drop_tolerance(alv)) { - add_new_element(i0, j, alv); - } - } - else { - auto & row_el_iv = i0_row_vals[j_offs]; - row_el_iv.m_value += alv; - if (settings.abs_val_is_smaller_than_drop_tolerance(row_el_iv.m_value)) { - became_zeros.push_back(j_offs); - ensure_increasing(became_zeros); - } - else { - m_columns[j].m_values[row_el_iv.m_other].set_value(row_el_iv.m_value); - } - } - } - - - // clean the work vector - for (unsigned k = 0; k < prev_size_i0; k++) { - m_work_pivot_vector[i0_row_vals[k].m_index] = -1; - } - - for (unsigned k = became_zeros.size(); k-- > 0; ) { - unsigned j = became_zeros[k]; - remove_element(i0_row_vals, i0_row_vals[j]); - if (i0_row_vals.empty()) - return false; - } - - if (numeric_traits::precise() == false) - set_max_in_row(i0_row_vals); - - return !i0_row_vals.empty(); -} - - - -// set the max val as well -// returns false if the resulting row is all zeroes, and true otherwise -template -bool square_sparse_matrix::set_row_from_work_vector_and_clean_work_vector_not_adjusted(unsigned i0, indexed_vector & work_vec, - lp_settings & settings) { - remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(i0, work_vec, settings); - // all non-zero elements in m_work_pivot_vector are new - for (unsigned j : work_vec.m_index) { - if (numeric_traits::is_zero(work_vec[j])) { - continue; - } - lp_assert(!settings.abs_val_is_smaller_than_drop_tolerance(work_vec[j])); - add_new_element(i0, adjust_column(j), work_vec[j]); - work_vec[j] = numeric_traits::zero(); - } - work_vec.m_index.clear(); - auto & row_vals = m_rows[i0]; - if (row_vals.empty()) { - return false; - } - set_max_in_row(row_vals); // it helps to find larger pivots - return true; -} - - - -template -void square_sparse_matrix::remove_zero_elements_and_set_data_on_existing_elements(unsigned row) { - auto & row_vals = m_rows[row]; - for (unsigned k = static_cast(row_vals.size()); k-- > 0;) { // we cannot simply run the iterator since we are removing - // elements from row_vals - auto & row_el_iv = row_vals[k]; - unsigned j = row_el_iv.m_index; - T & wj = m_work_pivot_vector[j]; - if (is_zero(wj)) { - remove_element(row_vals, row_el_iv); - } else { - m_columns[j].m_values[row_el_iv.m_other].set_value(wj); - row_el_iv.set_value(wj); - wj = zero_of_type(); - } - } -} - -// work_vec here has not adjusted column indices -template -void square_sparse_matrix::remove_zero_elements_and_set_data_on_existing_elements_not_adjusted(unsigned row, indexed_vector & work_vec, lp_settings & settings) { - auto & row_vals = m_rows[row]; - for (unsigned k = static_cast(row_vals.size()); k-- > 0;) { // we cannot simply run the iterator since we are removing - // elements from row_vals - auto & row_el_iv = row_vals[k]; - unsigned j = row_el_iv.m_index; - unsigned rj = adjust_column_inverse(j); - T val = work_vec[rj]; - if (settings.abs_val_is_smaller_than_drop_tolerance(val)) { - remove_element(row_vals, row_el_iv); - lp_assert(numeric_traits::is_zero(val)); - } else { - m_columns[j].m_values[row_el_iv.m_other].set_value(row_el_iv.m_value = val); - work_vec[rj] = numeric_traits::zero(); - } - } -} - - -// adding delta columns at the end of the matrix -template -void square_sparse_matrix::add_columns_at_the_end(unsigned delta) { - for (unsigned i = 0; i < delta; i++) { - col_header col_head; - m_columns.push_back(col_head); - } - m_column_permutation.enlarge(delta); -} - -template -void square_sparse_matrix::delete_column(int i) { - lp_assert(i < dimension()); - for (auto cell = m_columns[i].m_head; cell != nullptr;) { - auto next_cell = cell->m_down; - kill_cell(cell); - cell = next_cell; - } -} - -template -void square_sparse_matrix::divide_row_by_constant(unsigned i, const T & t, lp_settings & settings) { - lp_assert(!settings.abs_val_is_smaller_than_zero_tolerance(t)); - i = adjust_row(i); - for (auto & iv : m_rows[i]) { - T &v = iv.m_value; - v /= t; - if (settings.abs_val_is_smaller_than_drop_tolerance(v)){ - v = numeric_traits::zero(); - } - m_columns[iv.m_index].m_values[iv.m_other].set_value(v); - } -} - - -// solving x * this = y, and putting the answer into y -// the matrix here has to be upper triangular -template -void square_sparse_matrix::solve_y_U(vector & y) const { // works by rows -#ifdef Z3DEBUG - // T * rs = clone_vector(y, dimension()); -#endif - unsigned end = dimension(); - for (unsigned i = 0; i + 1 < end; i++) { - // all y[i] has correct values already - const T & yv = y[i]; - if (numeric_traits::is_zero(yv)) continue; - auto & mc = get_row_values(adjust_row(i)); - for (auto & c : mc) { - unsigned col = adjust_column_inverse(c.m_index); - if (col != i) { - y[col] -= c.m_value * yv; - } - } - } -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // T * clone_y = clone_vector(y, dimension()); - // deb.apply_from_right(clone_y); - // lp_assert(vectors_are_equal(rs, clone_y, dimension())); - // delete [] clone_y; - // delete [] rs; -#endif -} - -// solving x * this = y, and putting the answer into y -// the matrix here has to be upper triangular -template -void square_sparse_matrix::solve_y_U_indexed(indexed_vector & y, const lp_settings & settings) { -#if 0 && Z3DEBUG - vector ycopy(y.m_data); - if (numeric_traits::precise() == false) - solve_y_U(ycopy); -#endif - vector sorted_active_columns; - extend_and_sort_active_rows(y.m_index, sorted_active_columns); - for (unsigned k = sorted_active_columns.size(); k-- > 0; ) { - unsigned j = sorted_active_columns[k]; - auto & yj = y[j]; - for (auto & c: m_columns[adjust_column(j)].m_values) { - unsigned i = adjust_row_inverse(c.m_index); - if (i == j) continue; - yj -= y[i] * c.m_value; - } - } - y.m_index.clear(); - for (auto j : sorted_active_columns) { - if (!settings.abs_val_is_smaller_than_drop_tolerance(y[j])) - y.m_index.push_back(j); - else if (!numeric_traits::precise()) - y.m_data[j] = zero_of_type(); - } - - lp_assert(y.is_OK()); -#if 0 && Z3DEBUG - if (numeric_traits::precise() == false) - lp_assert(vectors_are_equal(ycopy, y.m_data)); -#endif -} - - -// fills the indices for such that y[i] can be not a zero -// sort them so the smaller indices come first -// void fill_reachable_indices(std::set & rset, T *y) { -// std::queue q; -// int m = dimension(); -// for (int i = m - 1; i >= 0; i--) { -// if (!numeric_traits::is_zero(y[i])){ -// for (cell * c = m_columns[adjust_column(i)].m_head; c != nullptr; c = c->m_down) { -// unsigned row = adjust_row_inverse(c->m_i); -// q.push(row); -// } -// } -// } -// while (!q.empty()) { -// unsigned i = q.front(); -// q.pop(); -// for (cell * c = m_columns[adjust_column(i)].m_head; c != nullptr; c = c->m_down) { -// unsigned row = adjust_row_inverse(c->m_i); -// if (rset.find(row) == rset.end()){ -// rset.insert(row); -// q.push(row); -// } -// } -// } -// } - -template -template -void square_sparse_matrix::find_error_in_solution_U_y(vector& y_orig, vector & y) { - unsigned i = dimension(); - while (i--) { - y_orig[i] -= dot_product_with_row(i, y); - } -} - -template -template -void square_sparse_matrix::find_error_in_solution_U_y_indexed(indexed_vector& y_orig, indexed_vector & y, const vector& sorted_active_rows) { - for (unsigned i: sorted_active_rows) - y_orig.add_value_at_index(i, -dot_product_with_row(i, y)); // cannot round up here!!! - // y_orig can contain very small values -} - - -template -template -void square_sparse_matrix::add_delta_to_solution(const vector& del, vector & y) { - unsigned i = dimension(); - while (i--) { - y[i] += del[i]; - } -} -template -template -void square_sparse_matrix::add_delta_to_solution(const indexed_vector& del, indexed_vector & y) { -// lp_assert(del.is_OK()); - // lp_assert(y.is_OK()); - for (auto i : del.m_index) { - y.add_value_at_index(i, del[i]); - } -} -template -template -void square_sparse_matrix::double_solve_U_y(indexed_vector& y, const lp_settings & settings){ - lp_assert(y.is_OK()); - indexed_vector y_orig(y); // copy y aside - vector active_rows; - solve_U_y_indexed_only(y, settings, active_rows); - lp_assert(y.is_OK()); - find_error_in_solution_U_y_indexed(y_orig, y, active_rows); - // y_orig contains the error now - if (y_orig.m_index.size() * ratio_of_index_size_to_all_size() < 32 * dimension()) { - active_rows.clear(); - solve_U_y_indexed_only(y_orig, settings, active_rows); - add_delta_to_solution(y_orig, y); - y.clean_up(); - } else { // the dense version - solve_U_y(y_orig.m_data); - add_delta_to_solution(y_orig.m_data, y.m_data); - y.restore_index_and_clean_from_data(); - } - lp_assert(y.is_OK()); -} -template -template -void square_sparse_matrix::double_solve_U_y(vector& y){ - vector y_orig(y); // copy y aside - solve_U_y(y); - find_error_in_solution_U_y(y_orig, y); - // y_orig contains the error now - solve_U_y(y_orig); - add_delta_to_solution(y_orig, y); -} - -// solving this * x = y, and putting the answer into y -// the matrix here has to be upper triangular -template -template -void square_sparse_matrix::solve_U_y(vector & y) { // it is a column wise version -#ifdef Z3DEBUG - // T * rs = clone_vector(y, dimension()); -#endif - - for (unsigned j = dimension(); j--; ) { - const L & yj = y[j]; - if (is_zero(yj)) continue; - for (const auto & iv : m_columns[adjust_column(j)].m_values) { - unsigned i = adjust_row_inverse(iv.m_index); - if (i != j) { - y[i] -= iv.m_value * yj; - } - } - } -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // T * clone_y = clone_vector(y, dimension()); - // deb.apply_from_left(clone_y); - // lp_assert(vectors_are_equal(rs, clone_y, dimension())); -#endif -} -template -void square_sparse_matrix::process_index_recursively_for_y_U(unsigned j, vector & sorted_active_rows) { - lp_assert(m_processed[j] == false); - m_processed[j]=true; - auto & row = m_rows[adjust_row(j)]; - for (auto & c : row) { - unsigned i = adjust_column_inverse(c.m_index); - if (i == j) continue; - if (!m_processed[i]) { - process_index_recursively_for_y_U(i, sorted_active_rows); - } - } - sorted_active_rows.push_back(j); -} - -template -void square_sparse_matrix::process_column_recursively(unsigned j, vector & sorted_active_rows) { - lp_assert(m_processed[j] == false); - auto & mc = m_columns[adjust_column(j)].m_values; - for (auto & iv : mc) { - unsigned i = adjust_row_inverse(iv.m_index); - if (i == j) continue; - if (!m_processed[i]) { - process_column_recursively(i, sorted_active_rows); - } - } - m_processed[j]=true; - sorted_active_rows.push_back(j); -} - - -template -void square_sparse_matrix::create_graph_G(const vector & index_or_right_side, vector & sorted_active_rows) { - for (auto i : index_or_right_side) { - if (m_processed[i]) continue; - process_column_recursively(i, sorted_active_rows); - } - - for (auto i : sorted_active_rows) { - m_processed[i] = false; - } -} - - -template -void square_sparse_matrix::extend_and_sort_active_rows(const vector & index_or_right_side, vector & sorted_active_rows) { - for (auto i : index_or_right_side) { - if (m_processed[i]) continue; - process_index_recursively_for_y_U(i, sorted_active_rows); - } - - for (auto i : sorted_active_rows) { - m_processed[i] = false; - } -} - - -template -template -void square_sparse_matrix::solve_U_y_indexed_only(indexed_vector & y, const lp_settings & settings, vector & sorted_active_rows) { // it is a column wise version - create_graph_G(y.m_index, sorted_active_rows); - - for (auto k = sorted_active_rows.size(); k-- > 0;) { - unsigned j = sorted_active_rows[k]; - const L & yj = y[j]; - if (is_zero(yj)) continue; - auto & mc = m_columns[adjust_column(j)].m_values; - for (auto & iv : mc) { - unsigned i = adjust_row_inverse(iv.m_index); - if (i != j) { - y[i] -= iv.m_value * yj; - } - } - } - y.m_index.clear(); - for (auto j : sorted_active_rows) { - if (!settings.abs_val_is_smaller_than_drop_tolerance(y[j])) - y.m_index.push_back(j); - else if (!numeric_traits::precise()) - y[j] = zero_of_type(); - } - - lp_assert(y.is_OK()); -#ifdef Z3DEBUG - // dense_matrix deb(this); - // vector clone_y(y.m_data); - // deb.apply_from_left(clone_y); - // lp_assert(vectors_are_equal(rs, clone_y)); -#endif -} - -template -template -L square_sparse_matrix::dot_product_with_row (unsigned row, const vector & y) const { - L ret = zero_of_type(); - auto & mc = get_row_values(adjust_row(row)); - for (auto & c : mc) { - unsigned col = m_column_permutation[c.m_index]; - ret += c.m_value * y[col]; - } - return ret; -} - -template -template -L square_sparse_matrix::dot_product_with_row (unsigned row, const indexed_vector & y) const { - L ret = zero_of_type(); - auto & mc = get_row_values(adjust_row(row)); - for (auto & c : mc) { - unsigned col = m_column_permutation[c.m_index]; - ret += c.m_value * y[col]; - } - return ret; -} - - -template -unsigned square_sparse_matrix::get_number_of_nonzeroes() const { - unsigned ret = 0; - for (unsigned i = dimension(); i--; ) { - ret += number_of_non_zeroes_in_row(i); - } - return ret; -} - -template -bool square_sparse_matrix::get_non_zero_column_in_row(unsigned i, unsigned *j) const { - // go over the i-th row - auto & mc = get_row_values(adjust_row(i)); - if (mc.size() > 0) { - *j = m_column_permutation[mc[0].m_index]; - return true; - } - return false; -} - -template -void square_sparse_matrix::remove_element_that_is_not_in_w(vector> & column_vals, indexed_value & col_el_iv) { - auto & row_chunk = m_rows[col_el_iv.m_index]; - indexed_value & row_el_iv = row_chunk[col_el_iv.m_other]; - unsigned index_in_row = col_el_iv.m_other; - remove_element(row_chunk, col_el_iv.m_other, column_vals, row_el_iv.m_other); - if (index_in_row == 0) - set_max_in_row(row_chunk); -} - - -// w contains the new column -// the old column inside of the matrix has not been changed yet -template -void square_sparse_matrix::remove_elements_that_are_not_in_w_and_update_common_elements(unsigned column_to_replace, indexed_vector & w) { - // -------------------------------- - // column_vals represents the old column - auto & column_vals = m_columns[column_to_replace].m_values; - for (unsigned k = static_cast(column_vals.size()); k-- > 0;) { - indexed_value & col_el_iv = column_vals[k]; - unsigned i = col_el_iv.m_index; - T &w_data_at_i = w[adjust_row_inverse(i)]; - if (numeric_traits::is_zero(w_data_at_i)) { - remove_element_that_is_not_in_w(column_vals, col_el_iv); - } else { - auto& row_chunk = m_rows[i]; - unsigned index_in_row = col_el_iv.m_other; - if (index_in_row == 0) { - bool look_for_max = abs(w_data_at_i) < abs(row_chunk[0].m_value); - row_chunk[0].set_value(col_el_iv.m_value = w_data_at_i); - if (look_for_max) - set_max_in_row(i); - } else { - row_chunk[index_in_row].set_value(col_el_iv.m_value = w_data_at_i); - if (abs(w_data_at_i) > abs(row_chunk[0].m_value)) - put_max_index_to_0(row_chunk, index_in_row); - } - w_data_at_i = numeric_traits::zero(); - } - } -} - -template -void square_sparse_matrix::add_new_element(unsigned row, unsigned col, const T& val) { - auto & row_vals = m_rows[row]; - auto & col_vals = m_columns[col].m_values; - unsigned row_el_offs = static_cast(row_vals.size()); - unsigned col_el_offs = static_cast(col_vals.size()); - row_vals.push_back(indexed_value(val, col, col_el_offs)); - col_vals.push_back(indexed_value(val, row, row_el_offs)); - m_n_of_active_elems++; -} - -// w contains the "rest" of the new column; all common elements of w and the old column has been zeroed -// the old column inside of the matrix has not been changed yet -template -void square_sparse_matrix::add_new_elements_of_w_and_clear_w(unsigned column_to_replace, indexed_vector & w, lp_settings & settings) { - for (unsigned i : w.m_index) { - T w_at_i = w[i]; - if (numeric_traits::is_zero(w_at_i)) continue; // was dealt with already - if (!settings.abs_val_is_smaller_than_drop_tolerance(w_at_i)) { - unsigned ai = adjust_row(i); - add_new_element(ai, column_to_replace, w_at_i); - auto & row_chunk = m_rows[ai]; - lp_assert(row_chunk.size() > 0); - if (abs(w_at_i) > abs(row_chunk[0].m_value)) - put_max_index_to_0(row_chunk, static_cast(row_chunk.size()) - 1); - } - w[i] = numeric_traits::zero(); - } - w.m_index.clear(); -} - -template -void square_sparse_matrix::replace_column(unsigned column_to_replace, indexed_vector & w, lp_settings &settings) { - column_to_replace = adjust_column(column_to_replace); - remove_elements_that_are_not_in_w_and_update_common_elements(column_to_replace, w); - add_new_elements_of_w_and_clear_w(column_to_replace, w, settings); -} - -template -unsigned square_sparse_matrix::pivot_score(unsigned i, unsigned j) { - // It goes like this (rnz-1)(cnz-1) is the Markovitz number, that is the max number of - // new non zeroes we can obtain after the pivoting. - // In addition we will get another cnz - 1 elements in the eta matrix created for this pivot, - // which gives rnz(cnz-1). For example, is 0 for a column singleton, but not for - // a row singleton ( which is not a column singleton). - - auto col_header = m_columns[j]; - - return static_cast(get_row_values(i).size() * (col_header.m_values.size() - col_header.m_shortened_markovitz - 1)); -} - -template -void square_sparse_matrix::enqueue_domain_into_pivot_queue() { - lp_assert(m_pivot_queue.size() == 0); - for (unsigned i = 0; i < dimension(); i++) { - auto & rh = m_rows[i]; - unsigned rnz = static_cast(rh.size()); - for (auto iv : rh) { - unsigned j = iv.m_index; - m_pivot_queue.enqueue(i, j, rnz * (static_cast(m_columns[j].m_values.size()) - 1)); - } - } -} - -template -void square_sparse_matrix::set_max_in_rows() { - unsigned i = dimension(); - while (i--) - set_max_in_row(i); -} - - -template -void square_sparse_matrix::zero_shortened_markovitz_numbers() { - for (auto & ch : m_columns) - ch.zero_shortened_markovitz(); -} - -template -void square_sparse_matrix::prepare_for_factorization() { - zero_shortened_markovitz_numbers(); - set_max_in_rows(); - enqueue_domain_into_pivot_queue(); -} - -template -void square_sparse_matrix::recover_pivot_queue(vector & rejected_pivots) { - for (auto p : rejected_pivots) { - m_pivot_queue.enqueue(p.first, p.second, pivot_score(p.first, p.second)); - } -} - -template -int square_sparse_matrix::elem_is_too_small(unsigned i, unsigned j, int c_partial_pivoting) { - auto & row_chunk = m_rows[i]; - - if (j == row_chunk[0].m_index) { - return 0; // the max element is at the head - } - T max = abs(row_chunk[0].m_value); - for (unsigned k = 1; k < row_chunk.size(); k++) { - auto &iv = row_chunk[k]; - if (iv.m_index == j) - return abs(iv.m_value) * c_partial_pivoting < max ? 1: 0; - } - return 2; // the element became zero but it still sits in the active pivots? -} - -template -bool square_sparse_matrix::remove_row_from_active_pivots_and_shorten_columns(unsigned row) { - unsigned arow = adjust_row(row); - for (auto & iv : m_rows[arow]) { - m_pivot_queue.remove(arow, iv.m_index); - m_n_of_active_elems--; // the value is correct only when refactoring - if (adjust_column_inverse(iv.m_index) <= row) - continue; // this column will be removed anyway - auto & col = m_columns[iv.m_index]; - - col.shorten_markovich_by_one(); - if (col.m_values.size() <= col.m_shortened_markovitz) - return false; // got a zero column - } - return true; -} - -template -void square_sparse_matrix::remove_pivot_column(unsigned row) { - unsigned acol = adjust_column(row); - for (const auto & iv : m_columns[acol].m_values) - if (adjust_row_inverse(iv.m_index) >= row) - m_pivot_queue.remove(iv.m_index, acol); -} - -template -void square_sparse_matrix::update_active_pivots(unsigned row) { - unsigned arow = adjust_row(row); - for (const auto & iv : m_rows[arow]) { - col_header & ch = m_columns[iv.m_index]; - int cols = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lp_assert(cols >= 0); - for (const auto &ivc : ch.m_values) { - unsigned i = ivc.m_index; - if (adjust_row_inverse(i) <= row) continue; // the i is not an active row - m_pivot_queue.enqueue(i, iv.m_index, static_cast(m_rows[i].size())*cols); - } - } -} - -template -bool square_sparse_matrix::shorten_active_matrix(unsigned row, eta_matrix *eta_matrix) { - if (!remove_row_from_active_pivots_and_shorten_columns(row)) - return false; - remove_pivot_column(row); - // need to know the max priority of the queue here - update_active_pivots(row); - if (eta_matrix == nullptr) return true; - // it looks like double work, but the pivot scores have changed for all rows - // touched by eta_matrix - for (auto & it : eta_matrix->m_column_vector.m_data) { - unsigned row = adjust_row(it.first); - const auto & row_values = m_rows[row]; - unsigned rnz = static_cast(row_values.size()); - for (auto & iv : row_values) { - const col_header& ch = m_columns[iv.m_index]; - int cnz = static_cast(ch.m_values.size()) - ch.m_shortened_markovitz - 1; - lp_assert(cnz >= 0); - m_pivot_queue.enqueue(row, iv.m_index, rnz * cnz); - } - } - - return true; -} - -template -unsigned square_sparse_matrix::pivot_score_without_shortened_counters(unsigned i, unsigned j, unsigned k) { - auto &cols = m_columns[j].m_values; - unsigned cnz = cols.size(); - for (auto & iv : cols) { - if (adjust_row_inverse(iv.m_index) < k) - cnz--; - } - lp_assert(cnz > 0); - return m_rows[i].m_values.size() * (cnz - 1); -} -#ifdef Z3DEBUG -template -bool square_sparse_matrix::can_improve_score_for_row(unsigned row, unsigned score, T const & c_partial_pivoting, unsigned k) { - unsigned arow = adjust_row(row); - auto & row_vals = m_rows[arow].m_values; - auto & begin_iv = row_vals[0]; - T row_max = abs(begin_iv.m_value); - lp_assert(adjust_column_inverse(begin_iv.m_index) >= k); - if (pivot_score_without_shortened_counters(arow, begin_iv.m_index, k) < score) { - print_active_matrix(k); - return true; - } - for (unsigned jj = 1; jj < row_vals.size(); jj++) { - auto & iv = row_vals[jj]; - lp_assert(adjust_column_inverse(iv.m_index) >= k); - lp_assert(abs(iv.m_value) <= row_max); - if (c_partial_pivoting * abs(iv.m_value) < row_max) continue; - if (pivot_score_without_shortened_counters(arow, iv.m_index, k) < score) { - print_active_matrix(k); - return true; - } - } - return false; -} - -template -bool square_sparse_matrix::really_best_pivot(unsigned i, unsigned j, T const & c_partial_pivoting, unsigned k) { - unsigned queue_pivot_score = pivot_score_without_shortened_counters(i, j, k); - for (unsigned ii = k; ii < dimension(); ii++) { - lp_assert(!can_improve_score_for_row(ii, queue_pivot_score, c_partial_pivoting, k)); - } - return true; -} -template -void square_sparse_matrix::print_active_matrix(unsigned k, std::ostream & out) { - out << "active matrix for k = " << k << std::endl; - if (k >= dimension()) { - out << "empty" << std::endl; - return; - } - unsigned dim = dimension() - k; - dense_matrix b(dim, dim); - for (unsigned i = 0; i < dim; i++) - for (unsigned j = 0; j < dim; j++ ) - b.set_elem(i, j, zero_of_type()); - for (int i = k; i < dimension(); i++) { - unsigned col = adjust_column(i); - for (auto &iv : get_column_values(col)) { - unsigned row = iv.m_index; - unsigned row_ex = this->adjust_row_inverse(row); - if (row_ex < k) continue; - auto v = this->get_not_adjusted(row, col); - b.set_elem(row_ex - k, i -k, v); - } - } - print_matrix(b, out); -} - -template -bool square_sparse_matrix::pivot_queue_is_correct_for_row(unsigned i, unsigned k) { - unsigned arow = adjust_row(i); - for (auto & iv : m_rows[arow].m_values) { - lp_assert(pivot_score_without_shortened_counters(arow, iv.m_index, k + 1) == - m_pivot_queue.get_priority(arow, iv.m_index)); - } - return true; -} - -template -bool square_sparse_matrix::pivot_queue_is_correct_after_pivoting(int k) { - for (unsigned i = k + 1; i < dimension(); i++ ) - lp_assert(pivot_queue_is_correct_for_row(i, k)); - lp_assert(m_pivot_queue.is_correct()); - return true; -} -#endif - -template -bool square_sparse_matrix::get_pivot_for_column(unsigned &i, unsigned &j, int c_partial_pivoting, unsigned k) { - vector pivots_candidates_that_are_too_small; - while (!m_pivot_queue.is_empty()) { - m_pivot_queue.dequeue(i, j); - unsigned i_inv = adjust_row_inverse(i); - if (i_inv < k) continue; - unsigned j_inv = adjust_column_inverse(j); - if (j_inv < k) continue; - int _small = elem_is_too_small(i, j, c_partial_pivoting); - if (!_small) { -#ifdef Z3DEBUG - // if (!really_best_pivot(i, j, c_partial_pivoting, k)) { - // print_active_matrix(k); - // lp_assert(false); - // } -#endif - recover_pivot_queue(pivots_candidates_that_are_too_small); - i = i_inv; - j = j_inv; - return true; - } - if (_small != 2) { // 2 means that the pair is not in the matrix - pivots_candidates_that_are_too_small.push_back(std::make_pair(i, j)); - } - } - recover_pivot_queue(pivots_candidates_that_are_too_small); - return false; -} - -template -bool square_sparse_matrix::elem_is_too_small(vector> & row_chunk, indexed_value & iv, int c_partial_pivoting) { - if (&iv == &row_chunk[0]) { - return false; // the max element is at the head - } - T val = abs(iv.m_value); - T max = abs(row_chunk[0].m_value); - return val * c_partial_pivoting < max; -} - -template -bool square_sparse_matrix::shorten_columns_by_pivot_row(unsigned i, unsigned pivot_column) { - vector> & row_chunk = get_row_values(i); - - for (indexed_value & iv : row_chunk) { - unsigned j = iv.m_index; - if (j == pivot_column) { - lp_assert(!col_is_active(j)); - continue; - } - m_columns[j].shorten_markovich_by_one(); - - if (m_columns[j].m_shortened_markovitz >= get_column_values(j).size()) { // got the zero column under the row! - return false; - } - } - return true; -} - -template -bool square_sparse_matrix::fill_eta_matrix(unsigned j, eta_matrix ** eta) { - const vector> & col_chunk = get_column_values(adjust_column(j)); - bool is_unit = true; - for (const auto & iv : col_chunk) { - unsigned i = adjust_row_inverse(iv.m_index); - if (i > j) { - is_unit = false; - break; - } - if (i == j && iv.m_value != 1) { - is_unit = false; - break; - } - } - - if (is_unit) { - *eta = nullptr; - return true; - } - -#ifdef Z3DEBUG - *eta = new eta_matrix(j, dimension()); -#else - *eta = new eta_matrix(j); -#endif - for (const auto & iv : col_chunk) { - unsigned i = adjust_row_inverse(iv.m_index); - if (i < j) { - continue; - } - if (i > j) { - (*eta)->push_back(i, - iv.m_value); - } else { // i == j - if ( !(*eta)->set_diagonal_element(iv.m_value)) { - delete *eta; - *eta = nullptr; - return false; - } - - } - } - - (*eta)->divide_by_diagonal_element(); - return true; -} -#ifdef Z3DEBUG -template -bool square_sparse_matrix::is_upper_triangular_and_maximums_are_set_correctly_in_rows(lp_settings & settings) const { - for (unsigned i = 0; i < dimension(); i++) { - vector> const & row_chunk = get_row_values(i); - lp_assert(row_chunk.size()); - T const & max = abs(row_chunk[0].m_value); - unsigned ai = adjust_row_inverse(i); - for (auto & iv : row_chunk) { - lp_assert(abs(iv.m_value) <= max); - unsigned aj = adjust_column_inverse(iv.m_index); - if (!(ai <= aj || numeric_traits::is_zero(iv.m_value))) - return false; - if (aj == ai) { - if (iv.m_value != 1) { - return false; - } - } - if (settings.abs_val_is_smaller_than_drop_tolerance(iv.m_value) && (!is_zero(iv.m_value))) - return false; - } - } - return true; -} - -template -bool square_sparse_matrix::is_upper_triangular_until(unsigned k) const { - for (unsigned j = 0; j < dimension() && j < k; j++) { - unsigned aj = adjust_column(j); - auto & col = get_column_values(aj); - for (auto & iv : col) { - unsigned row = adjust_row_inverse(iv.m_index); - if (row > j) - return false; - } - } - return true; -} - -template -void square_sparse_matrix::check_column_vs_rows(unsigned col) { - auto & mc = get_column_values(col); - for (indexed_value & column_iv : mc) { - indexed_value & row_iv = column_iv_other(column_iv); - if (row_iv.m_index != col) { - lp_assert(false); - } - - if (& row_iv_other(row_iv) != &column_iv) { - lp_assert(false); - } - - if (row_iv.m_value != column_iv.m_value) { - lp_assert(false); - } - } -} - -template -void square_sparse_matrix::check_row_vs_columns(unsigned row) { - auto & mc = get_row_values(row); - for (indexed_value & row_iv : mc) { - indexed_value & column_iv = row_iv_other(row_iv); - - if (column_iv.m_index != row) { - lp_assert(false); - } - - if (& row_iv != & column_iv_other(column_iv)) { - lp_assert(false); - } - - if (row_iv.m_value != column_iv.m_value) { - lp_assert(false); - } - } -} - -template -void square_sparse_matrix::check_rows_vs_columns() { - for (unsigned i = 0; i < dimension(); i++) { - check_row_vs_columns(i); - } -} - -template -void square_sparse_matrix::check_columns_vs_rows() { - for (unsigned i = 0; i < dimension(); i++) { - check_column_vs_rows(i); - } -} -template -void square_sparse_matrix::check_matrix() { - check_rows_vs_columns(); - check_columns_vs_rows(); -} -#endif -} - diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 2e8faeaedc5..b997b38f757 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -576,7 +576,7 @@ void test_lp_primal_core_solver() { - +#ifdef Z3DEBUG void fill_uniformly(dense_matrix & m, unsigned dim) { int v = 0; @@ -619,7 +619,7 @@ void test_dense_matrix() { auto c2 = d * p2; } - +#endif vector> vector_of_permutations() { From 4e90cfefa8156f2b1f2ed011fa0049078b971a13 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 14:38:59 -0800 Subject: [PATCH 23/36] more cleanup --- src/math/lp/CMakeLists.txt | 2 - src/math/lp/eta_matrix.cpp | 43 ------- src/math/lp/eta_matrix.h | 98 ---------------- src/math/lp/eta_matrix_def.h | 151 ------------------------- src/math/lp/row_eta_matrix.cpp | 47 -------- src/math/lp/row_eta_matrix.h | 89 --------------- src/math/lp/row_eta_matrix_def.h | 188 ------------------------------- src/test/lp/lp.cpp | 58 ---------- 8 files changed, 676 deletions(-) delete mode 100644 src/math/lp/eta_matrix.cpp delete mode 100644 src/math/lp/eta_matrix.h delete mode 100644 src/math/lp/eta_matrix_def.h delete mode 100644 src/math/lp/row_eta_matrix.cpp delete mode 100644 src/math/lp/row_eta_matrix.h delete mode 100644 src/math/lp/row_eta_matrix_def.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index ef363509fcb..98241bf603e 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -4,7 +4,6 @@ z3_add_component(lp binary_heap_upair_queue.cpp core_solver_pretty_printer.cpp dense_matrix.cpp - eta_matrix.cpp emonics.cpp factorization.cpp factorization_factory_imp.cpp @@ -40,7 +39,6 @@ z3_add_component(lp nra_solver.cpp permutation_matrix.cpp random_updater.cpp - row_eta_matrix.cpp static_matrix.cpp COMPONENT_DEPENDENCIES util diff --git a/src/math/lp/eta_matrix.cpp b/src/math/lp/eta_matrix.cpp deleted file mode 100644 index 77f53842697..00000000000 --- a/src/math/lp/eta_matrix.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include "util/vector.h" -#include "math/lp/numeric_pair.h" -#include "math/lp/eta_matrix_def.h" -#ifdef Z3DEBUG -template double lp::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lp::mpq lp::eta_matrix::get_elem(unsigned int, unsigned int) const; -template lp::mpq lp::eta_matrix >::get_elem(unsigned int, unsigned int) const; -#endif -template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); -template void lp::eta_matrix::apply_from_right(vector&); -template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); -template void lp::eta_matrix::apply_from_left(vector&, lp::lp_settings&); -template void lp::eta_matrix::apply_from_right(vector&); -template void lp::eta_matrix::conjugate_by_permutation(lp::permutation_matrix&); -template void lp::eta_matrix >::apply_from_left(vector >&, lp::lp_settings&); -template void lp::eta_matrix >::apply_from_right(vector&); -template void lp::eta_matrix >::conjugate_by_permutation(lp::permutation_matrix >&); -template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); -template void lp::eta_matrix::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); -template void lp::eta_matrix >::apply_from_left_local(lp::indexed_vector&, lp::lp_settings&); -template void lp::eta_matrix >::apply_from_right(lp::indexed_vector&); -template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); -template void lp::eta_matrix::apply_from_right(lp::indexed_vector&); diff --git a/src/math/lp/eta_matrix.h b/src/math/lp/eta_matrix.h deleted file mode 100644 index 14fe3ffea11..00000000000 --- a/src/math/lp/eta_matrix.h +++ /dev/null @@ -1,98 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "math/lp/tail_matrix.h" -#include "math/lp/permutation_matrix.h" -namespace lp { - -// This is the sum of a unit matrix and a one-column matrix -template -class eta_matrix - : public tail_matrix { -#ifdef Z3DEBUG - unsigned m_length; -#endif - unsigned m_column_index; -public: - sparse_vector m_column_vector; - T m_diagonal_element; -#ifdef Z3DEBUG - eta_matrix(unsigned column_index, unsigned length): -#else - eta_matrix(unsigned column_index): -#endif - -#ifdef Z3DEBUG - m_length(length), -#endif - m_column_index(column_index) {} - - bool is_dense() const override { return false; } - - void print(std::ostream & out) { - print_matrix(*this, out); - } - - bool is_unit() { - return m_column_vector.size() == 0 && m_diagonal_element == 1; - } - - bool set_diagonal_element(T const & diagonal_element) { - m_diagonal_element = diagonal_element; - return !lp_settings::is_eps_small_general(diagonal_element, 1e-12); - } - - const T & get_diagonal_element() const { - return m_diagonal_element; - } - - void apply_from_left(vector & w, lp_settings & ) override; - - template - void apply_from_left_local(indexed_vector & w, lp_settings & settings); - - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { - apply_from_left_local(w, settings); - } - - - void push_back(unsigned row_index, T val ) { - lp_assert(row_index != m_column_index); - m_column_vector.push_back(row_index, val); - } - - void apply_from_right(vector & w) override; - void apply_from_right(indexed_vector & w) override; - -#ifdef Z3DEBUG - T get_elem(unsigned i, unsigned j) const override; - unsigned row_count() const override { return m_length; } - unsigned column_count() const override { return m_length; } - void set_number_of_rows(unsigned m) override { m_length = m; } - void set_number_of_columns(unsigned n) override { m_length = n; } -#endif - void divide_by_diagonal_element() { - m_column_vector.divide(m_diagonal_element); - } - void conjugate_by_permutation(permutation_matrix & p); -}; -} diff --git a/src/math/lp/eta_matrix_def.h b/src/math/lp/eta_matrix_def.h deleted file mode 100644 index a6c908572f7..00000000000 --- a/src/math/lp/eta_matrix_def.h +++ /dev/null @@ -1,151 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "math/lp/eta_matrix.h" -namespace lp { - -// This is the sum of a unit matrix and a one-column matrix -template -void eta_matrix::apply_from_left(vector & w, lp_settings & ) { - auto & w_at_column_index = w[m_column_index]; - for (auto & it : m_column_vector.m_data) { - w[it.first] += w_at_column_index * it.second; - } - w_at_column_index /= m_diagonal_element; -} -template -template -void eta_matrix:: -apply_from_left_local(indexed_vector & w, lp_settings & settings) { - const L w_at_column_index = w[m_column_index]; - if (is_zero(w_at_column_index)) return; - - if (settings.abs_val_is_smaller_than_drop_tolerance(w[m_column_index] /= m_diagonal_element)) { - w[m_column_index] = zero_of_type(); - w.erase_from_index(m_column_index); - } - - for (auto & it : m_column_vector.m_data) { - unsigned i = it.first; - if (is_zero(w[i])) { - L v = w[i] = w_at_column_index * it.second; - if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { - w[i] = zero_of_type(); - continue; - } - w.m_index.push_back(i); - } else { - L v = w[i] += w_at_column_index * it.second; - if (settings.abs_val_is_smaller_than_drop_tolerance(v)) { - w[i] = zero_of_type(); - w.erase_from_index(i); - } - } - } -} -template -void eta_matrix::apply_from_right(vector & w) { -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // auto clone_w = clone_vector(w, get_number_of_rows()); - // deb.apply_from_right(clone_w); -#endif - T t = w[m_column_index] / m_diagonal_element; - for (auto & it : m_column_vector.m_data) { - t += w[it.first] * it.second; - } - w[m_column_index] = t; -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(clone_w, w, get_number_of_rows())); - // delete clone_w; -#endif -} -template -void eta_matrix::apply_from_right(indexed_vector & w) { - if (w.m_index.empty()) - return; -#ifdef Z3DEBUG - // vector wcopy(w.m_data); - // apply_from_right(wcopy); -#endif - T & t = w[m_column_index]; - t /= m_diagonal_element; - bool was_in_index = (!numeric_traits::is_zero(t)); - - for (auto & it : m_column_vector.m_data) { - t += w[it.first] * it.second; - } - - if (numeric_traits::precise() ) { - if (!numeric_traits::is_zero(t)) { - if (!was_in_index) - w.m_index.push_back(m_column_index); - } else { - if (was_in_index) - w.erase_from_index(m_column_index); - } - } else { - if (!lp_settings::is_eps_small_general(t, 1e-14)) { - if (!was_in_index) - w.m_index.push_back(m_column_index); - } else { - if (was_in_index) - w.erase_from_index(m_column_index); - t = zero_of_type(); - } - } - -#ifdef Z3DEBUG - // lp_assert(w.is_OK()); - // lp_assert(vectors_are_equal(wcopy, w.m_data)); -#endif -} -#ifdef Z3DEBUG -template -T eta_matrix::get_elem(unsigned i, unsigned j) const { - if (j == m_column_index){ - if (i == j) { - return 1 / m_diagonal_element; - } - return m_column_vector[i]; - } - - return i == j ? numeric_traits::one() : numeric_traits::zero(); -} -#endif -template -void eta_matrix::conjugate_by_permutation(permutation_matrix & p) { - // this = p * this * p(-1) -#ifdef Z3DEBUG - // auto rev = p.get_reverse(); - // auto deb = ((*this) * rev); - // deb = p * deb; -#endif - m_column_index = p.get_rev(m_column_index); - for (auto & pair : m_column_vector.m_data) { - pair.first = p.get_rev(pair.first); - } -#ifdef Z3DEBUG - // lp_assert(deb == *this); -#endif -} -} diff --git a/src/math/lp/row_eta_matrix.cpp b/src/math/lp/row_eta_matrix.cpp deleted file mode 100644 index 356f80b3c01..00000000000 --- a/src/math/lp/row_eta_matrix.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include -#include "util/vector.h" -#include "math/lp/row_eta_matrix_def.h" -namespace lp { -template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); -template void row_eta_matrix >::conjugate_by_permutation(permutation_matrix >&); -template void row_eta_matrix::conjugate_by_permutation(permutation_matrix&); -#ifdef Z3DEBUG -template mpq row_eta_matrix::get_elem(unsigned int, unsigned int) const; -template mpq row_eta_matrix >::get_elem(unsigned int, unsigned int) const; -template double row_eta_matrix::get_elem(unsigned int, unsigned int) const; -#endif -template void row_eta_matrix::apply_from_left(vector&, lp_settings&); -template void row_eta_matrix::apply_from_right(vector&); -template void row_eta_matrix::apply_from_right(indexed_vector&); -template void row_eta_matrix >::apply_from_left(vector>&, lp_settings&); -template void row_eta_matrix >::apply_from_right(vector&); -template void row_eta_matrix >::apply_from_right(indexed_vector&); -template void row_eta_matrix::apply_from_left(vector&, lp_settings&); -template void row_eta_matrix::apply_from_right(vector&); -template void row_eta_matrix::apply_from_right(indexed_vector&); -template void row_eta_matrix::apply_from_left_to_T(indexed_vector&, lp_settings&); -template void row_eta_matrix::apply_from_left_local_to_T(indexed_vector&, lp_settings&); -template void row_eta_matrix >::apply_from_left_to_T(indexed_vector&, lp_settings&); -template void row_eta_matrix >::apply_from_left_local_to_T(indexed_vector&, lp_settings&); -template void row_eta_matrix::apply_from_left_to_T(indexed_vector&, lp_settings&); -template void row_eta_matrix::apply_from_left_local_to_T(indexed_vector&, lp_settings&); -} diff --git a/src/math/lp/row_eta_matrix.h b/src/math/lp/row_eta_matrix.h deleted file mode 100644 index 50c500f007a..00000000000 --- a/src/math/lp/row_eta_matrix.h +++ /dev/null @@ -1,89 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "util/debug.h" -#include -#include "math/lp/sparse_vector.h" -#include "math/lp/indexed_vector.h" -#include "math/lp/permutation_matrix.h" -namespace lp { - // This is the sum of a unit matrix and a lower triangular matrix - // with non-zero elements only in one row -template -class row_eta_matrix - : public tail_matrix { -#ifdef Z3DEBUG - unsigned m_dimension; -#endif - unsigned m_row_start; - unsigned m_row; - sparse_vector m_row_vector; -public: -#ifdef Z3DEBUG - row_eta_matrix(unsigned row_start, unsigned row, unsigned dim): -#else - row_eta_matrix(unsigned row_start, unsigned row): -#endif - -#ifdef Z3DEBUG - m_dimension(dim), -#endif - m_row_start(row_start), m_row(row) { - } - - bool is_dense() const override { return false; } - - void print(std::ostream & out) { - print_matrix(*this, out); - } - - const T & get_diagonal_element() const { - return m_row_vector.m_data[m_row]; - } - - void apply_from_left(vector & w, lp_settings &) override; - - void apply_from_left_local_to_T(indexed_vector & w, lp_settings & settings); - void apply_from_left_local_to_X(indexed_vector & w, lp_settings & settings); - - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override { - apply_from_left_local_to_T(w, settings); - } - - void push_back(unsigned row_index, T val ) { - lp_assert(row_index != m_row); - m_row_vector.push_back(row_index, val); - } - - void apply_from_right(vector & w) override; - void apply_from_right(indexed_vector & w) override; - - void conjugate_by_permutation(permutation_matrix & p); -#ifdef Z3DEBUG - T get_elem(unsigned row, unsigned col) const override; - unsigned row_count() const override { return m_dimension; } - unsigned column_count() const override { return m_dimension; } - void set_number_of_rows(unsigned m) override { m_dimension = m; } - void set_number_of_columns(unsigned n) override { m_dimension = n; } -#endif -}; // end of row_eta_matrix -} diff --git a/src/math/lp/row_eta_matrix_def.h b/src/math/lp/row_eta_matrix_def.h deleted file mode 100644 index faac5c6fe0b..00000000000 --- a/src/math/lp/row_eta_matrix_def.h +++ /dev/null @@ -1,188 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include "util/vector.h" -#include "math/lp/row_eta_matrix.h" -namespace lp { -template -void row_eta_matrix::apply_from_left(vector & w, lp_settings &) { - // #ifdef Z3DEBUG - // dense_matrix deb(*this); - // auto clone_w = clone_vector(w, m_dimension); - // deb.apply_from_left(clone_w, settings); - // #endif - - auto & w_at_row = w[m_row]; - for (auto & it : m_row_vector.m_data) { - w_at_row += w[it.first] * it.second; - } - // w[m_row] = w_at_row; - // #ifdef Z3DEBUG - // lp_assert(vectors_are_equal(clone_w, w, m_dimension)); - // delete [] clone_w; - // #endif -} - -template -void row_eta_matrix::apply_from_left_local_to_T(indexed_vector & w, lp_settings & settings) { - auto w_at_row = w[m_row]; - bool was_zero_at_m_row = is_zero(w_at_row); - - for (auto & it : m_row_vector.m_data) { - w_at_row += w[it.first] * it.second; - } - - if (!settings.abs_val_is_smaller_than_drop_tolerance(w_at_row)){ - if (was_zero_at_m_row) { - w.m_index.push_back(m_row); - } - w[m_row] = w_at_row; - } else if (!was_zero_at_m_row){ - w[m_row] = zero_of_type(); - auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); - w.m_index.erase(it); - } - // TBD: lp_assert(check_vector_for_small_values(w, settings)); -} - -template -void row_eta_matrix::apply_from_left_local_to_X(indexed_vector & w, lp_settings & settings) { - auto w_at_row = w[m_row]; - bool was_zero_at_m_row = is_zero(w_at_row); - - for (auto & it : m_row_vector.m_data) { - w_at_row += w[it.first] * it.second; - } - - if (!settings.abs_val_is_smaller_than_drop_tolerance(w_at_row)){ - if (was_zero_at_m_row) { - w.m_index.push_back(m_row); - } - w[m_row] = w_at_row; - } else if (!was_zero_at_m_row){ - w[m_row] = zero_of_type(); - auto it = std::find(w.m_index.begin(), w.m_index.end(), m_row); - w.m_index.erase(it); - } - // TBD: does not compile lp_assert(check_vector_for_small_values(w, settings)); -} - -template -void row_eta_matrix::apply_from_right(vector & w) { - const T & w_row = w[m_row]; - if (numeric_traits::is_zero(w_row)) return; -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // auto clone_w = clone_vector(w, m_dimension); - // deb.apply_from_right(clone_w); -#endif - for (auto & it : m_row_vector.m_data) { - w[it.first] += w_row * it.second; - } -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(clone_w, w, m_dimension)); - // delete clone_w; -#endif -} - -template -void row_eta_matrix::apply_from_right(indexed_vector & w) { - lp_assert(w.is_OK()); - const T & w_row = w[m_row]; - if (numeric_traits::is_zero(w_row)) return; -#ifdef Z3DEBUG - // vector wcopy(w.m_data); - // apply_from_right(wcopy); -#endif - if (numeric_traits::precise()) { - for (auto & it : m_row_vector.m_data) { - unsigned j = it.first; - bool was_zero = numeric_traits::is_zero(w[j]); - const T & v = w[j] += w_row * it.second; - - if (was_zero) { - if (!numeric_traits::is_zero(v)) - w.m_index.push_back(j); - } else { - if (numeric_traits::is_zero(v)) - w.erase_from_index(j); - } - } - } else { // the non precise version - const double drop_eps = 1e-14; - for (auto & it : m_row_vector.m_data) { - unsigned j = it.first; - bool was_zero = numeric_traits::is_zero(w[j]); - T & v = w[j] += w_row * it.second; - - if (was_zero) { - if (!lp_settings::is_eps_small_general(v, drop_eps)) - w.m_index.push_back(j); - else - v = zero_of_type(); - } else { - if (lp_settings::is_eps_small_general(v, drop_eps)) { - w.erase_from_index(j); - v = zero_of_type(); - } - } - } - } -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(wcopy, w.m_data)); - -#endif -} - -template -void row_eta_matrix::conjugate_by_permutation(permutation_matrix & p) { - // this = p * this * p(-1) -#ifdef Z3DEBUG - // auto rev = p.get_reverse(); - // auto deb = ((*this) * rev); - // deb = p * deb; -#endif - m_row = p.apply_reverse(m_row); - // copy aside the column indices - vector columns; - for (auto & it : m_row_vector.m_data) - columns.push_back(it.first); - for (unsigned i = static_cast(columns.size()); i-- > 0;) - m_row_vector.m_data[i].first = p.get_rev(columns[i]); -#ifdef Z3DEBUG - // lp_assert(deb == *this); -#endif -} -#ifdef Z3DEBUG -template -T row_eta_matrix::get_elem(unsigned row, unsigned col) const { - if (row == m_row){ - if (col == row) { - return numeric_traits::one(); - } - return m_row_vector[col]; - } - - return col == row ? numeric_traits::one() : numeric_traits::zero(); -} -#endif -} - diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index b997b38f757..c993dbd7ddf 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -622,66 +622,8 @@ void test_dense_matrix() { #endif -vector> vector_of_permutations() { - vector> ret; - { - permutation_matrix p0(5); - p0[0] = 1; p0[1] = 2; p0[2] = 3; p0[3] = 4; - p0[4] = 0; - ret.push_back(p0); - } - { - permutation_matrix p0(5); - p0[0] = 2; p0[1] = 0; p0[2] = 1; p0[3] = 4; - p0[4] = 3; - ret.push_back(p0); - } - return ret; -} -void test_apply_reverse_from_right_to_perm(permutation_matrix & l) { - permutation_matrix p(5); - p[0] = 4; p[1] = 2; p[2] = 0; p[3] = 3; - p[4] = 1; - permutation_matrix pclone(5); - pclone[0] = 4; pclone[1] = 2; pclone[2] = 0; pclone[3] = 3; - pclone[4] = 1; - - p.multiply_by_reverse_from_right(l); -#ifdef Z3DEBUG - auto rev = l.get_inverse(); - auto rs = pclone * rev; - lp_assert(p == rs) -#endif - } - -void test_apply_reverse_from_right() { - auto vec = vector_of_permutations(); - for (unsigned i = 0; i < vec.size(); i++) { - test_apply_reverse_from_right_to_perm(vec[i]); - } -} - -void test_permutations() { - std::cout << "test permutations" << std::endl; - test_apply_reverse_from_right(); - vector v; v.resize(5, 0); - v[1] = 1; - v[3] = 3; - permutation_matrix p(5); - p[0] = 4; p[1] = 2; p[2] = 0; p[3] = 3; - p[4] = 1; - - indexed_vector vi(5); - vi.set_value(1, 1); - vi.set_value(3, 3); - - p.apply_reverse_from_right_to_T(v); - p.apply_reverse_from_right_to_T(vi); - lp_assert(vectors_are_equal(v, vi.m_data)); - lp_assert(vi.is_OK()); -} void lp_solver_test() { // lp_revised_solver lp_revised; From a9aa3f54fdd2a2436a17853abe866cf7fa20b8d3 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Mon, 6 Mar 2023 15:35:54 -0800 Subject: [PATCH 24/36] rm dead code --- src/math/lp/lp_core_solver_base.h | 7 +- src/math/lp/lp_core_solver_base_def.h | 2 - src/math/lp/lp_primal_core_solver.h | 14 +-- src/math/lp/lp_primal_core_solver_def.h | 114 +----------------- .../lp/lp_primal_core_solver_tableau_def.h | 5 +- 5 files changed, 7 insertions(+), 135 deletions(-) diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 5f723c1185f..cb275ebc908 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -86,21 +86,18 @@ class lp_core_solver_base { lp_settings & m_settings; vector m_y; // the buffer for yB = cb - // a device that is able to solve Bx=c, xB=d, and change the basis const column_namer & m_column_names; indexed_vector m_w; // the vector featuring in 24.3 of the Chvatal book vector m_d; // the vector of reduced costs indexed_vector m_ed; // the solution of B*m_ed = a const vector & m_column_types; const vector & m_lower_bounds; - const vector & m_upper_bounds; - vector m_column_norms; // the approximate squares of column norms that help choosing a profitable column + const vector & m_upper_bounds; vector m_copy_of_xB; unsigned m_basis_sort_counter; - vector m_steepest_edge_coefficients; vector m_trace_of_basis_change_vector; // the even positions are entering, the odd positions are leaving bool m_tracing_basis_changes; - u_set* m_pivoted_rows; + u_set* m_pivoted_rows; bool m_look_for_feasible_solution_only; void start_tracing_basis_changes() { diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 8b87728e090..474d39b572b 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -62,10 +62,8 @@ lp_core_solver_base(static_matrix & A, m_column_types(column_types), m_lower_bounds(lower_bound_values), m_upper_bounds(upper_bound_values), - m_column_norms(m_n()), m_copy_of_xB(m_m()), m_basis_sort_counter(0), - m_steepest_edge_coefficients(A.column_count()), m_tracing_basis_changes(false), m_pivoted_rows(nullptr), m_look_for_feasible_solution_only(false) { diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 10de624f55a..219cc2ad35d 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -369,24 +369,12 @@ class lp_primal_core_solver:public lp_core_solver_base { unsigned get_number_of_non_basic_column_to_try_for_enter(); - void print_column_norms(std::ostream & out); // returns the number of iterations unsigned solve(); - // according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" - void init_column_norms(); - - T calculate_column_norm_exactly(unsigned j); - - void update_or_init_column_norms(unsigned entering, unsigned leaving); - - // following Swietanowski - A new steepest ... - void update_column_norms(unsigned entering, unsigned leaving); - - T calculate_norm_of_entering_exactly(); - + void find_feasible_solution(); // bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;} diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 7a027f8d38c..dac1c15face 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -58,14 +58,8 @@ void lp_primal_core_solver::sort_non_basis() { sort_non_basis_rational(); return; } - for (unsigned j : this->m_nbasis) { - T const & da = this->m_d[j]; - this->m_steepest_edge_coefficients[j] = da * da / this->m_column_norms[j]; - } - std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { - return this->m_steepest_edge_coefficients[a] > this->m_steepest_edge_coefficients[b]; - }); - + + m_non_basis_list.clear(); // reinit m_basis_heading for (unsigned j = 0; j < this->m_nbasis.size(); j++) { @@ -190,41 +184,7 @@ int lp_primal_core_solver::choose_entering_column_presize(unsigned number_ template int lp_primal_core_solver::choose_entering_column(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - if (numeric_traits::precise()) - return choose_entering_column_presize(number_of_benefitial_columns_to_go_over); - if (number_of_benefitial_columns_to_go_over == 0) - return -1; - if (this->m_basis_sort_counter == 0) { - sort_non_basis(); - this->m_basis_sort_counter = 20; - } else { - this->m_basis_sort_counter--; - } - T steepest_edge = zero_of_type(); - std::list::iterator entering_iter = m_non_basis_list.end(); - for (auto non_basis_iter= m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) { - unsigned j = *non_basis_iter; - if (!column_is_benefitial_for_entering_basis(j)) - continue; - - // if we are here then j is a candidate to enter the basis - T dj = this->m_d[j]; - T t = dj * dj / this->m_column_norms[j]; - if (t > steepest_edge) { - steepest_edge = t; - entering_iter = non_basis_iter; - if (number_of_benefitial_columns_to_go_over) - number_of_benefitial_columns_to_go_over--; - } - }// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb); - if (entering_iter != m_non_basis_list.end()) { - unsigned entering = *entering_iter; - m_sign_of_entering_delta = this->m_d[entering] > 0? 1 : -1; - m_non_basis_list.erase(entering_iter); - m_non_basis_list.push_back(entering); - return entering; - } - return -1; + return choose_entering_column_presize(number_of_benefitial_columns_to_go_over); } @@ -607,13 +567,6 @@ template unsigned lp_primal_core_solver::get_num return std::max(static_cast(this->m_settings.random_next() % ret), 1u); } -template void lp_primal_core_solver::print_column_norms(std::ostream & out) { - out << " column norms " << std::endl; - for (unsigned j = 0; j < this->m_n(); j++) { - out << this->m_column_norms[j] << " "; - } - out << std::endl; - } // returns the number of iterations template unsigned lp_primal_core_solver::solve() { @@ -677,67 +630,6 @@ template unsigned lp_primal_core_solver::solve() return this->total_iterations(); } -// according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming" -template void lp_primal_core_solver::init_column_norms() { - lp_assert(numeric_traits::precise() == false); - for (unsigned j = 0; j < this->m_n(); j++) { - this->m_column_norms[j] = T(static_cast(this->m_A.m_columns[j].size() + 1)) - - + T(static_cast(this->m_settings.random_next() % 10000)) / T(100000); - } -} - -// debug only -template T lp_primal_core_solver::calculate_column_norm_exactly(unsigned j) { - lp_assert(false); -} - -template void lp_primal_core_solver::update_or_init_column_norms(unsigned entering, unsigned leaving) { - lp_assert(numeric_traits::precise() == false); - lp_assert(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency); - if (m_column_norm_update_counter == this->m_settings.column_norms_update_frequency) { - m_column_norm_update_counter = 0; - init_column_norms(); - } else { - m_column_norm_update_counter++; - update_column_norms(entering, leaving); - } -} - -// following Swietanowski - A new steepest ... -template void lp_primal_core_solver::update_column_norms(unsigned entering, unsigned leaving) { - lp_assert(numeric_traits::precise() == false); - T pivot = this->m_pivot_row[entering]; - T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot; - if (!numeric_traits::precise()) { - if (g_ent < T(0.000001)) - g_ent = T(0.000001); - } - this->m_column_norms[leaving] = g_ent; - - for (unsigned j : this->m_pivot_row.m_index) { - if (j == leaving) - continue; - const T & t = this->m_pivot_row[j]; - T s = this->m_A.dot_product_with_column(m_beta.m_data, j); - T k = -2 / pivot; - T tp = t/pivot; - if (this->m_column_types[j] != column_type::fixed) { // a fixed columns do not enter the basis, we don't use the norm of a fixed column - this->m_column_norms[j] = std::max(this->m_column_norms[j] + t * (t * g_ent + k * s), // see Istvan Maros, page 196 - 1 + tp * tp); - } - } -} - -template T lp_primal_core_solver::calculate_norm_of_entering_exactly() { - T r = numeric_traits::one(); - for (auto i : this->m_ed.m_index) { - T t = this->m_ed[i]; - r += t * t; - } - return r; -} - // calling it stage1 is too cryptic template void lp_primal_core_solver::find_feasible_solution() { this->m_look_for_feasible_solution_only = true; diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index b63c54bfd10..a63a6be17ad 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -295,10 +295,7 @@ template void lp_primal_core_solver::init_run_tab if (this->m_settings.backup_costs) backup_and_normalize_costs(); m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); - if (!numeric_traits::precise()) { - this->m_column_norm_update_counter = 0; - init_column_norms(); - } + if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); lp_assert(this->reduced_costs_are_correct_tableau()); From 3c737b6b895fc17729664c94b29fac103ccea38b Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 08:20:32 -0800 Subject: [PATCH 25/36] rp precise --- src/math/lp/core_solver_pretty_printer_def.h | 4 +- src/math/lp/lar_solver.cpp | 45 ++---- src/math/lp/lar_solver.h | 3 +- src/math/lp/lp_core_solver_base.cpp | 3 - src/math/lp/lp_core_solver_base.h | 9 +- src/math/lp/lp_core_solver_base_def.h | 18 +-- src/math/lp/lp_primal_core_solver.h | 93 ++--------- src/math/lp/lp_primal_core_solver_def.h | 152 +----------------- .../lp/lp_primal_core_solver_tableau_def.h | 11 +- src/math/lp/lp_settings.h | 9 +- src/math/lp/lp_settings_def.h | 26 +-- src/math/lp/lp_utils.h | 3 - src/math/lp/matrix_def.h | 13 +- src/math/lp/numeric_pair.h | 8 - src/math/lp/static_matrix.h | 1 - 15 files changed, 48 insertions(+), 350 deletions(-) diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index 6971061832b..2f1d99d22c6 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -88,7 +88,6 @@ template T core_solver_pretty_printer::current_co } template void core_solver_pretty_printer::init_m_A_and_signs() { - if (numeric_traits::precise() ) { for (unsigned column = 0; column < ncols(); column++) { vector t(nrows(), zero_of_type()); for (const auto & c : m_core_solver.m_A.m_columns[column]){ @@ -115,8 +114,7 @@ template void core_solver_pretty_printer::init_m_ name); m_rs[row] += t[row] * m_core_solver.m_x[column]; } - } - } + } } template void core_solver_pretty_printer::init_column_widths() { diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 9bc850848e5..9b2361b74f4 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -281,9 +281,9 @@ namespace lp { unsigned m = A_r().row_count(); clean_popped_elements(m, m_rows_with_changed_bounds); clean_inf_set_of_r_solver_after_pop(); - lp_assert(m_settings.simplex_strategy() == simplex_strategy_enum::undecided || - ( m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau())); - + lp_assert( + m_settings.simplex_strategy() == simplex_strategy_enum::undecided || + m_mpq_lar_core_solver.m_r_solver.reduced_costs_are_correct_tableau()); m_constraints.pop(k); m_term_count.pop(k); @@ -627,10 +627,6 @@ namespace lp { m_rows_with_changed_bounds.insert(rid); } - void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column(unsigned j) { - lp_assert(false); - } - void lar_solver::detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j) { @@ -676,20 +672,16 @@ namespace lp { } void lar_solver::change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair& delta) { - { - for (const auto& c : A_r().m_columns[j]) { - unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; - if (tableau_with_costs()) { - m_basic_columns_with_changed_cost.insert(bj); - } - m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta); - TRACE("change_x_del", - tout << "changed basis column " << bj << ", it is " << - (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;); - - } + for (const auto& c : A_r().m_columns[j]) { + unsigned bj = m_mpq_lar_core_solver.m_r_basis[c.var()]; + if (tableau_with_costs()) { + m_basic_columns_with_changed_cost.insert(bj); + } + m_mpq_lar_core_solver.m_r_solver.add_delta_to_x_and_track_feasibility(bj, -A_r().get_val(c) * delta); + TRACE("change_x_del", + tout << "changed basis column " << bj << ", it is " << + (m_mpq_lar_core_solver.m_r_solver.column_is_feasible(bj) ? "feas" : "inf") << std::endl;); } - } void lar_solver::update_x_and_inf_costs_for_column_with_changed_bounds(unsigned j) { @@ -819,19 +811,6 @@ namespace lp { A.set(last_row, basis_j, mpq(1)); } - template - void lar_solver::create_matrix_A(static_matrix& matr) { - lp_assert(false); // not implemented - /* - unsigned m = number_or_nontrivial_left_sides(); - unsigned n = m_vec_of_canonic_left_sides.size(); - if (matr.row_count() == m && matr.column_count() == n) - return; - matr.init_empty_matrix(m, n); - copy_from_mpq_matrix(matr); - */ - } - template void lar_solver::copy_from_mpq_matrix(static_matrix& matr) { matr.m_rows.resize(A_r().row_count()); diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index b925b5ef039..356c86c2f9b 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -205,10 +205,9 @@ class lar_solver : public column_namer { void set_lower_bound_witness(var_index j, constraint_index ci); void substitute_terms_in_linear_expression( const vector>& left_side_with_terms, vector> &left_side) const; - void detect_rows_of_bound_change_column_for_nbasic_column(unsigned j); + void detect_rows_of_bound_change_column_for_nbasic_column_tableau(unsigned j); bool use_tableau_costs() const; - void detect_rows_of_column_with_bound_change(unsigned j); bool tableau_with_costs() const; bool costs_are_used() const; void change_basic_columns_dependend_on_a_given_nb_column(unsigned j, const numeric_pair & delta); diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index b76976d371c..059d801a03c 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -43,7 +43,6 @@ template bool lp::lp_core_solver_base::print_statistics_with_ite template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template void lp::lp_core_solver_base::restore_x(unsigned int, double const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; @@ -51,7 +50,6 @@ template void lp::lp_core_solver_base::fill_reduced_costs_from template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lp::lp_core_solver_base::solve_Ax_eq_b(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); template void lp::lp_core_solver_base >::init(); template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); @@ -61,7 +59,6 @@ template lp::lp_core_solver_base >::lp_core_s const vector >&, const vector >&); template bool lp::lp_core_solver_base >::print_statistics_with_cost_and_check_that_the_time_is_over(lp::numeric_pair, std::ostream&); -template void lp::lp_core_solver_base >::solve_Ax_eq_b(); template void lp::lp_core_solver_base >::add_delta_to_entering(unsigned int, const lp::numeric_pair&); template lp::lp_core_solver_base::lp_core_solver_base( diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index cb275ebc908..6fa2ddead1c 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -238,11 +238,11 @@ class lp_core_solver_base { } bool below_bound(const X & x, const X & bound) const { - return precise()? x < bound : below_bound_numeric(x, bound, m_settings.primal_feasibility_tolerance); + return x < bound ; } bool above_bound(const X & x, const X & bound) const { - return precise()? x > bound : above_bound_numeric(x, bound, m_settings.primal_feasibility_tolerance); + return x > bound ; } bool x_below_low_bound(unsigned p) const { @@ -323,9 +323,6 @@ class lp_core_solver_base { void find_error_in_BxB(vector& rs); - // recalculates the projection of x to B, such that Ax = b, whereab is the right side - void solve_Ax_eq_b(); - bool snap_non_basic_x_to_bound() { bool ret = false; for (unsigned j : non_basis()) @@ -628,8 +625,6 @@ class lp_core_solver_base { bool pivot_column_tableau(unsigned j, unsigned row_index); bool divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col); - bool precise() const { return numeric_traits::precise(); } - simplex_strategy_enum simplex_strategy() const { return m_settings.simplex_strategy(); } diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 474d39b572b..213d67e6ea0 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -233,18 +233,12 @@ column_is_dual_feasible(unsigned j) const { } template bool lp_core_solver_base:: d_is_not_negative(unsigned j) const { - if (numeric_traits::precise()) { - return m_d[j] >= numeric_traits::zero(); - } - return m_d[j] > -T(0.00001); + return m_d[j] >= numeric_traits::zero(); } template bool lp_core_solver_base:: d_is_not_positive(unsigned j) const { - if (numeric_traits::precise()) { - return m_d[j] <= numeric_traits::zero(); - } - return m_d[j] < T(0.00001); + return m_d[j] <= numeric_traits::zero(); } @@ -319,7 +313,6 @@ template bool lp_core_solver_base::inf_set_is_cor template bool lp_core_solver_base:: divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) { - lp_assert(numeric_traits::precise()); int pivot_index = -1; auto & row = m_A.m_rows[pivot_row]; unsigned size = row.size(); @@ -517,13 +510,6 @@ find_error_in_BxB(vector& rs){ } } -// recalculates the projection of x to B, such that Ax = b -template void lp_core_solver_base:: -solve_Ax_eq_b() { - lp_assert(false); -} - - template non_basic_column_value_position lp_core_solver_base:: get_non_basic_column_value_position(unsigned j) const { switch (m_column_types[j]) { diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 219cc2ad35d..aa771d7ee80 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -511,7 +511,6 @@ class lp_primal_core_solver:public lp_core_solver_base { bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller lp_assert(m < 0); - if (numeric_traits::precise()) { if (this->below_bound(x, bound)) return false; if (this->above_bound(x, bound)) { limit_theta((bound - x) / m, theta, unlimited); @@ -519,59 +518,30 @@ class lp_primal_core_solver:public lp_core_solver_base { theta = zero_of_type(); unlimited = false; } - } else { - const X& eps = harris_eps_for_bound(bound); - if (this->below_bound(x, bound)) return false; - if (this->above_bound(x, bound)) { - limit_theta((bound - x - eps) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } - } return true; } bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets larger lp_assert(m > 0); - if (numeric_traits::precise()) { - if (this->above_bound(x, bound)) return false; - if (this->below_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } + if (this->above_bound(x, bound)) return false; + if (this->below_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); } else { - const X& eps = harris_eps_for_bound(bound); - if (this->above_bound(x, bound)) return false; - if (this->below_bound(x, bound)) { - limit_theta((bound - x + eps) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } + theta = zero_of_type(); + unlimited = false; } + return true; } void limit_inf_on_lower_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { - if (numeric_traits::precise()) { - // x gets larger - lp_assert(m > 0); - if (this->below_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); - } - } - else { // x gets larger - lp_assert(m > 0); - const X& eps = harris_eps_for_bound(bound); - if (this->below_bound(x, bound)) { - limit_theta((bound - x + eps) / m, theta, unlimited); - } - } + lp_assert(m > 0); + if (this->below_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); + } + } void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { @@ -877,46 +847,13 @@ class lp_primal_core_solver:public lp_core_solver_base { m_epsilon_of_reduced_cost(T(1)/T(10000000)), m_bland_mode_threshold(1000) { - if (!(numeric_traits::precise())) { - m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); - } else { - m_converted_harris_eps = zero_of_type(); - } + + m_converted_harris_eps = zero_of_type(); + this->set_status(lp_status::UNKNOWN); } - // constructor - lp_primal_core_solver(static_matrix & A, - vector & b, // the right side vector - vector & x, // the number of elements in x needs to be at least as large as the number of columns in A - vector & basis, - vector & nbasis, - vector & heading, - vector & costs, - const vector & column_type_array, - const vector & upper_bound_values, - lp_settings & settings, - const column_namer& column_names): - lp_core_solver_base(A, // b, - basis, - nbasis, - heading, - x, - costs, - settings, - column_names, - column_type_array, - m_lower_bounds_dummy, - upper_bound_values), - m_beta(A.row_count()), - m_converted_harris_eps(convert_struct::convert(this->m_settings.harris_feasibility_tolerance)) { - lp_assert(initial_x_is_correct()); - m_lower_bounds_dummy.resize(A.column_count(), zero_of_type()); - m_enter_price_eps = numeric_traits::precise() ? numeric_traits::zero() : T(1e-5); -#ifdef Z3DEBUG - lp_assert(false); -#endif - } + bool initial_x_is_correct() { std::set basis_set; diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index dac1c15face..fb62bbf540e 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -33,9 +33,7 @@ namespace lp { template void lp_primal_core_solver::sort_non_basis_rational() { - lp_assert(numeric_traits::precise()); - - std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { + std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { unsigned ca = this->m_A.number_of_non_zeroes_in_column(a); unsigned cb = this->m_A.number_of_non_zeroes_in_column(b); if (ca == 0 && cb != 0) return false; @@ -54,57 +52,15 @@ void lp_primal_core_solver::sort_non_basis_rational() { template void lp_primal_core_solver::sort_non_basis() { - if (numeric_traits::precise()) { - sort_non_basis_rational(); - return; - } - - - m_non_basis_list.clear(); - // reinit m_basis_heading - for (unsigned j = 0; j < this->m_nbasis.size(); j++) { - unsigned col = this->m_nbasis[j]; - this->m_basis_heading[col] = - static_cast(j) - 1; - m_non_basis_list.push_back(col); - } + sort_non_basis_rational(); } template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsigned j) const { - if (numeric_traits::precise()) - return column_is_benefitial_for_entering_basis_precise(j); - const T& dj = this->m_d[j]; - switch (this->m_column_types[j]) { - case column_type::fixed: break; - case column_type::free_column: - if (dj > m_epsilon_of_reduced_cost || dj < -m_epsilon_of_reduced_cost) - return true; - break; - case column_type::lower_bound: - if (dj > m_epsilon_of_reduced_cost) return true;; - break; - case column_type::upper_bound: - if (dj < -m_epsilon_of_reduced_cost) return true; - break; - case column_type::boxed: - if (dj > m_epsilon_of_reduced_cost) { - if (this->m_x[j] < this->m_upper_bounds[j] - this->bound_span(j)/2) - return true; - break; - } else if (dj < - m_epsilon_of_reduced_cost) { - if (this->m_x[j] > this->m_lower_bounds[j] + this->bound_span(j)/2) - return true; - } - break; - default: - lp_unreachable(); - break; - } - return false; + return column_is_benefitial_for_entering_basis_precise(j); } template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { - lp_assert (numeric_traits::precise()); const T& dj = this->m_d[j]; TRACE("lar_solver", tout << "dj=" << dj << "\n";); switch (this->m_column_types[j]) { @@ -144,7 +100,6 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis template int lp_primal_core_solver::choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - lp_assert(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -231,8 +186,6 @@ find_leaving_on_harris_theta(X const & harris_theta, X & t) { } if (++k == steps) k = 0; } while (k != initial_k); - if (!this->precise()) - restore_harris_eps(); return leaving; } @@ -479,47 +432,14 @@ void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned e // return 0 if the reduced cost at entering is close enough to the refreshed // 1 if it is way off, and 2 if it is unprofitable template int lp_primal_core_solver::refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) { - if (numeric_traits::precise()) return 0; - T reduced_at_entering_was = this->m_d[entering]; // can benefit from going over non-zeros of m_ed - lp_assert(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost); - T refreshed_cost = this->m_costs[entering]; - unsigned i = this->m_m(); - while (i--) refreshed_cost -= this->m_costs[this->m_basis[i]] * this->m_ed[i]; - this->m_d[entering] = refreshed_cost; - T delta = abs(reduced_at_entering_was - refreshed_cost); - if (delta * 2 > abs(reduced_at_entering_was)) { - // this->m_status = UNSTABLE; - if (reduced_at_entering_was > m_epsilon_of_reduced_cost) { - if (refreshed_cost <= zero_of_type()) - return 2; // abort entering - } else { - if (refreshed_cost > -m_epsilon_of_reduced_cost) - return 2; // abort entering - } - return 1; // go on with this entering - } else { - if (reduced_at_entering_was > m_epsilon_of_reduced_cost) { - if (refreshed_cost <= zero_of_type()) - return 2; // abort entering - } else { - if (refreshed_cost > -m_epsilon_of_reduced_cost) - return 2; // abort entering - } - } return 0; + } template void lp_primal_core_solver::backup_and_normalize_costs() { if (this->m_look_for_feasible_solution_only) return; // no need to backup cost, since we are going to use only feasibility costs - if (numeric_traits::precise() ) { - m_costs_backup = this->m_costs; - } else { - T cost_max = std::max(max_abs_in_vector(this->m_costs), T(1)); - lp_assert(m_costs_backup.size() == 0); - for (unsigned j = 0; j < this->m_costs.size(); j++) - m_costs_backup.push_back(this->m_costs[j] /= cost_max); - } + m_costs_backup = this->m_costs; } template void lp_primal_core_solver::init_run() { @@ -527,10 +447,6 @@ template void lp_primal_core_solver::init_run( } -template void lp_primal_core_solver::calc_working_vector_beta_for_column_norms(){ - lp_assert(false); -} - template void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering, X & t) { @@ -571,63 +487,7 @@ template unsigned lp_primal_core_solver::get_num // returns the number of iterations template unsigned lp_primal_core_solver::solve() { TRACE("lar_solver", tout << "solve " << this->get_status() << "\n";); - if (numeric_traits::precise()) - return solve_with_tableau(); - - init_run(); - if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { - this->set_status(lp_status::FEASIBLE); - return 0; - } - - - do { - if (this->print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over((this->using_infeas_costs()? "inf" : "feas"), * this->m_settings.get_message_ostream())) { - return this->total_iterations(); - } - one_iteration(); - - TRACE("lar_solver", tout << "one iteration: " << this->get_status() << "\n";); - lp_assert(!this->using_infeas_costs() || this->costs_on_nbasis_are_zeros()); - switch (this->get_status()) { - case lp_status::OPTIMAL: // double check that we are at optimum - case lp_status::INFEASIBLE: - if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) - break; - { // precise case - - } - break; - case lp_status::TENTATIVE_UNBOUNDED: - lp_assert(false); - break; - case lp_status::UNBOUNDED: - lp_assert(false); - break; - - case lp_status::UNSTABLE: - lp_assert(false); - break; - - default: - break; // do nothing - } - } while ( - this->get_status() != lp_status::UNBOUNDED - && - this->get_status() != lp_status::OPTIMAL - && - this->get_status() != lp_status::INFEASIBLE - && - this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements - && - !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)); - - lp_assert( - this->current_x_is_feasible() == false - || - this->calc_current_x_is_feasible_include_non_basis()); - return this->total_iterations(); + return solve_with_tableau(); } // calling it stage1 is too cryptic diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index a63a6be17ad..96df997b17c 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -43,19 +43,10 @@ template void lp_primal_core_solver::advance_on_e } advance_on_entering_and_leaving_tableau(entering, leaving, t); } -/* -template int lp_primal_core_solver::choose_entering_column_tableau_rows() { - int i = find_inf_row(); - if (i == -1) - return -1; - return find_shortest_beneficial_column_in_row(i); - } -*/ template int lp_primal_core_solver::choose_entering_column_tableau() { //this moment m_y = cB * B(-1) unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); - lp_assert(numeric_traits::precise()); if (number_of_benefitial_columns_to_go_over == 0) return -1; if (this->m_basis_sort_counter == 0) { @@ -294,7 +285,7 @@ template void lp_primal_core_solver::init_run_tab return; if (this->m_settings.backup_costs) backup_and_normalize_costs(); - m_epsilon_of_reduced_cost = numeric_traits::precise() ? zero_of_type() : T(1) / T(10000000); + m_epsilon_of_reduced_cost = zero_of_type(); if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 38270230e7e..86a97e615e9 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -78,9 +78,8 @@ enum class lp_status { // when the ratio of the vector length to domain size to is greater than the return value we switch to solve_By_for_T_indexed_only template unsigned ratio_of_index_size_to_all_size() { - if (numeric_traits::precise()) return 10; - return 120; + } const char* lp_status_to_string(lp_status status); @@ -274,7 +273,7 @@ struct lp_settings { statistics const& stats() const { return m_stats; } template static bool is_eps_small_general(const T & t, const double & eps) { - return (!numeric_traits::precise())? is_epsilon_small(t, eps) : numeric_traits::is_zero(t); + return numeric_traits::is_zero(t); } template @@ -373,9 +372,7 @@ inline std::string T_to_string(const mpq & t) { template bool val_is_smaller_than_eps(T const & t, double const & eps) { - if (!numeric_traits::precise()) { - return numeric_traits::get_double(t) < eps; - } + return t <= numeric_traits::zero(); } diff --git a/src/math/lp/lp_settings_def.h b/src/math/lp/lp_settings_def.h index bb87109f6fb..a439466d18c 100644 --- a/src/math/lp/lp_settings_def.h +++ b/src/math/lp/lp_settings_def.h @@ -70,19 +70,12 @@ lp_status lp_status_from_string(std::string status) { template bool vectors_are_equal(T * a, vector &b, unsigned n) { - if (numeric_traits::precise()) { for (unsigned i = 0; i < n; i ++){ if (!numeric_traits::is_zero(a[i] - b[i])) { return false; } } - } else { - for (unsigned i = 0; i < n; i ++){ - if (std::abs(numeric_traits::get_double(a[i] - b[i])) > 0.000001) { - return false; - } - } - } + return true; } @@ -91,27 +84,12 @@ template bool vectors_are_equal(const vector & a, const vector &b) { unsigned n = static_cast(a.size()); if (n != b.size()) return false; - if (numeric_traits::precise()) { for (unsigned i = 0; i < n; i ++){ if (!numeric_traits::is_zero(a[i] - b[i])) { return false; } } - } else { - for (unsigned i = 0; i < n; i ++){ - double da = numeric_traits::get_double(a[i]); - double db = numeric_traits::get_double(b[i]); - double amax = std::max(fabs(da), fabs(db)); - if (amax > 1) { - da /= amax; - db /= amax; - } - - if (fabs(da - db) > 0.000001) { - return false; - } - } - } + return true; } #ifdef Z3DEBUG diff --git a/src/math/lp/lp_utils.h b/src/math/lp/lp_utils.h index 40c5f063282..ad5ba380d91 100644 --- a/src/math/lp/lp_utils.h +++ b/src/math/lp/lp_utils.h @@ -153,9 +153,6 @@ template inline X ceil_ratio(const X & a, const X & b) { return num template inline X floor_ratio(const X & a, const X & b) { return numeric_traits::floor_ratio(a, b); } -template inline bool precise() { return numeric_traits::precise(); } - - // returns true if a factor of b template bool is_proper_factor(const T & a, const T & b) { diff --git a/src/math/lp/matrix_def.h b/src/math/lp/matrix_def.h index 95810bd5a96..e3ac08f7e03 100644 --- a/src/math/lp/matrix_def.h +++ b/src/math/lp/matrix_def.h @@ -32,16 +32,9 @@ bool matrix::is_equal(const matrix& other) { for (unsigned j = 0; j < column_count(); j++) { auto a = get_elem(i, j); auto b = other.get_elem(i, j); - if (numeric_traits::precise()) { - if (a != b) return false; - } else if (fabs(numeric_traits::get_double(a - b)) > 0.000001) { - // cout << "returning false from operator== of matrix comparison" << endl; - // cout << "this matrix is " << endl; - // print_matrix(*this); - // cout << "other matrix is " << endl; - // print_matrix(other); - return false; - } + + if (a != b) return false; + } } return true; diff --git a/src/math/lp/numeric_pair.h b/src/math/lp/numeric_pair.h index 9f7e27c18a1..f59aa84ba52 100644 --- a/src/math/lp/numeric_pair.h +++ b/src/math/lp/numeric_pair.h @@ -45,7 +45,6 @@ template class numeric_traits {}; template <> class numeric_traits { public: - static bool precise() { return true; } static unsigned zero() { return 0; } static unsigned one() { return 1; } static bool is_zero(unsigned v) { return v == 0; } @@ -56,7 +55,6 @@ template <> class numeric_traits { template <> class numeric_traits { public: - static bool precise() { return true; } static int zero() { return 0; } static int one() { return 1; } static bool is_zero(int v) { return v == 0; } @@ -71,7 +69,6 @@ template <> class numeric_traits { template <> class numeric_traits { public: - static bool precise() { return false; } static double g_zero; static double const &zero() { return g_zero; } static double g_one; @@ -88,7 +85,6 @@ template <> class numeric_traits { template<> class numeric_traits { public: - static bool precise() { return true; } static rational const & zero() { return rational::zero(); } static rational const & one() { return rational::one(); } static bool is_zero(const rational & v) { return v.is_zero(); } @@ -251,8 +247,6 @@ struct numeric_pair { return numeric_pair(-x, -y); } - static bool precize() { return lp::numeric_traits::precize();} - bool is_zero() const { return x.is_zero() && y.is_zero(); } bool is_pos() const { return x.is_pos() || (x.is_zero() && y.is_pos());} @@ -294,12 +288,10 @@ numeric_pair operator/(const numeric_pair & r, const X & a) { return numeric_pair(r.x / a, r.y / a); } -// template bool precise() { return numeric_traits::precise();} template double get_double(const lp::numeric_pair & ) { /* lp_unreachable(); */ return 0;} template class numeric_traits> { public: - static bool precise() { return numeric_traits::precise();} static lp::numeric_pair zero() { return lp::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } static bool is_zero(const lp::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } static double get_double(const lp::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate diff --git a/src/math/lp/static_matrix.h b/src/math/lp/static_matrix.h index a429268530d..7f81cae79f5 100644 --- a/src/math/lp/static_matrix.h +++ b/src/math/lp/static_matrix.h @@ -344,7 +344,6 @@ class static_matrix void fill_last_row_with_pivoting(const term& row, unsigned bj, // the index of the basis column const vector & basis_heading) { - lp_assert(numeric_traits::precise()); lp_assert(row_count() > 0); m_work_vector.resize(column_count()); T a; From 3b18c87759772ab885d4ba9127b9c2439a39d661 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 08:52:08 -0800 Subject: [PATCH 26/36] remove many methods dealing with double Signed-off-by: Lev Nachmanson --- src/math/lp/binary_heap_priority_queue.cpp | 3 - src/math/lp/conversion_helper.h | 23 ----- src/math/lp/core_solver_pretty_printer.cpp | 3 - src/math/lp/dense_matrix.cpp | 6 -- src/math/lp/dense_matrix.h | 6 +- src/math/lp/dense_matrix_def.h | 11 --- src/math/lp/indexed_vector.cpp | 18 ---- src/math/lp/indexed_vector.h | 55 +----------- src/math/lp/indexed_vector_def.h | 29 +------ src/math/lp/lar_core_solver.h | 44 +--------- src/math/lp/lar_solver.cpp | 75 +--------------- src/math/lp/lar_solver.h | 4 - src/math/lp/lp_core_solver_base.cpp | 27 ------ src/math/lp/lp_core_solver_base.h | 6 +- src/math/lp/lp_core_solver_base_def.h | 17 ---- src/math/lp/lp_primal_core_solver.cpp | 4 - src/math/lp/lp_primal_core_solver.h | 4 +- src/math/lp/lp_primal_core_solver_def.h | 12 --- .../lp/lp_primal_core_solver_tableau_def.h | 2 +- src/math/lp/lp_settings.cpp | 1 - src/math/lp/lp_settings.h | 86 ++----------------- src/math/lp/lp_utils.cpp | 3 +- src/math/lp/matrix.cpp | 2 - src/math/lp/permutation_matrix.cpp | 16 ---- src/math/lp/permutation_matrix_def.h | 6 +- src/math/lp/sparse_vector.h | 1 - src/math/lp/static_matrix.cpp | 20 ----- src/math/lp/static_matrix.h | 1 - 28 files changed, 20 insertions(+), 465 deletions(-) diff --git a/src/math/lp/binary_heap_priority_queue.cpp b/src/math/lp/binary_heap_priority_queue.cpp index bbe735e58bd..ec6630b1dbb 100644 --- a/src/math/lp/binary_heap_priority_queue.cpp +++ b/src/math/lp/binary_heap_priority_queue.cpp @@ -23,15 +23,12 @@ namespace lp { template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue::enqueue(unsigned int, int const&); -template void binary_heap_priority_queue::enqueue(unsigned int, double const&); template void binary_heap_priority_queue::enqueue(unsigned int, mpq const&); template void binary_heap_priority_queue::remove(unsigned int); template unsigned binary_heap_priority_queue >::dequeue(); -template unsigned binary_heap_priority_queue::dequeue(); template unsigned binary_heap_priority_queue::dequeue(); template void binary_heap_priority_queue >::enqueue(unsigned int, numeric_pair const&); template void binary_heap_priority_queue >::resize(unsigned int); -template void lp::binary_heap_priority_queue::resize(unsigned int); template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); template void binary_heap_priority_queue::resize(unsigned int); template unsigned binary_heap_priority_queue::dequeue(); diff --git a/src/math/lp/conversion_helper.h b/src/math/lp/conversion_helper.h index feb99974376..ba8b6a9835f 100644 --- a/src/math/lp/conversion_helper.h +++ b/src/math/lp/conversion_helper.h @@ -31,28 +31,5 @@ struct conversion_helper { } }; -template<> -struct conversion_helper { - static double get_upper_bound(const column_info & ci) { - if (!ci.upper_bound_is_strict()) - return ci.get_upper_bound().get_double(); - double eps = 0.00001; - if (!ci.lower_bound_is_set()) - return ci.get_upper_bound().get_double() - eps; - eps = std::min((ci.get_upper_bound() - ci.get_lower_bound()).get_double() / 1000, eps); - return ci.get_upper_bound().get_double() - eps; - } - - static double get_lower_bound(const column_info & ci) { - if (!ci.lower_bound_is_strict()) - return ci.get_lower_bound().get_double(); - double eps = 0.00001; - if (!ci.upper_bound_is_set()) - return ci.get_lower_bound().get_double() + eps; - eps = std::min((ci.get_upper_bound() - ci.get_lower_bound()).get_double() / 1000, eps); - return ci.get_lower_bound().get_double() + eps; - } - -}; } diff --git a/src/math/lp/core_solver_pretty_printer.cpp b/src/math/lp/core_solver_pretty_printer.cpp index 74d2f6048ea..18bef83030f 100644 --- a/src/math/lp/core_solver_pretty_printer.cpp +++ b/src/math/lp/core_solver_pretty_printer.cpp @@ -19,9 +19,6 @@ Revision History: --*/ #include "math/lp/numeric_pair.h" #include "math/lp/core_solver_pretty_printer_def.h" -template lp::core_solver_pretty_printer::core_solver_pretty_printer(const lp::lp_core_solver_base &, std::ostream & out); -template void lp::core_solver_pretty_printer::print(); -template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); template lp::core_solver_pretty_printer::core_solver_pretty_printer(const lp::lp_core_solver_base &, std::ostream & out); template void lp::core_solver_pretty_printer::print(); template lp::core_solver_pretty_printer::~core_solver_pretty_printer(); diff --git a/src/math/lp/dense_matrix.cpp b/src/math/lp/dense_matrix.cpp index f12e688d397..25fc65a5d41 100644 --- a/src/math/lp/dense_matrix.cpp +++ b/src/math/lp/dense_matrix.cpp @@ -21,11 +21,6 @@ Revision History: #include "math/lp/dense_matrix_def.h" #ifdef Z3DEBUG #include "util/vector.h" -template lp::dense_matrix lp::operator*(lp::matrix&, lp::matrix&); -template void lp::dense_matrix::apply_from_left(vector &); -template lp::dense_matrix::dense_matrix(lp::matrix const*); -template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); -template lp::dense_matrix& lp::dense_matrix::operator=(lp::dense_matrix const&); template lp::dense_matrix::dense_matrix(unsigned int, unsigned int); template lp::dense_matrix >::dense_matrix(lp::matrix > const*); template void lp::dense_matrix >::apply_from_left(vector&); @@ -35,6 +30,5 @@ template lp::dense_matrix >::dense_matrix(uns template lp::dense_matrix >& lp::dense_matrix >::operator=(lp::dense_matrix > const&); template lp::dense_matrix > lp::operator* >(lp::matrix >&, lp::matrix >&); template void lp::dense_matrix >::apply_from_right( vector< lp::mpq> &); -template void lp::dense_matrix::apply_from_right(vector &); template void lp::dense_matrix::apply_from_left(vector&); #endif diff --git a/src/math/lp/dense_matrix.h b/src/math/lp/dense_matrix.h index 342fc7aebe6..fcc85cdd17d 100644 --- a/src/math/lp/dense_matrix.h +++ b/src/math/lp/dense_matrix.h @@ -90,11 +90,7 @@ class dense_matrix: public matrix { void set_elem(unsigned i, unsigned j, const T& val) { m_values[i * m_n + j] = val; } - // This method pivots row i to row i0 by muliplying row i by - // alpha and adding it to row i0. - void pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, - const double & pivot_epsilon); - + // This method pivots void swap_columns(unsigned a, unsigned b); void swap_rows(unsigned a, unsigned b); diff --git a/src/math/lp/dense_matrix_def.h b/src/math/lp/dense_matrix_def.h index 8eb9ad5dd50..e850a9acd95 100644 --- a/src/math/lp/dense_matrix_def.h +++ b/src/math/lp/dense_matrix_def.h @@ -150,17 +150,6 @@ template void dense_matrix::apply_from_left_to_X( } } -// This method pivots row i to row i0 by muliplying row i by -// alpha and adding it to row i0. -template void dense_matrix::pivot_row_to_row(unsigned i, const T& alpha, unsigned i0, - const double & pivot_epsilon) { - for (unsigned j = 0; j < m_n; j++) { - m_values[i0 * m_n + j] += m_values[i * m_n + j] * alpha; - if (fabs(m_values[i0 + m_n + j]) < pivot_epsilon) { - m_values[i0 + m_n + j] = numeric_traits::zero();; - } - } -} template void dense_matrix::swap_columns(unsigned a, unsigned b) { for (unsigned i = 0; i < m_m; i++) { diff --git a/src/math/lp/indexed_vector.cpp b/src/math/lp/indexed_vector.cpp index d7cde2e1de5..fe089254186 100644 --- a/src/math/lp/indexed_vector.cpp +++ b/src/math/lp/indexed_vector.cpp @@ -20,10 +20,6 @@ Revision History: #include "util/vector.h" #include "math/lp/indexed_vector_def.h" namespace lp { -template void indexed_vector::clear(); -template void indexed_vector::clear_all(); -template void indexed_vector::erase_from_index(unsigned int); -template void indexed_vector::set_value(const double&, unsigned int); template void indexed_vector::clear(); template void indexed_vector::clear(); template void indexed_vector::clear_all(); @@ -32,22 +28,8 @@ template void indexed_vector::resize(unsigned int); template void indexed_vector::resize(unsigned int); template void indexed_vector::set_value(const mpq&, unsigned int); template void indexed_vector::set_value(const unsigned&, unsigned int); -#ifdef Z3DEBUG -template bool indexed_vector::is_OK() const; -template bool indexed_vector::is_OK() const; -template bool indexed_vector::is_OK() const; -template bool indexed_vector >::is_OK() const; -#endif template void lp::indexed_vector< lp::mpq>::print(std::basic_ostream > &); -template void lp::indexed_vector::print(std::basic_ostream > &); template void lp::indexed_vector >::print(std::ostream&); } -// template void lp::print_vector(vector const&, std::ostream&); -// template void lp::print_vector(vector const&, std::ostream&); -// template void lp::print_vector(vector const&, std::ostream&); -// template void lp::print_vector >(vector> const&, std::ostream&); -template void lp::indexed_vector::resize(unsigned int); -// template void lp::print_vector< lp::mpq>(vector< lp::mpq> const &, std::basic_ostream > &); -// template void lp::print_vector >(vector> const&, std::ostream&); template void lp::indexed_vector >::erase_from_index(unsigned int); diff --git a/src/math/lp/indexed_vector.h b/src/math/lp/indexed_vector.h index 017a25f6be2..9f3119e9a16 100644 --- a/src/math/lp/indexed_vector.h +++ b/src/math/lp/indexed_vector.h @@ -99,47 +99,9 @@ class indexed_vector { return m_data[i]; } - void clean_up() { -#if 0==1 - for (unsigned k = 0; k < m_index.size(); k++) { - unsigned i = m_index[k]; - T & v = m_data[i]; - if (lp_settings::is_eps_small_general(v, 1e-14)) { - v = zero_of_type(); - m_index.erase(m_index.begin() + k--); - } - } -#endif - vector index_copy; - for (unsigned i : m_index) { - T & v = m_data[i]; - if (!lp_settings::is_eps_small_general(v, 1e-14)) { - index_copy.push_back(i); - } else if (!numeric_traits::is_zero(v)) { - v = zero_of_type(); - } - } - m_index = index_copy; - } - void erase_from_index(unsigned j); - - void add_value_at_index_with_drop_tolerance(unsigned j, const T& val_to_add) { - T & v = m_data[j]; - bool was_zero = is_zero(v); - v += val_to_add; - if (lp_settings::is_eps_small_general(v, 1e-14)) { - v = zero_of_type(); - if (!was_zero) { - erase_from_index(j); - } - } else { - if (was_zero) - m_index.push_back(j); - } - } - + void add_value_at_index(unsigned j, const T& val_to_add) { T & v = m_data[j]; bool was_zero = is_zero(v); @@ -153,18 +115,6 @@ class indexed_vector { } } - void restore_index_and_clean_from_data() { - m_index.resize(0); - for (unsigned i = 0; i < m_data.size(); i++) { - T & v = m_data[i]; - if (lp_settings::is_eps_small_general(v, 1e-14)) { - v = zero_of_type(); - } else { - m_index.push_back(i); - } - } - } - struct ival { unsigned m_var; const T & m_coeff; @@ -215,9 +165,6 @@ class indexed_vector { } -#ifdef Z3DEBUG - bool is_OK() const; -#endif void print(std::ostream & out); }; } diff --git a/src/math/lp/indexed_vector_def.h b/src/math/lp/indexed_vector_def.h index 0e25ee27115..1b904e14af1 100644 --- a/src/math/lp/indexed_vector_def.h +++ b/src/math/lp/indexed_vector_def.h @@ -43,7 +43,7 @@ template void indexed_vector::resize(unsigned data_size) { clear(); m_data.resize(data_size, numeric_traits::zero()); - lp_assert(is_OK()); + } template @@ -72,33 +72,6 @@ void indexed_vector::erase_from_index(unsigned j) { m_index.erase(it); } -#ifdef Z3DEBUG -template -bool indexed_vector::is_OK() const { - return true; - const double drop_eps = 1e-14; - for (unsigned i = 0; i < m_data.size(); i++) { - if (!is_zero(m_data[i]) && lp_settings::is_eps_small_general(m_data[i], drop_eps)) { - return false; - } - if (lp_settings::is_eps_small_general(m_data[i], drop_eps) != (std::find(m_index.begin(), m_index.end(), i) == m_index.end())) { - return false; - } - } - - std::unordered_set s; - for (unsigned i : m_index) { - //no duplicates!!! - if (s.find(i) != s.end()) - return false; - s.insert(i); - if (i >= m_data.size()) - return false; - } - - return true; -} -#endif template void indexed_vector::print(std::ostream & out) { out << "m_index " << std::endl; diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index d40572b9e24..e024b199c1d 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -27,8 +27,7 @@ class lar_core_solver { int m_infeasible_sum_sign; // todo: get rid of this field vector> m_right_sides_dummy; vector m_costs_dummy; - vector m_d_right_sides_dummy; - vector m_d_costs_dummy; + public: stacked_value m_stacked_simplex_strategy; stacked_vector m_column_types; @@ -45,10 +44,6 @@ class lar_core_solver { stacked_vector m_r_rows_nz; // d - solver fields, for doubles - vector m_d_x; // the solution in doubles - vector m_d_lower_bounds; - vector m_d_upper_bounds; - static_matrix m_d_A; stacked_vector m_d_pushed_basis; vector m_d_basis; vector m_d_nbasis; @@ -146,7 +141,7 @@ class lar_core_solver { m_r_lower_bounds.push(); m_r_upper_bounds.push(); - m_d_A.push(); + } @@ -185,10 +180,6 @@ class lar_core_solver { m_r_solver.m_costs.resize(m_r_A.column_count()); m_r_solver.m_d.resize(m_r_A.column_count()); - m_d_A.pop(k); - // doubles - - m_d_x.resize(m_d_A.column_count()); pop_basis(k); m_stacked_simplex_strategy.pop(k); settings().set_simplex_strategy(m_stacked_simplex_strategy); @@ -279,15 +270,7 @@ class lar_core_solver { } - void create_double_matrix(static_matrix & A) { - for (unsigned i = 0; i < m_r_A.row_count(); i++) { - auto & row = m_r_A.m_rows[i]; - for (row_cell & c : row) { - A.add_new_element(i, c.var(), c.coeff().get_double()); - } - } - } - + void fill_basis_d( vector& basis_d, vector& heading_d, @@ -308,27 +291,6 @@ class lar_core_solver { } } - void get_bounds_for_double_solver() { - unsigned n = m_n(); - m_d_lower_bounds.resize(n); - m_d_upper_bounds.resize(n); - double delta = find_delta_for_strict_boxed_bounds().get_double(); - if (delta > 0.000001) - delta = 0.000001; - for (unsigned j = 0; j < n; j++) { - if (lower_bound_is_set(j)) { - const auto & lb = m_r_solver.m_lower_bounds[j]; - m_d_lower_bounds[j] = lb.x.get_double() + delta * lb.y.get_double(); - } - if (upper_bound_is_set(j)) { - const auto & ub = m_r_solver.m_upper_bounds[j]; - m_d_upper_bounds[j] = ub.x.get_double() + delta * ub.y.get_double(); - lp_assert(!lower_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_lower_bounds[j])); - } - } - } - - bool lower_bound_is_set(unsigned j) const { switch (m_column_types[j]) { diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 9b2361b74f4..67cf90bd081 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -8,10 +8,6 @@ namespace lp { - static_matrix& lar_solver::A_d() { return m_mpq_lar_core_solver.m_d_A; } - - static_matrix const& lar_solver::A_d() const { return m_mpq_lar_core_solver.m_d_A; } - lp_settings& lar_solver::settings() { return m_settings; } lp_settings const& lar_solver::settings() const { return m_settings; } @@ -574,7 +570,6 @@ namespace lp { void lar_solver::pop_core_solver_params(unsigned k) { A_r().pop(k); - A_d().pop(k); } @@ -1544,27 +1539,7 @@ namespace lp { add_new_var_to_core_fields_for_mpq(false); // false for not adding a row } - - void lar_solver::add_new_var_to_core_fields_for_doubles(bool register_in_basis) { - unsigned j = A_d().column_count(); - A_d().add_column(); - lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lp_assert(m_mpq_lar_core_solver.m_d_lower_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1); - m_mpq_lar_core_solver.m_d_lower_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - } - else { - m_mpq_lar_core_solver.m_d_heading.push_back(-static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - } - } - + void lar_solver::add_new_var_to_core_fields_for_mpq(bool register_in_basis) { unsigned j = A_r().column_count(); TRACE("add_var", tout << "j = " << j << std::endl;); @@ -1927,34 +1902,7 @@ namespace lp { } } - void lar_solver::adjust_initial_state_for_lu() { - copy_from_mpq_matrix(A_d()); - unsigned n = A_d().column_count(); - m_mpq_lar_core_solver.m_d_x.resize(n); - m_mpq_lar_core_solver.m_d_lower_bounds.resize(n); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(n); - m_mpq_lar_core_solver.m_d_heading = m_mpq_lar_core_solver.m_r_heading; - m_mpq_lar_core_solver.m_d_basis = m_mpq_lar_core_solver.m_r_basis; - - /* - unsigned j = A_d().column_count(); - A_d().add_column(); - lp_assert(m_mpq_lar_core_solver.m_d_x.size() == j); - // lp_assert(m_mpq_lar_core_solver.m_d_lower_bounds.size() == j && m_mpq_lar_core_solver.m_d_upper_bounds.size() == j); // restore later - m_mpq_lar_core_solver.m_d_x.resize(j + 1 ); - m_mpq_lar_core_solver.m_d_lower_bounds.resize(j + 1); - m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1); - lp_assert(m_mpq_lar_core_solver.m_d_heading.size() == j); // as A().column_count() on the entry to the method - if (register_in_basis) { - A_d().add_row(); - m_mpq_lar_core_solver.m_d_heading.push_back(m_mpq_lar_core_solver.m_d_basis.size()); - m_mpq_lar_core_solver.m_d_basis.push_back(j); - }else { - m_mpq_lar_core_solver.m_d_heading.push_back(- static_cast(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1); - m_mpq_lar_core_solver.m_d_nbasis.push_back(j); - }*/ - } - + void lar_solver::adjust_initial_state_for_tableau_rows() { for (unsigned i = 0; i < m_terms.size(); i++) { if (m_var_register.external_is_used(tv::mask_term(i))) @@ -1963,24 +1911,7 @@ namespace lp { } } - // this fills the last row of A_d and sets the basis column: -1 in the last column of the row - void lar_solver::fill_last_row_of_A_d(static_matrix& A, const lar_term* ls) { - lp_assert(A.row_count() > 0); - lp_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lp_assert(A.m_rows[last_row].empty()); - - for (auto t : *ls) { - lp_assert(!is_zero(t.coeff())); - var_index j = t.column(); - A.set(last_row, j, -t.coeff().get_double()); - } - - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, -1); - lp_assert(A.is_correct()); - } - + void lar_solver::update_column_type_and_bound_with_ub(unsigned j, lp::lconstraint_kind kind, const mpq& right_side, unsigned constraint_index) { SASSERT(column_has_upper_bound(j)); if (column_has_lower_bound(j)) { diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 356c86c2f9b..237b9de810a 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -112,8 +112,6 @@ class lar_solver : public column_namer { // end of fields ////////////////// methods //////////////////////////////// - static_matrix & A_d(); - static_matrix const & A_d() const; static bool valid_index(unsigned j) { return static_cast(j) >= 0;} const lar_term & get_term(unsigned j) const; @@ -162,9 +160,7 @@ class lar_solver : public column_namer { unsigned row_of_basic_column(unsigned) const; void decide_on_strategy_and_adjust_initial_state(); void adjust_initial_state(); - void adjust_initial_state_for_lu(); void adjust_initial_state_for_tableau_rows(); - void fill_last_row_of_A_d(static_matrix & A, const lar_term* ls); bool sizes_are_correct() const; bool implied_bound_is_correctly_explained(implied_bound const & be, const vector> & explanation) const; diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 059d801a03c..14c454d6f48 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -23,27 +23,10 @@ Revision History: #include "util/vector.h" #include #include "math/lp/lp_core_solver_base_def.h" -template bool lp::lp_core_solver_base::basis_heading_is_correct() const; -template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); -template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; -template lp::lp_core_solver_base::lp_core_solver_base( - lp::static_matrix&, // vector&, - vector&, - vector &, vector &, - vector&, - vector&, - lp::lp_settings&, const column_namer&, const vector&, - const vector&, - const vector&); -template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lp::lp_core_solver_base::restore_x(unsigned int, double const&); -template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); -template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const double&); template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); @@ -74,35 +57,25 @@ template lp::lp_core_solver_base::lp_core_solver_base( const vector&, const vector&); template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_check_that_the_time_is_over(std::ostream &); -template std::string lp::lp_core_solver_base::column_name(unsigned int) const; -template void lp::lp_core_solver_base::pretty_print(std::ostream & out); template std::string lp::lp_core_solver_base::column_name(unsigned int) const; template void lp::lp_core_solver_base::pretty_print(std::ostream & out); template std::string lp::lp_core_solver_base >::column_name(unsigned int) const; template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); -template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template int lp::lp_core_solver_base >::pivots_in_column_and_row_are_different(int, int) const; -template int lp::lp_core_solver_base::pivots_in_column_and_row_are_different(int, int) const; -template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; template void lp::lp_core_solver_base >::pivot_fixed_vars_from_basis(); -template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; // template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); -template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); template void lp::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base >::inf_set_is_correct() const; -template bool lp::lp_core_solver_base::inf_set_is_correct() const; template bool lp::lp_core_solver_base::inf_set_is_correct() const; template bool lp::lp_core_solver_base >::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; -template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int); template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int, lp::numeric_pair const&); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 6fa2ddead1c..14cb60ebf92 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -309,10 +309,7 @@ class lp_core_solver_base { column_type get_column_type(unsigned j) const {return m_column_types[j]; } - bool pivot_row_element_is_too_small_for_ratio_test(unsigned j) { - return m_settings.abs_val_is_smaller_than_pivot_tolerance(m_pivot_row[j]); - } - + X bound_span(unsigned j) const { return m_upper_bounds[j] - m_lower_bounds[j]; } @@ -410,7 +407,6 @@ class lp_core_solver_base { non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; - int pivots_in_column_and_row_are_different(int entering, int leaving) const; void pivot_fixed_vars_from_basis(); bool remove_from_basis(unsigned j); bool remove_from_basis(unsigned j, const impq&); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 213d67e6ea0..16f56bade6d 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -533,23 +533,6 @@ get_non_basic_column_value_position(unsigned j) const { return at_lower_bound; } -template int lp_core_solver_base::pivots_in_column_and_row_are_different(int entering, int leaving) const { - const T & column_p = this->m_ed[this->m_basis_heading[leaving]]; - const T & row_p = this->m_pivot_row[entering]; - if (is_zero(column_p) || is_zero(row_p)) return true; // pivots cannot be zero - // the pivots have to have the same sign - if (column_p < 0) { - if (row_p > 0) - return 2; - } else { // column_p > 0 - if (row_p < 0) - return 2; - } - T diff_normalized = abs((column_p - row_p) / (numeric_traits::one() + abs(row_p))); - if ( !this->m_settings.abs_val_is_smaller_than_harris_tolerance(diff_normalized / T(10))) - return 1; - return 0; -} template void lp_core_solver_base::transpose_rows_tableau(unsigned i, unsigned j) { transpose_basis(i, j); m_A.transpose_rows(i, j); diff --git a/src/math/lp/lp_primal_core_solver.cpp b/src/math/lp/lp_primal_core_solver.cpp index f4597da762c..22042668da3 100644 --- a/src/math/lp/lp_primal_core_solver.cpp +++ b/src/math/lp/lp_primal_core_solver.cpp @@ -27,15 +27,11 @@ Revision History: #include "math/lp/lp_primal_core_solver_tableau_def.h" namespace lp { -template void lp_primal_core_solver::find_feasible_solution(); template void lp::lp_primal_core_solver >::find_feasible_solution(); -template unsigned lp_primal_core_solver::solve(); -template unsigned lp_primal_core_solver::solve_with_tableau(); template unsigned lp_primal_core_solver::solve(); template unsigned lp_primal_core_solver >::solve(); template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, lp::mpq const&); -template bool lp::lp_primal_core_solver::update_basis_and_x_tableau(int, int, double const&); template bool lp::lp_primal_core_solver >::update_basis_and_x_tableau(int, int, lp::numeric_pair const&); template void lp::lp_primal_core_solver >::update_inf_cost_for_column_tableau(unsigned); diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index aa771d7ee80..aacabf94426 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -56,7 +56,7 @@ class lp_primal_core_solver:public lp_core_solver_base { unsigned m_bland_mode_threshold; unsigned m_left_basis_repeated; vector m_leaving_candidates; - // T m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); + std::list m_non_basis_list; void sort_non_basis(); void sort_non_basis_rational(); @@ -279,12 +279,10 @@ class lp_primal_core_solver:public lp_core_solver_base { bool get_harris_theta(X & theta); - void restore_harris_eps() { m_converted_harris_eps = convert_struct::convert(this->m_settings.harris_feasibility_tolerance); } void zero_harris_eps() { m_converted_harris_eps = zero_of_type(); } int find_leaving_on_harris_theta(X const & harris_theta, X & t); bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); - int find_leaving_and_t(unsigned entering, X & t); int find_leaving_and_t_precise(unsigned entering, X & t); int find_leaving_and_t_tableau(unsigned entering, X & t); diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index fb62bbf540e..cfd8fc947d6 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -144,7 +144,6 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef template bool lp_primal_core_solver::get_harris_theta(X & theta) { - lp_assert(this->m_ed.is_OK()); bool unlimited = true; for (unsigned i : this->m_ed.m_index) { if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; @@ -311,17 +310,6 @@ template int lp_primal_core_solver::find_leaving_ } -template int lp_primal_core_solver::find_leaving_and_t(unsigned entering, X & t) { - X theta = zero_of_type(); - bool unlimited = get_harris_theta(theta); - lp_assert(unlimited || theta >= zero_of_type()); - if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering; - if (unlimited) - return -1; - return find_leaving_on_harris_theta(theta, t); -} - - // m is the multiplier. updating t in a way that holds the following // x[j] + t * m >= m_lower_bounds[j] ( if m < 0 ) diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index 96df997b17c..256853be722 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -107,7 +107,7 @@ unsigned lp_primal_core_solver::solve_with_tableau() { } TRACE("lar_solver", tout << "one iteration tableau " << this->get_status() << "\n";); switch (this->get_status()) { - case lp_status::OPTIMAL: // double check that we are at optimum + case lp_status::OPTIMAL: // check again that we are at optimum case lp_status::INFEASIBLE: if (this->m_look_for_feasible_solution_only && this->current_x_is_feasible()) break; diff --git a/src/math/lp/lp_settings.cpp b/src/math/lp/lp_settings.cpp index 592a9898385..b72b837fd71 100644 --- a/src/math/lp/lp_settings.cpp +++ b/src/math/lp/lp_settings.cpp @@ -21,7 +21,6 @@ Revision History: #include "util/vector.h" #include "smt/params/smt_params_helper.hpp" #include "math/lp/lp_settings_def.h" -template bool lp::vectors_are_equal(vector const&, vector const&); template bool lp::vectors_are_equal(vector const&, vector const&); void lp::lp_settings::updt_params(params_ref const& _p) { diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 86a97e615e9..197b7c04f17 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -92,7 +92,6 @@ lp_status lp_status_from_string(std::string status); enum non_basic_column_value_position { at_lower_bound, at_upper_bound, at_fixed, free_of_bounds, not_at_bound }; -template bool is_epsilon_small(const X & v, const double& eps); // forward definition class lp_resource_limit { public: @@ -182,36 +181,18 @@ struct lp_settings { unsigned reps_in_scaler { 20 }; // when the absolute value of an element is less than pivot_epsilon // in pivoting, we treat it as a zero - double pivot_epsilon { 0.00000001 }; - // see Chatal, page 115 - double positive_price_epsilon { 1e-7 }; // a quotation "if some choice of the entering variable leads to an eta matrix // whose diagonal element in the eta column is less than e2 (entering_diag_epsilon) in magnitude, the this choice is rejected ... - double entering_diag_epsilon { 1e-8 }; int c_partial_pivoting { 10 }; // this is the constant c from page 410 unsigned depth_of_rook_search { 4 }; bool using_partial_pivoting { true }; // dissertation of Achim Koberstein // if Bx - b is different at any component more that refactor_epsilon then we refactor - double refactor_tolerance { 1e-4 }; - double pivot_tolerance { 1e-6 }; - double zero_tolerance { 1e-12 }; - double drop_tolerance { 1e-14 }; - double tolerance_for_artificials { 1e-4 }; - double can_be_taken_to_basis_tolerance { 0.00001 }; - + unsigned percent_of_entering_to_check { 5 }; // we try to find a profitable column in a percentage of the columns bool use_scaling { true }; - double scaling_maximum { 1.0 }; - double scaling_minimum { 0.5 }; - double harris_feasibility_tolerance { 1e-7 }; // page 179 of Istvan Maros - double ignore_epsilon_of_harris { 10e-5 }; unsigned max_number_of_iterations_with_no_improvements { 2000000 }; - double time_limit; // the maximum time limit of the total run time in seconds - // dual section - double dual_feasibility_tolerance { 1e-7 }; // page 71 of the PhD thesis of Achim Koberstein - double primal_feasibility_tolerance { 1e-7 }; // page 71 of the PhD thesis of Achim Koberstein - double relative_primal_feasibility_tolerance { 1e-9 }; // page 71 of the PhD thesis of Achim Koberstein + double time_limit; // the maximum time limit of the total run time in seconds // end of dual section bool m_bound_propagation { true }; bool presolve_with_double_solver_for_lar { true }; @@ -221,7 +202,6 @@ struct lp_settings { bool print_statistics { false }; unsigned column_norms_update_frequency { 12000 }; bool scale_with_ratio { true }; - double density_threshold { 0.7 }; unsigned max_row_length_for_bound_propagation { 300 }; bool backup_costs { true }; unsigned column_number_threshold_for_using_lu_in_lar_solver { 4000 }; @@ -272,61 +252,10 @@ struct lp_settings { statistics& stats() { return m_stats; } statistics const& stats() const { return m_stats; } - template static bool is_eps_small_general(const T & t, const double & eps) { - return numeric_traits::is_zero(t); - } - - template - bool abs_val_is_smaller_than_dual_feasibility_tolerance(T const & t) { - return is_eps_small_general(t, dual_feasibility_tolerance); - } - - template - bool abs_val_is_smaller_than_primal_feasibility_tolerance(T const & t) { - return is_eps_small_general(t, primal_feasibility_tolerance); - } - - template - bool abs_val_is_smaller_than_can_be_taken_to_basis_tolerance(T const & t) { - return is_eps_small_general(t, can_be_taken_to_basis_tolerance); - } - - template - bool abs_val_is_smaller_than_drop_tolerance(T const & t) const { - return is_eps_small_general(t, drop_tolerance); - } - - - template - bool abs_val_is_smaller_than_zero_tolerance(T const & t) { - return is_eps_small_general(t, zero_tolerance); - } - - template - bool abs_val_is_smaller_than_refactor_tolerance(T const & t) { - return is_eps_small_general(t, refactor_tolerance); - } - - - template - bool abs_val_is_smaller_than_pivot_tolerance(T const & t) { - return is_eps_small_general(t, pivot_tolerance); - } - - template - bool abs_val_is_smaller_than_harris_tolerance(T const & t) { - return is_eps_small_general(t, harris_feasibility_tolerance); - } - - template - bool abs_val_is_smaller_than_ignore_epslilon_for_harris(T const & t) { - return is_eps_small_general(t, ignore_epsilon_of_harris); - } + - template - bool abs_val_is_smaller_than_artificial_tolerance(T const & t) { - return is_eps_small_general(t, tolerance_for_artificials); - } + + // the method of lar solver to use simplex_strategy_enum simplex_strategy() const { return m_simplex_strategy; @@ -370,11 +299,6 @@ inline std::string T_to_string(const mpq & t) { return strs.str(); } -template -bool val_is_smaller_than_eps(T const & t, double const & eps) { - - return t <= numeric_traits::zero(); -} template bool vectors_are_equal(T * a, vector &b, unsigned n); diff --git a/src/math/lp/lp_utils.cpp b/src/math/lp/lp_utils.cpp index 9ce3b989435..b909a0389d0 100644 --- a/src/math/lp/lp_utils.cpp +++ b/src/math/lp/lp_utils.cpp @@ -20,8 +20,7 @@ Revision History: #include "math/lp/lp_utils.h" #ifdef lp_for_z3 namespace lp { -double numeric_traits::g_zero = 0.0; -double numeric_traits::g_one = 1.0; + } #endif diff --git a/src/math/lp/matrix.cpp b/src/math/lp/matrix.cpp index 5367c74d0d0..1ea2da263a3 100644 --- a/src/math/lp/matrix.cpp +++ b/src/math/lp/matrix.cpp @@ -22,10 +22,8 @@ Revision History: #include "math/lp/static_matrix.h" #include #ifdef Z3DEBUG -template bool lp::matrix::is_equal(lp::matrix const&); template bool lp::matrix >::is_equal(lp::matrix > const&); template bool lp::matrix::is_equal(lp::matrix const&); #endif -template void lp::print_matrix(lp::matrix const*, std::ostream & out); template void lp::print_matrix >(lp::matrix > const *, std::basic_ostream > &); template void lp::print_matrix(lp::matrix const*, std::ostream&); diff --git a/src/math/lp/permutation_matrix.cpp b/src/math/lp/permutation_matrix.cpp index 28319c2ee88..762b85d63f0 100644 --- a/src/math/lp/permutation_matrix.cpp +++ b/src/math/lp/permutation_matrix.cpp @@ -21,16 +21,8 @@ Revision History: #include "util/vector.h" #include "math/lp/permutation_matrix_def.h" #include "math/lp/numeric_pair.h" -template void lp::permutation_matrix::apply_from_right(vector&); -template void lp::permutation_matrix::init(unsigned int); template void lp::permutation_matrix::init(unsigned int); template void lp::permutation_matrix>::init(unsigned int); -template bool lp::permutation_matrix::is_identity() const; -template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); -template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); -template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); -template lp::permutation_matrix::permutation_matrix(unsigned int, vector const&); -template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); template void lp::permutation_matrix::apply_from_right(vector&); template bool lp::permutation_matrix::is_identity() const; @@ -50,21 +42,13 @@ template void lp::permutation_matrix >::multi template lp::permutation_matrix >::permutation_matrix(unsigned int); template void lp::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); template void lp::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); -template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); -template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); template void lp::permutation_matrix >::apply_reverse_from_left(lp::indexed_vector&); template void lp::permutation_matrix >::apply_reverse_from_left_to_T(vector&); template void lp::permutation_matrix >::apply_reverse_from_right_to_T(vector&); -template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); -template lp::permutation_matrix::permutation_matrix(unsigned int); -template void lp::permutation_matrix::apply_reverse_from_left_to_X(vector &); template void lp::permutation_matrix< lp::mpq, lp::mpq>::apply_reverse_from_left_to_X(vector &); template void lp::permutation_matrix< lp::mpq, lp::numeric_pair< lp::mpq> >::apply_reverse_from_left_to_X(vector> &); -template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); template void lp::permutation_matrix >::apply_reverse_from_right_to_T(lp::indexed_vector&); diff --git a/src/math/lp/permutation_matrix_def.h b/src/math/lp/permutation_matrix_def.h index 703830ffcf3..b6f9924ff3b 100644 --- a/src/math/lp/permutation_matrix_def.h +++ b/src/math/lp/permutation_matrix_def.h @@ -133,7 +133,7 @@ template void permutation_matrix::apply_from_righ unsigned pj = m_permutation[j]; w.set_value(buffer[i], pj); } - lp_assert(w.is_OK()); + #ifdef Z3DEBUG lp_assert(vectors_are_equal(wcopy, w.m_data)); #endif @@ -235,7 +235,6 @@ void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & // vector wcopy(w.m_data); // apply_reverse_from_right_to_T(wcopy); #endif - lp_assert(w.is_OK()); vector tmp; vector tmp_index(w.m_index); for (auto i : w.m_index) { @@ -248,8 +247,7 @@ void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & w.set_value(tmp[k], m_rev[j]); } - // lp_assert(w.is_OK()); - // lp_assert(vectors_are_equal(w.m_data, wcopy)); + } diff --git a/src/math/lp/sparse_vector.h b/src/math/lp/sparse_vector.h index 1c27a8d96e4..3de701e1036 100644 --- a/src/math/lp/sparse_vector.h +++ b/src/math/lp/sparse_vector.h @@ -42,7 +42,6 @@ class sparse_vector { } #endif void divide(T const & a) { - lp_assert(!lp_settings::is_eps_small_general(a, 1e-12)); for (auto & t : m_data) { t.second /= a; } } diff --git a/src/math/lp/static_matrix.cpp b/src/math/lp/static_matrix.cpp index 12d2f9f0df3..28a23b0c394 100644 --- a/src/math/lp/static_matrix.cpp +++ b/src/math/lp/static_matrix.cpp @@ -26,26 +26,8 @@ Revision History: #include "math/lp/lp_primal_core_solver.h" #include "math/lp/lar_solver.h" namespace lp { -template void static_matrix::add_columns_at_the_end(unsigned int); -template void static_matrix::clear(); -#ifdef Z3DEBUG -template bool static_matrix::is_correct() const; -#endif -template void static_matrix::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; - -template double static_matrix::get_balance() const; -template std::set> static_matrix::get_domain(); template std::set> lp::static_matrix::get_domain(); template std::set> lp::static_matrix >::get_domain(); -template double static_matrix::get_elem(unsigned int, unsigned int) const; -template double static_matrix::get_max_abs_in_column(unsigned int) const; -template double static_matrix::get_min_abs_in_column(unsigned int) const; -template double static_matrix::get_min_abs_in_row(unsigned int) const; -template void static_matrix::init_empty_matrix(unsigned int, unsigned int); -template void static_matrix::init_row_columns(unsigned int, unsigned int); -template static_matrix::ref & static_matrix::ref::operator=(double const&); -template void static_matrix::set(unsigned int, unsigned int, double const&); -template static_matrix::static_matrix(unsigned int, unsigned int); template void static_matrix::add_column_to_vector(mpq const&, unsigned int, mpq*) const; template void static_matrix::add_columns_at_the_end(unsigned int); template bool static_matrix::is_correct() const; @@ -55,7 +37,6 @@ template mpq static_matrix::get_balance() const; template mpq static_matrix::get_elem(unsigned int, unsigned int) const; template mpq static_matrix::get_max_abs_in_column(unsigned int) const; template mpq static_matrix::get_max_abs_in_row(unsigned int) const; -template double static_matrix::get_max_abs_in_row(unsigned int) const; template mpq static_matrix::get_min_abs_in_column(unsigned int) const; template mpq static_matrix::get_min_abs_in_row(unsigned int) const; template void static_matrix::init_row_columns(unsigned int, unsigned int); @@ -72,7 +53,6 @@ template void static_matrix >::init_empty_matrix(unsigned template void static_matrix >::set(unsigned int, unsigned int, mpq const&); -template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell &, unsigned int); template bool lp::static_matrix::pivot_row_to_row_given_cell(unsigned int, column_cell& , unsigned int); template bool lp::static_matrix >::pivot_row_to_row_given_cell(unsigned int, column_cell&, unsigned int); template void lp::static_matrix >::remove_element(vector, true, unsigned int>&, lp::row_cell&); diff --git a/src/math/lp/static_matrix.h b/src/math/lp/static_matrix.h index 7f81cae79f5..b9870ceb5f0 100644 --- a/src/math/lp/static_matrix.h +++ b/src/math/lp/static_matrix.h @@ -359,7 +359,6 @@ class static_matrix for (auto p : row) { fill_last_row_with_pivoting_loop_block(p.column().index(), basis_heading); } - lp_assert(m_work_vector.is_OK()); unsigned last_row = row_count() - 1; for (unsigned j : m_work_vector.m_index) { From 3b6e2ccc53609fdcc4da16e7dfccf0ea2ae317b0 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 11:34:43 -0800 Subject: [PATCH 27/36] rm lu related fields from lp_core_solver_base.h --- src/math/lp/core_solver_pretty_printer.h | 18 +--- src/math/lp/core_solver_pretty_printer_def.h | 19 +--- src/math/lp/indexed_vector_def.h | 8 -- src/math/lp/lp_core_solver_base.cpp | 3 - src/math/lp/lp_core_solver_base.h | 18 ---- src/math/lp/lp_core_solver_base_def.h | 93 +------------------- src/math/lp/permutation_matrix.h | 1 - src/math/lp/sparse_vector.h | 52 ----------- src/math/lp/static_matrix.h | 1 - 9 files changed, 8 insertions(+), 205 deletions(-) delete mode 100644 src/math/lp/sparse_vector.h diff --git a/src/math/lp/core_solver_pretty_printer.h b/src/math/lp/core_solver_pretty_printer.h index 353212dcd1a..5bf29d511db 100644 --- a/src/math/lp/core_solver_pretty_printer.h +++ b/src/math/lp/core_solver_pretty_printer.h @@ -59,7 +59,7 @@ class core_solver_pretty_printer { unsigned m_artificial_start; indexed_vector m_w_buff; indexed_vector m_ed_buff; - vector m_exact_column_norms; + public: core_solver_pretty_printer(const lp_core_solver_base & core_solver, std::ostream & out); @@ -85,14 +85,7 @@ class core_solver_pretty_printer { } unsigned get_column_width(unsigned column); - - unsigned regular_cell_width(unsigned row, unsigned column, const std::string & name) { - return regular_cell_string(row, column, name).size(); - } - - std::string regular_cell_string(unsigned row, unsigned column, std::string name); - - + void set_coeff(vector& row, vector & row_signs, unsigned col, const T & t, string name); void print_x(); @@ -105,12 +98,7 @@ class core_solver_pretty_printer { void print_lows(); void print_upps(); - - string get_exact_column_norm_string(unsigned col) { - return T_to_string(m_exact_column_norms[col]); - } - - + void print_approx_norms(); void print(); diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index 2f1d99d22c6..931333ee725 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -37,9 +37,8 @@ core_solver_pretty_printer::core_solver_pretty_printer(const lp_core_solve m_signs(core_solver.m_A.row_count(), vector(core_solver.m_A.column_count(), " ")), m_costs(ncols(), ""), m_cost_signs(ncols(), " "), - m_rs(ncols(), zero_of_type()), - m_w_buff(core_solver.m_w), - m_ed_buff(core_solver.m_ed) { + m_rs(ncols(), zero_of_type()) + { m_lower_bounds_title = "low"; m_upp_bounds_title = "upp"; m_exact_norm_title = "exact cn"; @@ -80,13 +79,6 @@ template void core_solver_pretty_printer::init_rs } } -template T core_solver_pretty_printer::current_column_norm() { - T ret = zero_of_type(); - for (auto i : m_core_solver.m_ed.m_index) - ret += m_core_solver.m_ed[i] * m_core_solver.m_ed[i]; - return ret; -} - template void core_solver_pretty_printer::init_m_A_and_signs() { for (unsigned column = 0; column < ncols(); column++) { vector t(nrows(), zero_of_type()); @@ -167,13 +159,6 @@ template unsigned core_solver_pretty_printer:: ge return w; } -template std::string core_solver_pretty_printer::regular_cell_string(unsigned row, unsigned /* column */, std::string name) { - T t = fabs(m_core_solver.m_ed[row]); - if ( t == 1) return name; - return T_to_string(t) + name; -} - - template void core_solver_pretty_printer::set_coeff(vector& row, vector & row_signs, unsigned col, const T & t, string name) { if (numeric_traits::is_zero(t)) { return; diff --git a/src/math/lp/indexed_vector_def.h b/src/math/lp/indexed_vector_def.h index 1b904e14af1..0343250884a 100644 --- a/src/math/lp/indexed_vector_def.h +++ b/src/math/lp/indexed_vector_def.h @@ -24,14 +24,6 @@ Revision History: #include "math/lp/lp_settings.h" namespace lp { -template -void print_sparse_vector(const vector & t, std::ostream & out) { - for (unsigned i = 0; i < t.size(); i++) { - if (is_zero(t[i]))continue; - out << "[" << i << "] = " << t[i] << ", "; - } - out << std::endl; -} void print_vector_as_doubles(const vector & t, std::ostream & out) { for (unsigned i = 0; i < t.size(); i++) diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 14c454d6f48..ccd6bf41927 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -29,9 +29,7 @@ template lp::non_basic_column_value_position lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; -template void lp::lp_core_solver_base::fill_reduced_costs_from_m_y_by_rows(); template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lp::lp_core_solver_base::restore_x(unsigned int, lp::mpq const&); template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); template void lp::lp_core_solver_base >::init(); @@ -68,7 +66,6 @@ template bool lp::lp_core_solver_base::column_is_feasible(unsi // template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); -template void lp::lp_core_solver_base >::restore_x(unsigned int, lp::numeric_pair const&); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); template void lp::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 14cb60ebf92..964e447a125 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -74,7 +74,6 @@ class lp_core_solver_base { void set_using_infeas_costs(bool val) { m_using_infeas_costs = val; } vector m_columns_nz; // m_columns_nz[i] keeps an approximate value of non zeroes the i-th column vector m_rows_nz; // m_rows_nz[i] keeps an approximate value of non zeroes in the i-th row - indexed_vector m_pivot_row_of_B_1; // the pivot row of the reverse of B indexed_vector m_pivot_row; // this is the real pivot row of the simplex tableu static_matrix & m_A; // the matrix A // vector const & m_b; // the right side @@ -85,15 +84,11 @@ class lp_core_solver_base { vector & m_costs; lp_settings & m_settings; - vector m_y; // the buffer for yB = cb const column_namer & m_column_names; - indexed_vector m_w; // the vector featuring in 24.3 of the Chvatal book vector m_d; // the vector of reduced costs - indexed_vector m_ed; // the solution of B*m_ed = a const vector & m_column_types; const vector & m_lower_bounds; const vector & m_upper_bounds; - vector m_copy_of_xB; unsigned m_basis_sort_counter; vector m_trace_of_basis_change_vector; // the even positions are entering, the odd positions are leaving bool m_tracing_basis_changes; @@ -162,10 +157,6 @@ class lp_core_solver_base { return dot_product(m_costs, m_x); } - void copy_m_w(T * buffer); - - void restore_m_w(T * buffer); - void add_delta_to_entering(unsigned entering, const X & delta); const X & get_var_value(unsigned j) const { @@ -298,11 +289,6 @@ class lp_core_solver_base { bool basis_heading_is_correct() const; - void restore_x(unsigned entering, X const & t); - - void fill_reduced_costs_from_m_y_by_rows(); - - void copy_rs_to_xB(vector & rs); virtual bool lower_bounds_are_set() const { return false; } X lower_bound_value(unsigned j) const { return m_lower_bounds[j]; } X upper_bound_value(unsigned j) const { return m_upper_bounds[j]; } @@ -316,10 +302,6 @@ class lp_core_solver_base { std::string column_name(unsigned column) const; - void add_delta_to_xB(vector & del); - - void find_error_in_BxB(vector& rs); - bool snap_non_basic_x_to_bound() { bool ret = false; for (unsigned j : non_basis()) diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 16f56bade6d..2d729656724 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -44,25 +44,19 @@ lp_core_solver_base(static_matrix & A, m_status(lp_status::FEASIBLE), m_inf_set(A.column_count()), m_using_infeas_costs(false), - m_pivot_row_of_B_1(A.row_count()), m_pivot_row(A.column_count()), m_A(A), - // m_b(b), m_basis(basis), m_nbasis(nbasis), m_basis_heading(heading), m_x(x), m_costs(costs), m_settings(settings), - m_y(m_m()), m_column_names(column_names), - m_w(m_m()), m_d(m_n()), - m_ed(m_m()), m_column_types(column_types), m_lower_bounds(lower_bound_values), m_upper_bounds(upper_bound_values), - m_copy_of_xB(m_m()), m_basis_sort_counter(0), m_tracing_basis_changes(false), m_pivoted_rows(nullptr), @@ -122,25 +116,6 @@ pretty_print(std::ostream & out) { } -template void lp_core_solver_base:: -copy_m_w(T * buffer) { - unsigned i = m_m(); - while (i --) { - buffer[i] = m_w[i]; - } -} - -template void lp_core_solver_base:: -restore_m_w(T * buffer) { - m_w.m_index.clear(); - unsigned i = m_m(); - while (i--) { - if (!is_zero(m_w[i] = buffer[i])) - m_w.m_index.push_back(i); - } -} - - template void lp_core_solver_base:: add_delta_to_entering(unsigned entering, const X& delta) { m_x[entering] += delta; @@ -443,73 +418,11 @@ template bool lp_core_solver_base:: return true; } -template void lp_core_solver_base:: -restore_x(unsigned entering, X const & t) { - if (is_zero(t)) return; - m_x[entering] -= t; - for (unsigned i : m_ed.m_index) { - m_x[m_basis[i]] = m_copy_of_xB[i]; - } -} - -template void lp_core_solver_base:: -fill_reduced_costs_from_m_y_by_rows() { - unsigned j = m_n(); - while (j--) { - if (m_basis_heading[j] < 0) - m_d[j] = m_costs[j]; - else - m_d[j] = numeric_traits::zero(); - } - - unsigned i = m_m(); - while (i--) { - const T & y = m_y[i]; - if (is_zero(y)) continue; - for (row_cell & c : m_A.m_rows[i]) { - j = c.var(); - if (m_basis_heading[j] < 0) { - m_d[j] -= y * c.coeff(); - } - } - } -} - -template void lp_core_solver_base:: -copy_rs_to_xB(vector & rs) { - unsigned j = m_m(); - while (j--) { - m_x[m_basis[j]] = rs[j]; - } -} - template std::string lp_core_solver_base:: column_name(unsigned column) const { return m_column_names.get_variable_name(column); } -template void lp_core_solver_base:: -add_delta_to_xB(vector & del) { - unsigned i = m_m(); - while (i--) { - this->m_x[this->m_basis[i]] -= del[i]; - } -} - -template void lp_core_solver_base:: -find_error_in_BxB(vector& rs){ - unsigned row = m_m(); - while (row--) { - auto &rsv = rs[row]; - for (auto & it : m_A.m_rows[row]) { - unsigned j = it.var(); - if (m_basis_heading[j] >= 0) { - rsv -= m_x[j] * it.coeff(); - } - } - } -} - template non_basic_column_value_position lp_core_solver_base:: get_non_basic_column_value_position(unsigned j) const { switch (m_column_types[j]) { @@ -543,9 +456,9 @@ template bool lp_core_solver_base::pivot_column_g lp_assert(m_basis_heading[j_basic] >= 0); unsigned row_index = m_basis_heading[j_basic]; // the tableau case - if (pivot_column_tableau(j, row_index)) - change_basis(j, j_basic); - else return false; + if (pivot_column_tableau(j, row_index)) + change_basis(j, j_basic); + else return false; return true; } diff --git a/src/math/lp/permutation_matrix.h b/src/math/lp/permutation_matrix.h index 8ec78c14a1c..35a58906ade 100644 --- a/src/math/lp/permutation_matrix.h +++ b/src/math/lp/permutation_matrix.h @@ -22,7 +22,6 @@ Revision History: #include #include "util/debug.h" #include -#include "math/lp/sparse_vector.h" #include "math/lp/indexed_vector.h" #include "math/lp/lp_settings.h" #include "math/lp/matrix.h" diff --git a/src/math/lp/sparse_vector.h b/src/math/lp/sparse_vector.h deleted file mode 100644 index 3de701e1036..00000000000 --- a/src/math/lp/sparse_vector.h +++ /dev/null @@ -1,52 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include -#include "util/debug.h" -#include "math/lp/lp_utils.h" -#include "math/lp/lp_settings.h" -namespace lp { - -template -class sparse_vector { -public: - vector> m_data; - void push_back(unsigned index, T val) { - m_data.push_back(std::make_pair(index, val)); - } -#ifdef Z3DEBUG - T operator[] (unsigned i) const { - for (auto &t : m_data) { - if (t.first == i) return t.second; - } - return numeric_traits::zero(); - } -#endif - void divide(T const & a) { - for (auto & t : m_data) { t.second /= a; } - } - - unsigned size() const { - return m_data.size(); - } -}; -} diff --git a/src/math/lp/static_matrix.h b/src/math/lp/static_matrix.h index b9870ceb5f0..d7e4370a344 100644 --- a/src/math/lp/static_matrix.h +++ b/src/math/lp/static_matrix.h @@ -12,7 +12,6 @@ Copyright (c) 2017 Microsoft Corporation #include #include #include -#include "math/lp/sparse_vector.h" #include "math/lp/indexed_vector.h" #include "math/lp/permutation_matrix.h" #include From 0aad50367da9ad15740a35af6f5223c0fced7fad Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 13:51:56 -0800 Subject: [PATCH 28/36] remove dead code Signed-off-by: Lev Nachmanson --- src/math/lp/lar_core_solver.h | 19 -- src/math/lp/lar_solver.cpp | 36 +-- src/math/lp/lar_solver.h | 16 - src/math/lp/lp_core_solver_base.h | 2 +- src/math/lp/lp_primal_core_solver.h | 135 +-------- src/math/lp/lp_primal_core_solver_def.h | 120 -------- .../lp/lp_primal_core_solver_tableau_def.h | 4 +- src/test/lp/lp.cpp | 279 ------------------ 8 files changed, 13 insertions(+), 598 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index e024b199c1d..52c5b6f1a84 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -43,12 +43,6 @@ class lar_core_solver { stacked_vector m_r_columns_nz; stacked_vector m_r_rows_nz; - // d - solver fields, for doubles - stacked_vector m_d_pushed_basis; - vector m_d_basis; - vector m_d_nbasis; - vector m_d_heading; - lp_primal_core_solver> m_r_solver; // solver in rational numbers @@ -123,14 +117,6 @@ class lar_core_solver { void fill_not_improvable_zero_sum(); - void pop_basis(unsigned k) { - - m_d_basis = m_r_basis; - m_d_nbasis = m_r_nbasis; - m_d_heading = m_r_heading; - - } - void push() { lp_assert(m_r_solver.basis_heading_is_correct()); lp_assert(m_column_types.size() == m_r_A.column_count()); @@ -180,7 +166,6 @@ class lar_core_solver { m_r_solver.m_costs.resize(m_r_A.column_count()); m_r_solver.m_d.resize(m_r_A.column_count()); - pop_basis(k); m_stacked_simplex_strategy.pop(k); settings().set_simplex_strategy(m_stacked_simplex_strategy); lp_assert(m_r_solver.basis_heading_is_correct()); @@ -356,10 +341,6 @@ class lar_core_solver { return delta; } - void init_column_row_nz_for_r_solver() { - m_r_solver.init_column_row_non_zeroes(); - } - bool column_is_fixed(unsigned j) const { return m_column_types()[j] == column_type::fixed || ( m_column_types()[j] == column_type::boxed && diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 67cf90bd081..500ee23e060 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -245,11 +245,7 @@ namespace lp { set.erase(j); } - void lar_solver::shrink_inf_set_after_pop(unsigned n, u_set& set) { - clean_popped_elements(n, set); - set.resize(n); - } - + void lar_solver::pop(unsigned k) { TRACE("lar_solver", tout << "k = " << k << std::endl;); @@ -714,11 +710,6 @@ namespace lp { detect_rows_with_changed_bounds_for_column(j); } - void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds() { - for (auto j : m_columns_with_changed_bounds) - update_x_and_inf_costs_for_column_with_changed_bounds(j); - } - void lar_solver::update_x_and_inf_costs_for_columns_with_changed_bounds_tableau() { for (auto j : m_columns_with_changed_bounds) update_x_and_inf_costs_for_column_with_changed_bounds(j); @@ -792,31 +783,6 @@ namespace lp { } - void lar_solver::fill_last_row_of_A_r(static_matrix>& A, const lar_term* ls) { - lp_assert(A.row_count() > 0); - lp_assert(A.column_count() > 0); - unsigned last_row = A.row_count() - 1; - lp_assert(A.m_rows[last_row].size() == 0); - for (auto t : *ls) { - lp_assert(!is_zero(t.coeff())); - var_index j = t.column(); - A.set(last_row, j, -t.coeff()); - } - unsigned basis_j = A.column_count() - 1; - A.set(last_row, basis_j, mpq(1)); - } - - template - void lar_solver::copy_from_mpq_matrix(static_matrix& matr) { - matr.m_rows.resize(A_r().row_count()); - matr.m_columns.resize(A_r().column_count()); - for (unsigned i = 0; i < matr.row_count(); i++) { - for (auto& it : A_r().m_rows[i]) { - matr.set(i, it.var(), convert_struct::convert(it.coeff())); - } - } - } - bool lar_solver::all_constrained_variables_are_registered(const vector>& left_side) { for (auto it : left_side) { if (!var_is_registered(it.second)) diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 237b9de810a..83d2a25fe29 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -122,7 +122,6 @@ class lar_solver : public column_namer { bool term_is_int(const lar_term * t) const; bool term_is_int(const vector> & coeffs) const; void add_non_basic_var_to_core_fields(unsigned ext_j, bool is_int); - void add_new_var_to_core_fields_for_doubles(bool register_in_basis); void add_new_var_to_core_fields_for_mpq(bool register_in_basis); mpq adjust_bound_for_int(lpvar j, lconstraint_kind&, const mpq&); @@ -131,7 +130,6 @@ class lar_solver : public column_namer { var_index add_term_undecided(const vector> & coeffs); bool term_coeffs_are_ok(const vector> & coeffs); void push_term(lar_term* t); - void add_row_for_term(const lar_term * term, unsigned term_ext_index); void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index); void add_basic_var_to_core_fields(); bool compare_values(impq const& lhs, lconstraint_kind k, const mpq & rhs); @@ -187,7 +185,6 @@ class lar_solver : public column_namer { analyze_new_bounds_on_row_tableau(i, bp); } static void clean_popped_elements(unsigned n, u_set& set); - static void shrink_inf_set_after_pop(unsigned n, u_set & set); bool maximize_term_on_tableau(const lar_term & term, impq &term_max); bool costs_are_zeros_for_r_solver() const; @@ -213,17 +210,10 @@ class lar_solver : public column_namer { void detect_rows_with_changed_bounds_for_column(unsigned j); void detect_rows_with_changed_bounds(); - void update_x_and_inf_costs_for_columns_with_changed_bounds(); void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); void solve_with_core_solver(); numeric_pair get_basic_var_value_from_row(unsigned i); bool x_is_correct() const; - void fill_last_row_of_A_r(static_matrix> & A, const lar_term * ls); - template - void create_matrix_A(static_matrix & matr); - template - void copy_from_mpq_matrix(static_matrix & matr); - bool try_to_set_fixed(column_info & ci); bool all_constrained_variables_are_registered(const vector>& left_side); bool all_constraints_hold() const; bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const; @@ -231,7 +221,6 @@ class lar_solver : public column_namer { static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); static void register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); bool the_left_sides_sum_to_zero(const vector> & evidence) const; - bool the_right_sides_do_not_sum_to_zero(const vector> & evidence); bool explanation_is_correct(explanation&) const; bool inf_explanation_is_correct() const; mpq sum_of_right_sides_of_explanation(explanation &) const; @@ -251,21 +240,16 @@ class lar_solver : public column_namer { void remove_last_column_from_tableau(); void pop_tableau(); void clean_inf_set_of_r_solver_after_pop(); - void shrink_explanation_to_minimum(vector> & explanation) const; inline bool column_value_is_integer(unsigned j) const { return get_column_value(j).is_int(); } bool model_is_int_feasible() const; bool bound_is_integer_for_integer_column(unsigned j, const mpq & right_side) const; inline lar_core_solver & get_core_solver() { return m_mpq_lar_core_solver; } - void catch_up_in_updating_int_solver(); var_index to_column(unsigned ext_j) const; void fix_terms_with_rounded_columns(); - void update_delta_for_terms(const impq & delta, unsigned j, const vector&); - void fill_vars_to_terms(vector> & vars_to_terms); bool remove_from_basis(unsigned); lar_term get_term_to_maximize(unsigned ext_j) const; bool sum_first_coords(const lar_term& t, mpq & val) const; - void collect_rounded_rows_to_fix(); void register_normalized_term(const lar_term&, lpvar); void deregister_normalized_term(const lar_term&); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 964e447a125..96f8729a009 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -80,7 +80,7 @@ class lp_core_solver_base { vector & m_basis; vector& m_nbasis; vector& m_basis_heading; - vector & m_x; // a feasible solution, the fist time set in the constructor + vector & m_x; // a feasible solution, the first time set in the constructor vector & m_costs; lp_settings & m_settings; diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index aacabf94426..fecf66e68cf 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -49,7 +49,6 @@ class lp_primal_core_solver:public lp_core_solver_base { indexed_vector m_beta; // see Swietanowski working vector beta for column norms T m_epsilon_of_reduced_cost; vector m_costs_backup; - T m_converted_harris_eps; unsigned m_inf_row_index_for_tableau; bool m_bland_mode_tableau; u_set m_left_basis_tableau; @@ -277,13 +276,8 @@ class lp_primal_core_solver:public lp_core_solver_base { return convert_struct::convert(std::numeric_limits::max()); } - bool get_harris_theta(X & theta); - - void zero_harris_eps() { m_converted_harris_eps = zero_of_type(); } - int find_leaving_on_harris_theta(X const & harris_theta, X & t); bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); - int find_leaving_and_t_precise(unsigned entering, X & t); int find_leaving_and_t_tableau(unsigned entering, X & t); void limit_theta(const X & lim, X & theta, bool & unlimited) { @@ -317,9 +311,6 @@ class lp_primal_core_solver:public lp_core_solver_base { limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); }; - X harris_eps_for_bound(const X & bound) const { return ( convert_struct::convert(1) + abs(bound)/10) * m_converted_harris_eps/3; - } - void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector & leavings, T m, X & t, T & abs_of_d_of_leaving); vector m_lower_bounds_dummy; // needed for the base class only @@ -489,20 +480,9 @@ class lp_primal_core_solver:public lp_core_solver_base { this->set_status(this->current_x_is_feasible()? lp_status::OPTIMAL: lp_status::INFEASIBLE); } - // void limit_theta_on_basis_column_for_feas_case_m_neg(unsigned j, const T & m, X & theta) { - // lp_assert(m < 0); - // lp_assert(this->m_column_type[j] == lower_bound || this->m_column_type[j] == boxed); - // const X & eps = harris_eps_for_bound(this->m_lower_bounds[j]); - // if (this->above_bound(this->m_x[j], this->m_lower_bounds[j])) { - // theta = std::min((this->m_lower_bounds[j] -this->m_x[j] - eps) / m, theta); - // if (theta < zero_of_type()) theta = zero_of_type(); - // } - // } - void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { lp_assert(m < 0); - const X& eps = harris_eps_for_bound(this->m_lower_bounds[j]); - limit_theta((this->m_lower_bounds[j] - this->m_x[j] - eps) / m, theta, unlimited); + limit_theta((this->m_lower_bounds[j] - this->m_x[j]) / m, theta, unlimited); if (theta < zero_of_type()) theta = zero_of_type(); } @@ -545,25 +525,21 @@ class lp_primal_core_solver:public lp_core_solver_base { void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { // x gets smaller lp_assert(m < 0); - const X& eps = harris_eps_for_bound(bound); if (this->above_bound(x, bound)) { - limit_theta((bound - x - eps) / m, theta, unlimited); + limit_theta((bound - x) / m, theta, unlimited); } } void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lp_assert(m > 0 && this->m_column_type[j] == column_type::boxed); const X & x = this->m_x[j]; const X & lbound = this->m_lower_bounds[j]; if (this->below_bound(x, lbound)) { - const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); - limit_theta((lbound - x + eps) / m, theta, unlimited); + limit_theta((lbound - x) / m, theta, unlimited); } else { const X & ubound = this->m_upper_bounds[j]; if (this->below_bound(x, ubound)){ - const X& eps = harris_eps_for_bound(ubound); - limit_theta((ubound - x + eps) / m, theta, unlimited); + limit_theta((ubound - x) / m, theta, unlimited); } else if (!this->above_bound(x, ubound)) { theta = zero_of_type(); unlimited = false; @@ -576,13 +552,11 @@ class lp_primal_core_solver:public lp_core_solver_base { const X & x = this->m_x[j]; const X & ubound = this->m_upper_bounds[j]; if (this->above_bound(x, ubound)) { - const X& eps = harris_eps_for_bound(ubound); - limit_theta((ubound - x - eps) / m, theta, unlimited); + limit_theta((ubound - x) / m, theta, unlimited); } else { const X & lbound = this->m_lower_bounds[j]; if (this->above_bound(x, lbound)){ - const X& eps = harris_eps_for_bound(lbound); - limit_theta((lbound - x - eps) / m, theta, unlimited); + limit_theta((lbound - x) / m, theta, unlimited); } else if (!this->below_bound(x, lbound)) { theta = zero_of_type(); unlimited = false; @@ -591,9 +565,8 @@ class lp_primal_core_solver:public lp_core_solver_base { } void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { lp_assert(m > 0); - const T& eps = harris_eps_for_bound(this->m_upper_bounds[j]); if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { - limit_theta((this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); + limit_theta((this->m_upper_bounds[j] - this->m_x[j]) / m, theta, unlimited); if (theta < zero_of_type()) { theta = zero_of_type(); unlimited = false; @@ -603,8 +576,7 @@ class lp_primal_core_solver:public lp_core_solver_base { void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { lp_assert(m > 0); - const X& eps = harris_eps_for_bound(this->m_upper_bounds[j]); - limit_theta( (this->m_upper_bounds[j] - this->m_x[j] + eps) / m, theta, unlimited); + limit_theta( (this->m_upper_bounds[j] - this->m_x[j]) / m, theta, unlimited); if (theta < zero_of_type()) { theta = zero_of_type(); } @@ -612,9 +584,9 @@ class lp_primal_core_solver:public lp_core_solver_base { // j is a basic column or the entering, in any case x[j] has to stay feasible. // m is the multiplier. updating t in a way that holds the following - // x[j] + t * m >= this->m_lower_bounds[j]- harris_feasibility_tolerance ( if m < 0 ) + // x[j] + t * m >= this->m_lower_bounds[j]( if m < 0 ) // or - // x[j] + t * m <= this->m_upper_bounds[j] + harris_feasibility_tolerance ( if m > 0) + // x[j] + t * m <= this->m_upper_bounds[j] ( if m > 0) void limit_theta_on_basis_column(unsigned j, T m, X & theta, bool & unlimited) { switch (this->m_column_types[j]) { case column_type::free_column: break; @@ -679,7 +651,6 @@ class lp_primal_core_solver:public lp_core_solver_base { bool column_is_benefitial_for_entering_basis(unsigned j) const; bool column_is_benefitial_for_entering_basis_precise(unsigned j) const; bool can_enter_basis(unsigned j); - bool done(); void init_infeasibility_costs(); void init_infeasibility_cost_for_column(unsigned j); @@ -694,90 +665,8 @@ class lp_primal_core_solver:public lp_core_solver_base { return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); } - - bool lower_bounds_are_set() const override { return true; } - void print_bound_info_and_x(unsigned j, std::ostream & out); - - void init_infeasibility_after_update_x_if_inf(unsigned leaving) { - if (this->using_infeas_costs()) { - init_infeasibility_costs_for_changed_basis_only(); - this->m_costs[leaving] = zero_of_type(); - this->remove_column_from_inf_set(leaving); - } - } - void init_inf_set() { - this->clear_inf_set(); - for (unsigned j = 0; j < this->m_n(); j++) { - if (this->m_basis_heading[j] < 0) - continue; - if (!this->column_is_feasible(j)) - this->insert_column_into_inf_set(j); - } - } - - int get_column_out_of_bounds_delta_sign(unsigned j) { - switch (this->m_column_types[j]) { - case column_type::fixed: - case column_type::boxed: - if (this->x_below_low_bound(j)) - return -1; - if (this->x_above_upper_bound(j)) - return 1; - break; - case column_type::lower_bound: - if (this->x_below_low_bound(j)) - return -1; - break; - case column_type::upper_bound: - if (this->x_above_upper_bound(j)) - return 1; - break; - case column_type::free_column: - return 0; - default: - lp_assert(false); - } - return 0; - } - - void init_column_row_non_zeroes() { - this->m_columns_nz.resize(this->m_A.column_count()); - this->m_rows_nz.resize(this->m_A.row_count()); - for (unsigned i = 0; i < this->m_A.column_count(); i++) { - if (this->m_columns_nz[i] == 0) - this->m_columns_nz[i] = this->m_A.m_columns[i].size(); - } - for (unsigned i = 0; i < this->m_A.row_count(); i++) { - if (this->m_rows_nz[i] == 0) - this->m_rows_nz[i] = this->m_A.m_rows[i].size(); - } - } - - - int x_at_bound_sign(unsigned j) { - switch (this->m_column_types[j]) { - case column_type::fixed: - return 0; - case column_type::boxed: - if (this->x_is_at_lower_bound(j)) - return 1; - return -1; - break; - case column_type::lower_bound: - return 1; - break; - case column_type::upper_bound: - return -1; - break; - default: - lp_assert(false); - } - return 0; - - } - unsigned solve_with_tableau(); bool basis_column_is_set_correctly(unsigned j) const { @@ -844,10 +733,6 @@ class lp_primal_core_solver:public lp_core_solver_base { m_beta(A.row_count()), m_epsilon_of_reduced_cost(T(1)/T(10000000)), m_bland_mode_threshold(1000) { - - - m_converted_harris_eps = zero_of_type(); - this->set_status(lp_status::UNKNOWN); } diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index cfd8fc947d6..04c32d41c51 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -142,53 +142,6 @@ int lp_primal_core_solver::choose_entering_column(unsigned number_of_benef return choose_entering_column_presize(number_of_benefitial_columns_to_go_over); } - -template bool lp_primal_core_solver::get_harris_theta(X & theta) { - bool unlimited = true; - for (unsigned i : this->m_ed.m_index) { - if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(this->m_ed[i])) continue; - limit_theta_on_basis_column(this->m_basis[i], - this->m_ed[i] * m_sign_of_entering_delta, theta, unlimited); - if (!unlimited && is_zero(theta)) break; - } - return unlimited; -} - - -template int lp_primal_core_solver:: -find_leaving_on_harris_theta(X const & harris_theta, X & t) { - int leaving = -1; - T pivot_abs_max = zero_of_type(); - // we know already that there is no bound flip on entering - // we also know that harris_theta is limited, so we will find a leaving - zero_harris_eps(); - unsigned steps = this->m_ed.m_index.size(); - unsigned k = this->m_settings.random_next() % steps; - unsigned initial_k = k; - do { - unsigned i = this->m_ed.m_index[k]; - const T & ed = this->m_ed[i]; - if (this->m_settings.abs_val_is_smaller_than_pivot_tolerance(ed)) { - if (++k == steps) - k = 0; - continue; - } - X ratio; - unsigned j = this->m_basis[i]; - bool unlimited = true; - limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, ratio, unlimited); - if ((!unlimited) && ratio <= harris_theta) { - if (leaving == -1 || abs(ed) > pivot_abs_max) { - t = ratio; - leaving = j; - pivot_abs_max = abs(ed); - } - } - if (++k == steps) k = 0; - } while (k != initial_k); - return leaving; -} - - template bool lp_primal_core_solver::try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, @@ -246,68 +199,6 @@ try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t ) { return true; } -template int lp_primal_core_solver::find_leaving_and_t_precise(unsigned entering, X & t) { - bool unlimited = true; - unsigned steps = this->m_ed.m_index.size(); - unsigned k = this->m_settings.random_next() % steps; - unsigned initial_k = k; - unsigned row_min_nz = this->m_n() + 1; - m_leaving_candidates.clear(); - do { - unsigned i = this->m_ed.m_index[k]; - const T & ed = this->m_ed[i]; - lp_assert(!numeric_traits::is_zero(ed)); - unsigned j = this->m_basis[i]; - limit_theta_on_basis_column(j, - ed * m_sign_of_entering_delta, t, unlimited); - if (!unlimited) { - m_leaving_candidates.push_back(j); - row_min_nz = this->m_rows_nz[i]; - } - if (++k == steps) k = 0; - } while (unlimited && k != initial_k); - if (unlimited) { - if (try_jump_to_another_bound_on_entering_unlimited(entering, t)) - return entering; - return -1; - } - - X ratio; - while (k != initial_k) { - unsigned i = this->m_ed.m_index[k]; - const T & ed = this->m_ed[i]; - lp_assert(!numeric_traits::is_zero(ed)); - unsigned j = this->m_basis[i]; - unlimited = true; - limit_theta_on_basis_column(j, -ed * m_sign_of_entering_delta, ratio, unlimited); - if (unlimited) { - if (++k == steps) k = 0; - continue; - } - unsigned i_nz = this->m_rows_nz[i]; - if (ratio < t) { - t = ratio; - m_leaving_candidates.clear(); - m_leaving_candidates.push_back(j); - row_min_nz = this->m_rows_nz[i]; - } else if (ratio == t && i_nz < row_min_nz) { - m_leaving_candidates.clear(); - m_leaving_candidates.push_back(j); - row_min_nz = this->m_rows_nz[i]; - } else if (ratio == t && i_nz == row_min_nz) { - m_leaving_candidates.push_back(j); - } - if (++k == steps) k = 0; - } - - ratio = t; - unlimited = false; - if (try_jump_to_another_bound_on_entering(entering, t, ratio, unlimited)) { - t = ratio; - return entering; - } - k = this->m_settings.random_next() % m_leaving_candidates.size(); - return m_leaving_candidates[k]; -} @@ -499,17 +390,6 @@ template void lp_primal_core_solver::one_iteratio -template bool lp_primal_core_solver::done() { - if (this->get_status() == lp_status::OPTIMAL) return true; - if (this->get_status() == lp_status::INFEASIBLE) { - return true; - } - if (this->m_iters_with_no_cost_growing >= this->m_settings.max_number_of_iterations_with_no_improvements) { - this->set_status(lp_status::CANCELLED); - return true; - } - return false; -} template void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_only() { diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index 256853be722..d4355fa800e 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -43,6 +43,7 @@ template void lp_primal_core_solver::advance_on_e } advance_on_entering_and_leaving_tableau(entering, leaving, t); } + template int lp_primal_core_solver::choose_entering_column_tableau() { //this moment m_y = cB * B(-1) unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); @@ -85,9 +86,6 @@ template void lp_primal_core_solver::advance_on_e } - - - template unsigned lp_primal_core_solver::solve_with_tableau() { init_run_tableau(); diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index c993dbd7ddf..24aa8767a37 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -56,7 +56,6 @@ #include "math/lp/int_cube.h" #include "math/lp/emonics.h" #include "math/lp/static_matrix.h" -#include "math/lp/dense_matrix.h" bool my_white_space(const char & a) { return a == ' ' || a == '\t'; @@ -431,205 +430,8 @@ void change_basis(unsigned entering, unsigned leaving, vector& basis, nbasis[place_in_non_basis] = leaving; } - - -#ifdef Z3DEBUG -void test_small_lu(lp_settings & settings) { - -} - -#endif - - -void fill_long_row(static_matrix &m, int i) { - int n = m.column_count(); - for (int j = 0; j < n; j ++) { - m (i, (j + i) % n) = j * j; - } -} - - - -void fill_long_row_exp(static_matrix &m, int i) { - int n = m.column_count(); - - for (int j = 0; j < n; j ++) { - m(i, j) = my_random() % 20; - } -} - - - - - - int perm_id = 0; - - - - - - - -void init_b(vector & b, static_matrix & m, vector & x) { - for (unsigned i = 0; i < m.row_count(); i++) { - b.push_back(m.dot_product_with_row(i, x)); - } -} - - -void test_lp_0() { - std::cout << " test_lp_0 " << std::endl; - static_matrix m_(3, 7); - m_(0, 0) = 3; m_(0, 1) = 2; m_(0, 2) = 1; m_(0, 3) = 2; m_(0, 4) = 1; - m_(1, 0) = 1; m_(1, 1) = 1; m_(1, 2) = 1; m_(1, 3) = 1; m_(1, 5) = 1; - m_(2, 0) = 4; m_(2, 1) = 3; m_(2, 2) = 3; m_(2, 3) = 4; m_(2, 6) = 1; - vector x_star(7); - x_star[0] = 225; x_star[1] = 117; x_star[2] = 420; - x_star[3] = x_star[4] = x_star[5] = x_star[6] = 0; - vector b; - init_b(b, m_, x_star); - vector basis(3); - basis[0] = 0; basis[1] = 1; basis[2] = 2; - vector costs(7); - costs[0] = 19; - costs[1] = 13; - costs[2] = 12; - costs[3] = 17; - costs[4] = 0; - costs[5] = 0; - costs[6] = 0; - - vector column_types(7, column_type::lower_bound); - vector upper_bound_values; - lp_settings settings; - simple_column_namer cn; - vector nbasis; - vector heading; - - lp_primal_core_solver lpsolver(m_, b, x_star, basis, nbasis, heading, costs, column_types, upper_bound_values, settings, cn); - - lpsolver.solve(); -} - -void test_lp_1() { - std::cout << " test_lp_1 " << std::endl; - static_matrix m(4, 7); - m(0, 0) = 1; m(0, 1) = 3; m(0, 2) = 1; m(0, 3) = 1; - m(1, 0) = -1; m(1, 2) = 3; m(1, 4) = 1; - m(2, 0) = 2; m(2, 1) = -1; m(2, 2) = 2; m(2, 5) = 1; - m(3, 0) = 2; m(3, 1) = 3; m(3, 2) = -1; m(3, 6) = 1; -#ifdef Z3DEBUG - //print_matrix(m, std::cout); -#endif - vector x_star(7); - x_star[0] = 0; x_star[1] = 0; x_star[2] = 0; - x_star[3] = 3; x_star[4] = 2; x_star[5] = 4; x_star[6] = 2; - - vector basis(4); - basis[0] = 3; basis[1] = 4; basis[2] = 5; basis[3] = 6; - - vector b; - b.push_back(3); - b.push_back(2); - b.push_back(4); - b.push_back(2); - - vector costs(7); - costs[0] = 5; - costs[1] = 5; - costs[2] = 3; - costs[3] = 0; - costs[4] = 0; - costs[5] = 0; - costs[6] = 0; - - - - vector column_types(7, column_type::lower_bound); - vector upper_bound_values; - - std::cout << "calling lp\n"; - lp_settings settings; - simple_column_namer cn; - - vector nbasis; - vector heading; - - lp_primal_core_solver lpsolver(m, b, - x_star, - basis, - nbasis, heading, - costs, - column_types, upper_bound_values, settings, cn); - - lpsolver.solve(); -} - - -void test_lp_primal_core_solver() { - test_lp_0(); - test_lp_1(); -} - - - - -#ifdef Z3DEBUG - -void fill_uniformly(dense_matrix & m, unsigned dim) { - int v = 0; - for (unsigned i = 0; i < dim; i++) { - for (unsigned j = 0; j < dim; j++) { - m.set_elem(i, j, v++); - } - } -} - - - - -void test_dense_matrix() { - dense_matrix d(3, 2); - d.set_elem(0, 0, 1); - d.set_elem(1, 1, 2); - d.set_elem(2, 0, 3); - // print_matrix(d); - - dense_matrix unit(2, 2); - d.set_elem(0, 0, 1); - d.set_elem(1, 1, 1); - - dense_matrix c = d * unit; - - // print_matrix(d); - - dense_matrix perm(3, 3); - perm.set_elem(0, 1, 1); - perm.set_elem(1, 0, 1); - perm.set_elem(2, 2, 1); - auto c1 = perm * d; - // print_matrix(c1); - - - dense_matrix p2(2, 2); - p2.set_elem(0, 1, 1); - p2.set_elem(1, 0, 1); - auto c2 = d * p2; -} - -#endif - - - - - -void lp_solver_test() { - // lp_revised_solver lp_revised; - // lp_revised.get_minimal_solution(); -} - bool get_int_from_args_parser(const char * option, argument_parser & args_parser, unsigned & n) { std::string s = args_parser.get_option_value(option); if (!s.empty()) { @@ -650,9 +452,6 @@ bool get_double_from_args_parser(const char * option, argument_parser & args_par -bool values_are_one_percent_close(double a, double b); - - void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, unsigned & time_limit); // forward definition @@ -939,10 +738,6 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("-gomory", "gomory"); parser.add_option_with_help_string("-intd", "test integer_domain"); parser.add_option_with_help_string("-xyz_sample", "run a small interactive scenario"); - parser.add_option_with_after_string_with_help("--density", "the percentage of non-zeroes in the matrix below which it is not dense"); - parser.add_option_with_after_string_with_help("--harris_toler", "harris tolerance"); - parser.add_option_with_after_string_with_help("--checklu", "the file name for lu checking"); - parser.add_option_with_after_string_with_help("--partial_pivot", "the partial pivot constant, a number somewhere between 10 and 100"); parser.add_option_with_after_string_with_help("--percent_for_enter", "which percent of columns check for entering column"); parser.add_option_with_help_string("--totalinf", "minimizes the total infeasibility instead of diminishing infeasibility of the rows"); parser.add_option_with_after_string_with_help("--rep_frq", "the report frequency, in how many iterations print the cost and other info "); @@ -1202,71 +997,6 @@ void get_matrix_dimensions(std::ifstream & f, unsigned & m, unsigned & n) { n = atoi(r[1].c_str()); } -void read_row_cols(unsigned i, static_matrix& A, std::ifstream & f) { - do { - std::string line; - getline(f, line); - if (line== "row_end") - break; - auto r = split_and_trim(line); - lp_assert(r.size() == 4); - unsigned j = atoi(r[1].c_str()); - double v = atof(r[3].c_str()); - A.set(i, j, v); - } while (true); -} - -bool read_row(static_matrix & A, std::ifstream & f) { - std::string line; - getline(f, line); - if (static_cast(line.find("row")) == -1) - return false; - auto r = split_and_trim(line); - if (r[0] != "row") - std::cout << "wrong row line" << line << std::endl; - unsigned i = atoi(r[1].c_str()); - read_row_cols(i, A, f); - return true; -} - -void read_rows(static_matrix& A, std::ifstream & f) { - while (read_row(A, f)) {} -} - -void read_basis(vector & basis, std::ifstream & f) { - std::cout << "reading basis" << std::endl; - std::string line; - getline(f, line); - lp_assert(line == "basis_start"); - do { - getline(f, line); - if (line == "basis_end") - break; - unsigned j = atoi(line.c_str()); - basis.push_back(j); - } while (true); -} - -void read_indexed_vector(indexed_vector & v, std::ifstream & f) { - std::string line; - getline(f, line); - lp_assert(line == "vector_start"); - do { - getline(f, line); - if (line == "vector_end") break; - auto r = split_and_trim(line); - unsigned i = atoi(r[0].c_str()); - double val = atof(r[1].c_str()); - v.set_value(val, i); - std::cout << "setting value " << i << " = " << val << std::endl; - } while (true); -} - -void check_lu_from_file(std::string lufile_name) { - lp_assert(false); -} - - void print_st(lp_status status) { std::cout << lp_status_to_string(status) << std::endl; @@ -2298,15 +2028,6 @@ void test_lp_local(int argn, char**argv) { test_bound_propagation(); return finalize(0); } - - - std::string lufile = args_parser.get_option_value("--checklu"); - if (!lufile.empty()) { - check_lu_from_file(lufile); - return finalize(0); - } - - if (args_parser.option_is_used("-tbq")) { From 826c42ca1688622558611ac0fe273a0391871e2a Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 13:53:23 -0800 Subject: [PATCH 29/36] more dead code removal --- src/math/lp/lar_solver.cpp | 4 ---- src/math/lp/lar_solver.h | 2 -- 2 files changed, 6 deletions(-) diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 500ee23e060..952f2ad43e0 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -2330,10 +2330,6 @@ namespace lp { return true; } - void lar_solver::pivot_column_tableau(unsigned j, unsigned row_index) { - m_mpq_lar_core_solver.m_r_solver.pivot_column_tableau(j, row_index); - m_mpq_lar_core_solver.m_r_solver.change_basis(j, r_basis()[row_index]); - } } // namespace lp diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 83d2a25fe29..a321632fb61 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -519,8 +519,6 @@ class lar_solver : public column_namer { return m_mpq_lar_core_solver.lower_bound(j); } - void pivot_column_tableau(unsigned j, unsigned row_index); - inline const impq & column_upper_bound(unsigned j) const { return m_mpq_lar_core_solver.upper_bound(j); } From 81fd0937d1ca71836ff7030a6c03de1da36c6617 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 15:37:22 -0800 Subject: [PATCH 30/36] remove more dead code --- src/math/lp/lar_core_solver.h | 128 +----------------- src/math/lp/lar_core_solver_def.h | 1 - src/math/lp/lp_core_solver_base.h | 2 - src/math/lp/lp_primal_core_solver.h | 55 +------- src/math/lp/lp_primal_core_solver_def.h | 64 +-------- .../lp/lp_primal_core_solver_tableau_def.h | 1 - src/math/lp/lp_settings.h | 6 - src/math/lp/numeric_pair.h | 15 +- 8 files changed, 5 insertions(+), 267 deletions(-) diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 52c5b6f1a84..966e2f0d765 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -20,9 +20,6 @@ Copyright (c) 2017 Microsoft Corporation namespace lp { class lar_core_solver { - // m_sign_of_entering is set to 1 if the entering variable needs - // to grow and is set to -1 otherwise - int m_sign_of_entering_delta; vector> m_infeasible_linear_combination; int m_infeasible_sum_sign; // todo: get rid of this field vector> m_right_sides_dummy; @@ -40,8 +37,6 @@ class lar_core_solver { vector m_r_basis; vector m_r_nbasis; vector m_r_heading; - stacked_vector m_r_columns_nz; - stacked_vector m_r_rows_nz; lp_primal_core_solver> m_r_solver; // solver in rational numbers @@ -82,16 +77,9 @@ class lar_core_solver { m_r_solver.print_column_bound_info(m_r_solver.m_basis[row_index], out); } - bool row_is_infeasible(unsigned row); - - bool row_is_evidence(unsigned row); - - bool find_evidence_row(); - + void prefix_r(); - void prefix_d(); - unsigned m_m() const { return m_r_A.row_count(); } unsigned m_n() const { return m_r_A.column_count(); } @@ -103,8 +91,6 @@ class lar_core_solver { template int get_sign(const L & v) { return v > zero_of_type() ? 1 : (v < zero_of_type() ? -1 : 0); } - void fill_evidence(unsigned row); - unsigned get_number_of_non_ints() const; void solve(); @@ -131,31 +117,6 @@ class lar_core_solver { } - template - void push_vector(stacked_vector & pushed_vector, const vector & vector) { - lp_assert(pushed_vector.size() <= vector.size()); - for (unsigned i = 0; i < vector.size();i++) { - if (i == pushed_vector.size()) { - pushed_vector.push_back(vector[i]); - } else { - pushed_vector[i] = vector[i]; - } - } - pushed_vector.push(); - } - - void pop_markowitz_counts(unsigned k) { - m_r_columns_nz.pop(k); - m_r_rows_nz.pop(k); - m_r_solver.m_columns_nz.resize(m_r_columns_nz.size()); - m_r_solver.m_rows_nz.resize(m_r_rows_nz.size()); - for (unsigned i = 0; i < m_r_columns_nz.size(); i++) - m_r_solver.m_columns_nz[i] = m_r_columns_nz[i]; - for (unsigned i = 0; i < m_r_rows_nz.size(); i++) - m_r_solver.m_rows_nz[i] = m_r_rows_nz[i]; - } - - void pop(unsigned k) { // rationals m_r_lower_bounds.pop(k); @@ -172,72 +133,7 @@ class lar_core_solver { } - template - bool is_zero_vector(const vector & b) { - for (const L & m: b) - if (!is_zero(m)) return false; - return true; - } - - - bool update_xj_and_get_delta(unsigned j, non_basic_column_value_position pos_type, numeric_pair & delta) { - auto & x = m_r_x[j]; - switch (pos_type) { - case at_lower_bound: - if (x == m_r_solver.m_lower_bounds[j]) - return false; - delta = m_r_solver.m_lower_bounds[j] - x; - m_r_solver.m_x[j] = m_r_solver.m_lower_bounds[j]; - break; - case at_fixed: - case at_upper_bound: - if (x == m_r_solver.m_upper_bounds[j]) - return false; - delta = m_r_solver.m_upper_bounds[j] - x; - x = m_r_solver.m_upper_bounds[j]; - break; - case free_of_bounds: { - return false; - } - case not_at_bound: - switch (m_column_types[j]) { - case column_type::free_column: - return false; - case column_type::upper_bound: - delta = m_r_solver.m_upper_bounds[j] - x; - x = m_r_solver.m_upper_bounds[j]; - break; - case column_type::lower_bound: - delta = m_r_solver.m_lower_bounds[j] - x; - x = m_r_solver.m_lower_bounds[j]; - break; - case column_type::boxed: - if (x > m_r_solver.m_upper_bounds[j]) { - delta = m_r_solver.m_upper_bounds[j] - x; - x += m_r_solver.m_upper_bounds[j]; - } else { - delta = m_r_solver.m_lower_bounds[j] - x; - x = m_r_solver.m_lower_bounds[j]; - } - break; - case column_type::fixed: - delta = m_r_solver.m_lower_bounds[j] - x; - x = m_r_solver.m_lower_bounds[j]; - break; - - default: - lp_assert(false); - } - break; - default: - lp_unreachable(); - } - m_r_solver.remove_column_from_inf_set(j); - return true; - } - - bool r_basis_is_OK() const { #ifdef Z3DEBUG @@ -255,28 +151,6 @@ class lar_core_solver { } - - void fill_basis_d( - vector& basis_d, - vector& heading_d, - vector& nbasis_d){ - basis_d = m_r_basis; - heading_d = m_r_heading; - nbasis_d = m_r_nbasis; - } - - template - void extract_signature_from_lp_core_solver(const lp_primal_core_solver & solver, lar_solution_signature & signature) { - signature.clear(); - lp_assert(signature.size() == 0); - for (unsigned j = 0; j < solver.m_basis_heading.size(); j++) { - if (solver.m_basis_heading[j] < 0) { - signature[j] = solver.get_non_basic_column_value_position(j); - } - } - } - - bool lower_bound_is_set(unsigned j) const { switch (m_column_types[j]) { case column_type::free_column: diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index 419345f0ca0..2e205291e6f 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -46,7 +46,6 @@ void lar_core_solver::prefix_r() { } - void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() { unsigned bj = m_r_basis[m_r_solver.m_inf_row_index_for_tableau]; m_infeasible_sum_sign = m_r_solver.inf_sign_of_column(bj); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 96f8729a009..9fb4d4333cd 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -72,8 +72,6 @@ class lp_core_solver_base { unsigned inf_set_size() const { return m_inf_set.size(); } bool using_infeas_costs() const { return m_using_infeas_costs; } void set_using_infeas_costs(bool val) { m_using_infeas_costs = val; } - vector m_columns_nz; // m_columns_nz[i] keeps an approximate value of non zeroes the i-th column - vector m_rows_nz; // m_rows_nz[i] keeps an approximate value of non zeroes in the i-th row indexed_vector m_pivot_row; // this is the real pivot row of the simplex tableu static_matrix & m_A; // the matrix A // vector const & m_b; // the right side diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index fecf66e68cf..17b1ea494d0 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -41,54 +41,21 @@ namespace lp { template class lp_primal_core_solver:public lp_core_solver_base { public: - // m_sign_of_entering is set to 1 if the entering variable needs - // to grow and is set to -1 otherwise - unsigned m_column_norm_update_counter; - T m_enter_price_eps; int m_sign_of_entering_delta; - indexed_vector m_beta; // see Swietanowski working vector beta for column norms - T m_epsilon_of_reduced_cost; vector m_costs_backup; unsigned m_inf_row_index_for_tableau; bool m_bland_mode_tableau; - u_set m_left_basis_tableau; + u_set m_left_basis_tableau; unsigned m_bland_mode_threshold; unsigned m_left_basis_repeated; vector m_leaving_candidates; std::list m_non_basis_list; void sort_non_basis(); - void sort_non_basis_rational(); int choose_entering_column(unsigned number_of_benefitial_columns_to_go_over); int choose_entering_column_tableau(); int choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over); - bool column_is_benefitial_for_entering_basis_on_sign_row_strategy(unsigned j, int sign) const { - // sign = 1 means the x of the basis column of the row has to grow to become feasible, when the coeff before j is neg, or x - has to diminish when the coeff is pos - // we have xbj = -aj * xj - lp_assert(this->m_basis_heading[j] < 0); - lp_assert(this->column_is_feasible(j)); - switch (this->m_column_types[j]) { - case column_type::free_column: return true; - case column_type::fixed: return false; - case column_type::lower_bound: - if (sign < 0) - return true; - return !this->x_is_at_lower_bound(j); - case column_type::upper_bound: - if (sign > 0) - return true; - return !this->x_is_at_upper_bound(j); - case column_type::boxed: - if (sign < 0) - return !this->x_is_at_lower_bound(j); - return !this->x_is_at_upper_bound(j); - } - - lp_assert(false); // cannot be here - return false; - } - bool needs_to_grow(unsigned bj) const { lp_assert(!this->column_is_feasible(bj)); @@ -272,10 +239,7 @@ class lp_primal_core_solver:public lp_core_solver_base { a_ent = rc.coeff(); return rc.var(); } - static X positive_infinity() { - return convert_struct::convert(std::numeric_limits::max()); - } - + bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); int find_leaving_and_t_tableau(unsigned entering, X & t); @@ -313,8 +277,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector & leavings, T m, X & t, T & abs_of_d_of_leaving); - vector m_lower_bounds_dummy; // needed for the base class only - X get_max_bound(vector & b); #ifdef Z3DEBUG @@ -334,10 +296,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void backup_and_normalize_costs(); - void init_run(); - - void calc_working_vector_beta_for_column_norms(); - void advance_on_entering_and_leaving(int entering, int leaving, X & t); void advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t); void advance_on_entering_equal_leaving(int entering, X & t); @@ -368,7 +326,6 @@ class lp_primal_core_solver:public lp_core_solver_base { // bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;} - void one_iteration(); void one_iteration_tableau(); // this version assumes that the leaving already has the right value, and does not update it @@ -658,12 +615,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void init_infeasibility_costs_for_changed_basis_only(); void print_column(unsigned j, std::ostream & out); - // j is the basic column, x is the value at x[j] - // d is the coefficient before m_entering in the row with j as the basis column - template - bool same_sign_with_entering_delta(const L & a) { - return (a > zero_of_type() && m_sign_of_entering_delta > 0) || (a < zero_of_type() && m_sign_of_entering_delta < 0); - } void print_bound_info_and_x(unsigned j, std::ostream & out); @@ -730,8 +681,6 @@ class lp_primal_core_solver:public lp_core_solver_base { column_type_array, lower_bound_values, upper_bound_values), - m_beta(A.row_count()), - m_epsilon_of_reduced_cost(T(1)/T(10000000)), m_bland_mode_threshold(1000) { this->set_status(lp_status::UNKNOWN); } diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 04c32d41c51..1c48f11636c 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -32,7 +32,7 @@ namespace lp { // The right side b is given implicitly by x and the basis template -void lp_primal_core_solver::sort_non_basis_rational() { +void lp_primal_core_solver::sort_non_basis() { std::sort(this->m_nbasis.begin(), this->m_nbasis.end(), [this](unsigned a, unsigned b) { unsigned ca = this->m_A.number_of_non_zeroes_in_column(a); unsigned cb = this->m_A.number_of_non_zeroes_in_column(b); @@ -50,10 +50,6 @@ void lp_primal_core_solver::sort_non_basis_rational() { } -template -void lp_primal_core_solver::sort_non_basis() { - sort_non_basis_rational(); -} template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsigned j) const { @@ -249,15 +245,6 @@ lp_primal_core_solver::get_bound_on_variable_and_update_leaving_precisely( } } -template X lp_primal_core_solver::get_max_bound(vector & b) { - X ret = zero_of_type(); - for (auto & v : b) { - X a = abs(v); - if (a > ret) ret = a; - } - return ret; -} - #ifdef Z3DEBUG template void lp_primal_core_solver::check_Ax_equal_b() { dense_matrix d(this->m_A); @@ -282,38 +269,6 @@ template void lp_primal_core_solver::check_cor } #endif -// from page 183 of Istvan Maros's book -// the basis structures have not changed yet -template -void lp_primal_core_solver::update_reduced_costs_from_pivot_row(unsigned entering, unsigned leaving) { - // the basis heading has changed already -#ifdef Z3DEBUG - auto & basis_heading = this->m_basis_heading; - lp_assert(basis_heading[entering] >= 0 && static_cast(basis_heading[entering]) < this->m_m()); - lp_assert(basis_heading[leaving] < 0); -#endif - T pivot = this->m_pivot_row[entering]; - T dq = this->m_d[entering]/pivot; - for (auto j : this->m_pivot_row.m_index) { - // for (auto j : this->m_nbasis) - if (this->m_basis_heading[j] >= 0) continue; - if (j != leaving) - this->m_d[j] -= dq * this->m_pivot_row[j]; - } - this->m_d[leaving] = -dq; - if (this->current_x_is_infeasible()) { - this->m_d[leaving] -= this->m_costs[leaving]; - this->m_costs[leaving] = zero_of_type(); - } - this->m_d[entering] = numeric_traits::zero(); -} - -// return 0 if the reduced cost at entering is close enough to the refreshed -// 1 if it is way off, and 2 if it is unprofitable -template int lp_primal_core_solver::refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) { - return 0; - -} template void lp_primal_core_solver::backup_and_normalize_costs() { if (this->m_look_for_feasible_solution_only) @@ -321,9 +276,6 @@ template void lp_primal_core_solver::backup_an m_costs_backup = this->m_costs; } -template void lp_primal_core_solver::init_run() { - -} template @@ -377,20 +329,6 @@ template void lp_primal_core_solver::find_feas solve(); } -template void lp_primal_core_solver::one_iteration() { - unsigned number_of_benefitial_columns_to_go_over = get_number_of_non_basic_column_to_try_for_enter(); - int entering = choose_entering_column(number_of_benefitial_columns_to_go_over); - if (entering == -1) { - decide_on_status_when_cannot_find_entering(); - } - else { - advance_on_entering(entering); - } -} - - - - template void lp_primal_core_solver::init_infeasibility_costs_for_changed_basis_only() { for (unsigned i : this->m_ed.m_index) diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index d4355fa800e..de2f1c208af 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -283,7 +283,6 @@ template void lp_primal_core_solver::init_run_tab return; if (this->m_settings.backup_costs) backup_and_normalize_costs(); - m_epsilon_of_reduced_cost = zero_of_type(); if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) init_tableau_rows(); diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 197b7c04f17..314930fc175 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -179,15 +179,9 @@ struct lp_settings { bool int_run_gcd_test() const { return m_int_run_gcd_test; } bool& int_run_gcd_test() { return m_int_run_gcd_test; } unsigned reps_in_scaler { 20 }; - // when the absolute value of an element is less than pivot_epsilon - // in pivoting, we treat it as a zero - // a quotation "if some choice of the entering variable leads to an eta matrix - // whose diagonal element in the eta column is less than e2 (entering_diag_epsilon) in magnitude, the this choice is rejected ... int c_partial_pivoting { 10 }; // this is the constant c from page 410 unsigned depth_of_rook_search { 4 }; bool using_partial_pivoting { true }; - // dissertation of Achim Koberstein - // if Bx - b is different at any component more that refactor_epsilon then we refactor unsigned percent_of_entering_to_check { 5 }; // we try to find a profitable column in a percentage of the columns bool use_scaling { true }; diff --git a/src/math/lp/numeric_pair.h b/src/math/lp/numeric_pair.h index f59aa84ba52..4a60c82ca9e 100644 --- a/src/math/lp/numeric_pair.h +++ b/src/math/lp/numeric_pair.h @@ -107,7 +107,6 @@ class numeric_traits { template struct convert_struct { static X convert(const Y & y){ return X(y);} - static bool is_epsilon_small(const X & x, const double & y) { return std::abs(numeric_traits::get_double(x)) < y; } static bool below_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false;} static bool above_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false; } }; @@ -316,16 +315,12 @@ struct convert_struct> { typedef numeric_pair impq; -template bool is_epsilon_small(const X & v, const double& eps); // forward definition { return convert_struct::is_epsilon_small(v, eps);} template struct convert_struct, double> { static numeric_pair convert(const double & q) { return numeric_pair(convert_struct::convert(q), numeric_traits::zero()); } - static bool is_epsilon_small(const numeric_pair & p, const double & eps) { - return convert_struct::is_epsilon_small(p.x, eps) && convert_struct::is_epsilon_small(p.y, eps); - } static bool below_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { // lp_unreachable(); return false; @@ -340,10 +335,7 @@ struct convert_struct, double> { static numeric_pair convert(const double & q) { return numeric_pair(q, 0.0); } - static bool is_epsilon_small(const numeric_pair & p, const double & eps) { - return std::abs(p.x) < eps && std::abs(p.y) < eps; - } - + static int compare_on_coord(const double & x, const double & bound, const double eps) { if (bound == 0) return (x < - eps)? -1: (x > eps? 1 : 0); // it is an important special case double relative = (bound > 0)? - eps: eps; @@ -369,9 +361,6 @@ struct convert_struct, double> { template <> struct convert_struct { - static bool is_epsilon_small(const double& x, const double & eps) { - return x < eps && x > -eps; - } static double convert(const double & y){ return y;} static bool below_bound_numeric(const double & x, const double & bound, const double & eps) { if (bound == 0) return x < - eps; @@ -384,8 +373,6 @@ struct convert_struct { return x > bound * (1.0 + relative) + eps; } }; - -template bool is_epsilon_small(const X & v, const double &eps) { return convert_struct::is_epsilon_small(v, eps);} template bool below_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::below_bound_numeric(x, bound, eps);} template bool above_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::above_bound_numeric(x, bound, eps);} template T floor(const numeric_pair & r) { From 29f6525018ea9eebaf48d61a6e5a6518df43e163 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 16:58:49 -0800 Subject: [PATCH 31/36] more dead code --- src/math/lp/numeric_pair.h | 75 -------------------------------------- 1 file changed, 75 deletions(-) diff --git a/src/math/lp/numeric_pair.h b/src/math/lp/numeric_pair.h index 4a60c82ca9e..a64825cd8f1 100644 --- a/src/math/lp/numeric_pair.h +++ b/src/math/lp/numeric_pair.h @@ -112,18 +112,6 @@ struct convert_struct { }; -template <> -struct convert_struct { - static double convert(const mpq & q) {return q.get_double();} -}; - - -template <> -struct convert_struct { - static mpq convert(unsigned q) {return mpq(q);} -}; - - template struct numeric_pair { @@ -308,71 +296,8 @@ class numeric_traits> { } }; -template <> -struct convert_struct> { - static double convert(const numeric_pair & q) {return q.x;} -}; - typedef numeric_pair impq; - -template -struct convert_struct, double> { - static numeric_pair convert(const double & q) { - return numeric_pair(convert_struct::convert(q), numeric_traits::zero()); - } - static bool below_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lp_unreachable(); - return false; - } - static bool above_bound_numeric(const numeric_pair &, const numeric_pair &, const double &) { - // lp_unreachable(); - return false; - } -}; -template <> -struct convert_struct, double> { - static numeric_pair convert(const double & q) { - return numeric_pair(q, 0.0); - } - - static int compare_on_coord(const double & x, const double & bound, const double eps) { - if (bound == 0) return (x < - eps)? -1: (x > eps? 1 : 0); // it is an important special case - double relative = (bound > 0)? - eps: eps; - return (x < bound * (1.0 + relative) - eps)? -1 : ((x > bound * (1.0 - relative) + eps)? 1 : 0); - } - - static bool below_bound_numeric(const numeric_pair & x, const numeric_pair & bound, const double & eps) { - int r = compare_on_coord(x.x, bound.x, eps); - if (r == 1) return false; - if (r == -1) return true; - // the first coordinates are almost the same - return compare_on_coord(x.y, bound.y, eps) == -1; - } - - static bool above_bound_numeric(const numeric_pair & x, const numeric_pair & bound, const double & eps) { - int r = compare_on_coord(x.x, bound.x, eps); - if (r == -1) return false; - if (r == 1) return true; - // the first coordinates are almost the same - return compare_on_coord(x.y, bound.y, eps) == 1; - } -}; - -template <> -struct convert_struct { - static double convert(const double & y){ return y;} - static bool below_bound_numeric(const double & x, const double & bound, const double & eps) { - if (bound == 0) return x < - eps; - double relative = (bound > 0)? - eps: eps; - return x < bound * (1.0 + relative) - eps; - } - static bool above_bound_numeric(const double & x, const double & bound, const double & eps) { - if (bound == 0) return x > eps; - double relative = (bound > 0)? eps: - eps; - return x > bound * (1.0 + relative) + eps; - } -}; template bool below_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::below_bound_numeric(x, bound, eps);} template bool above_bound_numeric(const X & x, const X & bound, const double& eps) { return convert_struct::above_bound_numeric(x, bound, eps);} template T floor(const numeric_pair & r) { From 8c5b316faf681765872a1182272b0cf3ed10bde1 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 17:11:26 -0800 Subject: [PATCH 32/36] rm dead code --- src/math/lp/CMakeLists.txt | 1 - src/math/lp/lp_primal_core_solver.h | 2 -- src/math/lp/lp_primal_core_solver_def.h | 5 ---- .../lp/lp_primal_core_solver_tableau_def.h | 3 ++- src/math/lp/lp_utils.cpp | 26 ------------------- 5 files changed, 2 insertions(+), 35 deletions(-) delete mode 100644 src/math/lp/lp_utils.cpp diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 98241bf603e..4ca8cb1d2ae 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -20,7 +20,6 @@ z3_add_component(lp lp_core_solver_base.cpp lp_primal_core_solver.cpp lp_settings.cpp - lp_utils.cpp matrix.cpp mon_eq.cpp monomial_bounds.cpp diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 17b1ea494d0..1719f9c556c 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -618,8 +618,6 @@ class lp_primal_core_solver:public lp_core_solver_base { void print_bound_info_and_x(unsigned j, std::ostream & out); - unsigned solve_with_tableau(); - bool basis_column_is_set_correctly(unsigned j) const { return this->m_A.m_columns[j].size() == 1; diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index 1c48f11636c..cc8ad88b392 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -315,11 +315,6 @@ template unsigned lp_primal_core_solver::get_num } -// returns the number of iterations -template unsigned lp_primal_core_solver::solve() { - TRACE("lar_solver", tout << "solve " << this->get_status() << "\n";); - return solve_with_tableau(); -} // calling it stage1 is too cryptic template void lp_primal_core_solver::find_feasible_solution() { diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index de2f1c208af..c7b604b9553 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -87,7 +87,8 @@ template void lp_primal_core_solver::advance_on_e } template -unsigned lp_primal_core_solver::solve_with_tableau() { +unsigned lp_primal_core_solver::solve() { + TRACE("lar_solver", tout << "solve " << this->get_status() << "\n";); init_run_tableau(); if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) { this->set_status(lp_status::FEASIBLE); diff --git a/src/math/lp/lp_utils.cpp b/src/math/lp/lp_utils.cpp deleted file mode 100644 index b909a0389d0..00000000000 --- a/src/math/lp/lp_utils.cpp +++ /dev/null @@ -1,26 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include "math/lp/lp_utils.h" -#ifdef lp_for_z3 -namespace lp { - -} -#endif - From 9d964fcafa95ecfa49d109dfd258bf80985c7673 Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 17:52:59 -0800 Subject: [PATCH 33/36] more dead code --- src/math/lp/CMakeLists.txt | 2 - src/math/lp/binary_heap_priority_queue.cpp | 38 --- src/math/lp/binary_heap_priority_queue.h | 83 ------ src/math/lp/binary_heap_priority_queue_def.h | 214 --------------- src/math/lp/binary_heap_upair_queue.cpp | 32 --- src/math/lp/binary_heap_upair_queue.h | 65 ----- src/math/lp/binary_heap_upair_queue_def.h | 126 --------- src/math/lp/conversion_helper.h | 35 --- src/math/lp/indexer_of_constraints.h | 45 ---- src/math/lp/lar_core_solver.h | 1 - src/math/lp/lar_solver.h | 1 - src/math/lp/lp_primal_core_solver.h | 1 - src/math/lp/permutation_matrix.cpp | 23 -- src/math/lp/permutation_matrix.h | 61 +---- src/math/lp/permutation_matrix_def.h | 261 +------------------ src/math/lp/tail_matrix.h | 50 ---- src/test/lp/lp.cpp | 67 ----- 17 files changed, 10 insertions(+), 1095 deletions(-) delete mode 100644 src/math/lp/binary_heap_priority_queue.cpp delete mode 100644 src/math/lp/binary_heap_priority_queue.h delete mode 100644 src/math/lp/binary_heap_priority_queue_def.h delete mode 100644 src/math/lp/binary_heap_upair_queue.cpp delete mode 100644 src/math/lp/binary_heap_upair_queue.h delete mode 100644 src/math/lp/binary_heap_upair_queue_def.h delete mode 100644 src/math/lp/conversion_helper.h delete mode 100644 src/math/lp/indexer_of_constraints.h delete mode 100644 src/math/lp/tail_matrix.h diff --git a/src/math/lp/CMakeLists.txt b/src/math/lp/CMakeLists.txt index 4ca8cb1d2ae..dd72f36ee8a 100644 --- a/src/math/lp/CMakeLists.txt +++ b/src/math/lp/CMakeLists.txt @@ -1,7 +1,5 @@ z3_add_component(lp SOURCES - binary_heap_priority_queue.cpp - binary_heap_upair_queue.cpp core_solver_pretty_printer.cpp dense_matrix.cpp emonics.cpp diff --git a/src/math/lp/binary_heap_priority_queue.cpp b/src/math/lp/binary_heap_priority_queue.cpp deleted file mode 100644 index ec6630b1dbb..00000000000 --- a/src/math/lp/binary_heap_priority_queue.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include "math/lp/numeric_pair.h" -#include "math/lp/binary_heap_priority_queue_def.h" -namespace lp { -template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); -template unsigned binary_heap_priority_queue::dequeue(); -template void binary_heap_priority_queue::enqueue(unsigned int, int const&); -template void binary_heap_priority_queue::enqueue(unsigned int, mpq const&); -template void binary_heap_priority_queue::remove(unsigned int); -template unsigned binary_heap_priority_queue >::dequeue(); -template unsigned binary_heap_priority_queue::dequeue(); -template void binary_heap_priority_queue >::enqueue(unsigned int, numeric_pair const&); -template void binary_heap_priority_queue >::resize(unsigned int); -template binary_heap_priority_queue::binary_heap_priority_queue(unsigned int); -template void binary_heap_priority_queue::resize(unsigned int); -template unsigned binary_heap_priority_queue::dequeue(); -template void binary_heap_priority_queue::enqueue(unsigned int, unsigned int const&); -template void binary_heap_priority_queue::remove(unsigned int); -template void lp::binary_heap_priority_queue::resize(unsigned int); -} diff --git a/src/math/lp/binary_heap_priority_queue.h b/src/math/lp/binary_heap_priority_queue.h deleted file mode 100644 index 1ea8363efe1..00000000000 --- a/src/math/lp/binary_heap_priority_queue.h +++ /dev/null @@ -1,83 +0,0 @@ - -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once -#include "util/vector.h" -#include "util/debug.h" -#include "math/lp/lp_utils.h" -namespace lp { -// the elements with the smallest priority are dequeued first -template -class binary_heap_priority_queue { - vector m_priorities; - - // indexing for A starts from 1 - vector m_heap; // keeps the elements of the queue - vector m_heap_inverse; // o = m_heap[m_heap_inverse[o]] - unsigned m_heap_size; - // is is the child place in heap - void swap_with_parent(unsigned i); - void put_at(unsigned i, unsigned h); - void decrease_priority(unsigned o, T newPriority); -public: -#ifdef Z3DEBUG - bool is_consistent() const; -#endif -public: - void remove(unsigned o); - unsigned size() const { return m_heap_size; } - binary_heap_priority_queue(): m_heap(1), m_heap_size(0) {} // the empty constructror - // n is the initial queue capacity. - // The capacity will be enlarged each time twice if needed - binary_heap_priority_queue(unsigned n); - - void clear() { - for (unsigned i = 0; i < m_heap_size; i++) { - unsigned o = m_heap[i+1]; - m_heap_inverse[o] = -1; - } - m_heap_size = 0; - } - - void resize(unsigned n); - void put_to_heap(unsigned i, unsigned o); - - void enqueue_new(unsigned o, const T& priority); - - // This method can work with an element that is already in the queue. - // In this case the priority will be changed and the queue adjusted. - void enqueue(unsigned o, const T & priority); - void change_priority_for_existing(unsigned o, const T & priority); - T get_priority(unsigned o) const { return m_priorities[o]; } - bool is_empty() const { return m_heap_size == 0; } - - /// return the first element of the queue and removes it from the queue - unsigned dequeue_and_get_priority(T & priority); - void fix_heap_under(unsigned i); - void put_the_last_at_the_top_and_fix_the_heap(); - /// return the first element of the queue and removes it from the queue - unsigned dequeue(); - unsigned peek() const { - lp_assert(m_heap_size > 0); - return m_heap[1]; - } - void print(std::ostream & out); -}; -} diff --git a/src/math/lp/binary_heap_priority_queue_def.h b/src/math/lp/binary_heap_priority_queue_def.h deleted file mode 100644 index 0e640d949df..00000000000 --- a/src/math/lp/binary_heap_priority_queue_def.h +++ /dev/null @@ -1,214 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include "util/vector.h" -#include "math/lp/binary_heap_priority_queue.h" -namespace lp { -// "i" is the child's place in the heap -template void binary_heap_priority_queue::swap_with_parent(unsigned i) { - unsigned parent = m_heap[i >> 1]; - put_at(i >> 1, m_heap[i]); - put_at(i, parent); -} - -template void binary_heap_priority_queue::put_at(unsigned i, unsigned h) { - m_heap[i] = h; - m_heap_inverse[h] = i; -} - -template void binary_heap_priority_queue::decrease_priority(unsigned o, T newPriority) { - m_priorities[o] = newPriority; - int i = m_heap_inverse[o]; - while (i > 1) { - if (m_priorities[m_heap[i]] < m_priorities[m_heap[i >> 1]]) - swap_with_parent(i); - else - break; - i >>= 1; - } -} - -#ifdef Z3DEBUG -template bool binary_heap_priority_queue::is_consistent() const { - for (int i = 0; i < m_heap_inverse.size(); i++) { - int i_index = m_heap_inverse[i]; - lp_assert(i_index <= static_cast(m_heap_size)); - lp_assert(i_index == -1 || m_heap[i_index] == i); - } - for (unsigned i = 1; i < m_heap_size; i++) { - unsigned ch = i << 1; - for (int k = 0; k < 2; k++) { - if (ch > m_heap_size) break; - if (!(m_priorities[m_heap[i]] <= m_priorities[m_heap[ch]])){ - return false; - } - ch++; - } - } - return true; -} -#endif - -template void binary_heap_priority_queue::remove(unsigned o) { - T priority_of_o = m_priorities[o]; - int o_in_heap = m_heap_inverse[o]; - if (o_in_heap == -1) { - return; // nothing to do - } - lp_assert(static_cast(o_in_heap) <= m_heap_size); - if (static_cast(o_in_heap) < m_heap_size) { - put_at(o_in_heap, m_heap[m_heap_size--]); - if (m_priorities[m_heap[o_in_heap]] > priority_of_o) { - fix_heap_under(o_in_heap); - } else { // we need to propagate the m_heap[o_in_heap] up - unsigned i = o_in_heap; - while (i > 1) { - unsigned ip = i >> 1; - if (m_priorities[m_heap[i]] < m_priorities[m_heap[ip]]) - swap_with_parent(i); - else - break; - i = ip; - } - } - } else { - lp_assert(static_cast(o_in_heap) == m_heap_size); - m_heap_size--; - } - m_heap_inverse[o] = -1; - // lp_assert(is_consistent()); -} -// n is the initial queue capacity. -// The capacity will be enlarged two times automatically if needed -template binary_heap_priority_queue::binary_heap_priority_queue(unsigned n) : - m_priorities(n), - m_heap(n + 1), // because the indexing for A starts from 1 - m_heap_inverse(n, -1), - m_heap_size(0) -{ } - - -template void binary_heap_priority_queue::resize(unsigned n) { - m_priorities.resize(n); - m_heap.resize(n + 1); - m_heap_inverse.resize(n, -1); -} - -template void binary_heap_priority_queue::put_to_heap(unsigned i, unsigned o) { - m_heap[i] = o; - m_heap_inverse[o] = i; -} - -template void binary_heap_priority_queue::enqueue_new(unsigned o, const T& priority) { - m_heap_size++; - int i = m_heap_size; - lp_assert(o < m_priorities.size()); - m_priorities[o] = priority; - put_at(i, o); - while (i > 1 && m_priorities[m_heap[i >> 1]] > priority) { - swap_with_parent(i); - i >>= 1; - } -} -// This method can work with an element that is already in the queue. -// In this case the priority will be changed and the queue adjusted. -template void binary_heap_priority_queue::enqueue(unsigned o, const T & priority) { - if (o >= m_priorities.size()) { - if (o == 0) - resize(2); - else - resize(o << 1); // make the size twice larger - } - - if (m_heap_inverse[o] == -1) - enqueue_new(o, priority); - else - change_priority_for_existing(o, priority); -} - -template void binary_heap_priority_queue::change_priority_for_existing(unsigned o, const T & priority) { - if (m_priorities[o] > priority) { - decrease_priority(o, priority); - } else { - m_priorities[o] = priority; - fix_heap_under(m_heap_inverse[o]); - } -} - - -/// return the first element of the queue and removes it from the queue -template unsigned binary_heap_priority_queue::dequeue_and_get_priority(T & priority) { - lp_assert(m_heap_size != 0); - int ret = m_heap[1]; - priority = m_priorities[ret]; - put_the_last_at_the_top_and_fix_the_heap(); - return ret; -} - -template void binary_heap_priority_queue::fix_heap_under(unsigned i) { - while (true) { - unsigned smallest = i; - unsigned l = i << 1; - if (l <= m_heap_size && m_priorities[m_heap[l]] < m_priorities[m_heap[i]]) - smallest = l; - unsigned r = l + 1; - if (r <= m_heap_size && m_priorities[m_heap[r]] < m_priorities[m_heap[smallest]]) - smallest = r; - if (smallest != i) - swap_with_parent(smallest); - else - break; - i = smallest; - } -} - -template void binary_heap_priority_queue::put_the_last_at_the_top_and_fix_the_heap() { - if (m_heap_size > 1) { - put_at(1, m_heap[m_heap_size--]); - fix_heap_under(1); - } else { - m_heap_size--; - } -} -/// return the first element of the queue and removes it from the queue -template unsigned binary_heap_priority_queue::dequeue() { - lp_assert(m_heap_size > 0); - int ret = m_heap[1]; - put_the_last_at_the_top_and_fix_the_heap(); - m_heap_inverse[ret] = -1; - return ret; -} -template void binary_heap_priority_queue::print(std::ostream & out) { - vector index; - vector prs; - while (size()) { - T prior; - int j = dequeue_and_get_priority(prior); - index.push_back(j); - prs.push_back(prior); - out << "(" << j << ", " << prior << ")"; - } - out << std::endl; - // restore the queue - for (int i = 0; i < index.size(); i++) - enqueue(index[i], prs[i]); -} -} diff --git a/src/math/lp/binary_heap_upair_queue.cpp b/src/math/lp/binary_heap_upair_queue.cpp deleted file mode 100644 index f1ff1d63946..00000000000 --- a/src/math/lp/binary_heap_upair_queue.cpp +++ /dev/null @@ -1,32 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#include "math/lp/binary_heap_upair_queue_def.h" -namespace lp { -template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); -template binary_heap_upair_queue::binary_heap_upair_queue(unsigned int); -template unsigned binary_heap_upair_queue::dequeue_available_spot(); -template unsigned binary_heap_upair_queue::dequeue_available_spot(); -template void binary_heap_upair_queue::enqueue(unsigned int, unsigned int, int const&); -template void binary_heap_upair_queue::remove(unsigned int, unsigned int); -template void binary_heap_upair_queue::remove(unsigned int, unsigned int); -template void binary_heap_upair_queue::dequeue(unsigned int&, unsigned int&); -template void binary_heap_upair_queue::enqueue(unsigned int, unsigned int, unsigned int const&); -template void binary_heap_upair_queue::dequeue(unsigned int&, unsigned int&); -} diff --git a/src/math/lp/binary_heap_upair_queue.h b/src/math/lp/binary_heap_upair_queue.h deleted file mode 100644 index ce454280394..00000000000 --- a/src/math/lp/binary_heap_upair_queue.h +++ /dev/null @@ -1,65 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include -#include -#include -#include "util/vector.h" -#include -#include -#include "math/lp/binary_heap_priority_queue.h" - - -typedef std::pair upair; - -namespace lp { -template -class binary_heap_upair_queue { - binary_heap_priority_queue m_q; - std::unordered_map m_pairs_to_index; - svector m_pairs; // inverse to index - svector m_available_spots; -public: - binary_heap_upair_queue(unsigned size); - - unsigned dequeue_available_spot(); - bool is_empty() const { return m_q.is_empty(); } - - unsigned size() const {return m_q.size(); } - - bool contains(unsigned i, unsigned j) const { return m_pairs_to_index.find(std::make_pair(i, j)) != m_pairs_to_index.end(); - } - - void remove(unsigned i, unsigned j); - bool ij_index_is_new(unsigned ij_index) const; - void enqueue(unsigned i, unsigned j, const T & priority); - void dequeue(unsigned & i, unsigned &j); - T get_priority(unsigned i, unsigned j) const; -#ifdef Z3DEBUG - bool pair_to_index_is_a_bijection() const; - bool available_spots_are_correct() const; - bool is_correct() const { - return m_q.is_consistent() && pair_to_index_is_a_bijection() && available_spots_are_correct(); - } -#endif - void resize(unsigned size) { m_q.resize(size); } -}; -} diff --git a/src/math/lp/binary_heap_upair_queue_def.h b/src/math/lp/binary_heap_upair_queue_def.h deleted file mode 100644 index 65485a6ebf8..00000000000 --- a/src/math/lp/binary_heap_upair_queue_def.h +++ /dev/null @@ -1,126 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ -#pragma once - -#include -#include "math/lp/lp_utils.h" -#include "math/lp/binary_heap_upair_queue.h" -namespace lp { -template binary_heap_upair_queue::binary_heap_upair_queue(unsigned size) : m_q(size), m_pairs(size) { - for (unsigned i = 0; i < size; i++) - m_available_spots.push_back(i); -} - -template unsigned -binary_heap_upair_queue::dequeue_available_spot() { - lp_assert(m_available_spots.empty() == false); - unsigned ret = m_available_spots.back(); - m_available_spots.pop_back(); - return ret; -} - -template void binary_heap_upair_queue::remove(unsigned i, unsigned j) { - upair p(i, j); - auto it = m_pairs_to_index.find(p); - if (it == m_pairs_to_index.end()) - return; // nothing to do - m_q.remove(it->second); - m_available_spots.push_back(it->second); - m_pairs_to_index.erase(it); -} - - -template bool binary_heap_upair_queue::ij_index_is_new(unsigned ij_index) const { - for (auto it : m_pairs_to_index) { - if (it.second == ij_index) - return false; - } - return true; -} - -template void binary_heap_upair_queue::enqueue(unsigned i, unsigned j, const T & priority) { - upair p(i, j); - auto it = m_pairs_to_index.find(p); - unsigned ij_index; - if (it == m_pairs_to_index.end()) { - // it is a new pair, let us find a spot for it - if (m_available_spots.empty()) { - // we ran out of empty spots - unsigned size_was = static_cast(m_pairs.size()); - unsigned new_size = size_was << 1; - for (unsigned i = size_was; i < new_size; i++) - m_available_spots.push_back(i); - m_pairs.resize(new_size); - } - ij_index = dequeue_available_spot(); - // lp_assert(ij_indexsecond; - } - m_q.enqueue(ij_index, priority); -} - -template void binary_heap_upair_queue::dequeue(unsigned & i, unsigned &j) { - lp_assert(!m_q.is_empty()); - unsigned ij_index = m_q.dequeue(); - upair & p = m_pairs[ij_index]; - i = p.first; - j = p.second; - m_available_spots.push_back(ij_index); - m_pairs_to_index.erase(p); -} - - -template T binary_heap_upair_queue::get_priority(unsigned i, unsigned j) const { - auto it = m_pairs_to_index.find(std::make_pair(i, j)); - if (it == m_pairs_to_index.end()) - return T(0xFFFFFF); // big number - return m_q.get_priority(it->second); -} - -#ifdef Z3DEBUG -template bool binary_heap_upair_queue::pair_to_index_is_a_bijection() const { - std::set tmp; - for (auto p : m_pairs_to_index) { - unsigned j = p.second; - unsigned size = tmp.size(); - tmp.insert(j); - if (tmp.size() == size) - return false; - } - return true; -} - -template bool binary_heap_upair_queue::available_spots_are_correct() const { - std::set tmp; - for (auto p : m_available_spots){ - tmp.insert(p); - } - if (tmp.size() != m_available_spots.size()) - return false; - for (auto it : m_pairs_to_index) - if (tmp.find(it.second) != tmp.end()) - return false; - return true; -} -#endif -} diff --git a/src/math/lp/conversion_helper.h b/src/math/lp/conversion_helper.h deleted file mode 100644 index ba8b6a9835f..00000000000 --- a/src/math/lp/conversion_helper.h +++ /dev/null @@ -1,35 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -namespace lp { -template -struct conversion_helper { - static V get_lower_bound(const column_info & ci) { - return V(ci.get_lower_bound(), ci.lower_bound_is_strict()? 1 : 0); - } - - static V get_upper_bound(const column_info & ci) { - return V(ci.get_upper_bound(), ci.upper_bound_is_strict()? -1 : 0); - } -}; - - -} diff --git a/src/math/lp/indexer_of_constraints.h b/src/math/lp/indexer_of_constraints.h deleted file mode 100644 index 9bda22bc17a..00000000000 --- a/src/math/lp/indexer_of_constraints.h +++ /dev/null @@ -1,45 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - Nikolaj Bjorner (nbjorner) - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "math/lp/binary_heap_priority_queue.h" -namespace lp { - -class indexer_of_constraints { - binary_heap_priority_queue m_queue_of_released_indices; - unsigned m_max; -public: - indexer_of_constraints() :m_max(0) {} - unsigned get_new_index() { - unsigned ret; - if (m_queue_of_released_indices.is_empty()) { - ret = m_max++; - } - else { - ret = m_queue_of_released_indices.dequeue(); - } - return ret; - }; - void release_index(unsigned i) { - m_queue_of_released_indices.enqueue(i, i); - }; - unsigned max() const { return m_max; } -}; -} diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 966e2f0d765..59929e34f52 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -12,7 +12,6 @@ Copyright (c) 2017 Microsoft Corporation #include "math/lp/lp_core_solver_base.h" #include #include "math/lp/indexed_vector.h" -#include "math/lp/binary_heap_priority_queue.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/stacked_vector.h" #include "math/lp/lar_solution_signature.h" diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index a321632fb61..5c77c679a47 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -37,7 +37,6 @@ #include "math/lp/stacked_vector.h" #include "math/lp/implied_bound.h" #include "math/lp/bound_analyzer_on_row.h" -#include "math/lp/conversion_helper.h" #include "math/lp/int_solver.h" #include "math/lp/nra_solver.h" #include "math/lp/lp_types.h" diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 1719f9c556c..628777f3328 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -32,7 +32,6 @@ Revision History: #include "math/lp/static_matrix.h" #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/lp_core_solver_base.h" -#include "math/lp/binary_heap_priority_queue.h" #include "math/lp/u_set.h" namespace lp { diff --git a/src/math/lp/permutation_matrix.cpp b/src/math/lp/permutation_matrix.cpp index 762b85d63f0..be4b7335c65 100644 --- a/src/math/lp/permutation_matrix.cpp +++ b/src/math/lp/permutation_matrix.cpp @@ -24,31 +24,8 @@ Revision History: template void lp::permutation_matrix::init(unsigned int); template void lp::permutation_matrix>::init(unsigned int); -template void lp::permutation_matrix::apply_from_right(vector&); -template bool lp::permutation_matrix::is_identity() const; -template void lp::permutation_matrix::multiply_by_permutation_from_left(lp::permutation_matrix&); -template void lp::permutation_matrix::multiply_by_permutation_from_right(lp::permutation_matrix&); -template void lp::permutation_matrix::multiply_by_permutation_reverse_from_left(lp::permutation_matrix&); -template void lp::permutation_matrix::multiply_by_reverse_from_right(lp::permutation_matrix&); template lp::permutation_matrix::permutation_matrix(unsigned int); template void lp::permutation_matrix::transpose_from_left(unsigned int, unsigned int); template void lp::permutation_matrix::transpose_from_right(unsigned int, unsigned int); -template void lp::permutation_matrix >::apply_from_right(vector&); -template bool lp::permutation_matrix >::is_identity() const; -template void lp::permutation_matrix >::multiply_by_permutation_from_left(lp::permutation_matrix >&); -template void lp::permutation_matrix >::multiply_by_permutation_from_right(lp::permutation_matrix >&); -template void lp::permutation_matrix >::multiply_by_permutation_reverse_from_left(lp::permutation_matrix >&); -template void lp::permutation_matrix >::multiply_by_reverse_from_right(lp::permutation_matrix >&); template lp::permutation_matrix >::permutation_matrix(unsigned int); template void lp::permutation_matrix >::transpose_from_left(unsigned int, unsigned int); -template void lp::permutation_matrix >::transpose_from_right(unsigned int, unsigned int); -template void lp::permutation_matrix::apply_reverse_from_left(lp::indexed_vector&); -template void lp::permutation_matrix::apply_reverse_from_left_to_T(vector&); -template void lp::permutation_matrix::apply_reverse_from_right_to_T(vector&); -template void lp::permutation_matrix >::apply_reverse_from_left(lp::indexed_vector&); -template void lp::permutation_matrix >::apply_reverse_from_left_to_T(vector&); -template void lp::permutation_matrix >::apply_reverse_from_right_to_T(vector&); -template void lp::permutation_matrix< lp::mpq, lp::mpq>::apply_reverse_from_left_to_X(vector &); -template void lp::permutation_matrix< lp::mpq, lp::numeric_pair< lp::mpq> >::apply_reverse_from_left_to_X(vector> &); -template void lp::permutation_matrix::apply_reverse_from_right_to_T(lp::indexed_vector&); -template void lp::permutation_matrix >::apply_reverse_from_right_to_T(lp::indexed_vector&); diff --git a/src/math/lp/permutation_matrix.h b/src/math/lp/permutation_matrix.h index 35a58906ade..a3fff4f7fa5 100644 --- a/src/math/lp/permutation_matrix.h +++ b/src/math/lp/permutation_matrix.h @@ -25,20 +25,16 @@ Revision History: #include "math/lp/indexed_vector.h" #include "math/lp/lp_settings.h" #include "math/lp/matrix.h" -#include "math/lp/tail_matrix.h" namespace lp { -#ifdef Z3DEBUG - inline bool is_even(int k) { return (k/2)*2 == k; } -#endif - template -class permutation_matrix : public tail_matrix { +template +class permutation_matrix +#ifdef Z3DEBUG + : public matrix +#endif +{ vector m_permutation; vector m_rev; - vector m_work_array; - vector m_T_buffer; - vector m_X_buffer; - class ref { permutation_matrix & m_p; @@ -63,42 +59,15 @@ class permutation_matrix : public tail_matrix { // create a unit permutation of the given length void init(unsigned length); unsigned get_rev(unsigned i) { return m_rev[i]; } - bool is_dense() const override { return false; } -#ifdef Z3DEBUG - permutation_matrix get_inverse() const { - return permutation_matrix(size(), m_rev); - } + +#ifdef Z3DEBUG void print(std::ostream & out) const; #endif ref operator[](unsigned i) { return ref(*this, i); } unsigned operator[](unsigned i) const { return m_permutation[i]; } - - void apply_from_left(vector & w, lp_settings &) override; - - void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) override; - - void apply_from_right(vector & w) override; - - void apply_from_right(indexed_vector & w) override; - template - void copy_aside(vector & t, vector & tmp_index, indexed_vector & w); - - template - void clear_data(indexed_vector & w); - - template - void apply_reverse_from_left(indexed_vector & w); - - void apply_reverse_from_left_to_T(vector & w); - void apply_reverse_from_left_to_X(vector & w); - - void apply_reverse_from_right_to_T(vector & w); - void apply_reverse_from_right_to_T(indexed_vector & w); - void apply_reverse_from_right_to_X(vector & w); - void set_val(unsigned i, unsigned pi) { lp_assert(i < size() && pi < size()); m_permutation[i] = pi; m_rev[pi] = i; } @@ -116,18 +85,6 @@ class permutation_matrix : public tail_matrix { void set_number_of_rows(unsigned /*m*/) override { } void set_number_of_columns(unsigned /*n*/) override { } #endif - void multiply_by_permutation_from_left(permutation_matrix & p); - - // this is multiplication in the matrix sense - void multiply_by_permutation_from_right(permutation_matrix & p); - - void multiply_by_reverse_from_right(permutation_matrix & q); - - void multiply_by_permutation_reverse_from_left(permutation_matrix & r); - - void shrink_by_one_identity(); - - bool is_identity() const; unsigned size() const { return static_cast(m_rev.size()); } @@ -135,8 +92,6 @@ class permutation_matrix : public tail_matrix { unsigned old_size = m_permutation.size(); m_permutation.resize(size); m_rev.resize(size); - m_T_buffer.resize(size); - m_X_buffer.resize(size); for (unsigned i = old_size; i < size; i++) { m_permutation[i] = m_rev[i] = i; } diff --git a/src/math/lp/permutation_matrix_def.h b/src/math/lp/permutation_matrix_def.h index b6f9924ff3b..c86fef4f422 100644 --- a/src/math/lp/permutation_matrix_def.h +++ b/src/math/lp/permutation_matrix_def.h @@ -22,13 +22,13 @@ Revision History: #include "util/vector.h" #include "math/lp/permutation_matrix.h" namespace lp { -template permutation_matrix::permutation_matrix(unsigned length): m_permutation(length), m_rev(length), m_T_buffer(length), m_X_buffer(length) { +template permutation_matrix::permutation_matrix(unsigned length): m_permutation(length), m_rev(length) { for (unsigned i = 0; i < length; i++) { // do not change the direction of the loop because of the vectorization bug in clang3.3 m_permutation[i] = m_rev[i] = i; } } -template permutation_matrix::permutation_matrix(unsigned length, vector const & values): m_permutation(length), m_rev(length) , m_T_buffer(length), m_X_buffer(length) { +template permutation_matrix::permutation_matrix(unsigned length, vector const & values): m_permutation(length), m_rev(length) { for (unsigned i = 0; i < length; i++) { set_val(i, values[i]); } @@ -37,8 +37,6 @@ template permutation_matrix::permutation_matrix(u template void permutation_matrix::init(unsigned length) { m_permutation.resize(length); m_rev.resize(length); - m_T_buffer.resize(length); - m_X_buffer.resize(length); for (unsigned i = 0; i < length; i++) { m_permutation[i] = m_rev[i] = i; } @@ -59,211 +57,6 @@ template void permutation_matrix::print(std::ostr } #endif -template -void permutation_matrix::apply_from_left(vector & w, lp_settings & ) { -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // L * deb_w = clone_vector(w, row_count()); - // deb.apply_from_left(deb_w); -#endif - lp_assert(m_X_buffer.size() == w.size()); - unsigned i = size(); - while (i-- > 0) { - m_X_buffer[i] = w[m_permutation[i]]; - } - i = size(); - while (i-- > 0) { - w[i] = m_X_buffer[i]; - } -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(deb_w, w, row_count())); - // delete [] deb_w; -#endif -} - -template -void permutation_matrix::apply_from_left_to_T(indexed_vector & w, lp_settings & ) { - vector t(w.m_index.size()); - vector tmp_index(w.m_index.size()); - copy_aside(t, tmp_index, w); // todo: is it too much copying - clear_data(w); - // set the new values - for (unsigned i = static_cast(t.size()); i > 0;) { - i--; - unsigned j = m_rev[tmp_index[i]]; - w[j] = t[i]; - w.m_index[i] = j; - } -} - -template void permutation_matrix::apply_from_right(vector & w) { -#ifdef Z3DEBUG - // dense_matrix deb(*this); - // T * deb_w = clone_vector(w, row_count()); - // deb.apply_from_right(deb_w); -#endif - lp_assert(m_T_buffer.size() == w.size()); - for (unsigned i = 0; i < size(); i++) { - m_T_buffer[i] = w[m_rev[i]]; - } - - for (unsigned i = 0; i < size(); i++) { - w[i] = m_T_buffer[i]; - } -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(deb_w, w, row_count())); - // delete [] deb_w; -#endif -} - -template void permutation_matrix::apply_from_right(indexed_vector & w) { -#ifdef Z3DEBUG - vector wcopy(w.m_data); - apply_from_right(wcopy); -#endif - vector buffer(w.m_index.size()); - vector index_copy(w.m_index); - for (unsigned i = 0; i < w.m_index.size(); i++) { - buffer[i] = w.m_data[w.m_index[i]]; - } - w.clear(); - - for (unsigned i = 0; i < index_copy.size(); i++) { - unsigned j = index_copy[i]; - unsigned pj = m_permutation[j]; - w.set_value(buffer[i], pj); - } - -#ifdef Z3DEBUG - lp_assert(vectors_are_equal(wcopy, w.m_data)); -#endif -} - - -template template -void permutation_matrix::copy_aside(vector & t, vector & tmp_index, indexed_vector & w) { - for (unsigned i = static_cast(t.size()); i > 0;) { - i--; - unsigned j = w.m_index[i]; - t[i] = w[j]; // copy aside all non-zeroes - tmp_index[i] = j; // and the indices too - } -} - -template template -void permutation_matrix::clear_data(indexed_vector & w) { - // clear old non-zeroes - for (unsigned i = static_cast(w.m_index.size()); i > 0;) { - i--; - unsigned j = w.m_index[i]; - w[j] = zero_of_type(); - } -} - -template template -void permutation_matrix::apply_reverse_from_left(indexed_vector & w) { - // the result will be w = p(-1) * w -#ifdef Z3DEBUG - // dense_matrix deb(get_reverse()); - // L * deb_w = clone_vector(w.m_data, row_count()); - // deb.apply_from_left(deb_w); -#endif - vector t(w.m_index.size()); - vector tmp_index(w.m_index.size()); - - copy_aside(t, tmp_index, w); - clear_data(w); - - // set the new values - for (unsigned i = static_cast(t.size()); i > 0;) { - i--; - unsigned j = m_permutation[tmp_index[i]]; - w[j] = t[i]; - w.m_index[i] = j; - } -#ifdef Z3DEBUG - // lp_assert(vectors_are_equal(deb_w, w.m_data, row_count())); - // delete [] deb_w; -#endif -} - -template -void permutation_matrix::apply_reverse_from_left_to_T(vector & w) { - // the result will be w = p(-1) * w - lp_assert(m_T_buffer.size() == w.size()); - unsigned i = size(); - while (i-- > 0) { - m_T_buffer[m_permutation[i]] = w[i]; - } - i = size(); - while (i-- > 0) { - w[i] = m_T_buffer[i]; - } -} -template -void permutation_matrix::apply_reverse_from_left_to_X(vector & w) { - // the result will be w = p(-1) * w - lp_assert(m_X_buffer.size() == w.size()); - unsigned i = size(); - while (i-- > 0) { - m_X_buffer[m_permutation[i]] = w[i]; - } - i = size(); - while (i-- > 0) { - w[i] = m_X_buffer[i]; - } -} - -template -void permutation_matrix::apply_reverse_from_right_to_T(vector & w) { - // the result will be w = w * p(-1) - lp_assert(m_T_buffer.size() == w.size()); - unsigned i = size(); - while (i-- > 0) { - m_T_buffer[i] = w[m_permutation[i]]; - } - i = size(); - while (i-- > 0) { - w[i] = m_T_buffer[i]; - } -} - -template -void permutation_matrix::apply_reverse_from_right_to_T(indexed_vector & w) { - // the result will be w = w * p(-1) -#ifdef Z3DEBUG - // vector wcopy(w.m_data); - // apply_reverse_from_right_to_T(wcopy); -#endif - vector tmp; - vector tmp_index(w.m_index); - for (auto i : w.m_index) { - tmp.push_back(w[i]); - } - w.clear(); - - for (unsigned k = 0; k < tmp_index.size(); k++) { - unsigned j = tmp_index[k]; - w.set_value(tmp[k], m_rev[j]); - } - - -} - - -template -void permutation_matrix::apply_reverse_from_right_to_X(vector & w) { - // the result will be w = w * p(-1) - lp_assert(m_X_buffer.size() == w.size()); - unsigned i = size(); - while (i-- > 0) { - m_X_buffer[i] = w[m_permutation[i]]; - } - i = size(); - while (i-- > 0) { - w[i] = m_X_buffer[i]; - } -} template void permutation_matrix::transpose_from_left(unsigned i, unsigned j) { // the result will be this = (i,j)*this @@ -283,55 +76,5 @@ template void permutation_matrix::transpose_from_ set_val(j, pi); } -template void permutation_matrix::multiply_by_permutation_from_left(permutation_matrix & p) { - m_work_array = m_permutation; - lp_assert(p.size() == size()); - unsigned i = size(); - while (i-- > 0) { - set_val(i, m_work_array[p[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation - } -} - -// this is multiplication in the matrix sense -template void permutation_matrix::multiply_by_permutation_from_right(permutation_matrix & p) { - m_work_array = m_permutation; - lp_assert(p.size() == size()); - unsigned i = size(); - while (i-- > 0) - set_val(i, p[m_work_array[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation - -} - -template void permutation_matrix::multiply_by_reverse_from_right(permutation_matrix & q){ // todo : condensed permutations ? - lp_assert(q.size() == size()); - m_work_array = m_permutation; - // the result is this = this*q(-1) - unsigned i = size(); - while (i-- > 0) { - set_val(i, q.m_rev[m_work_array[i]]); // we have m(P)*m(Q) = m(QP), where m is the matrix of the permutation - } -} - -template void permutation_matrix::multiply_by_permutation_reverse_from_left(permutation_matrix & r){ // todo : condensed permutations? - // the result is this = r(-1)*this - m_work_array = m_permutation; - // the result is this = this*q(-1) - unsigned i = size(); - while (i-- > 0) { - set_val(i, m_work_array[r.m_rev[i]]); - } -} - - -template bool permutation_matrix::is_identity() const { - unsigned i = size(); - while (i-- > 0) { - if (m_permutation[i] != i) { - return false; - } - } - return true; -} - } diff --git a/src/math/lp/tail_matrix.h b/src/math/lp/tail_matrix.h deleted file mode 100644 index 9fa1a4a4782..00000000000 --- a/src/math/lp/tail_matrix.h +++ /dev/null @@ -1,50 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "math/lp/indexed_vector.h" -#include "math/lp/matrix.h" -#include "math/lp/lp_settings.h" -// These matrices appear at the end of the list - -namespace lp { -template -class tail_matrix -#ifdef Z3DEBUG - : public matrix -#endif -{ -public: - virtual void apply_from_left_to_T(indexed_vector & w, lp_settings & settings) = 0; - virtual void apply_from_left(vector & w, lp_settings & settings) = 0; - virtual void apply_from_right(vector & w) = 0; - virtual void apply_from_right(indexed_vector & w) = 0; - virtual ~tail_matrix() = default; - virtual bool is_dense() const = 0; - struct ref_row { - const tail_matrix & m_A; - unsigned m_row; - ref_row(const tail_matrix& m, unsigned row): m_A(m), m_row(row) {} - T operator[](unsigned j) const { return m_A.get_elem(m_row, j);} - }; - ref_row operator[](unsigned i) const { return ref_row(*this, i);} -}; -} diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 24aa8767a37..446ead41526 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -34,13 +34,11 @@ #include #include "math/lp/lp_utils.h" #include "test/lp/smt_reader.h" -#include "math/lp/binary_heap_priority_queue.h" #include "test/lp/argument_parser.h" #include "test/lp/test_file_reader.h" #include "math/lp/indexed_value.h" #include "math/lp/lar_solver.h" #include "math/lp/numeric_pair.h" -#include "math/lp/binary_heap_upair_queue.h" #include "util/stacked_value.h" #include "math/lp/u_set.h" #include "util/stopwatch.h" @@ -458,72 +456,7 @@ void get_time_limit_and_max_iters_from_parser(argument_parser & args_parser, uns -void test_upair_queue() { - int n = 10; - binary_heap_upair_queue q(2); - std::unordered_map m; - for (int k = 0; k < 100; k++) { - int i = my_random()%n; - int j = my_random()%n; - q.enqueue(i, j, my_random()%n); - } - - q.remove(5, 5); - - while (!q.is_empty()) { - unsigned i, j; - q.dequeue(i, j); - } -} -void test_binary_priority_queue() { - std::cout << "testing binary_heap_priority_queue..."; - auto q = binary_heap_priority_queue(10); - q.enqueue(2, 2); - q.enqueue(1, 1); - q.enqueue(9, 9); - q.enqueue(8, 8); - q.enqueue(5, 25); - q.enqueue(3, 3); - q.enqueue(4, 4); - q.enqueue(7, 30); - q.enqueue(6, 6); - q.enqueue(0, 0); - q.enqueue(5, 5); - q.enqueue(7, 7); - - for (unsigned i = 0; i < 10; i++) { - unsigned de = q.dequeue(); - lp_assert(i == de); - std::cout << de << std::endl; - } - q.enqueue(2, 2); - q.enqueue(1, 1); - q.enqueue(9, 9); - q.enqueue(8, 8); - q.enqueue(5, 5); - q.enqueue(3, 3); - q.enqueue(4, 4); - q.enqueue(7, 2); - q.enqueue(0, 1); - q.enqueue(6, 6); - q.enqueue(7, 7); - q.enqueue(33, 1000); - q.enqueue(20, 0); - q.dequeue(); - q.remove(33); - q.enqueue(0, 0); -#ifdef Z3DEBUG - unsigned t = 0; - while (q.size() > 0) { - unsigned d =q.dequeue(); - lp_assert(t++ == d); - std::cout << d << std::endl; - } -#endif - test_upair_queue(); - std::cout << " done" << std::endl; -} int get_random_rows() { From 78a36024aaa2231c5da9d6f7a5dd2e761625d10e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Tue, 7 Mar 2023 17:54:34 -0800 Subject: [PATCH 34/36] fix lp_tst --- src/test/lp/lp.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 446ead41526..8ad73f0c003 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -693,7 +693,6 @@ void setup_args_parser(argument_parser & parser) { parser.add_option_with_help_string("--compare_with_primal", "using the primal simplex solver for comparison"); parser.add_option_with_help_string("--lar", "test lar_solver"); parser.add_option_with_after_string_with_help("--maxng", "max iterations without progress"); - parser.add_option_with_help_string("-tbq", "test binary queue"); parser.add_option_with_help_string("--randomize_lar", "test randomize functionality"); parser.add_option_with_help_string("--smap", "test stacked_map"); parser.add_option_with_help_string("--term", "simple term test"); @@ -1962,13 +1961,6 @@ void test_lp_local(int argn, char**argv) { return finalize(0); } - - if (args_parser.option_is_used("-tbq")) { - test_binary_priority_queue(); - ret = 0; - return finalize(ret); - } - return finalize(0); // has_violations() ? 1 : 0); } } From 5577314e64b20f775c6086c34e1b40cb7bf8d45e Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 8 Mar 2023 08:22:25 -0800 Subject: [PATCH 35/36] more dead code --- src/math/lp/lar_core_solver.h | 1 - src/math/lp/lar_core_solver_def.h | 1 - src/math/lp/lar_solution_signature.h | 28 ----------------- src/math/lp/lar_solver.cpp | 45 --------------------------- src/math/lp/lar_solver.h | 12 ++----- src/math/lp/lp_core_solver_base.cpp | 4 --- src/math/lp/lp_core_solver_base.h | 5 --- src/math/lp/lp_core_solver_base_def.h | 44 -------------------------- src/math/lp/lp_settings.h | 2 -- 9 files changed, 2 insertions(+), 140 deletions(-) delete mode 100644 src/math/lp/lar_solution_signature.h diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 59929e34f52..4aa62f0df09 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -14,7 +14,6 @@ Copyright (c) 2017 Microsoft Corporation #include "math/lp/indexed_vector.h" #include "math/lp/lp_primal_core_solver.h" #include "math/lp/stacked_vector.h" -#include "math/lp/lar_solution_signature.h" #include "util/stacked_value.h" namespace lp { diff --git a/src/math/lp/lar_core_solver_def.h b/src/math/lp/lar_core_solver_def.h index 2e205291e6f..e22d77c1b30 100644 --- a/src/math/lp/lar_core_solver_def.h +++ b/src/math/lp/lar_core_solver_def.h @@ -14,7 +14,6 @@ Revision History: #include #include "util/vector.h" #include "math/lp/lar_core_solver.h" -#include "math/lp/lar_solution_signature.h" namespace lp { lar_core_solver::lar_core_solver( lp_settings & settings, diff --git a/src/math/lp/lar_solution_signature.h b/src/math/lp/lar_solution_signature.h deleted file mode 100644 index 5b8bfae48aa..00000000000 --- a/src/math/lp/lar_solution_signature.h +++ /dev/null @@ -1,28 +0,0 @@ -/*++ -Copyright (c) 2017 Microsoft Corporation - -Module Name: - - - -Abstract: - - - -Author: - - Lev Nachmanson (levnach) - -Revision History: - - ---*/ - -#pragma once -#include "util/vector.h" -#include "util/debug.h" -#include "math/lp/lp_settings.h" -#include -namespace lp { -typedef std::unordered_map lar_solution_signature; -} diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 952f2ad43e0..1c9f5461beb 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -221,9 +221,6 @@ namespace lp { evidence.add_pair(ul.lower_bound_witness(), -numeric_traits::one()); } - - unsigned lar_solver::get_total_iterations() const { return m_mpq_lar_core_solver.m_r_solver.total_iterations(); } - void lar_solver::push() { m_simplex_strategy = m_settings.simplex_strategy(); m_simplex_strategy.push(); @@ -761,20 +758,6 @@ namespace lp { return r; } - bool lar_solver::x_is_correct() const { - if (m_mpq_lar_core_solver.m_r_x.size() != A_r().column_count()) { - return false; - } - for (unsigned i = 0; i < A_r().row_count(); i++) { - numeric_pair delta = A_r().dot_product_with_row(i, m_mpq_lar_core_solver.m_r_x); - if (!delta.is_zero()) { - return false; - } - } - return true;; - - } - bool lar_solver::var_is_registered(var_index vj) const { if (tv::is_term(vj)) { return tv::unmask_term(vj) < m_terms.size(); @@ -824,28 +807,6 @@ namespace lp { return false; // it is unreachable } - bool lar_solver::the_relations_are_of_same_type(const vector>& evidence, lconstraint_kind& the_kind_of_sum) const { - unsigned n_of_G = 0, n_of_L = 0; - bool strict = false; - for (auto& it : evidence) { - mpq coeff = it.first; - constraint_index con_ind = it.second; - lconstraint_kind kind = coeff.is_pos() ? - m_constraints[con_ind].kind() : - flip_kind(m_constraints[con_ind].kind()); - if (kind == GT || kind == LT) - strict = true; - if (kind == GE || kind == GT) - n_of_G++; - else if (kind == LE || kind == LT) - n_of_L++; - } - the_kind_of_sum = n_of_G ? GE : (n_of_L ? LE : EQ); - if (strict) - the_kind_of_sum = static_cast((static_cast(the_kind_of_sum) / 2)); - - return n_of_G == 0 || n_of_L == 0; - } void lar_solver::register_in_map(std::unordered_map& coeffs, const lar_base_constraint& cn, const mpq& a) { for (auto& it : cn.coeffs()) { @@ -1227,12 +1188,6 @@ namespace lp { insert_row_with_changed_bounds(r.var()); } - - - void lar_solver::pivot_fixed_vars_from_basis() { - m_mpq_lar_core_solver.m_r_solver.pivot_fixed_vars_from_basis(); - } - void lar_solver::pop() { pop(1); } diff --git a/src/math/lp/lar_solver.h b/src/math/lp/lar_solver.h index 5c77c679a47..955710b3c52 100644 --- a/src/math/lp/lar_solver.h +++ b/src/math/lp/lar_solver.h @@ -212,11 +212,9 @@ class lar_solver : public column_namer { void update_x_and_inf_costs_for_columns_with_changed_bounds_tableau(); void solve_with_core_solver(); numeric_pair get_basic_var_value_from_row(unsigned i); - bool x_is_correct() const; bool all_constrained_variables_are_registered(const vector>& left_side); bool all_constraints_hold() const; bool constraint_holds(const lar_base_constraint & constr, std::unordered_map & var_map) const; - bool the_relations_are_of_same_type(const vector> & evidence, lconstraint_kind & the_kind_of_sum) const; static void register_in_map(std::unordered_map & coeffs, const lar_base_constraint & cn, const mpq & a); static void register_monoid_in_map(std::unordered_map & coeffs, const mpq & a, unsigned j); bool the_left_sides_sum_to_zero(const vector> & evidence) const; @@ -229,7 +227,6 @@ class lar_solver : public column_namer { int inf_sign) const; mpq get_left_side_val(const lar_base_constraint & cns, const std::unordered_map & var_map) const; void fill_var_set_for_random_update(unsigned sz, var_index const * vars, vector& column_list); - void pivot_fixed_vars_from_basis(); bool column_represents_row_in_tableau(unsigned j); void make_sure_that_the_bottom_right_elem_not_zero_in_tableau(unsigned i, unsigned j); void remove_last_row_and_column_from_tableau(unsigned j); @@ -264,10 +261,7 @@ class lar_solver : public column_namer { return m_fixed_var_table_int; } - map, default_eq>& fixed_var_table_int() { - return m_fixed_var_table_int; - } - + const map, default_eq>& fixed_var_table_real() const { return m_fixed_var_table_real; } @@ -293,9 +287,7 @@ class lar_solver : public column_namer { inline void set_column_value_test(unsigned j, const impq& v) { set_column_value(j, v); } - - unsigned get_total_iterations() const; - + var_index add_named_var(unsigned ext_j, bool is_integer, const std::string&); lp_status maximize_term(unsigned j_or_term, impq &term_max); diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index ccd6bf41927..61eae344f6c 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -23,9 +23,6 @@ Revision History: #include "util/vector.h" #include #include "math/lp/lp_core_solver_base_def.h" -template lp::non_basic_column_value_position lp::lp_core_solver_base >::get_non_basic_column_value_position(unsigned int) const; -template lp::non_basic_column_value_position lp::lp_core_solver_base::get_non_basic_column_value_position(unsigned int) const; - template bool lp::lp_core_solver_base >::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; @@ -61,7 +58,6 @@ template std::string lp::lp_core_solver_base template void lp::lp_core_solver_base >::pretty_print(std::ostream & out); template bool lp::lp_core_solver_base::calc_current_x_is_feasible_include_non_basis(void)const; template bool lp::lp_core_solver_base >::calc_current_x_is_feasible_include_non_basis() const; -template void lp::lp_core_solver_base >::pivot_fixed_vars_from_basis(); template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; // template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 9fb4d4333cd..2e751330b69 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -383,11 +383,6 @@ class lp_core_solver_base { } - - - non_basic_column_value_position get_non_basic_column_value_position(unsigned j) const; - - void pivot_fixed_vars_from_basis(); bool remove_from_basis(unsigned j); bool remove_from_basis(unsigned j, const impq&); bool pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index 2d729656724..a1255ade3e2 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -423,29 +423,6 @@ column_name(unsigned column) const { return m_column_names.get_variable_name(column); } -template non_basic_column_value_position lp_core_solver_base:: -get_non_basic_column_value_position(unsigned j) const { - switch (m_column_types[j]) { - case column_type::fixed: - return x_is_at_lower_bound(j)? at_fixed : not_at_bound; - case column_type::free_column: - return free_of_bounds; - case column_type::boxed: - return x_is_at_lower_bound(j)? at_lower_bound :( - x_is_at_upper_bound(j)? at_upper_bound: - not_at_bound - ); - case column_type::lower_bound: - return x_is_at_lower_bound(j)? at_lower_bound : not_at_bound; - case column_type::upper_bound: - return x_is_at_upper_bound(j)? at_upper_bound : not_at_bound; - default: - lp_unreachable(); - } - lp_unreachable(); - return at_lower_bound; -} - template void lp_core_solver_base::transpose_rows_tableau(unsigned i, unsigned j) { transpose_basis(i, j); m_A.transpose_rows(i, j); @@ -463,27 +440,6 @@ template bool lp_core_solver_base::pivot_column_g return true; } -template void lp_core_solver_base::pivot_fixed_vars_from_basis() { - // run over basis and non-basis at the same time - indexed_vector w(m_basis.size()); // the buffer - unsigned i = 0; // points to basis - for (; i < m_basis.size(); i++) { - unsigned basic_j = m_basis[i]; - - if (get_column_type(basic_j) != column_type::fixed) continue; - T a; - unsigned j; - for (auto &c : m_A.m_rows[i]) { - j = c.var(); - if (j == basic_j) - continue; - if (get_column_type(j) != column_type::fixed) { - if (pivot_column_general(j, basic_j, w)) - break; - } - } - } -} template bool lp_core_solver_base::remove_from_basis(unsigned basic_j) { indexed_vector w(m_basis.size()); // the buffer diff --git a/src/math/lp/lp_settings.h b/src/math/lp/lp_settings.h index 314930fc175..9a38fd582cb 100644 --- a/src/math/lp/lp_settings.h +++ b/src/math/lp/lp_settings.h @@ -90,8 +90,6 @@ inline std::ostream& operator<<(std::ostream& out, lp_status status) { lp_status lp_status_from_string(std::string status); -enum non_basic_column_value_position { at_lower_bound, at_upper_bound, at_fixed, free_of_bounds, not_at_bound }; - class lp_resource_limit { public: From d80ab99f7eaa9427e41cfbbae50b8af6d28f63dd Mon Sep 17 00:00:00 2001 From: Lev Nachmanson Date: Wed, 8 Mar 2023 09:27:09 -0800 Subject: [PATCH 36/36] replace lp_assert(false) with UNREACHABLE --- src/math/lp/core_solver_pretty_printer_def.h | 2 +- src/math/lp/general_matrix.h | 22 +- src/math/lp/lar_constraints.h | 2 +- src/math/lp/lar_core_solver.h | 4 +- src/math/lp/lar_solver.cpp | 16 +- src/math/lp/lar_term.h | 2 +- src/math/lp/lia_move.h | 2 +- src/math/lp/lp_core_solver_base.cpp | 3 - src/math/lp/lp_core_solver_base.h | 81 +- src/math/lp/lp_core_solver_base_def.h | 40 +- src/math/lp/lp_primal_core_solver.h | 1272 ++++++++--------- src/math/lp/lp_primal_core_solver_def.h | 76 +- .../lp/lp_primal_core_solver_tableau_def.h | 4 +- src/math/lp/lp_settings_def.h | 6 +- src/math/lp/lp_utils.h | 1 - src/math/lp/nra_solver.cpp | 2 +- src/math/lp/numeric_pair.h | 12 +- src/math/lp/static_matrix.cpp | 2 - src/math/lp/static_matrix.h | 4 +- src/math/lp/static_matrix_def.h | 8 - src/test/lp/gomory_test.h | 2 +- src/test/lp/lp.cpp | 26 +- src/test/lp/smt_reader.h | 2 +- 23 files changed, 677 insertions(+), 914 deletions(-) diff --git a/src/math/lp/core_solver_pretty_printer_def.h b/src/math/lp/core_solver_pretty_printer_def.h index 931333ee725..27aa6c75d72 100644 --- a/src/math/lp/core_solver_pretty_printer_def.h +++ b/src/math/lp/core_solver_pretty_printer_def.h @@ -139,7 +139,7 @@ template void core_solver_pretty_printer::adjust_ case column_type::free_column: break; default: - lp_assert(false); + UNREACHABLE(); break; } } diff --git a/src/math/lp/general_matrix.h b/src/math/lp/general_matrix.h index 749fa30dc43..a4f6693a211 100644 --- a/src/math/lp/general_matrix.h +++ b/src/math/lp/general_matrix.h @@ -114,9 +114,6 @@ class general_matrix { } } - void copy_column_to_indexed_vector(unsigned entering, indexed_vector &w ) const { - lp_assert(false); // not implemented - } general_matrix operator*(const general_matrix & m) const { lp_assert(m.row_count() == column_count()); general_matrix ret(row_count(), m.column_count()); @@ -172,24 +169,7 @@ class general_matrix { return r; } - // bool create_upper_triangle(general_matrix& m, vector& x) { - // for (unsigned i = 1; i < m.row_count(); i++) { - // lp_assert(false); // to be continued - // } - // } - - // bool solve_A_x_equal_b(const general_matrix& m, vector& x, const vector& b) const { - // auto m_copy = m; - // // for square matrices - // lp_assert(row_count() == b.size()); - // lp_assert(x.size() == column_count()); - // lp_assert(row_count() == column_count()); - // x = b; - // create_upper_triangle(copy_of_m, x); - // solve_on_triangle(copy_of_m, x); - // } - // - + void transpose_rows(unsigned i, unsigned l) { lp_assert(i != l); m_row_permutation.transpose_from_right(i, l); diff --git a/src/math/lp/lar_constraints.h b/src/math/lp/lar_constraints.h index 8e6311683b5..f8cffbe5793 100644 --- a/src/math/lp/lar_constraints.h +++ b/src/math/lp/lar_constraints.h @@ -44,7 +44,7 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) { case EQ: return std::string("="); case NE: return std::string("!="); } - lp_unreachable(); + UNREACHABLE(); return std::string(); // it is unreachable } diff --git a/src/math/lp/lar_core_solver.h b/src/math/lp/lar_core_solver.h index 4aa62f0df09..06ef4d50ba3 100644 --- a/src/math/lp/lar_core_solver.h +++ b/src/math/lp/lar_core_solver.h @@ -159,7 +159,7 @@ class lar_core_solver { case column_type::fixed: return true; default: - lp_assert(false); + UNREACHABLE(); } return false; } @@ -174,7 +174,7 @@ class lar_core_solver { case column_type::fixed: return true; default: - lp_assert(false); + UNREACHABLE(); } return false; } diff --git a/src/math/lp/lar_solver.cpp b/src/math/lp/lar_solver.cpp index 1c9f5461beb..9fab5e4371d 100644 --- a/src/math/lp/lar_solver.cpp +++ b/src/math/lp/lar_solver.cpp @@ -466,7 +466,7 @@ namespace lp { default: - lp_unreachable(); // wrong mode + UNREACHABLE(); // wrong mode } return false; } @@ -802,7 +802,7 @@ namespace lp { case GT: return left_side_val > constr.rhs(); case EQ: return left_side_val == constr.rhs(); default: - lp_unreachable(); + UNREACHABLE(); } return false; // it is unreachable } @@ -857,7 +857,7 @@ namespace lp { case EQ: lp_assert(rs != zero_of_type()); break; default: - lp_assert(false); + UNREACHABLE(); return false; } #endif @@ -1816,7 +1816,7 @@ namespace lp { adjust_initial_state_for_tableau_rows(); break; case simplex_strategy_enum::tableau_costs: - lp_assert(false); // not implemented + UNREACHABLE(); // not implemented case simplex_strategy_enum::undecided: adjust_initial_state_for_tableau_rows(); break; @@ -1905,7 +1905,7 @@ namespace lp { } default: - lp_unreachable(); + UNREACHABLE(); } if (m_mpq_lar_core_solver.m_r_upper_bounds[j] == m_mpq_lar_core_solver.m_r_lower_bounds[j]) { m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed; @@ -1959,7 +1959,7 @@ namespace lp { } default: - lp_unreachable(); + UNREACHABLE(); } } @@ -2009,7 +2009,7 @@ namespace lp { } default: - lp_unreachable(); + UNREACHABLE(); } } void lar_solver::update_bound_with_no_ub_no_lb(var_index j, lconstraint_kind kind, const mpq& right_side, constraint_index ci) { @@ -2050,7 +2050,7 @@ namespace lp { } default: - lp_unreachable(); + UNREACHABLE(); } } diff --git a/src/math/lp/lar_term.h b/src/math/lp/lar_term.h index 3ef424e243e..fc73f949f1f 100644 --- a/src/math/lp/lar_term.h +++ b/src/math/lp/lar_term.h @@ -179,7 +179,7 @@ class lar_term { return p.coeff().is_one(); } } - lp_unreachable(); + UNREACHABLE(); return false; } diff --git a/src/math/lp/lia_move.h b/src/math/lp/lia_move.h index 65da5826e7b..ca61d7b7aba 100644 --- a/src/math/lp/lia_move.h +++ b/src/math/lp/lia_move.h @@ -45,7 +45,7 @@ inline std::string lia_move_to_string(lia_move m) { case lia_move::unsat: return "unsat"; default: - lp_assert(false); + UNREACHABLE(); }; return "strange"; } diff --git a/src/math/lp/lp_core_solver_base.cpp b/src/math/lp/lp_core_solver_base.cpp index 61eae344f6c..9a4c375f638 100644 --- a/src/math/lp/lp_core_solver_base.cpp +++ b/src/math/lp/lp_core_solver_base.cpp @@ -27,7 +27,6 @@ template bool lp::lp_core_solver_base >::prin template bool lp::lp_core_solver_base::basis_heading_is_correct() const ; template bool lp::lp_core_solver_base::column_is_dual_feasible(unsigned int) const; template bool lp::lp_core_solver_base::print_statistics_with_iterations_and_nonzeroes_and_cost_and_check_that_the_time_is_over(char const*, std::ostream &); -template void lp::lp_core_solver_base::set_non_basic_x_to_correct_bounds(); template void lp::lp_core_solver_base::add_delta_to_entering(unsigned int, const lp::mpq&); template void lp::lp_core_solver_base >::init(); template void lp::lp_core_solver_base >::init_basis_heading_and_non_basic_columns_vector(); @@ -61,7 +60,6 @@ template bool lp::lp_core_solver_base >::calc template bool lp::lp_core_solver_base::column_is_feasible(unsigned int) const; // template void lp::lp_core_solver_base >::print_linear_combination_of_column_indices(vector, std::allocator > > const&, std::ostream&) const; template bool lp::lp_core_solver_base >::column_is_feasible(unsigned int) const; -template bool lp::lp_core_solver_base >::snap_non_basic_x_to_bound(); template bool lp::lp_core_solver_base>::pivot_column_tableau(unsigned int, unsigned int); template bool lp::lp_core_solver_base::pivot_column_tableau(unsigned int, unsigned int); template void lp::lp_core_solver_base >::transpose_rows_tableau(unsigned int, unsigned int); @@ -70,6 +68,5 @@ template bool lp::lp_core_solver_base::inf_set_is_correct() co template bool lp::lp_core_solver_base >::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base::infeasibility_costs_are_correct() const; template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int); -template bool lp::lp_core_solver_base >::remove_from_basis(unsigned int, lp::numeric_pair const&); diff --git a/src/math/lp/lp_core_solver_base.h b/src/math/lp/lp_core_solver_base.h index 2e751330b69..fc167324234 100644 --- a/src/math/lp/lp_core_solver_base.h +++ b/src/math/lp/lp_core_solver_base.h @@ -173,8 +173,6 @@ class lp_core_solver_base { void set_total_iterations(unsigned s) { m_total_iterations = s; } - void set_non_basic_x_to_correct_bounds(); - bool at_bound(const X &x, const X & bound) const { return !below_bound(x, bound) && !above_bound(x, bound); } @@ -300,45 +298,6 @@ class lp_core_solver_base { std::string column_name(unsigned column) const; - bool snap_non_basic_x_to_bound() { - bool ret = false; - for (unsigned j : non_basis()) - ret = snap_column_to_bound(j) || ret; - return ret; - } - - bool snap_column_to_bound(unsigned j) { - switch (m_column_types[j]) { - case column_type::fixed: - if (x_is_at_bound(j)) - break; - m_x[j] = m_lower_bounds[j]; - return true; - case column_type::boxed: - if (x_is_at_bound(j)) - break; // we should preserve x if possible - // snap randomly - if (m_settings.random_next() % 2 == 1) - m_x[j] = m_lower_bounds[j]; - else - m_x[j] = m_upper_bounds[j]; - return true; - case column_type::lower_bound: - if (x_is_at_lower_bound(j)) - break; - m_x[j] = m_lower_bounds[j]; - return true; - case column_type::upper_bound: - if (x_is_at_upper_bound(j)) - break; - m_x[j] = m_upper_bounds[j]; - return true; - default: - break; - } - return false; - } - bool make_column_feasible(unsigned j, numeric_pair & delta) { bool ret = false; lp_assert(m_basis_heading[j] < 0); @@ -384,7 +343,6 @@ class lp_core_solver_base { } bool remove_from_basis(unsigned j); - bool remove_from_basis(unsigned j, const impq&); bool pivot_column_general(unsigned j, unsigned j_basic, indexed_vector & w); void init_basic_part_of_basis_heading() { unsigned m = m_basis.size(); @@ -456,31 +414,6 @@ class lp_core_solver_base { change_basis_unconditionally(leaving, entering); } - bool non_basic_column_is_set_correctly(unsigned j) const { - if (j >= this->m_n()) - return false; - switch (this->m_column_types[j]) { - case column_type::fixed: - case column_type::boxed: - if (!this->x_is_at_bound(j)) - return false; - break; - case column_type::lower_bound: - if (!this->x_is_at_lower_bound(j)) - return false; - break; - case column_type::upper_bound: - if (!this->x_is_at_upper_bound(j)) - return false; - break; - case column_type::free_column: - break; - default: - lp_assert(false); - break; - } - return true; - } bool non_basic_columns_are_set_correctly() const { for (unsigned j : this->m_nbasis) if (!column_is_feasible(j)) { @@ -540,13 +473,11 @@ class lp_core_solver_base { out << "[-oo, oo]"; break; default: - lp_assert(false); + UNREACHABLE(); } return out << "\n"; } - bool column_is_free(unsigned j) const { return this->m_column_types[j] == column_type::free_column; } - bool column_is_fixed(unsigned j) const { return this->m_column_types[j] == column_type::fixed; } @@ -579,16 +510,6 @@ class lp_core_solver_base { } } - // only check for basic columns - bool calc_current_x_is_feasible() const { - unsigned i = this->m_m(); - while (i--) { - if (!column_is_feasible(m_basis[i])) - return false; - } - return true; - } - void transpose_rows_tableau(unsigned i, unsigned ii); void pivot_to_reduced_costs_tableau(unsigned i, unsigned j); diff --git a/src/math/lp/lp_core_solver_base_def.h b/src/math/lp/lp_core_solver_base_def.h index a1255ade3e2..cb0084a168a 100644 --- a/src/math/lp/lp_core_solver_base_def.h +++ b/src/math/lp/lp_core_solver_base_def.h @@ -166,26 +166,6 @@ print_statistics_with_cost_and_check_that_the_time_is_over(X cost, std::ostream return time_is_over(); } -template void lp_core_solver_base:: -set_non_basic_x_to_correct_bounds() { - for (unsigned j : non_basis()) { - switch (m_column_types[j]) { - case column_type::boxed: - m_x[j] = m_d[j] < 0? m_upper_bounds[j]: m_lower_bounds[j]; - break; - case column_type::lower_bound: - m_x[j] = m_lower_bounds[j]; - lp_assert(column_is_dual_feasible(j)); - break; - case column_type::upper_bound: - m_x[j] = m_upper_bounds[j]; - lp_assert(column_is_dual_feasible(j)); - break; - default: - break; - } - } -} template bool lp_core_solver_base:: column_is_dual_feasible(unsigned j) const { switch (m_column_types[j]) { @@ -201,9 +181,9 @@ column_is_dual_feasible(unsigned j) const { case column_type::free_column: return numeric_traits::is_zero(m_d[j]); default: - lp_unreachable(); + UNREACHABLE(); } - lp_unreachable(); + UNREACHABLE(); return false; } template bool lp_core_solver_base:: @@ -257,7 +237,7 @@ template bool lp_core_solver_base::column_is_feas return true; break; default: - lp_unreachable(); + UNREACHABLE(); } return false; // it is unreachable } @@ -453,18 +433,6 @@ template bool lp_core_solver_base::remove_from_ba return false; } -template bool lp_core_solver_base::remove_from_basis(unsigned basic_j, const impq& val) { - indexed_vector w(m_basis.size()); // the buffer - unsigned i = m_basis_heading[basic_j]; - for (auto &c : m_A.m_rows[i]) { - if (c.var() == basic_j) - continue; - if (pivot_column_general(c.var(), basic_j, w)) - return true; - } - return false; -} - template bool lp_core_solver_base::infeasibility_costs_are_correct() const { @@ -513,7 +481,7 @@ lp_core_solver_base::infeasibility_cost_is_correct_for_column(unsigned j) case column_type::free_column: return is_zero(this->m_costs[j]); default: - lp_assert(false); + UNREACHABLE(); return true; } } diff --git a/src/math/lp/lp_primal_core_solver.h b/src/math/lp/lp_primal_core_solver.h index 628777f3328..641f6be2160 100644 --- a/src/math/lp/lp_primal_core_solver.h +++ b/src/math/lp/lp_primal_core_solver.h @@ -19,704 +19,680 @@ Revision History: --*/ #pragma once -#include -#include -#include -#include -#include -#include "util/vector.h" -#include -#include -#include -#include -#include "math/lp/static_matrix.h" #include "math/lp/core_solver_pretty_printer.h" #include "math/lp/lp_core_solver_base.h" +#include "math/lp/static_matrix.h" #include "math/lp/u_set.h" +#include "util/vector.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace lp { -// This core solver solves (Ax=b, lower_bound_values \leq x \leq upper_bound_values, maximize costs*x ) -// The right side b is given implicitly by x and the basis +// This core solver solves (Ax=b, lower_bound_values \leq x \leq +// upper_bound_values, maximize costs*x ) The right side b is given implicitly +// by x and the basis template -class lp_primal_core_solver:public lp_core_solver_base { +class lp_primal_core_solver : public lp_core_solver_base { public: - int m_sign_of_entering_delta; - vector m_costs_backup; - unsigned m_inf_row_index_for_tableau; - bool m_bland_mode_tableau; - u_set m_left_basis_tableau; - unsigned m_bland_mode_threshold; - unsigned m_left_basis_repeated; - vector m_leaving_candidates; - - std::list m_non_basis_list; - void sort_non_basis(); - int choose_entering_column(unsigned number_of_benefitial_columns_to_go_over); - int choose_entering_column_tableau(); - int choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over); - - - bool needs_to_grow(unsigned bj) const { - lp_assert(!this->column_is_feasible(bj)); - switch(this->m_column_types[bj]) { - case column_type::free_column: - return false; - case column_type::fixed: - case column_type::lower_bound: - case column_type::boxed: - return this-> x_below_low_bound(bj); - default: - return false; - } - lp_assert(false); // unreachable - return false; - } - - int inf_sign_of_column(unsigned bj) const { - lp_assert(!this->column_is_feasible(bj)); - switch(this->m_column_types[bj]) { - case column_type::free_column: - return 0; - case column_type::lower_bound: - return 1; - case column_type::fixed: - case column_type::boxed: - return this->x_above_upper_bound(bj)? -1: 1; - default: - return -1; - } - lp_assert(false); // unreachable - return 0; - - } - - - bool monoid_can_decrease(const row_cell & rc) const { - unsigned j = rc.var(); - lp_assert(this->column_is_feasible(j)); - switch (this->m_column_types[j]) { - case column_type::free_column: - return true; - case column_type::fixed: - return false; - case column_type::lower_bound: - if (is_pos(rc.coeff())) { - return this->x_above_lower_bound(j); - } - - return true; - case column_type::upper_bound: - if (is_pos(rc.coeff())) { - return true; - } - - return this->x_below_upper_bound(j); - case column_type::boxed: - if (is_pos(rc.coeff())) { - return this->x_above_lower_bound(j); - } - - return this->x_below_upper_bound(j); - default: - return false; - } - lp_assert(false); // unreachable - return false; - } - - bool monoid_can_increase(const row_cell & rc) const { - unsigned j = rc.var(); - lp_assert(this->column_is_feasible(j)); - switch (this->m_column_types[j]) { - case column_type::free_column: - return true; - case column_type::fixed: - return false; - case column_type::lower_bound: - if (is_neg(rc.coeff())) { - return this->x_above_lower_bound(j); - } - - return true; - case column_type::upper_bound: - if (is_neg(rc.coeff())) { - return true; - } - - return this->x_below_upper_bound(j); - case column_type::boxed: - if (is_neg(rc.coeff())) { - return this->x_above_lower_bound(j); - } - - return this->x_below_upper_bound(j); - default: - return false; - } - lp_assert(false); // unreachable - return false; - } + int m_sign_of_entering_delta; + vector m_costs_backup; + unsigned m_inf_row_index_for_tableau; + bool m_bland_mode_tableau; + u_set m_left_basis_tableau; + unsigned m_bland_mode_threshold; + unsigned m_left_basis_repeated; + vector m_leaving_candidates; + + std::list m_non_basis_list; + void sort_non_basis(); + int choose_entering_column_tableau(); + + bool needs_to_grow(unsigned bj) const { + lp_assert(!this->column_is_feasible(bj)); + switch (this->m_column_types[bj]) { + case column_type::free_column: + return false; + case column_type::fixed: + case column_type::lower_bound: + case column_type::boxed: + return this->x_below_low_bound(bj); + default: + return false; + } + UNREACHABLE(); // unreachable + return false; + } + + int inf_sign_of_column(unsigned bj) const { + lp_assert(!this->column_is_feasible(bj)); + switch (this->m_column_types[bj]) { + case column_type::free_column: + return 0; + case column_type::lower_bound: + return 1; + case column_type::fixed: + case column_type::boxed: + return this->x_above_upper_bound(bj) ? -1 : 1; + default: + return -1; + } + UNREACHABLE(); // unreachable + return 0; + } + + bool monoid_can_decrease(const row_cell &rc) const { + unsigned j = rc.var(); + lp_assert(this->column_is_feasible(j)); + switch (this->m_column_types[j]) { + case column_type::free_column: + return true; + case column_type::fixed: + return false; + case column_type::lower_bound: + if (is_pos(rc.coeff())) { + return this->x_above_lower_bound(j); + } - unsigned get_number_of_basic_vars_that_might_become_inf(unsigned j) const { // consider looking at the signs here: todo - unsigned r = 0; - for (const auto & cc : this->m_A.m_columns[j]) { - unsigned k = this->m_basis[cc.var()]; - if (this->m_column_types[k] != column_type::free_column) - r++; - } - return r; - } + return true; + case column_type::upper_bound: + if (is_pos(rc.coeff())) { + return true; + } - - int find_beneficial_column_in_row_tableau_rows_bland_mode(int i, T & a_ent) { - int j = -1; - unsigned bj = this->m_basis[i]; - bool bj_needs_to_grow = needs_to_grow(bj); - for (const row_cell& rc : this->m_A.m_rows[i]) { - if (rc.var() == bj) - continue; - if (bj_needs_to_grow) { - if (!monoid_can_decrease(rc)) - continue; - } else { - if (!monoid_can_increase(rc)) - continue; - } - if (rc.var() < static_cast(j) ) { - j = rc.var(); - a_ent = rc.coeff(); - } - } - if (j == -1) { - m_inf_row_index_for_tableau = i; - } - - return j; - } - - int find_beneficial_column_in_row_tableau_rows(int i, T & a_ent) { - if (m_bland_mode_tableau) - return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); - // a short row produces short infeasibility explanation and benefits at least one pivot operation - int choice = -1; - int nchoices = 0; - unsigned num_of_non_free_basics = 1000000; - unsigned len = 100000000; - unsigned bj = this->m_basis[i]; - bool bj_needs_to_grow = needs_to_grow(bj); - for (unsigned k = 0; k < this->m_A.m_rows[i].size(); k++) { - const row_cell& rc = this->m_A.m_rows[i][k]; - unsigned j = rc.var(); - if (j == bj) - continue; - if (bj_needs_to_grow) { - if (!monoid_can_decrease(rc)) - continue; - } else { - if (!monoid_can_increase(rc)) - continue; - } - unsigned damage = get_number_of_basic_vars_that_might_become_inf(j); - if (damage < num_of_non_free_basics) { - num_of_non_free_basics = damage; - len = this->m_A.m_columns[j].size(); - choice = k; - nchoices = 1; - } else if (damage == num_of_non_free_basics && - this->m_A.m_columns[j].size() <= len && (this->m_settings.random_next() % (++nchoices))) { - choice = k; - len = this->m_A.m_columns[j].size(); - } - } - + return this->x_below_upper_bound(j); + case column_type::boxed: + if (is_pos(rc.coeff())) { + return this->x_above_lower_bound(j); + } - if (choice == -1) { - m_inf_row_index_for_tableau = i; - return -1; - } - const row_cell& rc = this->m_A.m_rows[i][choice]; - a_ent = rc.coeff(); - return rc.var(); - } - - bool try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, bool & unlimited); - bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t); - int find_leaving_and_t_tableau(unsigned entering, X & t); - - void limit_theta(const X & lim, X & theta, bool & unlimited) { - if (unlimited) { - theta = lim; - unlimited = false; - } else { - theta = std::min(lim, theta); - } - } + return this->x_below_upper_bound(j); + default: + return false; + } + UNREACHABLE(); // unreachable + return false; + } + + bool monoid_can_increase(const row_cell &rc) const { + unsigned j = rc.var(); + lp_assert(this->column_is_feasible(j)); + switch (this->m_column_types[j]) { + case column_type::free_column: + return true; + case column_type::fixed: + return false; + case column_type::lower_bound: + if (is_neg(rc.coeff())) { + return this->x_above_lower_bound(j); + } - void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m < 0 && this->m_column_types[j] == column_type::upper_bound); - limit_inf_on_upper_bound_m_neg(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); - } + return true; + case column_type::upper_bound: + if (is_neg(rc.coeff())) { + return true; + } + return this->x_below_upper_bound(j); + case column_type::boxed: + if (is_neg(rc.coeff())) { + return this->x_above_lower_bound(j); + } - void limit_theta_on_basis_column_for_inf_case_m_neg_lower_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m < 0 && this->m_column_types[j] == column_type::lower_bound); - limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_lower_bounds[j], theta, unlimited); + return this->x_below_upper_bound(j); + default: + return false; + } + UNREACHABLE(); // unreachable + return false; + } + + unsigned get_number_of_basic_vars_that_might_become_inf( + unsigned j) const { // consider looking at the signs here: todo + unsigned r = 0; + for (const auto &cc : this->m_A.m_columns[j]) { + unsigned k = this->m_basis[cc.var()]; + if (this->m_column_types[k] != column_type::free_column) + r++; + } + return r; + } + + int find_beneficial_column_in_row_tableau_rows_bland_mode(int i, T &a_ent) { + int j = -1; + unsigned bj = this->m_basis[i]; + bool bj_needs_to_grow = needs_to_grow(bj); + for (const row_cell &rc : this->m_A.m_rows[i]) { + if (rc.var() == bj) + continue; + if (bj_needs_to_grow) { + if (!monoid_can_decrease(rc)) + continue; + } else { + if (!monoid_can_increase(rc)) + continue; + } + if (rc.var() < static_cast(j)) { + j = rc.var(); + a_ent = rc.coeff(); + } } - - - void limit_theta_on_basis_column_for_inf_case_m_pos_lower_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m > 0 && this->m_column_types[j] == column_type::lower_bound); - limit_inf_on_lower_bound_m_pos(m, this->m_x[j], this->m_lower_bounds[j], theta, unlimited); + if (j == -1) { + m_inf_row_index_for_tableau = i; + } + + return j; + } + + int find_beneficial_column_in_row_tableau_rows(int i, T &a_ent) { + if (m_bland_mode_tableau) + return find_beneficial_column_in_row_tableau_rows_bland_mode(i, a_ent); + // a short row produces short infeasibility explanation and benefits at + // least one pivot operation + int choice = -1; + int nchoices = 0; + unsigned num_of_non_free_basics = 1000000; + unsigned len = 100000000; + unsigned bj = this->m_basis[i]; + bool bj_needs_to_grow = needs_to_grow(bj); + for (unsigned k = 0; k < this->m_A.m_rows[i].size(); k++) { + const row_cell &rc = this->m_A.m_rows[i][k]; + unsigned j = rc.var(); + if (j == bj) + continue; + if (bj_needs_to_grow) { + if (!monoid_can_decrease(rc)) + continue; + } else { + if (!monoid_can_increase(rc)) + continue; + } + unsigned damage = get_number_of_basic_vars_that_might_become_inf(j); + if (damage < num_of_non_free_basics) { + num_of_non_free_basics = damage; + len = this->m_A.m_columns[j].size(); + choice = k; + nchoices = 1; + } else if (damage == num_of_non_free_basics && + this->m_A.m_columns[j].size() <= len && + (this->m_settings.random_next() % (++nchoices))) { + choice = k; + len = this->m_A.m_columns[j].size(); + } } - void limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); - limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, unlimited); - }; - - void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector & leavings, T m, X & t, T & abs_of_d_of_leaving); - - X get_max_bound(vector & b); + if (choice == -1) { + m_inf_row_index_for_tableau = i; + return -1; + } + const row_cell &rc = this->m_A.m_rows[i][choice]; + a_ent = rc.coeff(); + return rc.var(); + } + + bool try_jump_to_another_bound_on_entering(unsigned entering, const X &theta, + X &t, bool &unlimited); + bool try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X &t); + int find_leaving_and_t_tableau(unsigned entering, X &t); + + void limit_theta(const X &lim, X &theta, bool &unlimited) { + if (unlimited) { + theta = lim; + unlimited = false; + } else { + theta = std::min(lim, theta); + } + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m < 0 && this->m_column_types[j] == column_type::upper_bound); + limit_inf_on_upper_bound_m_neg(m, this->m_x[j], this->m_upper_bounds[j], + theta, unlimited); + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_lower_bound( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m < 0 && this->m_column_types[j] == column_type::lower_bound); + limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_lower_bounds[j], theta, + unlimited); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_lower_bound( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m > 0 && this->m_column_types[j] == column_type::lower_bound); + limit_inf_on_lower_bound_m_pos(m, this->m_x[j], this->m_lower_bounds[j], + theta, unlimited); + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m > 0 && this->m_column_types[j] == column_type::upper_bound); + limit_inf_on_bound_m_pos(m, this->m_x[j], this->m_upper_bounds[j], theta, + unlimited); + }; + + void get_bound_on_variable_and_update_leaving_precisely( + unsigned j, vector &leavings, T m, X &t, + T &abs_of_d_of_leaving); + + X get_max_bound(vector &b); #ifdef Z3DEBUG - void check_Ax_equal_b(); - void check_the_bounds(); - void check_bound(unsigned i); - void check_correctness(); + void check_Ax_equal_b(); + void check_the_bounds(); + void check_bound(unsigned i); + void check_correctness(); #endif - // from page 183 of Istvan Maros's book - // the basis structures have not changed yet - void update_reduced_costs_from_pivot_row(unsigned entering, unsigned leaving); + // from page 183 of Istvan Maros's book + // the basis structures have not changed yet + void update_reduced_costs_from_pivot_row(unsigned entering, unsigned leaving); - // return 0 if the reduced cost at entering is close enough to the refreshed - // 1 if it is way off, and 2 if it is unprofitable - int refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering); + // return 0 if the reduced cost at entering is close enough to the refreshed + // 1 if it is way off, and 2 if it is unprofitable + int refresh_reduced_cost_at_entering_and_check_that_it_is_off( + unsigned entering); - void backup_and_normalize_costs(); + void backup_and_normalize_costs(); - void advance_on_entering_and_leaving(int entering, int leaving, X & t); - void advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t); - void advance_on_entering_equal_leaving(int entering, X & t); - void advance_on_entering_equal_leaving_tableau(int entering, X & t); + void advance_on_entering_and_leaving_tableau(int entering, int leaving, X &t); + void advance_on_entering_equal_leaving_tableau(int entering, X &t); - bool need_to_switch_costs() const { - if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows) - return false; - // lp_assert(calc_current_x_is_feasible() == current_x_is_feasible()); - return this->current_x_is_feasible() == this->using_infeas_costs(); - } + bool need_to_switch_costs() const { + if (this->m_settings.simplex_strategy() == + simplex_strategy_enum::tableau_rows) + return false; + // lp_assert(calc_current_x_is_feasible() == + // current_x_is_feasible()); + return this->current_x_is_feasible() == this->using_infeas_costs(); + } + void advance_on_entering_tableau(int entering); - void advance_on_entering(int entering); - void advance_on_entering_tableau(int entering); - void advance_on_entering_precise(int entering); - void push_forward_offset_in_non_basis(unsigned & offset_in_nb); - - unsigned get_number_of_non_basic_column_to_try_for_enter(); - - - // returns the number of iterations - unsigned solve(); - - - - void find_feasible_solution(); - - // bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;} - - void one_iteration_tableau(); - - // this version assumes that the leaving already has the right value, and does not update it - void update_x_tableau_rows(unsigned entering, unsigned leaving, const X& delta) { - this->add_delta_to_x(entering, delta); - if (!this->using_infeas_costs()) { - for (const auto & c : this->m_A.m_columns[entering]) { - if (leaving != this->m_basis[c.var()]) { - this->add_delta_to_x_and_track_feasibility(this->m_basis[c.var()], - delta * this->m_A.get_val(c)); - } - } - } else { // using_infeas_costs() == true - lp_assert(this->column_is_feasible(entering)); - lp_assert(this->m_costs[entering] == zero_of_type()); - // m_d[entering] can change because of the cost change for basic columns. - for (const auto & c : this->m_A.m_columns[entering]) { - unsigned j = this->m_basis[c.var()]; - if (j != leaving) - this->add_delta_to_x(j, -delta * this->m_A.get_val(c)); - update_inf_cost_for_column_tableau(j); - if (is_zero(this->m_costs[j])) - this->remove_column_from_inf_set(j); - else - this->insert_column_into_inf_set(j); - } - } - } - - void update_basis_and_x_tableau_rows(int entering, int leaving, X const & tt) { - lp_assert(entering != leaving); - update_x_tableau_rows(entering, leaving, tt); - this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); - this->change_basis(entering, leaving); - } + void push_forward_offset_in_non_basis(unsigned &offset_in_nb); - - void advance_on_entering_and_leaving_tableau_rows(int entering, int leaving, const X &theta ) { - update_basis_and_x_tableau_rows(entering, leaving, theta); - this->track_column_feasibility(entering); - } + unsigned get_number_of_non_basic_column_to_try_for_enter(); - int find_smallest_inf_column() { - int j = -1; - for (unsigned k : this->inf_set()) { - if (k < static_cast(j)) { - j = k; - } - } - return j; - } + // returns the number of iterations + unsigned solve(); - const X& get_val_for_leaving(unsigned j) const { - lp_assert(!this->column_is_feasible(j)); - switch (this->m_column_types[j]) { - case column_type::fixed: - case column_type::upper_bound: - return this->m_upper_bounds[j]; - case column_type::lower_bound: - return this->m_lower_bounds[j]; - break; - case column_type::boxed: - if (this->x_above_upper_bound(j)) - return this->m_upper_bounds[j]; - else - return this->m_lower_bounds[j]; - break; - default: - UNREACHABLE(); - return this->m_lower_bounds[j]; - } - } - - - void one_iteration_tableau_rows() { - int leaving = find_smallest_inf_column(); - if (leaving == -1) { - this->set_status(lp_status::OPTIMAL); - return; - } - - SASSERT(this->column_is_base(leaving)); - - if (!m_bland_mode_tableau) { - if (m_left_basis_tableau.contains(leaving)) { - if (++m_left_basis_repeated > m_bland_mode_threshold) { - m_bland_mode_tableau = true; - } - } else { - m_left_basis_tableau.insert(leaving); - } - } - T a_ent; - int entering = find_beneficial_column_in_row_tableau_rows(this->m_basis_heading[leaving], a_ent); - if (entering == -1) { - this->set_status(lp_status::INFEASIBLE); - return; - } - const X& new_val_for_leaving = get_val_for_leaving(leaving); - X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; - this->m_x[leaving] = new_val_for_leaving; - this->remove_column_from_inf_set(leaving); - advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta ); - if (this->current_x_is_feasible()) - this->set_status(lp_status::OPTIMAL); - } - - void decide_on_status_when_cannot_find_entering() { - lp_assert(!need_to_switch_costs()); - this->set_status(this->current_x_is_feasible()? lp_status::OPTIMAL: lp_status::INFEASIBLE); - } + void find_feasible_solution(); - void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m < 0); - limit_theta((this->m_lower_bounds[j] - this->m_x[j]) / m, theta, unlimited); - if (theta < zero_of_type()) theta = zero_of_type(); - } + // bool is_tiny() const {return this->m_m < 10 && this->m_n < 20;} - bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { - // x gets smaller - lp_assert(m < 0); - if (this->below_bound(x, bound)) return false; - if (this->above_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; - } - return true; - } + void one_iteration_tableau(); - bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { - // x gets larger - lp_assert(m > 0); - if (this->above_bound(x, bound)) return false; - if (this->below_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); - } else { - theta = zero_of_type(); - unlimited = false; + // this version assumes that the leaving already has the right value, and does + // not update it + void update_x_tableau_rows(unsigned entering, unsigned leaving, + const X &delta) { + this->add_delta_to_x(entering, delta); + if (!this->using_infeas_costs()) { + for (const auto &c : this->m_A.m_columns[entering]) { + if (leaving != this->m_basis[c.var()]) { + this->add_delta_to_x_and_track_feasibility( + this->m_basis[c.var()], -delta * this->m_A.get_val(c)); } - - return true; + } + } else { // using_infeas_costs() == true + lp_assert(this->column_is_feasible(entering)); + lp_assert(this->m_costs[entering] == zero_of_type()); + // m_d[entering] can change because of the cost change for basic columns. + for (const auto &c : this->m_A.m_columns[entering]) { + unsigned j = this->m_basis[c.var()]; + if (j != leaving) + this->add_delta_to_x(j, -delta * this->m_A.get_val(c)); + update_inf_cost_for_column_tableau(j); + if (is_zero(this->m_costs[j])) + this->remove_column_from_inf_set(j); + else + this->insert_column_into_inf_set(j); + } } - - void limit_inf_on_lower_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { - // x gets larger - lp_assert(m > 0); - if (this->below_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); + } + + void update_basis_and_x_tableau_rows(int entering, int leaving, X const &tt) { + lp_assert(entering != leaving); + update_x_tableau_rows(entering, leaving, tt); + this->pivot_column_tableau(entering, this->m_basis_heading[leaving]); + this->change_basis(entering, leaving); + } + + void advance_on_entering_and_leaving_tableau_rows(int entering, int leaving, + const X &theta) { + update_basis_and_x_tableau_rows(entering, leaving, theta); + this->track_column_feasibility(entering); + } + + int find_smallest_inf_column() { + int j = -1; + for (unsigned k : this->inf_set()) { + if (k < static_cast(j)) { + j = k; } - } - - void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) { - // x gets smaller - lp_assert(m < 0); - if (this->above_bound(x, bound)) { - limit_theta((bound - x) / m, theta, unlimited); + return j; + } + + const X &get_val_for_leaving(unsigned j) const { + lp_assert(!this->column_is_feasible(j)); + switch (this->m_column_types[j]) { + case column_type::fixed: + case column_type::upper_bound: + return this->m_upper_bounds[j]; + case column_type::lower_bound: + return this->m_lower_bounds[j]; + break; + case column_type::boxed: + if (this->x_above_upper_bound(j)) + return this->m_upper_bounds[j]; + else + return this->m_lower_bounds[j]; + break; + default: + UNREACHABLE(); + return this->m_lower_bounds[j]; + } + } + + void one_iteration_tableau_rows() { + int leaving = find_smallest_inf_column(); + if (leaving == -1) { + this->set_status(lp_status::OPTIMAL); + return; + } + + SASSERT(this->column_is_base(leaving)); + + if (!m_bland_mode_tableau) { + if (m_left_basis_tableau.contains(leaving)) { + if (++m_left_basis_repeated > m_bland_mode_threshold) { + m_bland_mode_tableau = true; } + } else { + m_left_basis_tableau.insert(leaving); + } } - - void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - const X & x = this->m_x[j]; - const X & lbound = this->m_lower_bounds[j]; - - if (this->below_bound(x, lbound)) { - limit_theta((lbound - x) / m, theta, unlimited); + T a_ent; + int entering = find_beneficial_column_in_row_tableau_rows( + this->m_basis_heading[leaving], a_ent); + if (entering == -1) { + this->set_status(lp_status::INFEASIBLE); + return; + } + const X &new_val_for_leaving = get_val_for_leaving(leaving); + X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent; + this->m_x[leaving] = new_val_for_leaving; + this->remove_column_from_inf_set(leaving); + advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta); + if (this->current_x_is_feasible()) + this->set_status(lp_status::OPTIMAL); + } + + void decide_on_status_when_cannot_find_entering() { + lp_assert(!need_to_switch_costs()); + this->set_status(this->current_x_is_feasible() ? lp_status::OPTIMAL + : lp_status::INFEASIBLE); + } + + void limit_theta_on_basis_column_for_feas_case_m_neg_no_check( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m < 0); + limit_theta((this->m_lower_bounds[j] - this->m_x[j]) / m, theta, unlimited); + if (theta < zero_of_type()) + theta = zero_of_type(); + } + + bool limit_inf_on_bound_m_neg(const T &m, const X &x, const X &bound, + X &theta, bool &unlimited) { + // x gets smaller + lp_assert(m < 0); + if (this->below_bound(x, bound)) + return false; + if (this->above_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); + } else { + theta = zero_of_type(); + unlimited = false; + } + return true; + } + + bool limit_inf_on_bound_m_pos(const T &m, const X &x, const X &bound, + X &theta, bool &unlimited) { + // x gets larger + lp_assert(m > 0); + if (this->above_bound(x, bound)) + return false; + if (this->below_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); + } else { + theta = zero_of_type(); + unlimited = false; + } + + return true; + } + + void limit_inf_on_lower_bound_m_pos(const T &m, const X &x, const X &bound, + X &theta, bool &unlimited) { + // x gets larger + lp_assert(m > 0); + if (this->below_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); + } + } + + void limit_inf_on_upper_bound_m_neg(const T &m, const X &x, const X &bound, + X &theta, bool &unlimited) { + // x gets smaller + lp_assert(m < 0); + if (this->above_bound(x, bound)) { + limit_theta((bound - x) / m, theta, unlimited); + } + } + + void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, + const T &m, + X &theta, + bool &unlimited) { + const X &x = this->m_x[j]; + const X &lbound = this->m_lower_bounds[j]; + + if (this->below_bound(x, lbound)) { + limit_theta((lbound - x) / m, theta, unlimited); + } else { + const X &ubound = this->m_upper_bounds[j]; + if (this->below_bound(x, ubound)) { + limit_theta((ubound - x) / m, theta, unlimited); + } else if (!this->above_bound(x, ubound)) { + theta = zero_of_type(); + unlimited = false; + } + } + } + + void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, + const T &m, + X &theta, + bool &unlimited) { + // lp_assert(m < 0 && this->m_column_type[j] == column_type::boxed); + const X &x = this->m_x[j]; + const X &ubound = this->m_upper_bounds[j]; + if (this->above_bound(x, ubound)) { + limit_theta((ubound - x) / m, theta, unlimited); + } else { + const X &lbound = this->m_lower_bounds[j]; + if (this->above_bound(x, lbound)) { + limit_theta((lbound - x) / m, theta, unlimited); + } else if (!this->below_bound(x, lbound)) { + theta = zero_of_type(); + unlimited = false; + } + } + } + + void limit_theta_on_basis_column_for_feas_case_m_pos_no_check( + unsigned j, const T &m, X &theta, bool &unlimited) { + lp_assert(m > 0); + limit_theta((this->m_upper_bounds[j] - this->m_x[j]) / m, theta, unlimited); + if (theta < zero_of_type()) { + theta = zero_of_type(); + } + } + + // j is a basic column or the entering, in any case x[j] has to stay feasible. + // m is the multiplier. updating t in a way that holds the following + // x[j] + t * m >= this->m_lower_bounds[j]( if m < 0 ) + // or + // x[j] + t * m <= this->m_upper_bounds[j] ( if m > 0) + void limit_theta_on_basis_column(unsigned j, T m, X &theta, bool &unlimited) { + switch (this->m_column_types[j]) { + case column_type::free_column: + break; + case column_type::upper_bound: + if (this->current_x_is_feasible()) { + if (m > 0) + limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta, + unlimited); + } else { // inside of feasibility_loop + if (m > 0) + limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound( + j, m, theta, unlimited); + else + limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound( + j, m, theta, unlimited); + } + break; + case column_type::lower_bound: + if (this->current_x_is_feasible()) { + if (m < 0) + limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta, + unlimited); + } else { + if (m < 0) + limit_theta_on_basis_column_for_inf_case_m_neg_lower_bound( + j, m, theta, unlimited); + else + limit_theta_on_basis_column_for_inf_case_m_pos_lower_bound( + j, m, theta, unlimited); + } + break; + // case fixed: + // if (get_this->current_x_is_feasible()) { + // theta = zero_of_type(); + // break; + // } + // if (m < 0) + // limit_theta_on_basis_column_for_inf_case_m_neg_fixed(j, m, + // theta); + // else + // limit_theta_on_basis_column_for_inf_case_m_pos_fixed(j, m, + // theta); + // break; + case column_type::fixed: + case column_type::boxed: + if (this->current_x_is_feasible()) { + if (m > 0) { + limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta, + unlimited); } else { - const X & ubound = this->m_upper_bounds[j]; - if (this->below_bound(x, ubound)){ - limit_theta((ubound - x) / m, theta, unlimited); - } else if (!this->above_bound(x, ubound)) { - theta = zero_of_type(); - unlimited = false; - } + limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta, + unlimited); } - } - - void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) { - // lp_assert(m < 0 && this->m_column_type[j] == column_type::boxed); - const X & x = this->m_x[j]; - const X & ubound = this->m_upper_bounds[j]; - if (this->above_bound(x, ubound)) { - limit_theta((ubound - x) / m, theta, unlimited); + } else { + if (m > 0) { + limit_theta_on_basis_column_for_inf_case_m_pos_boxed(j, m, theta, + unlimited); } else { - const X & lbound = this->m_lower_bounds[j]; - if (this->above_bound(x, lbound)){ - limit_theta((lbound - x) / m, theta, unlimited); - } else if (!this->below_bound(x, lbound)) { - theta = zero_of_type(); - unlimited = false; - } + limit_theta_on_basis_column_for_inf_case_m_neg_boxed(j, m, theta, + unlimited); } + } + + break; + default: + UNREACHABLE(); } - void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) { - lp_assert(m > 0); - if (this->below_bound(this->m_x[j], this->m_upper_bounds[j])) { - limit_theta((this->m_upper_bounds[j] - this->m_x[j]) / m, theta, unlimited); - if (theta < zero_of_type()) { - theta = zero_of_type(); - unlimited = false; - } - } + if (!unlimited && theta < zero_of_type()) { + theta = zero_of_type(); } + } - void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) { - lp_assert(m > 0); - limit_theta( (this->m_upper_bounds[j] - this->m_x[j]) / m, theta, unlimited); - if (theta < zero_of_type()) { - theta = zero_of_type(); - } - } + bool column_is_benefitial_for_entering_basis(unsigned j) const; + void init_infeasibility_costs(); - // j is a basic column or the entering, in any case x[j] has to stay feasible. - // m is the multiplier. updating t in a way that holds the following - // x[j] + t * m >= this->m_lower_bounds[j]( if m < 0 ) - // or - // x[j] + t * m <= this->m_upper_bounds[j] ( if m > 0) - void limit_theta_on_basis_column(unsigned j, T m, X & theta, bool & unlimited) { - switch (this->m_column_types[j]) { - case column_type::free_column: break; - case column_type::upper_bound: - if (this->current_x_is_feasible()) { - if (m > 0) - limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta, unlimited); - } else { // inside of feasibility_loop - if (m > 0) - limit_theta_on_basis_column_for_inf_case_m_pos_upper_bound(j, m, theta, unlimited); - else - limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(j, m, theta, unlimited); - } - break; - case column_type::lower_bound: - if (this->current_x_is_feasible()) { - if (m < 0) - limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta, unlimited); - } else { - if (m < 0) - limit_theta_on_basis_column_for_inf_case_m_neg_lower_bound(j, m, theta, unlimited); - else - limit_theta_on_basis_column_for_inf_case_m_pos_lower_bound(j, m, theta, unlimited); - } - break; - // case fixed: - // if (get_this->current_x_is_feasible()) { - // theta = zero_of_type(); - // break; - // } - // if (m < 0) - // limit_theta_on_basis_column_for_inf_case_m_neg_fixed(j, m, theta); - // else - // limit_theta_on_basis_column_for_inf_case_m_pos_fixed(j, m, theta); - // break; - case column_type::fixed: - case column_type::boxed: - if (this->current_x_is_feasible()) { - if (m > 0) { - limit_theta_on_basis_column_for_feas_case_m_pos_no_check(j, m, theta, unlimited); - } else { - limit_theta_on_basis_column_for_feas_case_m_neg_no_check(j, m, theta, unlimited); - } - } else { - if (m > 0) { - limit_theta_on_basis_column_for_inf_case_m_pos_boxed(j, m, theta, unlimited); - } else { - limit_theta_on_basis_column_for_inf_case_m_neg_boxed(j, m, theta, unlimited); - } - } - - break; - default: - lp_unreachable(); - } - if (!unlimited && theta < zero_of_type()) { - theta = zero_of_type(); - } - } + void init_infeasibility_cost_for_column(unsigned j); + T get_infeasibility_cost_for_column(unsigned j) const; + void init_infeasibility_costs_for_changed_basis_only(); - - bool column_is_benefitial_for_entering_basis(unsigned j) const; - bool column_is_benefitial_for_entering_basis_precise(unsigned j) const; - bool can_enter_basis(unsigned j); - void init_infeasibility_costs(); - - void init_infeasibility_cost_for_column(unsigned j); - T get_infeasibility_cost_for_column(unsigned j) const; - void init_infeasibility_costs_for_changed_basis_only(); - - void print_column(unsigned j, std::ostream & out); - - void print_bound_info_and_x(unsigned j, std::ostream & out); - - bool basis_column_is_set_correctly(unsigned j) const { - return this->m_A.m_columns[j].size() == 1; - - } - - bool basis_columns_are_set_correctly() const { - for (unsigned j : this->m_basis) - if(!basis_column_is_set_correctly(j)) - return false; - - return this->m_basis_heading.size() == this->m_A.column_count() && this->m_basis.size() == this->m_A.row_count(); - } + void print_column(unsigned j, std::ostream &out); - void init_run_tableau(); - void update_x_tableau(unsigned entering, const X & delta); - void update_inf_cost_for_column_tableau(unsigned j); - -// the delta is between the old and the new cost (old - new) - void update_reduced_cost_for_basic_column_cost_change(const T & delta, unsigned j) { - lp_assert(this->m_basis_heading[j] >= 0); - unsigned i = static_cast(this->m_basis_heading[j]); - for (const row_cell & rc : this->m_A.m_rows[i]) { - unsigned k = rc.var(); - if (k == j) - continue; - this->m_d[k] += delta * rc.coeff(); - } - } - - bool update_basis_and_x_tableau(int entering, int leaving, X const & tt); - void init_reduced_costs_tableau(); - void init_tableau_rows() { - m_bland_mode_tableau = false; - m_left_basis_tableau.clear(); - m_left_basis_tableau.resize(this->m_A.column_count()); - m_left_basis_repeated = 0; - } -// stage1 constructor - lp_primal_core_solver(static_matrix & A, - vector & b, // the right side vector - vector & x, // the number of elements in x needs to be at least as large as the number of columns in A - vector & basis, - vector & nbasis, - vector & heading, - vector & costs, - const vector & column_type_array, - const vector & lower_bound_values, - const vector & upper_bound_values, - lp_settings & settings, - const column_namer& column_names): - lp_core_solver_base(A, // b, - basis, - nbasis, - heading, - x, - costs, - settings, - column_names, - column_type_array, - lower_bound_values, - upper_bound_values), - m_bland_mode_threshold(1000) { - this->set_status(lp_status::UNKNOWN); - } + void print_bound_info_and_x(unsigned j, std::ostream &out); - + bool basis_column_is_set_correctly(unsigned j) const { + return this->m_A.m_columns[j].size() == 1; + } - bool initial_x_is_correct() { - std::set basis_set; - for (unsigned i = 0; i < this->m_A.row_count(); i++) { - basis_set.insert(this->m_basis[i]); - } - for (unsigned j = 0; j < this->m_n(); j++) { - if (this->column_has_lower_bound(j) && this->m_x[j] < numeric_traits::zero()) { - LP_OUT(this->m_settings, "low bound for variable " << j << " does not hold: this->m_x[" << j << "] = " << this->m_x[j] << " is negative " << std::endl); - return false; - } - - if (this->column_has_upper_bound(j) && this->m_x[j] > this->m_upper_bounds[j]) { - LP_OUT(this->m_settings, "upper bound for " << j << " does not hold: " << this->m_upper_bounds[j] << ">" << this->m_x[j] << std::endl); - return false; - } - - if (basis_set.find(j) != basis_set.end()) continue; - if (this->m_column_types[j] == column_type::lower_bound) { - if (numeric_traits::zero() != this->m_x[j]) { - LP_OUT(this->m_settings, "only low bound is set for " << j << " but low bound value " << numeric_traits::zero() << " is not equal to " << this->m_x[j] << std::endl); - return false; - } - } - if (this->m_column_types[j] == column_type::boxed) { - if (this->m_upper_bounds[j] != this->m_x[j] && !numeric_traits::is_zero(this->m_x[j])) { - return false; - } - } - } - return true; - } + bool basis_columns_are_set_correctly() const { + for (unsigned j : this->m_basis) + if (!basis_column_is_set_correctly(j)) + return false; + return this->m_basis_heading.size() == this->m_A.column_count() && + this->m_basis.size() == this->m_A.row_count(); + } + + void init_run_tableau(); + void update_x_tableau(unsigned entering, const X &delta); + void update_inf_cost_for_column_tableau(unsigned j); + + // the delta is between the old and the new cost (old - new) + void update_reduced_cost_for_basic_column_cost_change(const T &delta, + unsigned j) { + lp_assert(this->m_basis_heading[j] >= 0); + unsigned i = static_cast(this->m_basis_heading[j]); + for (const row_cell &rc : this->m_A.m_rows[i]) { + unsigned k = rc.var(); + if (k == j) + continue; + this->m_d[k] += delta * rc.coeff(); + } + } + + bool update_basis_and_x_tableau(int entering, int leaving, X const &tt); + void init_reduced_costs_tableau(); + void init_tableau_rows() { + m_bland_mode_tableau = false; + m_left_basis_tableau.clear(); + m_left_basis_tableau.resize(this->m_A.column_count()); + m_left_basis_repeated = 0; + } + // stage1 constructor + lp_primal_core_solver( + static_matrix &A, + vector &b, // the right side vector + vector &x, // the number of elements in x needs to be at least as large + // as the number of columns in A + vector &basis, vector &nbasis, vector &heading, + vector &costs, const vector &column_type_array, + const vector &lower_bound_values, const vector &upper_bound_values, + lp_settings &settings, const column_namer &column_names) + : lp_core_solver_base(A, // b, + basis, nbasis, heading, x, costs, settings, + column_names, column_type_array, + lower_bound_values, upper_bound_values), + m_bland_mode_threshold(1000) { + this->set_status(lp_status::UNKNOWN); + } - friend core_solver_pretty_printer; + friend core_solver_pretty_printer; }; -} +} // namespace lp diff --git a/src/math/lp/lp_primal_core_solver_def.h b/src/math/lp/lp_primal_core_solver_def.h index cc8ad88b392..4ee8305fa1a 100644 --- a/src/math/lp/lp_primal_core_solver_def.h +++ b/src/math/lp/lp_primal_core_solver_def.h @@ -53,10 +53,6 @@ void lp_primal_core_solver::sort_non_basis() { template bool lp_primal_core_solver::column_is_benefitial_for_entering_basis(unsigned j) const { - return column_is_benefitial_for_entering_basis_precise(j); -} -template -bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precise(unsigned j) const { const T& dj = this->m_d[j]; TRACE("lar_solver", tout << "dj=" << dj << "\n";); switch (this->m_column_types[j]) { @@ -88,56 +84,12 @@ bool lp_primal_core_solver::column_is_benefitial_for_entering_basis_precis } break; default: - lp_unreachable(); + UNREACHABLE(); break; } return false; } -template -int lp_primal_core_solver::choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - if (number_of_benefitial_columns_to_go_over == 0) - return -1; - if (this->m_basis_sort_counter == 0) { - sort_non_basis(); - this->m_basis_sort_counter = 20; - } - else { - this->m_basis_sort_counter--; - } - unsigned j_nz = this->m_m() + 1; // this number is greater than the max column size - std::list::iterator entering_iter = m_non_basis_list.end(); - for (auto non_basis_iter = m_non_basis_list.begin(); number_of_benefitial_columns_to_go_over && non_basis_iter != m_non_basis_list.end(); ++non_basis_iter) { - unsigned j = *non_basis_iter; - if (!column_is_benefitial_for_entering_basis(j)) - continue; - - // if we are here then j is a candidate to enter the basis - unsigned t = this->m_columns_nz[j]; - if (t < j_nz) { - j_nz = t; - entering_iter = non_basis_iter; - if (number_of_benefitial_columns_to_go_over) - number_of_benefitial_columns_to_go_over--; - } else if (t == j_nz && this->m_settings.random_next() % 2 == 0) { - entering_iter = non_basis_iter; - } - }// while (number_of_benefitial_columns_to_go_over && initial_offset_in_non_basis != offset_in_nb); - if (entering_iter == m_non_basis_list.end()) - return -1; - unsigned entering = *entering_iter; - m_sign_of_entering_delta = this->m_d[entering] > 0 ? 1 : -1; - m_non_basis_list.erase(entering_iter); - m_non_basis_list.push_back(entering); - return entering; -} - - -template -int lp_primal_core_solver::choose_entering_column(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1) - return choose_entering_column_presize(number_of_benefitial_columns_to_go_over); -} - template bool lp_primal_core_solver::try_jump_to_another_bound_on_entering(unsigned entering, const X & theta, X & t, @@ -278,24 +230,6 @@ template void lp_primal_core_solver::backup_an -template -void lp_primal_core_solver::advance_on_entering_equal_leaving(int entering, X & t) { - -} - -template void lp_primal_core_solver::advance_on_entering_and_leaving(int entering, int leaving, X & t) { - -} - - -template void lp_primal_core_solver::advance_on_entering_precise(int entering) { - lp_assert(false); -} - -template void lp_primal_core_solver::advance_on_entering(int entering) { - lp_assert(false); -} - template void lp_primal_core_solver::push_forward_offset_in_non_basis(unsigned & offset_in_nb) { if (++offset_in_nb == this->m_nbasis.size()) offset_in_nb = 0; @@ -377,7 +311,7 @@ lp_primal_core_solver::get_infeasibility_cost_for_column(unsigned j) const ret = numeric_traits::zero(); break; default: - lp_assert(false); + UNREACHABLE(); ret = numeric_traits::zero(); // does not matter break; } @@ -427,7 +361,7 @@ lp_primal_core_solver::init_infeasibility_cost_for_column(unsigned j) { this->m_costs[j] = numeric_traits::zero(); break; default: - lp_assert(false); + UNREACHABLE(); break; } @@ -458,7 +392,7 @@ template void lp_primal_core_solver::print_column out << "( _" << this->m_x[j] << "_)" << std::endl; break; default: - lp_unreachable(); + UNREACHABLE(); } } @@ -480,7 +414,7 @@ template void lp_primal_core_solver::print_bound_ out << "inf, inf" << std::endl; break; default: - lp_assert(false); + UNREACHABLE(); break; } } diff --git a/src/math/lp/lp_primal_core_solver_tableau_def.h b/src/math/lp/lp_primal_core_solver_tableau_def.h index c7b604b9553..241164c023f 100644 --- a/src/math/lp/lp_primal_core_solver_tableau_def.h +++ b/src/math/lp/lp_primal_core_solver_tableau_def.h @@ -122,7 +122,7 @@ unsigned lp_primal_core_solver::solve() { } break; case lp_status::TENTATIVE_UNBOUNDED: - lp_assert(false); + UNREACHABLE(); break; case lp_status::UNBOUNDED: if (this->current_x_is_infeasible()) { @@ -132,7 +132,7 @@ unsigned lp_primal_core_solver::solve() { break; case lp_status::UNSTABLE: - lp_assert(false); + UNREACHABLE(); break; default: diff --git a/src/math/lp/lp_settings_def.h b/src/math/lp/lp_settings_def.h index a439466d18c..a19558949c3 100644 --- a/src/math/lp/lp_settings_def.h +++ b/src/math/lp/lp_settings_def.h @@ -31,7 +31,7 @@ std::string column_type_to_string(column_type t) { case column_type::lower_bound: return "lower_bound"; case column_type::upper_bound: return "upper_bound"; case column_type::free_column: return "free_column"; - default: lp_unreachable(); + default: UNREACHABLE(); } return "unknown"; // it is unreachable } @@ -50,7 +50,7 @@ const char* lp_status_to_string(lp_status status) { case lp_status::UNSTABLE: return "UNSTABLE"; case lp_status::CANCELLED: return "CANCELLED"; default: - lp_unreachable(); + UNREACHABLE(); } return "UNKNOWN"; // it is unreachable } @@ -63,7 +63,7 @@ lp_status lp_status_from_string(std::string status) { if (status == "FEASIBLE") return lp_status::FEASIBLE; if (status == "TIME_EXHAUSTED") return lp_status::TIME_EXHAUSTED; if (status == "EMPTY") return lp_status::EMPTY; - lp_unreachable(); + UNREACHABLE(); return lp_status::UNKNOWN; // it is unreachable } diff --git a/src/math/lp/lp_utils.h b/src/math/lp/lp_utils.h index ad5ba380d91..3c1383cb39e 100644 --- a/src/math/lp/lp_utils.h +++ b/src/math/lp/lp_utils.h @@ -141,7 +141,6 @@ inline void throw_exception(std::string && str) { typedef z3_exception exception; #define lp_assert(_x_) { SASSERT(_x_); } -inline void lp_unreachable() { lp_assert(false); } template inline X zero_of_type() { return numeric_traits::zero(); } template inline X one_of_type() { return numeric_traits::one(); } template inline bool is_zero(const X & v) { return numeric_traits::is_zero(v); } diff --git a/src/math/lp/nra_solver.cpp b/src/math/lp/nra_solver.cpp index 56a84d1f0d7..1f4e0b76abb 100644 --- a/src/math/lp/nra_solver.cpp +++ b/src/math/lp/nra_solver.cpp @@ -171,7 +171,7 @@ struct solver::imp { lit = m_nlsat->mk_ineq_literal(nlsat::atom::kind::EQ, 1, ps, is_even); break; default: - lp_assert(false); // unreachable + UNREACHABLE(); // unreachable } m_nlsat->mk_clause(1, &lit, a); } diff --git a/src/math/lp/numeric_pair.h b/src/math/lp/numeric_pair.h index a64825cd8f1..25127400627 100644 --- a/src/math/lp/numeric_pair.h +++ b/src/math/lp/numeric_pair.h @@ -107,8 +107,8 @@ class numeric_traits { template struct convert_struct { static X convert(const Y & y){ return X(y);} - static bool below_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false;} - static bool above_bound_numeric(const X &, const X &, const Y &) { /*lp_unreachable();*/ return false; } + static bool below_bound_numeric(const X &, const X &, const Y &) { /*UNREACHABLE();*/ return false;} + static bool above_bound_numeric(const X &, const X &, const Y &) { /*UNREACHABLE();*/ return false; } }; @@ -190,7 +190,7 @@ struct numeric_pair { } numeric_pair operator/(const numeric_pair &) const { - // lp_unreachable(); + // UNREACHABLE(); } @@ -199,7 +199,7 @@ struct numeric_pair { } numeric_pair operator*(const numeric_pair & /*a*/) const { - // lp_unreachable(); + // UNREACHABLE(); } numeric_pair& operator+=(const numeric_pair & a) { @@ -275,14 +275,14 @@ numeric_pair operator/(const numeric_pair & r, const X & a) { return numeric_pair(r.x / a, r.y / a); } -template double get_double(const lp::numeric_pair & ) { /* lp_unreachable(); */ return 0;} +template double get_double(const lp::numeric_pair & ) { /* UNREACHABLE(); */ return 0;} template class numeric_traits> { public: static lp::numeric_pair zero() { return lp::numeric_pair(numeric_traits::zero(), numeric_traits::zero()); } static bool is_zero(const lp::numeric_pair & v) { return numeric_traits::is_zero(v.x) && numeric_traits::is_zero(v.y); } static double get_double(const lp::numeric_pair & v){ return numeric_traits::get_double(v.x); } // just return the double of the first coordinate - static double one() { /*lp_unreachable();*/ return 0;} + static double one() { /*UNREACHABLE();*/ return 0;} static bool is_pos(const numeric_pair &p) { return numeric_traits::is_pos(p.x) || (numeric_traits::is_zero(p.x) && numeric_traits::is_pos(p.y)); diff --git a/src/math/lp/static_matrix.cpp b/src/math/lp/static_matrix.cpp index 28a23b0c394..efb6e07cf75 100644 --- a/src/math/lp/static_matrix.cpp +++ b/src/math/lp/static_matrix.cpp @@ -31,7 +31,6 @@ template std::set> lp::static_matrix::add_column_to_vector(mpq const&, unsigned int, mpq*) const; template void static_matrix::add_columns_at_the_end(unsigned int); template bool static_matrix::is_correct() const; -template void static_matrix::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; template mpq static_matrix::get_balance() const; template mpq static_matrix::get_elem(unsigned int, unsigned int) const; @@ -47,7 +46,6 @@ template static_matrix::static_matrix(unsigned int, unsigned int); #ifdef Z3DEBUG template bool static_matrix >::is_correct() const; #endif -template void static_matrix >::copy_column_to_indexed_vector(unsigned int, indexed_vector&) const; template mpq static_matrix >::get_elem(unsigned int, unsigned int) const; template void static_matrix >::init_empty_matrix(unsigned int, unsigned int); template void static_matrix >::set(unsigned int, unsigned int, mpq const&); diff --git a/src/math/lp/static_matrix.h b/src/math/lp/static_matrix.h index d7e4370a344..f79ff36ac38 100644 --- a/src/math/lp/static_matrix.h +++ b/src/math/lp/static_matrix.h @@ -168,8 +168,6 @@ class static_matrix std::set> get_domain(); - void copy_column_to_indexed_vector(unsigned j, indexed_vector & v) const; - T get_max_abs_in_row(unsigned row) const; void add_column_to_vector (const T & a, unsigned j, T * v) const { for (const auto & it : m_columns[j]) { @@ -222,7 +220,7 @@ class static_matrix virtual void set_number_of_columns(unsigned /*n*/) { } #endif - T get_max_val_in_row(unsigned /* i */) const { lp_unreachable(); } + T get_max_val_in_row(unsigned /* i */) const { UNREACHABLE(); } T get_balance() const; diff --git a/src/math/lp/static_matrix_def.h b/src/math/lp/static_matrix_def.h index af2eac36017..76c1dec546c 100644 --- a/src/math/lp/static_matrix_def.h +++ b/src/math/lp/static_matrix_def.h @@ -174,14 +174,6 @@ std::set> static_matrix::get_domain() { return ret; } -template void static_matrix::copy_column_to_indexed_vector (unsigned j, indexed_vector & v) const { - lp_assert(j < m_columns.size()); - for (auto & it : m_columns[j]) { - const T& val = get_val(it); - if (!is_zero(val)) - v.set_value(val, it.var()); - } -} template T static_matrix::get_max_abs_in_row(unsigned row) const { T ret = numeric_traits::zero(); diff --git a/src/test/lp/gomory_test.h b/src/test/lp/gomory_test.h index 890ff90e352..c64c0103653 100644 --- a/src/test/lp/gomory_test.h +++ b/src/test/lp/gomory_test.h @@ -130,7 +130,7 @@ struct gomory_test { void report_conflict_from_gomory_cut(mpq &k) { - lp_assert(false); + UNREACHABLE(); } void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq &lcm_den) { diff --git a/src/test/lp/lp.cpp b/src/test/lp/lp.cpp index 8ad73f0c003..9120d64cfdf 100644 --- a/src/test/lp/lp.cpp +++ b/src/test/lp/lp.cpp @@ -1365,7 +1365,7 @@ void test_gomory_cut_0() { if (j == 2) return zero_of_type(); if (j == 3) return mpq(3); - lp_assert(false); + UNREACHABLE(); return zero_of_type(); }, [](unsigned j) { // at_low_p @@ -1375,7 +1375,7 @@ void test_gomory_cut_0() { return true; if (j == 3) return true; - lp_assert(false); + UNREACHABLE(); return false; }, [](unsigned j) { // at_upper @@ -1385,31 +1385,31 @@ void test_gomory_cut_0() { return true; if (j == 3) return false; - lp_assert(false); + UNREACHABLE(); return false; }, [](unsigned j) { // lower_bound if (j == 1) { - lp_assert(false); //unlimited from below + UNREACHABLE(); //unlimited from below return impq(0); } if (j == 2) return impq(0); if (j == 3) return impq(3); - lp_assert(false); + UNREACHABLE(); return impq(0); }, [](unsigned j) { // upper if (j == 1) { - lp_assert(false); //unlimited from above + UNREACHABLE(); //unlimited from above return impq(0); } if (j == 2) return impq(0); if (j == 3) return impq(10); - lp_assert(false); + UNREACHABLE(); return impq(0); }, [] (unsigned) { return 0; }, @@ -1437,7 +1437,7 @@ void test_gomory_cut_1() { return mpq(4363334, 2730001); if (j == 3) return mpq(1); - lp_assert(false); + UNREACHABLE(); return zero_of_type(); }, [](unsigned j) { // at_low_p @@ -1447,7 +1447,7 @@ void test_gomory_cut_1() { return false; if (j == 3) return true; - lp_assert(false); + UNREACHABLE(); return false; }, [](unsigned j) { // at_upper @@ -1457,19 +1457,19 @@ void test_gomory_cut_1() { return false; if (j == 3) return true; - lp_assert(false); + UNREACHABLE(); return false; }, [](unsigned j) { // lower_bound if (j == 1) { - lp_assert(false); //unlimited from below + UNREACHABLE(); //unlimited from below return impq(0); } if (j == 2) return impq(1); if (j == 3) return impq(1); - lp_assert(false); + UNREACHABLE(); return impq(0); }, [](unsigned j) { // upper @@ -1480,7 +1480,7 @@ void test_gomory_cut_1() { return impq(3333); if (j == 3) return impq(10000); - lp_assert(false); + UNREACHABLE(); return impq(0); }, [] (unsigned) { return 0; }, diff --git a/src/test/lp/smt_reader.h b/src/test/lp/smt_reader.h index 75edb23b987..7843d5714d2 100644 --- a/src/test/lp/smt_reader.h +++ b/src/test/lp/smt_reader.h @@ -272,7 +272,7 @@ namespace lp { } else if (el.m_head == "+") { add_sum(c, el.m_elems); } else { - lp_assert(false); // unexpected input + UNREACHABLE(); // unexpected input } }