mirror of
				https://github.com/Z3Prover/z3
				synced 2025-11-04 05:19:11 +00:00 
			
		
		
		
	Merge pull request #1716 from Z3Prover/lev
integrate theory_lra with master
This commit is contained in:
		
						commit
						5e0da456a9
					
				
					 161 changed files with 14252 additions and 9293 deletions
				
			
		| 
						 | 
				
			
			@ -115,7 +115,6 @@ void prove_example1() {
 | 
			
		|||
*/
 | 
			
		||||
void prove_example2() {
 | 
			
		||||
    std::cout << "prove_example1\n";
 | 
			
		||||
    
 | 
			
		||||
    context c;
 | 
			
		||||
    expr x      = c.int_const("x");
 | 
			
		||||
    expr y      = c.int_const("y");
 | 
			
		||||
| 
						 | 
				
			
			@ -139,6 +138,7 @@ void prove_example2() {
 | 
			
		|||
    s.reset();
 | 
			
		||||
    s.add(!conjecture2);
 | 
			
		||||
    std::cout << "conjecture 2:\n" << conjecture2 << "\n";
 | 
			
		||||
 | 
			
		||||
    if (s.check() == unsat) {
 | 
			
		||||
        std::cout << "proved" << "\n";
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -534,3 +534,4 @@ inline app_ref operator>(app_ref const& x, app_ref const& y) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
#endif /* ARITH_DECL_PLUGIN_H_ */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -801,106 +801,104 @@ br_status arith_rewriter::mk_idiv_core(expr * arg1, expr * arg2, expr_ref & resu
 | 
			
		|||
        return BR_DONE;
 | 
			
		||||
    }
 | 
			
		||||
    if (m_util.is_numeral(arg2, v2, is_int) && v2.is_one()) {
 | 
			
		||||
        result = arg1;
 | 
			
		||||
        return BR_DONE;
 | 
			
		||||
    }
 | 
			
		||||
    if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) {
 | 
			
		||||
        return BR_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
    if (arg1 == arg2) {
 | 
			
		||||
        expr_ref zero(m_util.mk_int(0), m());
 | 
			
		||||
        result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1));
 | 
			
		||||
        return BR_REWRITE3;
 | 
			
		||||
    }
 | 
			
		||||
    if (divides(arg1, arg2, result)) {
 | 
			
		||||
        return BR_REWRITE_FULL;
 | 
			
		||||
    }
 | 
			
		||||
        result = arg1; 
 | 
			
		||||
        return BR_DONE; 
 | 
			
		||||
    } 
 | 
			
		||||
    if (m_util.is_numeral(arg2, v2, is_int) && v2.is_zero()) { 
 | 
			
		||||
        return BR_FAILED; 
 | 
			
		||||
    } 
 | 
			
		||||
    if (arg1 == arg2) { 
 | 
			
		||||
        expr_ref zero(m_util.mk_int(0), m()); 
 | 
			
		||||
        result = m().mk_ite(m().mk_eq(arg1, zero), m_util.mk_idiv(zero, zero), m_util.mk_int(1)); 
 | 
			
		||||
        return BR_REWRITE3; 
 | 
			
		||||
    } 
 | 
			
		||||
    if (divides(arg1, arg2, result)) { 
 | 
			
		||||
        return BR_REWRITE_FULL; 
 | 
			
		||||
    }  
 | 
			
		||||
    return BR_FAILED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// 
 | 
			
		||||
// implement div ab ac = floor( ab / ac) = floor (b / c) = div b c
 | 
			
		||||
 
 | 
			
		||||
//  
 | 
			
		||||
// implement div ab ac = floor( ab / ac) = floor (b / c) = div b c 
 | 
			
		||||
//
 | 
			
		||||
bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) {
 | 
			
		||||
    expr_fast_mark1 mark;
 | 
			
		||||
    rational num_r(1), den_r(1);
 | 
			
		||||
    expr* num_e = nullptr, *den_e = nullptr;
 | 
			
		||||
    ptr_buffer<expr> args1, args2;
 | 
			
		||||
    flat_mul(num, args1);
 | 
			
		||||
    flat_mul(den, args2);
 | 
			
		||||
    for (expr * arg : args1) {
 | 
			
		||||
        mark.mark(arg);
 | 
			
		||||
        if (m_util.is_numeral(arg, num_r)) num_e = arg;
 | 
			
		||||
    }
 | 
			
		||||
    for (expr* arg : args2) {
 | 
			
		||||
        if (mark.is_marked(arg)) {
 | 
			
		||||
            result = remove_divisor(arg, num, den);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_util.is_numeral(arg, den_r)) den_e = arg;
 | 
			
		||||
    }
 | 
			
		||||
    rational g = gcd(num_r, den_r);
 | 
			
		||||
    if (!g.is_one()) {
 | 
			
		||||
        SASSERT(g.is_pos());
 | 
			
		||||
        // replace num_e, den_e by their gcd reduction.
 | 
			
		||||
        for (unsigned i = 0; i < args1.size(); ++i) {
 | 
			
		||||
            if (args1[i] == num_e) {
 | 
			
		||||
                args1[i] = m_util.mk_numeral(num_r / g, true);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        for (unsigned i = 0; i < args2.size(); ++i) {
 | 
			
		||||
            if (args2[i] == den_e) {
 | 
			
		||||
                args2[i] = m_util.mk_numeral(den_r / g, true);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        num = m_util.mk_mul(args1.size(), args1.c_ptr());
 | 
			
		||||
        den = m_util.mk_mul(args2.size(), args2.c_ptr());
 | 
			
		||||
        result = m_util.mk_idiv(num, den);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) {
 | 
			
		||||
    ptr_buffer<expr> args1, args2;
 | 
			
		||||
    flat_mul(num, args1);
 | 
			
		||||
    flat_mul(den, args2);
 | 
			
		||||
    remove_divisor(arg, args1);
 | 
			
		||||
    remove_divisor(arg, args2);
 | 
			
		||||
    expr_ref zero(m_util.mk_int(0), m());
 | 
			
		||||
    num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr());
 | 
			
		||||
    den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr());
 | 
			
		||||
    return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arith_rewriter::flat_mul(expr* e, ptr_buffer<expr>& args) {
 | 
			
		||||
    args.push_back(e);
 | 
			
		||||
    for (unsigned i = 0; i < args.size(); ++i) {
 | 
			
		||||
        e = args[i];
 | 
			
		||||
        if (m_util.is_mul(e)) {
 | 
			
		||||
            args.append(to_app(e)->get_num_args(), to_app(e)->get_args());
 | 
			
		||||
            args[i] = args.back();
 | 
			
		||||
            args.shrink(args.size()-1);
 | 
			
		||||
            --i;
 | 
			
		||||
        }                
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void arith_rewriter::remove_divisor(expr* d, ptr_buffer<expr>& args) {
 | 
			
		||||
    for (unsigned i = 0; i < args.size(); ++i) {
 | 
			
		||||
        if (args[i] == d) {
 | 
			
		||||
            args[i] = args.back();
 | 
			
		||||
            args.shrink(args.size()-1);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    UNREACHABLE();
 | 
			
		||||
}
 | 
			
		||||
bool arith_rewriter::divides(expr* num, expr* den, expr_ref& result) { 
 | 
			
		||||
    expr_fast_mark1 mark; 
 | 
			
		||||
    rational num_r(1), den_r(1); 
 | 
			
		||||
    expr* num_e = nullptr, *den_e = nullptr; 
 | 
			
		||||
    ptr_buffer<expr> args1, args2; 
 | 
			
		||||
    flat_mul(num, args1); 
 | 
			
		||||
    flat_mul(den, args2); 
 | 
			
		||||
    for (expr * arg : args1) { 
 | 
			
		||||
        mark.mark(arg); 
 | 
			
		||||
        if (m_util.is_numeral(arg, num_r)) num_e = arg; 
 | 
			
		||||
    } 
 | 
			
		||||
    for (expr* arg : args2) { 
 | 
			
		||||
        if (mark.is_marked(arg)) { 
 | 
			
		||||
            result = remove_divisor(arg, num, den); 
 | 
			
		||||
            return true; 
 | 
			
		||||
        } 
 | 
			
		||||
        if (m_util.is_numeral(arg, den_r)) den_e = arg; 
 | 
			
		||||
    } 
 | 
			
		||||
    rational g = gcd(num_r, den_r); 
 | 
			
		||||
    if (!g.is_one()) { 
 | 
			
		||||
        SASSERT(g.is_pos()); 
 | 
			
		||||
        // replace num_e, den_e by their gcd reduction. 
 | 
			
		||||
        for (unsigned i = 0; i < args1.size(); ++i) { 
 | 
			
		||||
            if (args1[i] == num_e) { 
 | 
			
		||||
                args1[i] = m_util.mk_numeral(num_r / g, true); 
 | 
			
		||||
                break; 
 | 
			
		||||
            } 
 | 
			
		||||
        } 
 | 
			
		||||
        for (unsigned i = 0; i < args2.size(); ++i) { 
 | 
			
		||||
            if (args2[i] == den_e) { 
 | 
			
		||||
                args2[i] = m_util.mk_numeral(den_r / g, true); 
 | 
			
		||||
                break; 
 | 
			
		||||
            } 
 | 
			
		||||
        } 
 | 
			
		||||
        num = m_util.mk_mul(args1.size(), args1.c_ptr()); 
 | 
			
		||||
        den = m_util.mk_mul(args2.size(), args2.c_ptr()); 
 | 
			
		||||
        result = m_util.mk_idiv(num, den); 
 | 
			
		||||
        return true; 
 | 
			
		||||
    } 
 | 
			
		||||
    return false; 
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
expr_ref arith_rewriter::remove_divisor(expr* arg, expr* num, expr* den) { 
 | 
			
		||||
    ptr_buffer<expr> args1, args2; 
 | 
			
		||||
    flat_mul(num, args1); 
 | 
			
		||||
    flat_mul(den, args2); 
 | 
			
		||||
    remove_divisor(arg, args1); 
 | 
			
		||||
    remove_divisor(arg, args2); 
 | 
			
		||||
    expr_ref zero(m_util.mk_int(0), m()); 
 | 
			
		||||
    num = args1.empty() ? m_util.mk_int(1) : m_util.mk_mul(args1.size(), args1.c_ptr()); 
 | 
			
		||||
    den = args2.empty() ? m_util.mk_int(1) : m_util.mk_mul(args2.size(), args2.c_ptr()); 
 | 
			
		||||
    return expr_ref(m().mk_ite(m().mk_eq(zero, arg), m_util.mk_idiv(zero, zero), m_util.mk_idiv(num, den)), m()); 
 | 
			
		||||
} 
 | 
			
		||||
 
 | 
			
		||||
void arith_rewriter::flat_mul(expr* e, ptr_buffer<expr>& args) { 
 | 
			
		||||
    args.push_back(e); 
 | 
			
		||||
    for (unsigned i = 0; i < args.size(); ++i) { 
 | 
			
		||||
        e = args[i]; 
 | 
			
		||||
        if (m_util.is_mul(e)) { 
 | 
			
		||||
            args.append(to_app(e)->get_num_args(), to_app(e)->get_args()); 
 | 
			
		||||
            args[i] = args.back(); 
 | 
			
		||||
            args.shrink(args.size()-1); 
 | 
			
		||||
            --i; 
 | 
			
		||||
        }                 
 | 
			
		||||
    } 
 | 
			
		||||
} 
 | 
			
		||||
 
 | 
			
		||||
void arith_rewriter::remove_divisor(expr* d, ptr_buffer<expr>& args) { 
 | 
			
		||||
    for (unsigned i = 0; i < args.size(); ++i) { 
 | 
			
		||||
        if (args[i] == d) { 
 | 
			
		||||
            args[i] = args.back(); 
 | 
			
		||||
            args.shrink(args.size()-1); 
 | 
			
		||||
            return; 
 | 
			
		||||
        } 
 | 
			
		||||
    } 
 | 
			
		||||
    UNREACHABLE(); 
 | 
			
		||||
} 
 | 
			
		||||
    
 | 
			
		||||
br_status arith_rewriter::mk_mod_core(expr * arg1, expr * arg2, expr_ref & result) {
 | 
			
		||||
    set_curr_sort(m().get_sort(arg1));
 | 
			
		||||
    numeral v1, v2;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -96,10 +96,9 @@ class arith_rewriter : public poly_rewriter<arith_rewriter_core> {
 | 
			
		|||
    expr * mk_sin_value(rational const & k);
 | 
			
		||||
    app * mk_sqrt(rational const & k);
 | 
			
		||||
    bool divides(expr* d, expr* n, expr_ref& result);
 | 
			
		||||
    expr_ref remove_divisor(expr* arg, expr* num, expr* den);
 | 
			
		||||
    void flat_mul(expr* e, ptr_buffer<expr>& args);
 | 
			
		||||
    void remove_divisor(expr* d, ptr_buffer<expr>& args);
 | 
			
		||||
 | 
			
		||||
    expr_ref remove_divisor(expr* arg, expr* num, expr* den); 
 | 
			
		||||
    void flat_mul(expr* e, ptr_buffer<expr>& args); 
 | 
			
		||||
    void remove_divisor(expr* d, ptr_buffer<expr>& args); 
 | 
			
		||||
public:
 | 
			
		||||
    arith_rewriter(ast_manager & m, params_ref const & p = params_ref()):
 | 
			
		||||
        poly_rewriter<arith_rewriter_core>(m, p) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ void run_solver(lp_params & params, char const * mps_file_name) {
 | 
			
		|||
    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::OPTIMAL) {
 | 
			
		||||
    if (solver->get_status() == lp::lp_status::OPTIMAL) {
 | 
			
		||||
        if (params.min()) {
 | 
			
		||||
            solver->flip_costs();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,11 +25,11 @@ Revision History:
 | 
			
		|||
enum arith_solver_id {
 | 
			
		||||
    AS_NO_ARITH,              // 0
 | 
			
		||||
    AS_DIFF_LOGIC,            // 1
 | 
			
		||||
    AS_ARITH,                 // 2
 | 
			
		||||
    AS_OLD_ARITH,             // 2
 | 
			
		||||
    AS_DENSE_DIFF_LOGIC,      // 3
 | 
			
		||||
    AS_UTVPI,                 // 4
 | 
			
		||||
    AS_OPTINF,                // 5
 | 
			
		||||
    AS_LRA                    // 6
 | 
			
		||||
    AS_NEW_ARITH              // 6
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum bound_prop_mode {
 | 
			
		||||
| 
						 | 
				
			
			@ -113,7 +113,7 @@ struct theory_arith_params {
 | 
			
		|||
    theory_arith_params(params_ref const & p = params_ref()):
 | 
			
		||||
        m_arith_eq2ineq(false),
 | 
			
		||||
        m_arith_process_all_eqs(false),
 | 
			
		||||
        m_arith_mode(AS_ARITH),
 | 
			
		||||
        m_arith_mode(AS_NEW_ARITH),
 | 
			
		||||
        m_arith_auto_config_simplex(false),
 | 
			
		||||
        m_arith_blands_rule_threshold(1000),
 | 
			
		||||
        m_arith_propagate_eqs(true),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -3763,6 +3763,7 @@ namespace smt {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        m_stats.m_num_final_checks++;
 | 
			
		||||
		TRACE("final_check_stats", tout << "m_stats.m_num_final_checks = " << m_stats.m_num_final_checks << "\n";);
 | 
			
		||||
 | 
			
		||||
        final_check_status ok = m_qmanager->final_check_eh(false);
 | 
			
		||||
        if (ok != FC_DONE)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -849,7 +849,7 @@ namespace smt {
 | 
			
		|||
            std::cerr << v << " ::=\n" << mk_ll_pp(n, m_manager) << "<END-OF-FORMULA>\n";
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        TRACE("mk_bool_var", tout << "creating boolean variable: " << v << " for:\n" << mk_pp(n, m_manager) << "\n";);
 | 
			
		||||
        TRACE("mk_bool_var", tout << "creating boolean variable: " << v << " for:\n" << mk_pp(n, m_manager) << " " << n->get_id() << "\n";);
 | 
			
		||||
        TRACE("mk_var_bug", tout << "mk_bool: " << v << "\n";);                
 | 
			
		||||
        set_bool_var(id, v);
 | 
			
		||||
        m_bdata.reserve(v+1);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -332,7 +332,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_arith_propagate_eqs = false;
 | 
			
		||||
        m_params.m_arith_small_lemma_size = 30;
 | 
			
		||||
        m_params.m_nnf_cnf             = false;
 | 
			
		||||
        setup_i_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_IDL(static_features & st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_restart_strategy = RS_GEOMETRIC;
 | 
			
		||||
        m_params.m_restart_factor   = 1.5;
 | 
			
		||||
        m_params.m_restart_adaptive = false;
 | 
			
		||||
        setup_i_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_UFIDL(static_features & st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -454,7 +454,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_arith_propagate_eqs = false;
 | 
			
		||||
        m_params.m_eliminate_term_ite  = true;
 | 
			
		||||
        m_params.m_nnf_cnf             = false;
 | 
			
		||||
        setup_r_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_LRA(static_features const & st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -479,7 +479,7 @@ namespace smt {
 | 
			
		|||
            m_params.m_restart_adaptive      = false;
 | 
			
		||||
        }
 | 
			
		||||
        m_params.m_arith_small_lemma_size = 32;
 | 
			
		||||
        setup_r_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_LIRA(static_features const& st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -493,7 +493,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_arith_reflect       = false; 
 | 
			
		||||
        m_params.m_arith_propagate_eqs = false; 
 | 
			
		||||
        m_params.m_nnf_cnf             = false;
 | 
			
		||||
        setup_i_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_LIA(static_features const & st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -534,7 +534,7 @@ namespace smt {
 | 
			
		|||
            m_params.m_arith_bound_prop      = BP_NONE;
 | 
			
		||||
            m_params.m_arith_stronger_lemmas = false;
 | 
			
		||||
        }
 | 
			
		||||
        setup_i_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_UFLIA() {
 | 
			
		||||
| 
						 | 
				
			
			@ -542,7 +542,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_arith_reflect       = false; 
 | 
			
		||||
        m_params.m_nnf_cnf             = false;
 | 
			
		||||
        m_params.m_arith_propagation_threshold = 1000;
 | 
			
		||||
        setup_i_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_UFLIA(static_features & st) {
 | 
			
		||||
| 
						 | 
				
			
			@ -555,7 +555,7 @@ namespace smt {
 | 
			
		|||
        m_params.m_relevancy_lvl       = 0;
 | 
			
		||||
        m_params.m_arith_reflect       = false; 
 | 
			
		||||
        m_params.m_nnf_cnf             = false;
 | 
			
		||||
        setup_r_arith();
 | 
			
		||||
        setup_lra_arith();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_QF_BV() {
 | 
			
		||||
| 
						 | 
				
			
			@ -740,23 +740,34 @@ namespace smt {
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_i_arith() {
 | 
			
		||||
        // m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params));
 | 
			
		||||
        m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));        
 | 
			
		||||
        if (AS_OLD_ARITH == m_params.m_arith_mode) {
 | 
			
		||||
            m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            setup_lra_arith();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_r_arith() {
 | 
			
		||||
    void setup::setup_lra_arith() {
 | 
			
		||||
        m_context.register_plugin(alloc(smt::theory_lra, m_manager, m_params));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setup::setup_mi_arith() {
 | 
			
		||||
        if (m_params.m_arith_mode == AS_OPTINF) {
 | 
			
		||||
        switch (m_params.m_arith_mode) {
 | 
			
		||||
        case AS_OPTINF:
 | 
			
		||||
            m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params));            
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            break;
 | 
			
		||||
        case AS_NEW_ARITH:
 | 
			
		||||
            setup_lra_arith();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void setup::setup_arith() {
 | 
			
		||||
        static_features    st(m_manager);
 | 
			
		||||
        IF_VERBOSE(100, verbose_stream() << "(smt.collecting-features)\n";);
 | 
			
		||||
| 
						 | 
				
			
			@ -810,15 +821,18 @@ namespace smt {
 | 
			
		|||
        case AS_OPTINF:
 | 
			
		||||
            m_context.register_plugin(alloc(smt::theory_inf_arith, m_manager, m_params));            
 | 
			
		||||
            break;
 | 
			
		||||
        case AS_LRA:
 | 
			
		||||
            setup_r_arith();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
        case AS_OLD_ARITH:
 | 
			
		||||
            if (m_params.m_arith_int_only && int_only)
 | 
			
		||||
                m_context.register_plugin(alloc(smt::theory_i_arith, m_manager, m_params));
 | 
			
		||||
            else
 | 
			
		||||
                m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
 | 
			
		||||
            break;
 | 
			
		||||
        case AS_NEW_ARITH:
 | 
			
		||||
            setup_lra_arith();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            m_context.register_plugin(alloc(smt::theory_mi_arith, m_manager, m_params));
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -978,7 +992,7 @@ namespace smt {
 | 
			
		|||
        if (st.num_theories() == 2 && st.has_uf() && is_arith(st)) {
 | 
			
		||||
            if (!st.m_has_real)
 | 
			
		||||
                setup_QF_UFLIA(st);
 | 
			
		||||
            else if (!st.m_has_int && st.m_num_non_linear == 0)
 | 
			
		||||
            else if (!st.m_has_int && st.m_num_non_linear == 0) 
 | 
			
		||||
                setup_QF_UFLRA();
 | 
			
		||||
            else
 | 
			
		||||
                setup_unknown();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -101,7 +101,7 @@ namespace smt {
 | 
			
		|||
        void setup_card();
 | 
			
		||||
        void setup_i_arith();
 | 
			
		||||
        void setup_mi_arith();
 | 
			
		||||
        void setup_r_arith();
 | 
			
		||||
        void setup_lra_arith();
 | 
			
		||||
        void setup_fpa();
 | 
			
		||||
        void setup_str();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -42,7 +42,7 @@ Revision History:
 | 
			
		|||
namespace smt {
 | 
			
		||||
    
 | 
			
		||||
    struct theory_arith_stats {
 | 
			
		||||
        unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests;
 | 
			
		||||
        unsigned m_conflicts, m_add_rows, m_pivots, m_diseq_cs, m_gomory_cuts, m_branches, m_gcd_tests, m_patches, m_patches_succ;
 | 
			
		||||
        unsigned m_assert_lower, m_assert_upper, m_assert_diseq, m_core2th_eqs, m_core2th_diseqs;
 | 
			
		||||
        unsigned m_th2core_eqs, m_th2core_diseqs, m_bound_props, m_offset_eqs, m_fixed_eqs, m_offline_eqs;
 | 
			
		||||
        unsigned m_max_min; 
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1335,7 +1335,7 @@ namespace smt {
 | 
			
		|||
                      }
 | 
			
		||||
                  }
 | 
			
		||||
              });
 | 
			
		||||
 | 
			
		||||
        m_stats.m_patches++;
 | 
			
		||||
        patch_int_infeasible_vars();
 | 
			
		||||
        fix_non_base_vars();
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -1368,6 +1368,7 @@ namespace smt {
 | 
			
		|||
        
 | 
			
		||||
        theory_var int_var = find_infeasible_int_base_var();
 | 
			
		||||
        if (int_var == null_theory_var) {
 | 
			
		||||
            m_stats.m_patches_succ++;
 | 
			
		||||
            TRACE("arith_int_incomp", tout << "FC_DONE 2...\n"; display(tout););
 | 
			
		||||
            return m_liberal_final_check || !m_changed_assignment ? FC_DONE : FC_CONTINUE;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1385,6 +1386,7 @@ namespace smt {
 | 
			
		|||
 | 
			
		||||
        m_branch_cut_counter++;
 | 
			
		||||
        // TODO: add giveup code
 | 
			
		||||
        TRACE("gomory_cut", tout << m_branch_cut_counter << ", " << m_params.m_arith_branch_cut_ratio << std::endl;);
 | 
			
		||||
        if (m_branch_cut_counter % m_params.m_arith_branch_cut_ratio == 0) {
 | 
			
		||||
            TRACE("opt_verbose", display(tout););
 | 
			
		||||
            move_non_base_vars_to_bounds();
 | 
			
		||||
| 
						 | 
				
			
			@ -1399,7 +1401,7 @@ namespace smt {
 | 
			
		|||
                SASSERT(is_base(int_var));
 | 
			
		||||
                row const & r = m_rows[get_var_row(int_var)];
 | 
			
		||||
                if (!mk_gomory_cut(r)) {
 | 
			
		||||
                    // silent failure
 | 
			
		||||
                    TRACE("gomory_cut", tout << "silent failure\n";);
 | 
			
		||||
                }
 | 
			
		||||
                return FC_CONTINUE;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,6 +38,8 @@ namespace smt {
 | 
			
		|||
        st.update("arith gcd tests", m_stats.m_gcd_tests);
 | 
			
		||||
        st.update("arith ineq splits", m_stats.m_branches);
 | 
			
		||||
        st.update("arith gomory cuts", m_stats.m_gomory_cuts);
 | 
			
		||||
        st.update("arith patches", m_stats.m_patches);
 | 
			
		||||
        st.update("arith patches_succ", m_stats.m_patches_succ);
 | 
			
		||||
        st.update("arith max-min", m_stats.m_max_min);
 | 
			
		||||
        st.update("arith grobner", m_stats.m_gb_compute_basis);
 | 
			
		||||
        st.update("arith pseudo nonlinear", m_stats.m_nl_linear);
 | 
			
		||||
| 
						 | 
				
			
			@ -389,8 +391,19 @@ namespace smt {
 | 
			
		|||
    void theory_arith<Ext>::display_vars(std::ostream & out) const {
 | 
			
		||||
        out << "vars:\n";
 | 
			
		||||
        int n = get_num_vars();
 | 
			
		||||
        for (theory_var v = 0; v < n; v++)
 | 
			
		||||
            display_var(out, v);
 | 
			
		||||
		int inf_vars = 0;
 | 
			
		||||
		int int_inf_vars = 0;
 | 
			
		||||
		for (theory_var v = 0; v < n; v++) {
 | 
			
		||||
			if ((lower(v) && lower(v)->get_value() > get_value(v))
 | 
			
		||||
				|| (upper(v) && upper(v)->get_value() < get_value(v)))
 | 
			
		||||
				inf_vars++;
 | 
			
		||||
			if (is_int(v) && !get_value(v).is_int())
 | 
			
		||||
				int_inf_vars++;
 | 
			
		||||
		}
 | 
			
		||||
		out << "infeasibles = " << inf_vars << " int_inf = " << int_inf_vars << std::endl;
 | 
			
		||||
		for (theory_var v = 0; v < n; v++) {
 | 
			
		||||
			display_var(out, v);
 | 
			
		||||
		}
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template<typename Ext>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							| 
						 | 
				
			
			@ -31,7 +31,7 @@ namespace smt {
 | 
			
		|||
        theory_lra(ast_manager& m, theory_arith_params& ap);
 | 
			
		||||
        ~theory_lra() override;
 | 
			
		||||
        theory* mk_fresh(context* new_ctx) override;
 | 
			
		||||
        char const* get_name() const override { return "lra"; }
 | 
			
		||||
        char const* get_name() const override { return "arithmetic"; }
 | 
			
		||||
        
 | 
			
		||||
        void init(context * ctx) override;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -78,6 +78,8 @@ namespace smt {
 | 
			
		|||
        model_value_proc * mk_value(enode * n, model_generator & mg) override;
 | 
			
		||||
 | 
			
		||||
        bool get_value(enode* n, expr_ref& r) override;
 | 
			
		||||
        bool get_lower(enode* n, expr_ref& r);
 | 
			
		||||
        bool get_upper(enode* n, expr_ref& r);
 | 
			
		||||
 | 
			
		||||
        bool validate_eq_in_model(theory_var v1, theory_var v2, bool is_true) const override;
 | 
			
		||||
                
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -26,6 +26,7 @@ Revision History:
 | 
			
		|||
#include "smt/smt_model_generator.h"
 | 
			
		||||
#include "smt/theory_seq.h"
 | 
			
		||||
#include "smt/theory_arith.h"
 | 
			
		||||
#include "smt/theory_lra.h"
 | 
			
		||||
#include "smt/smt_kernel.h"
 | 
			
		||||
 | 
			
		||||
using namespace smt;
 | 
			
		||||
| 
						 | 
				
			
			@ -4546,6 +4547,8 @@ static bool get_arith_value(context& ctx, theory_id afid, expr* e, expr_ref& v)
 | 
			
		|||
    if (tha) return tha->get_value(ctx.get_enode(e), v);
 | 
			
		||||
    theory_i_arith* thi = get_th_arith<theory_i_arith>(ctx, afid, e);
 | 
			
		||||
    if (thi) return thi->get_value(ctx.get_enode(e), v);
 | 
			
		||||
    theory_lra* thr = get_th_arith<theory_lra>(ctx, afid, e);
 | 
			
		||||
    if (thr) return thr->get_value(ctx.get_enode(e), v);
 | 
			
		||||
    TRACE("seq", tout << "no arithmetic theory\n";);
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -4571,12 +4574,18 @@ bool theory_seq::lower_bound(expr* _e, rational& lo) const {
 | 
			
		|||
    context& ctx = get_context();
 | 
			
		||||
    expr_ref e(m_util.str.mk_length(_e), m);
 | 
			
		||||
    expr_ref _lo(m);
 | 
			
		||||
    theory_mi_arith* tha = get_th_arith<theory_mi_arith>(ctx, m_autil.get_family_id(), e);
 | 
			
		||||
    if (tha && !tha->get_lower(ctx.get_enode(e), _lo)) return false;
 | 
			
		||||
    if (!tha) {
 | 
			
		||||
        theory_i_arith* thi = get_th_arith<theory_i_arith>(ctx, m_autil.get_family_id(), e);
 | 
			
		||||
        if (!thi || !thi->get_lower(ctx.get_enode(e), _lo)) return false;
 | 
			
		||||
    family_id afid = m_autil.get_family_id();
 | 
			
		||||
    do {
 | 
			
		||||
        theory_mi_arith* tha = get_th_arith<theory_mi_arith>(ctx, afid, e);
 | 
			
		||||
        if (tha && tha->get_lower(ctx.get_enode(e), _lo)) break;
 | 
			
		||||
        theory_i_arith* thi = get_th_arith<theory_i_arith>(ctx, afid, e);
 | 
			
		||||
        if (thi && thi->get_lower(ctx.get_enode(e), _lo)) break;
 | 
			
		||||
        theory_lra* thr = get_th_arith<theory_lra>(ctx, afid, e);
 | 
			
		||||
        if (thr && thr->get_lower(ctx.get_enode(e), _lo)) break;
 | 
			
		||||
        TRACE("seq", tout << "no lower bound " << mk_pp(_e, m) << "\n";);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    while (false);
 | 
			
		||||
    return m_autil.is_numeral(_lo, lo) && lo.is_int();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -4622,13 +4631,19 @@ bool theory_seq::lower_bound2(expr* _e, rational& lo) {
 | 
			
		|||
bool theory_seq::upper_bound(expr* _e, rational& hi) const {
 | 
			
		||||
    context& ctx = get_context();
 | 
			
		||||
    expr_ref e(m_util.str.mk_length(_e), m);
 | 
			
		||||
    theory_mi_arith* tha = get_th_arith<theory_mi_arith>(ctx, m_autil.get_family_id(), e);
 | 
			
		||||
    family_id afid = m_autil.get_family_id();
 | 
			
		||||
    expr_ref _hi(m);
 | 
			
		||||
    if (tha && !tha->get_upper(ctx.get_enode(e), _hi)) return false;
 | 
			
		||||
    if (!tha) {
 | 
			
		||||
        theory_i_arith* thi = get_th_arith<theory_i_arith>(ctx, m_autil.get_family_id(), e);
 | 
			
		||||
        if (!thi || !thi->get_upper(ctx.get_enode(e), _hi)) return false;
 | 
			
		||||
    do {
 | 
			
		||||
        theory_mi_arith* tha = get_th_arith<theory_mi_arith>(ctx, afid, e);
 | 
			
		||||
        if (tha && tha->get_upper(ctx.get_enode(e), _hi)) break;
 | 
			
		||||
        theory_i_arith* thi = get_th_arith<theory_i_arith>(ctx, afid, e);
 | 
			
		||||
        if (thi && thi->get_upper(ctx.get_enode(e), _hi)) break;
 | 
			
		||||
        theory_lra* thr = get_th_arith<theory_lra>(ctx, afid, e);
 | 
			
		||||
        if (thr && thr->get_upper(ctx.get_enode(e), _hi)) break;
 | 
			
		||||
        TRACE("seq", tout << "no upper bound " << mk_pp(_e, m) << "\n";);
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    while (false);
 | 
			
		||||
    return m_autil.is_numeral(_hi, hi) && hi.is_int();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,6 @@ namespace smt {
 | 
			
		|||
 | 
			
		||||
        class seq_value_proc;
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        // cache to track evaluations under equalities
 | 
			
		||||
        class eval_cache {
 | 
			
		||||
            eqdep_map_t             m_map;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -211,17 +211,23 @@ tactic * mk_qflia_tactic(ast_manager & m, params_ref const & p) {
 | 
			
		|||
    
 | 
			
		||||
    params_ref no_cut_p;
 | 
			
		||||
    no_cut_p.set_uint("arith.branch_cut_ratio", 10000000);
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    tactic * st = using_params(and_then(preamble_st,
 | 
			
		||||
#if 0
 | 
			
		||||
                                        mk_smt_tactic()),
 | 
			
		||||
#else
 | 
			
		||||
                                        or_else(mk_ilp_model_finder_tactic(m),
 | 
			
		||||
                                                mk_pb_tactic(m),
 | 
			
		||||
                                                and_then(fail_if_not(mk_is_quasi_pb_probe()), 
 | 
			
		||||
                                                         using_params(mk_lia2sat_tactic(m), quasi_pb_p),
 | 
			
		||||
                                                         mk_fail_if_undecided_tactic()),
 | 
			
		||||
                                                mk_bounded_tactic(m),
 | 
			
		||||
                                                mk_psmt_tactic(m, p))),
 | 
			
		||||
                                                mk_smt_tactic())),
 | 
			
		||||
#endif
 | 
			
		||||
                               main_p);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    st->updt_params(p);
 | 
			
		||||
    return st;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,5 @@
 | 
			
		|||
add_subdirectory(fuzzing)
 | 
			
		||||
add_subdirectory(lp)
 | 
			
		||||
################################################################################
 | 
			
		||||
# z3-test executable
 | 
			
		||||
################################################################################
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +121,7 @@ add_executable(test-z3
 | 
			
		|||
  upolynomial.cpp
 | 
			
		||||
  var_subst.cpp
 | 
			
		||||
  vector.cpp
 | 
			
		||||
  lp/lp.cpp
 | 
			
		||||
  ${z3_test_extra_object_files}
 | 
			
		||||
)
 | 
			
		||||
z3_add_install_tactic_rule(${z3_test_deps})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										8
									
								
								src/test/lp/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/test/lp/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,8 @@
 | 
			
		|||
add_executable(lp_tst
 | 
			
		||||
EXCLUDE_FROM_ALL
 | 
			
		||||
lp_main.cpp lp.cpp $<TARGET_OBJECTS:util> $<TARGET_OBJECTS:polynomial> $<TARGET_OBJECTS:nlsat>  $<TARGET_OBJECTS:lp> )
 | 
			
		||||
target_compile_definitions(lp_tst PRIVATE ${Z3_COMPONENT_CXX_DEFINES})
 | 
			
		||||
target_compile_options(lp_tst PRIVATE ${Z3_COMPONENT_CXX_FLAGS})
 | 
			
		||||
target_include_directories(lp_tst PRIVATE ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
 | 
			
		||||
target_link_libraries(lp_tst PRIVATE ${Z3_DEPENDENT_LIBS})
 | 
			
		||||
z3_append_linker_flag_list_to_target(lp_tst ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS})
 | 
			
		||||
							
								
								
									
										236
									
								
								src/test/lp/gomory_test.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								src/test/lp/gomory_test.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,236 @@
 | 
			
		|||
namespace lp {
 | 
			
		||||
struct gomory_test {
 | 
			
		||||
    gomory_test(
 | 
			
		||||
        std::function<std::string (unsigned)> name_function_p,
 | 
			
		||||
        std::function<mpq (unsigned)> get_value_p,
 | 
			
		||||
        std::function<bool (unsigned)> at_low_p,
 | 
			
		||||
        std::function<bool (unsigned)> at_upper_p,
 | 
			
		||||
        std::function<impq (unsigned) > lower_bound_p,
 | 
			
		||||
        std::function<impq (unsigned) > upper_bound_p,
 | 
			
		||||
        std::function<unsigned (unsigned) > column_lower_bound_constraint_p,
 | 
			
		||||
        std::function<unsigned (unsigned) > column_upper_bound_constraint_p
 | 
			
		||||
                ) :
 | 
			
		||||
        m_name_function(name_function_p),
 | 
			
		||||
        get_value(get_value_p),
 | 
			
		||||
        at_low(at_low_p),
 | 
			
		||||
        at_upper(at_upper_p),
 | 
			
		||||
        lower_bound(lower_bound_p),
 | 
			
		||||
        upper_bound(upper_bound_p),
 | 
			
		||||
        column_lower_bound_constraint(column_lower_bound_constraint_p),
 | 
			
		||||
        column_upper_bound_constraint(column_upper_bound_constraint_p)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    std::function<std::string (unsigned)> m_name_function;
 | 
			
		||||
    std::function<mpq (unsigned)> get_value;
 | 
			
		||||
    std::function<bool (unsigned)> at_low;
 | 
			
		||||
    std::function<bool (unsigned)> at_upper;
 | 
			
		||||
    std::function<impq (unsigned) > lower_bound;
 | 
			
		||||
    std::function<impq (unsigned) > upper_bound;
 | 
			
		||||
    std::function<unsigned (unsigned) > column_lower_bound_constraint;
 | 
			
		||||
    std::function<unsigned (unsigned) > column_upper_bound_constraint;
 | 
			
		||||
    
 | 
			
		||||
    bool is_real(unsigned) { return false; } // todo: test real case
 | 
			
		||||
    void print_row(std::ostream& out, vector<std::pair<mpq, unsigned>> & row ) {
 | 
			
		||||
        bool first = true;
 | 
			
		||||
        for (const auto & it : row) {
 | 
			
		||||
            auto val = it.first;
 | 
			
		||||
            if (first) {
 | 
			
		||||
                first = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (numeric_traits<mpq>::is_pos(val)) {
 | 
			
		||||
                    out << " + ";
 | 
			
		||||
                } else {
 | 
			
		||||
                    out << " - ";
 | 
			
		||||
                    val = -val;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (val == -numeric_traits<mpq>::one())
 | 
			
		||||
                out << " - ";
 | 
			
		||||
            else if (val != numeric_traits<mpq>::one())
 | 
			
		||||
                out << T_to_string(val);
 | 
			
		||||
        
 | 
			
		||||
            out << m_name_function(it.second);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void real_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term& pol, explanation & expl, const mpq& f_0, const mpq& one_minus_f_0) {
 | 
			
		||||
        TRACE("gomory_cut_detail_real", tout << "real\n";);
 | 
			
		||||
        mpq new_a;
 | 
			
		||||
        if (at_low(x_j)) {
 | 
			
		||||
            if (a.is_pos()) {
 | 
			
		||||
                new_a  =  a / (1 - f_0);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                new_a  =  a / f_0;
 | 
			
		||||
                new_a.neg();
 | 
			
		||||
            }
 | 
			
		||||
            k.addmul(new_a, lower_bound(x_j).x); // is it a faster operation than
 | 
			
		||||
            // k += lower_bound(x_j).x * new_a;  
 | 
			
		||||
            expl.push_justification(column_lower_bound_constraint(x_j), new_a);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            lp_assert(at_upper(x_j));
 | 
			
		||||
            if (a.is_pos()) {
 | 
			
		||||
                new_a =   a / f_0; 
 | 
			
		||||
                new_a.neg(); // the upper terms are inverted.
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                new_a =   a / (mpq(1) - f_0); 
 | 
			
		||||
            }
 | 
			
		||||
            k.addmul(new_a, upper_bound(x_j).x); //  k += upper_bound(x_j).x * new_a; 
 | 
			
		||||
            expl.push_justification(column_upper_bound_constraint(x_j), new_a);
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("gomory_cut_detail_real", tout << a << "*v" << x_j << " k: " << k << "\n";);
 | 
			
		||||
        pol.add_monomial(new_a, x_j);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & k, lar_term & t, explanation& expl, mpq & lcm_den, const mpq& f_0, const mpq& one_minus_f_0) {
 | 
			
		||||
        lp_assert(is_int(x_j));
 | 
			
		||||
        lp_assert(!a.is_int());
 | 
			
		||||
             lp_assert(f_0 > zero_of_type<mpq>() && f_0 < one_of_type<mpq>());
 | 
			
		||||
        mpq f_j =  int_solver::fractional_part(a);
 | 
			
		||||
        TRACE("gomory_cut_detail", 
 | 
			
		||||
              tout << a << " x_j = " << x_j << ", k = " << k << "\n";
 | 
			
		||||
              tout << "f_j: " << f_j << "\n";
 | 
			
		||||
              tout << "f_0: " << f_0 << "\n";
 | 
			
		||||
              tout << "1 - f_0: " << one_minus_f_0 << "\n";
 | 
			
		||||
              tout << "at_low(" << x_j << ") = " << at_low(x_j) << std::endl;
 | 
			
		||||
              );
 | 
			
		||||
        lp_assert (!f_j.is_zero());
 | 
			
		||||
        mpq new_a;
 | 
			
		||||
        if (at_low(x_j)) {
 | 
			
		||||
            if (f_j <= one_minus_f_0) {
 | 
			
		||||
                new_a = f_j / one_minus_f_0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                new_a = (1 - f_j) / f_0;
 | 
			
		||||
            }
 | 
			
		||||
            k.addmul(new_a, lower_bound(x_j).x);
 | 
			
		||||
            expl.push_justification(column_lower_bound_constraint(x_j), new_a);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            lp_assert(at_upper(x_j));
 | 
			
		||||
            if (f_j <= f_0) {
 | 
			
		||||
                new_a = f_j / f_0;
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                new_a = (mpq(1) - f_j) / (one_minus_f_0);
 | 
			
		||||
            }
 | 
			
		||||
            new_a.neg(); // the upper terms are inverted
 | 
			
		||||
            k.addmul(new_a, upper_bound(x_j).x);
 | 
			
		||||
            expl.push_justification(column_upper_bound_constraint(x_j), new_a);
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("gomory_cut_detail", tout << "new_a: " << new_a << " k: " << k << "\n";);
 | 
			
		||||
        t.add_monomial(new_a, x_j);
 | 
			
		||||
        lcm_den = lcm(lcm_den, denominator(new_a));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void report_conflict_from_gomory_cut(mpq &k) {
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void adjust_term_and_k_for_some_ints_case_gomory(lar_term& t, mpq& k, mpq &lcm_den) {
 | 
			
		||||
        lp_assert(!t.is_empty());
 | 
			
		||||
        auto pol = t.coeffs_as_vector();
 | 
			
		||||
        t.clear();
 | 
			
		||||
        if (pol.size() == 1) {
 | 
			
		||||
            TRACE("gomory_cut_detail", tout << "pol.size() is 1" << std::endl;);
 | 
			
		||||
            unsigned v = pol[0].second;
 | 
			
		||||
            lp_assert(is_int(v));
 | 
			
		||||
            const mpq& a = pol[0].first;
 | 
			
		||||
            k /= a;
 | 
			
		||||
            if (a.is_pos()) { // we have av >= k
 | 
			
		||||
                if (!k.is_int())
 | 
			
		||||
                    k = ceil(k);
 | 
			
		||||
                // switch size
 | 
			
		||||
                t.add_monomial(- mpq(1), v);
 | 
			
		||||
                k.neg();
 | 
			
		||||
            } else {
 | 
			
		||||
                if (!k.is_int())
 | 
			
		||||
                    k = floor(k);
 | 
			
		||||
                t.add_monomial(mpq(1), v);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            TRACE("gomory_cut_detail", tout << "pol.size() > 1" << std::endl;);
 | 
			
		||||
            lcm_den = lcm(lcm_den, denominator(k));
 | 
			
		||||
            TRACE("gomory_cut_detail", tout << "k: " << k << " lcm_den: " << lcm_den << "\n";
 | 
			
		||||
                  for (unsigned i = 0; i < pol.size(); i++) {
 | 
			
		||||
                      tout << pol[i].first << " " << pol[i].second << "\n";
 | 
			
		||||
                  }
 | 
			
		||||
                  tout << "k: " << k << "\n";);
 | 
			
		||||
            lp_assert(lcm_den.is_pos());
 | 
			
		||||
            if (!lcm_den.is_one()) {
 | 
			
		||||
                // normalize coefficients of integer parameters to be integers.
 | 
			
		||||
                for (auto & pi: pol) {
 | 
			
		||||
                    pi.first *= lcm_den;
 | 
			
		||||
                    SASSERT(!is_int(pi.second) || pi.first.is_int());
 | 
			
		||||
                }
 | 
			
		||||
                k *= lcm_den;
 | 
			
		||||
            }
 | 
			
		||||
            TRACE("gomory_cut_detail", tout << "after *lcm\n";
 | 
			
		||||
                  for (unsigned i = 0; i < pol.size(); i++) {
 | 
			
		||||
                      tout << pol[i].first << " * v" << pol[i].second << "\n";
 | 
			
		||||
                  }
 | 
			
		||||
                  tout << "k: " << k << "\n";);
 | 
			
		||||
            
 | 
			
		||||
            // negate everything to return -pol <= -k
 | 
			
		||||
            for (const auto & pi: pol)
 | 
			
		||||
                t.add_monomial(-pi.first, pi.second);
 | 
			
		||||
            k.neg();
 | 
			
		||||
        }
 | 
			
		||||
        TRACE("gomory_cut_detail", tout << "k = " << k << std::endl;);
 | 
			
		||||
        lp_assert(k.is_int());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void print_term(lar_term & t, std::ostream & out) {
 | 
			
		||||
        lp_assert(is_zero(t.m_v));
 | 
			
		||||
        vector<std::pair<mpq, unsigned>>  row;
 | 
			
		||||
        for (auto p : t.m_coeffs)
 | 
			
		||||
            row.push_back(std::make_pair(p.second, p.first));
 | 
			
		||||
        print_row(out, row);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void mk_gomory_cut(lar_term& t, mpq& k, explanation & expl, unsigned inf_col, vector<std::pair<mpq, unsigned>> & row) {
 | 
			
		||||
        enable_trace("gomory_cut");
 | 
			
		||||
        enable_trace("gomory_cut_detail");
 | 
			
		||||
 | 
			
		||||
        TRACE("gomory_cut",
 | 
			
		||||
              tout << "applying cut at:\n"; print_row(tout, row); 
 | 
			
		||||
              tout << std::endl << "inf_col = " << inf_col << std::endl;
 | 
			
		||||
              );
 | 
			
		||||
        
 | 
			
		||||
        // gomory will be   t >= k
 | 
			
		||||
        k = 1;
 | 
			
		||||
        mpq lcm_den(1);
 | 
			
		||||
        unsigned x_j;
 | 
			
		||||
        mpq a;
 | 
			
		||||
        bool some_int_columns = false;
 | 
			
		||||
        mpq f_0  = int_solver::fractional_part(get_value(inf_col));
 | 
			
		||||
        mpq one_min_f_0 = 1 - f_0;
 | 
			
		||||
        for ( auto pp : row) {
 | 
			
		||||
            a = pp.first;
 | 
			
		||||
            x_j = pp.second;
 | 
			
		||||
            if (x_j == inf_col)
 | 
			
		||||
                continue;
 | 
			
		||||
            // make the format compatible with the format used in: Integrating Simplex with DPLL(T)
 | 
			
		||||
            a.neg();  
 | 
			
		||||
            if (is_real(x_j)) 
 | 
			
		||||
                real_case_in_gomory_cut(a, x_j, k, t, expl, f_0, one_min_f_0);
 | 
			
		||||
            else {
 | 
			
		||||
                if (a.is_int()) continue; // f_j will be zero and no monomial will be added
 | 
			
		||||
                some_int_columns = true;
 | 
			
		||||
                int_case_in_gomory_cut(a, x_j, k, t, expl, lcm_den, f_0, one_min_f_0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (t.is_empty())
 | 
			
		||||
            return report_conflict_from_gomory_cut(k);
 | 
			
		||||
        if (some_int_columns)
 | 
			
		||||
            adjust_term_and_k_for_some_ints_case_gomory(t, k, lcm_den);
 | 
			
		||||
 | 
			
		||||
        TRACE("gomory_cut", tout<<"new cut :"; print_term(t, tout); tout << " >= " << k << std::endl;);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										14
									
								
								src/test/lp/lp_main.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/test/lp/lp_main.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,14 @@
 | 
			
		|||
void        gparams_register_modules(){}
 | 
			
		||||
void mem_initialize() {}
 | 
			
		||||
void mem_finalize() {}
 | 
			
		||||
#include "util/rational.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
void test_lp_local(int argc, char**argv);
 | 
			
		||||
}
 | 
			
		||||
int main(int argn, char**argv){
 | 
			
		||||
    rational::initialize();
 | 
			
		||||
    lp::test_lp_local(argn, argv);
 | 
			
		||||
    rational::finalize();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -121,13 +121,13 @@ namespace lp {
 | 
			
		|||
 | 
			
		||||
        void fill_simple_elem(lisp_elem & lm) {
 | 
			
		||||
            int separator = first_separator();
 | 
			
		||||
            SASSERT(-1 != separator && separator != 0);
 | 
			
		||||
            lp_assert(-1 != separator && separator != 0);
 | 
			
		||||
            lm.m_head = m_line.substr(0, separator);
 | 
			
		||||
            m_line = m_line.substr(separator);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void fill_nested_elem(lisp_elem & lm) {
 | 
			
		||||
            SASSERT(m_line[0] == '(');
 | 
			
		||||
            lp_assert(m_line[0] == '(');
 | 
			
		||||
            m_line = m_line.substr(1);
 | 
			
		||||
            int separator = first_separator();
 | 
			
		||||
            lm.m_head = m_line.substr(0, separator);
 | 
			
		||||
| 
						 | 
				
			
			@ -194,11 +194,11 @@ namespace lp {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        void adjust_rigth_side(formula_constraint & /* c*/, lisp_elem & /*el*/) {
 | 
			
		||||
            // SASSERT(el.m_head == "0"); // do nothing for the time being
 | 
			
		||||
            // lp_assert(el.m_head == "0"); // do nothing for the time being
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        void set_constraint_coeffs(formula_constraint & c, lisp_elem & el) {
 | 
			
		||||
            SASSERT(el.m_elems.size() == 2);
 | 
			
		||||
            lp_assert(el.m_elems.size() == 2);
 | 
			
		||||
            set_constraint_coeffs_on_coeff_element(c, el.m_elems[0]);
 | 
			
		||||
            adjust_rigth_side(c, el.m_elems[1]);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +214,7 @@ namespace lp {
 | 
			
		|||
                add_mult_elem(c, el.m_elems);
 | 
			
		||||
            } else if (el.m_head == "~") {
 | 
			
		||||
                lisp_elem & minel = el.m_elems[0];
 | 
			
		||||
                SASSERT(minel.is_simple());
 | 
			
		||||
                lp_assert(minel.is_simple());
 | 
			
		||||
                c.m_right_side += mpq(str_to_int(minel.m_head));
 | 
			
		||||
            } else {
 | 
			
		||||
                std::cout << "unexpected input " << el.m_head << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -224,14 +224,14 @@ namespace lp {
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        std::string get_name(lisp_elem & name) {
 | 
			
		||||
            SASSERT(name.is_simple());
 | 
			
		||||
            SASSERT(!is_integer(name.m_head));
 | 
			
		||||
            lp_assert(name.is_simple());
 | 
			
		||||
            lp_assert(!is_integer(name.m_head));
 | 
			
		||||
            return name.m_head;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        void add_mult_elem(formula_constraint & c, std::vector<lisp_elem> & els) {
 | 
			
		||||
            SASSERT(els.size() == 2);
 | 
			
		||||
            lp_assert(els.size() == 2);
 | 
			
		||||
            mpq coeff = get_coeff(els[0]);
 | 
			
		||||
            std::string col_name = get_name(els[1]);
 | 
			
		||||
            c.add_pair(coeff, col_name);
 | 
			
		||||
| 
						 | 
				
			
			@ -241,16 +241,16 @@ namespace lp {
 | 
			
		|||
            if (le.is_simple()) {
 | 
			
		||||
                return mpq(str_to_int(le.m_head));
 | 
			
		||||
            } else {
 | 
			
		||||
                SASSERT(le.m_head == "~");
 | 
			
		||||
                SASSERT(le.size() == 1);
 | 
			
		||||
                lp_assert(le.m_head == "~");
 | 
			
		||||
                lp_assert(le.size() == 1);
 | 
			
		||||
                lisp_elem & el = le.m_elems[0];
 | 
			
		||||
                SASSERT(el.is_simple());
 | 
			
		||||
                lp_assert(el.is_simple());
 | 
			
		||||
                return -mpq(str_to_int(el.m_head));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        int str_to_int(std::string & s) {
 | 
			
		||||
            SASSERT(is_integer(s));
 | 
			
		||||
            lp_assert(is_integer(s));
 | 
			
		||||
            return atoi(s.c_str());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +258,7 @@ namespace lp {
 | 
			
		|||
            if (el.size()) {
 | 
			
		||||
                add_complex_sum_elem(c, el);
 | 
			
		||||
            } else {
 | 
			
		||||
                SASSERT(is_integer(el.m_head));
 | 
			
		||||
                lp_assert(is_integer(el.m_head));
 | 
			
		||||
                int v = atoi(el.m_head.c_str());
 | 
			
		||||
                mpq vr(v);
 | 
			
		||||
                c.m_right_side -= vr;
 | 
			
		||||
| 
						 | 
				
			
			@ -276,7 +276,7 @@ namespace lp {
 | 
			
		|||
            } else if (el.m_head == "+") {
 | 
			
		||||
                add_sum(c, el.m_elems);
 | 
			
		||||
            } else {
 | 
			
		||||
                SASSERT(false); // unexpected input
 | 
			
		||||
                lp_assert(false); // unexpected input
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -389,7 +389,7 @@ namespace lp {
 | 
			
		|||
        void add_constraint_to_solver(lar_solver * solver, formula_constraint & fc) {
 | 
			
		||||
            vector<std::pair<mpq, var_index>> ls;
 | 
			
		||||
            for (auto & it : fc.m_coeffs) {
 | 
			
		||||
                ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second))));
 | 
			
		||||
                ls.push_back(std::make_pair(it.first, solver->add_var(register_name(it.second), false)));
 | 
			
		||||
            }
 | 
			
		||||
            solver->add_constraint(ls, fc.m_kind, fc.m_right_side);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -4,7 +4,6 @@ Copyright (c) 2015 Microsoft Corporation
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#include "util/lp/sparse_matrix.h"
 | 
			
		||||
#include "math/simplex/sparse_matrix_def.h"
 | 
			
		||||
#include "math/simplex/simplex.h"
 | 
			
		||||
#include "math/simplex/simplex_def.h"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,33 +1,37 @@
 | 
			
		|||
z3_add_component(lp
 | 
			
		||||
  SOURCES
 | 
			
		||||
    lp_utils.cpp
 | 
			
		||||
    binary_heap_priority_queue_instances.cpp
 | 
			
		||||
    binary_heap_upair_queue_instances.cpp
 | 
			
		||||
    lp_bound_propagator.cpp
 | 
			
		||||
    core_solver_pretty_printer_instances.cpp
 | 
			
		||||
    dense_matrix_instances.cpp
 | 
			
		||||
    eta_matrix_instances.cpp
 | 
			
		||||
    indexed_vector_instances.cpp
 | 
			
		||||
    lar_core_solver_instances.cpp
 | 
			
		||||
    lp_core_solver_base_instances.cpp
 | 
			
		||||
    lp_dual_core_solver_instances.cpp
 | 
			
		||||
    lp_dual_simplex_instances.cpp
 | 
			
		||||
    lp_primal_core_solver_instances.cpp
 | 
			
		||||
    lp_primal_simplex_instances.cpp
 | 
			
		||||
    lp_settings_instances.cpp
 | 
			
		||||
    lp_solver_instances.cpp
 | 
			
		||||
    lu_instances.cpp
 | 
			
		||||
    matrix_instances.cpp
 | 
			
		||||
    permutation_matrix_instances.cpp
 | 
			
		||||
    quick_xplain.cpp
 | 
			
		||||
    row_eta_matrix_instances.cpp
 | 
			
		||||
    scaler_instances.cpp
 | 
			
		||||
    sparse_matrix_instances.cpp
 | 
			
		||||
    square_dense_submatrix_instances.cpp
 | 
			
		||||
    static_matrix_instances.cpp
 | 
			
		||||
    random_updater_instances.cpp      
 | 
			
		||||
    binary_heap_priority_queue.cpp
 | 
			
		||||
    binary_heap_upair_queue.cpp
 | 
			
		||||
    bound_propagator.cpp
 | 
			
		||||
    core_solver_pretty_printer.cpp
 | 
			
		||||
    dense_matrix.cpp
 | 
			
		||||
    eta_matrix.cpp
 | 
			
		||||
    indexed_vector.cpp
 | 
			
		||||
    int_solver.cpp
 | 
			
		||||
    lar_solver.cpp
 | 
			
		||||
    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
 | 
			
		||||
    matrix.cpp
 | 
			
		||||
    nra_solver.cpp
 | 
			
		||||
    permutation_matrix.cpp
 | 
			
		||||
    row_eta_matrix.cpp
 | 
			
		||||
    scaler.cpp
 | 
			
		||||
    square_sparse_matrix.cpp
 | 
			
		||||
    square_dense_submatrix.cpp
 | 
			
		||||
    static_matrix.cpp
 | 
			
		||||
    random_updater.cpp      
 | 
			
		||||
  COMPONENT_DEPENDENCIES
 | 
			
		||||
    util
 | 
			
		||||
    polynomial
 | 
			
		||||
    nlsat
 | 
			
		||||
  PYG_FILES
 | 
			
		||||
    lp_params.pyg
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										76
									
								
								src/util/lp/active_set.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								src/util/lp/active_set.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
class active_set {
 | 
			
		||||
    std::unordered_set<constraint*, constraint_hash, constraint_equal> m_cs;
 | 
			
		||||
    binary_heap_priority_queue<int>                                    m_q;
 | 
			
		||||
    std::unordered_map<unsigned, constraint *>                         m_id_to_constraint;
 | 
			
		||||
public:
 | 
			
		||||
    std::unordered_set<constraint*, constraint_hash, constraint_equal> cs() const { return m_cs;}
 | 
			
		||||
 | 
			
		||||
    bool contains(const constraint* c)  const {
 | 
			
		||||
        return m_id_to_constraint.find(c->id()) != m_id_to_constraint.end();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bool is_empty() const { return m_cs.size() == 0; }
 | 
			
		||||
    // low priority will be dequeued first
 | 
			
		||||
    void add_constraint(constraint* c, int priority) {
 | 
			
		||||
        if (contains(c))
 | 
			
		||||
            return;
 | 
			
		||||
        m_cs.insert(c);
 | 
			
		||||
        m_id_to_constraint[c->id()] = c;
 | 
			
		||||
        m_q.enqueue(c->id(), priority);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clear() {
 | 
			
		||||
        m_cs.clear();
 | 
			
		||||
        m_id_to_constraint.clear();
 | 
			
		||||
        m_q.clear();
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
    constraint* remove_constraint() {
 | 
			
		||||
        if (m_cs.size() == 0)
 | 
			
		||||
            return nullptr;
 | 
			
		||||
        unsigned id = m_q.dequeue();
 | 
			
		||||
        auto it = m_id_to_constraint.find(id);
 | 
			
		||||
        lp_assert(it != m_id_to_constraint.end());
 | 
			
		||||
        constraint* c = it->second;
 | 
			
		||||
        m_cs.erase(c);
 | 
			
		||||
        m_id_to_constraint.erase(it);
 | 
			
		||||
        return c;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    unsigned size() const {
 | 
			
		||||
        return static_cast<unsigned>(m_cs.size());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void remove_constraint(constraint * c) {
 | 
			
		||||
        if (! contains(c)) return;
 | 
			
		||||
        
 | 
			
		||||
        m_cs.erase(c);
 | 
			
		||||
        m_id_to_constraint.erase(c->id());
 | 
			
		||||
        m_q.remove(c->id());
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.hpp"
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue_def.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template binary_heap_priority_queue<int>::binary_heap_priority_queue(unsigned int);
 | 
			
		||||
template unsigned binary_heap_priority_queue<int>::dequeue();
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +45,7 @@ public:
 | 
			
		|||
    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 two times automatically if needed
 | 
			
		||||
    // The capacity will be enlarged each time twice if needed
 | 
			
		||||
    binary_heap_priority_queue(unsigned n);
 | 
			
		||||
 | 
			
		||||
    void clear() {
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ public:
 | 
			
		|||
    /// return the first element of the queue and removes it from the queue
 | 
			
		||||
    unsigned dequeue();
 | 
			
		||||
    unsigned peek() const {
 | 
			
		||||
        SASSERT(m_heap_size > 0);
 | 
			
		||||
        lp_assert(m_heap_size > 0);
 | 
			
		||||
        return m_heap[1];
 | 
			
		||||
    }
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ Revision History:
 | 
			
		|||
#include "util/vector.h"
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
// this is the child place in the heap
 | 
			
		||||
// "i" is the child's place in the heap
 | 
			
		||||
template <typename T> void binary_heap_priority_queue<T>::swap_with_parent(unsigned i) {
 | 
			
		||||
    unsigned parent = m_heap[i >> 1];
 | 
			
		||||
    put_at(i >> 1, m_heap[i]);
 | 
			
		||||
| 
						 | 
				
			
			@ -48,8 +48,8 @@ template <typename T> void binary_heap_priority_queue<T>::decrease_priority(unsi
 | 
			
		|||
template <typename T> bool binary_heap_priority_queue<T>::is_consistent() const {
 | 
			
		||||
    for (int i = 0; i < m_heap_inverse.size(); i++) {
 | 
			
		||||
        int i_index = m_heap_inverse[i];
 | 
			
		||||
        SASSERT(i_index <= static_cast<int>(m_heap_size));
 | 
			
		||||
        SASSERT(i_index == -1 || m_heap[i_index] == i);
 | 
			
		||||
        lp_assert(i_index <= static_cast<int>(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;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,7 +71,7 @@ template <typename T> void binary_heap_priority_queue<T>::remove(unsigned o) {
 | 
			
		|||
    if (o_in_heap == -1)  {
 | 
			
		||||
        return;  // nothing to do
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(static_cast<unsigned>(o_in_heap) <= m_heap_size);
 | 
			
		||||
    lp_assert(static_cast<unsigned>(o_in_heap) <= m_heap_size);
 | 
			
		||||
    if (static_cast<unsigned>(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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -88,11 +88,11 @@ template <typename T> void binary_heap_priority_queue<T>::remove(unsigned o) {
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        SASSERT(static_cast<unsigned>(o_in_heap) == m_heap_size);
 | 
			
		||||
        lp_assert(static_cast<unsigned>(o_in_heap) == m_heap_size);
 | 
			
		||||
        m_heap_size--;
 | 
			
		||||
    }
 | 
			
		||||
    m_heap_inverse[o] = -1;
 | 
			
		||||
    // SASSERT(is_consistent());
 | 
			
		||||
    // lp_assert(is_consistent());
 | 
			
		||||
}
 | 
			
		||||
// n is the initial queue capacity.
 | 
			
		||||
// The capacity will be enlarged two times automatically if needed
 | 
			
		||||
| 
						 | 
				
			
			@ -118,7 +118,7 @@ template <typename T> void binary_heap_priority_queue<T>::put_to_heap(unsigned i
 | 
			
		|||
template <typename T> void binary_heap_priority_queue<T>::enqueue_new(unsigned o, const T& priority) {
 | 
			
		||||
    m_heap_size++;
 | 
			
		||||
    int i = m_heap_size;
 | 
			
		||||
    SASSERT(o < m_priorities.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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -130,8 +130,12 @@ template <typename T> void binary_heap_priority_queue<T>::enqueue_new(unsigned o
 | 
			
		|||
// In this case the priority will be changed and the queue adjusted.
 | 
			
		||||
template <typename T> void binary_heap_priority_queue<T>::enqueue(unsigned o, const T & priority) {
 | 
			
		||||
    if (o >= m_priorities.size()) {
 | 
			
		||||
        resize(o << 1); // make the size twice larger
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			@ -150,7 +154,7 @@ template <typename T> void binary_heap_priority_queue<T>::change_priority_for_ex
 | 
			
		|||
 | 
			
		||||
/// return the first element of the queue and removes it from the queue
 | 
			
		||||
template <typename T> unsigned binary_heap_priority_queue<T>::dequeue_and_get_priority(T & priority) {
 | 
			
		||||
    SASSERT(m_heap_size != 0);
 | 
			
		||||
    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();
 | 
			
		||||
| 
						 | 
				
			
			@ -184,7 +188,7 @@ template <typename T> void binary_heap_priority_queue<T>::put_the_last_at_the_to
 | 
			
		|||
}
 | 
			
		||||
/// return the first element of the queue and removes it from the queue
 | 
			
		||||
template <typename T> unsigned binary_heap_priority_queue<T>::dequeue() {
 | 
			
		||||
    SASSERT(m_heap_size > 0);
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/binary_heap_upair_queue.hpp"
 | 
			
		||||
#include "util/lp/binary_heap_upair_queue_def.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template binary_heap_upair_queue<int>::binary_heap_upair_queue(unsigned int);
 | 
			
		||||
template binary_heap_upair_queue<unsigned int>::binary_heap_upair_queue(unsigned int);
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +29,7 @@ template <typename T> binary_heap_upair_queue<T>::binary_heap_upair_queue(unsign
 | 
			
		|||
 | 
			
		||||
template <typename T> unsigned
 | 
			
		||||
binary_heap_upair_queue<T>::dequeue_available_spot() {
 | 
			
		||||
    SASSERT(m_available_spots.empty() == false);
 | 
			
		||||
    lp_assert(m_available_spots.empty() == false);
 | 
			
		||||
    unsigned ret = m_available_spots.back();
 | 
			
		||||
    m_available_spots.pop_back();
 | 
			
		||||
    return ret;
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +69,7 @@ template <typename T> void binary_heap_upair_queue<T>::enqueue(unsigned i, unsig
 | 
			
		|||
            m_pairs.resize(new_size);
 | 
			
		||||
        }
 | 
			
		||||
        ij_index = dequeue_available_spot();
 | 
			
		||||
        // SASSERT(ij_index<m_pairs.size() && ij_index_is_new(ij_index));
 | 
			
		||||
        // lp_assert(ij_index<m_pairs.size() && ij_index_is_new(ij_index));
 | 
			
		||||
        m_pairs[ij_index] = p;
 | 
			
		||||
        m_pairs_to_index[p] = ij_index;
 | 
			
		||||
    } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -79,7 +79,7 @@ template <typename T> void binary_heap_upair_queue<T>::enqueue(unsigned i, unsig
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T> void binary_heap_upair_queue<T>::dequeue(unsigned & i, unsigned &j) {
 | 
			
		||||
    SASSERT(!m_q.is_empty());
 | 
			
		||||
    lp_assert(!m_q.is_empty());
 | 
			
		||||
    unsigned ij_index = m_q.dequeue();
 | 
			
		||||
    upair & p = m_pairs[ij_index];
 | 
			
		||||
    i = p.first;
 | 
			
		||||
| 
						 | 
				
			
			@ -19,37 +19,93 @@ Revision History:
 | 
			
		|||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
#include "util/lp/implied_bound.h"
 | 
			
		||||
#include "util/lp/test_bound_analyzer.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lp_bound_propagator.h"
 | 
			
		||||
#include "implied_bound.h"
 | 
			
		||||
#include "test_bound_analyzer.h"
 | 
			
		||||
#include "util/lp/bound_propagator.h"
 | 
			
		||||
// We have an equality : sum by j of row[j]*x[j] = rs
 | 
			
		||||
// We try to pin a var by pushing the total by using the variable bounds
 | 
			
		||||
// In a loop we drive the partial sum down, denoting the variables of this process by _u.
 | 
			
		||||
// In the same loop trying to pin variables by pushing the partial sum up, denoting the variable related to it by _l
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
template <typename C> // C plays a role of a container
 | 
			
		||||
class bound_analyzer_on_row {
 | 
			
		||||
    struct term_with_basis_col {
 | 
			
		||||
        const C &  m_row;
 | 
			
		||||
        unsigned   m_bj;
 | 
			
		||||
        struct ival {
 | 
			
		||||
            unsigned m_var;
 | 
			
		||||
            const mpq & m_coeff;
 | 
			
		||||
            ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) {
 | 
			
		||||
            }
 | 
			
		||||
            unsigned var() const { return m_var;}
 | 
			
		||||
            const mpq & coeff() const { return m_coeff; }
 | 
			
		||||
        };
 | 
			
		||||
        
 | 
			
		||||
        term_with_basis_col(const C& row, unsigned bj) : m_row(row), m_bj(bj) {}
 | 
			
		||||
        struct const_iterator {
 | 
			
		||||
            // fields
 | 
			
		||||
            typename C::const_iterator m_it;
 | 
			
		||||
            unsigned m_bj;
 | 
			
		||||
            
 | 
			
		||||
 | 
			
		||||
    linear_combination_iterator<mpq> & m_it;
 | 
			
		||||
    lp_bound_propagator &                 m_bp;
 | 
			
		||||
    unsigned           m_row_or_term_index;
 | 
			
		||||
    int                m_column_of_u; // index of an unlimited from above monoid
 | 
			
		||||
                               // -1 means that such a value is not found, -2 means that at least two of such monoids were found
 | 
			
		||||
    int                m_column_of_l; // index of an unlimited from below monoid
 | 
			
		||||
    impq               m_rs;
 | 
			
		||||
            //typedefs
 | 
			
		||||
            
 | 
			
		||||
            
 | 
			
		||||
            typedef const_iterator self_type;
 | 
			
		||||
            typedef ival value_type;
 | 
			
		||||
            typedef ival reference;
 | 
			
		||||
            typedef int difference_type;
 | 
			
		||||
            typedef std::forward_iterator_tag iterator_category;
 | 
			
		||||
 | 
			
		||||
            reference operator*() const {
 | 
			
		||||
                if (m_bj == static_cast<unsigned>(-1))
 | 
			
		||||
                    return ival((*m_it).var(), (*m_it).coeff());
 | 
			
		||||
                return ival(m_bj, - 1);
 | 
			
		||||
            }        
 | 
			
		||||
            self_type operator++() {  self_type i = *this; operator++(1); return i;  }
 | 
			
		||||
            
 | 
			
		||||
            self_type operator++(int) {
 | 
			
		||||
                if (m_bj == static_cast<unsigned>(-1))
 | 
			
		||||
                    m_it++;
 | 
			
		||||
                else
 | 
			
		||||
                    m_bj = static_cast<unsigned>(-1);
 | 
			
		||||
                return *this;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // constructor
 | 
			
		||||
            const_iterator(const typename C::const_iterator& it, unsigned bj) :
 | 
			
		||||
                m_it(it),
 | 
			
		||||
                m_bj(bj)
 | 
			
		||||
            {}
 | 
			
		||||
            bool operator==(const self_type &other) const {
 | 
			
		||||
                return m_it == other.m_it && m_bj == other.m_bj ;
 | 
			
		||||
            }
 | 
			
		||||
            bool operator!=(const self_type &other) const { return !(*this == other); }
 | 
			
		||||
        };
 | 
			
		||||
        const_iterator begin() const {
 | 
			
		||||
            return const_iterator( m_row.begin(), m_bj);
 | 
			
		||||
        }
 | 
			
		||||
        const_iterator end() const { return const_iterator(m_row.end(), m_bj); }
 | 
			
		||||
    };
 | 
			
		||||
    term_with_basis_col                m_row;
 | 
			
		||||
    bound_propagator &                 m_bp;
 | 
			
		||||
    unsigned                           m_row_or_term_index;
 | 
			
		||||
    int                                m_column_of_u; // index of an unlimited from above monoid
 | 
			
		||||
    // -1 means that such a value is not found, -2 means that at least two of such monoids were found
 | 
			
		||||
    int                                m_column_of_l; // index of an unlimited from below monoid
 | 
			
		||||
    impq                               m_rs;
 | 
			
		||||
 | 
			
		||||
public :
 | 
			
		||||
    // constructor
 | 
			
		||||
    bound_analyzer_on_row(
 | 
			
		||||
                          linear_combination_iterator<mpq> &it,
 | 
			
		||||
                          const numeric_pair<mpq>& rs,
 | 
			
		||||
                          unsigned row_or_term_index,
 | 
			
		||||
                          lp_bound_propagator & bp
 | 
			
		||||
        const C & it,
 | 
			
		||||
        unsigned  bj, // basis column for the row
 | 
			
		||||
        const numeric_pair<mpq>& rs,
 | 
			
		||||
        unsigned row_or_term_index,
 | 
			
		||||
        bound_propagator & bp
 | 
			
		||||
                          )
 | 
			
		||||
        :
 | 
			
		||||
        m_it(it),
 | 
			
		||||
        m_row(it, bj),
 | 
			
		||||
        m_bp(bp),
 | 
			
		||||
        m_row_or_term_index(row_or_term_index),
 | 
			
		||||
        m_column_of_u(-1),
 | 
			
		||||
| 
						 | 
				
			
			@ -60,11 +116,11 @@ public :
 | 
			
		|||
 | 
			
		||||
    unsigned j;
 | 
			
		||||
    void analyze() {
 | 
			
		||||
 | 
			
		||||
        mpq a; unsigned j;
 | 
			
		||||
        while (((m_column_of_l != -2) || (m_column_of_u != -2)) && m_it.next(a, j))
 | 
			
		||||
            analyze_bound_on_var_on_coeff(j, a);
 | 
			
		||||
 | 
			
		||||
        for (const auto & c : m_row) {
 | 
			
		||||
            if ((m_column_of_l == -2) && (m_column_of_u == -2))
 | 
			
		||||
                break;
 | 
			
		||||
            analyze_bound_on_var_on_coeff(c.var(), c.coeff());
 | 
			
		||||
        }
 | 
			
		||||
        if (m_column_of_u >= 0)
 | 
			
		||||
            limit_monoid_u_from_below();
 | 
			
		||||
        else if (m_column_of_u == -1)
 | 
			
		||||
| 
						 | 
				
			
			@ -76,42 +132,42 @@ public :
 | 
			
		|||
            limit_all_monoids_from_above();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool bound_is_available(unsigned j, bool low_bound) {
 | 
			
		||||
        return (low_bound && low_bound_is_available(j)) ||
 | 
			
		||||
            (!low_bound && upper_bound_is_available(j));
 | 
			
		||||
    bool bound_is_available(unsigned j, bool lower_bound) {
 | 
			
		||||
        return (lower_bound && lower_bound_is_available(j)) ||
 | 
			
		||||
            (!lower_bound && upper_bound_is_available(j));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool upper_bound_is_available(unsigned j) const {
 | 
			
		||||
        switch (m_bp.get_column_type(j))
 | 
			
		||||
        {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
            {
 | 
			
		||||
            case column_type::fixed:
 | 
			
		||||
            case column_type::boxed:
 | 
			
		||||
            case column_type::upper_bound:
 | 
			
		||||
                return true;
 | 
			
		||||
            default:
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool low_bound_is_available(unsigned j) const {
 | 
			
		||||
    bool lower_bound_is_available(unsigned j) const {
 | 
			
		||||
        switch (m_bp.get_column_type(j))
 | 
			
		||||
        {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
            {
 | 
			
		||||
            case column_type::fixed:
 | 
			
		||||
            case column_type::boxed:
 | 
			
		||||
            case column_type::lower_bound:
 | 
			
		||||
                return true;
 | 
			
		||||
            default:
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const impq & ub(unsigned j) const {
 | 
			
		||||
        SASSERT(upper_bound_is_available(j));
 | 
			
		||||
        lp_assert(upper_bound_is_available(j));
 | 
			
		||||
        return m_bp.get_upper_bound(j);
 | 
			
		||||
    }
 | 
			
		||||
    const impq & lb(unsigned j) const {
 | 
			
		||||
        SASSERT(low_bound_is_available(j));
 | 
			
		||||
        return m_bp.get_low_bound(j);
 | 
			
		||||
        lp_assert(lower_bound_is_available(j));
 | 
			
		||||
        return m_bp.get_lower_bound(j);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,7 +207,7 @@ public :
 | 
			
		|||
            strict = !is_zero(ub(j).y);
 | 
			
		||||
            return a * ub(j).x;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        strict = !is_zero(lb(j).y);
 | 
			
		||||
        return a * lb(j).x;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -160,34 +216,32 @@ public :
 | 
			
		|||
        if (is_neg(a)) {
 | 
			
		||||
            return a * ub(j).x;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        return a * lb(j).x;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    void limit_all_monoids_from_above() {
 | 
			
		||||
        int strict = 0;
 | 
			
		||||
        mpq total;
 | 
			
		||||
        SASSERT(is_zero(total));
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        mpq a; unsigned j;
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
        lp_assert(is_zero(total));
 | 
			
		||||
        for (const auto& p : m_row) {
 | 
			
		||||
            bool str;
 | 
			
		||||
            total -= monoid_min(a, j, str);
 | 
			
		||||
            total -= monoid_min(p.coeff(), p.var(), str);
 | 
			
		||||
            if (str)
 | 
			
		||||
                strict++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
        
 | 
			
		||||
        for (const auto &p : m_row) {
 | 
			
		||||
            bool str;
 | 
			
		||||
            bool a_is_pos = is_pos(a);
 | 
			
		||||
            mpq bound = total / a + monoid_min_no_mult(a_is_pos, j, str);
 | 
			
		||||
            bool a_is_pos = is_pos(p.coeff());
 | 
			
		||||
            mpq bound = total / p.coeff() + monoid_min_no_mult(a_is_pos, p.var(), str);
 | 
			
		||||
            if (a_is_pos) {
 | 
			
		||||
                limit_j(j, bound, true, false, strict - static_cast<int>(str) > 0);
 | 
			
		||||
                limit_j(p.var(), bound, true, false, strict - static_cast<int>(str) > 0);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                limit_j(j, bound, false, true, strict - static_cast<int>(str) > 0);
 | 
			
		||||
                limit_j(p.var(), bound, false, true, strict - static_cast<int>(str) > 0);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -195,52 +249,50 @@ public :
 | 
			
		|||
    void limit_all_monoids_from_below() {
 | 
			
		||||
        int strict = 0;
 | 
			
		||||
        mpq total;
 | 
			
		||||
        SASSERT(is_zero(total));
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        mpq a; unsigned j;
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
        lp_assert(is_zero(total));
 | 
			
		||||
        for (const auto &p : m_row) {
 | 
			
		||||
            bool str;
 | 
			
		||||
            total -= monoid_max(a, j, str);
 | 
			
		||||
            total -= monoid_max(p.coeff(), p.var(), str);
 | 
			
		||||
            if (str)
 | 
			
		||||
                strict++;
 | 
			
		||||
        }
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
 | 
			
		||||
        for (const auto& p : m_row) {
 | 
			
		||||
            bool str;
 | 
			
		||||
            bool a_is_pos = is_pos(a);
 | 
			
		||||
            mpq bound = total / a + monoid_max_no_mult(a_is_pos, j, str);
 | 
			
		||||
            bool astrict = strict - static_cast<int>(str) > 0;
 | 
			
		||||
            bool a_is_pos = is_pos(p.coeff());
 | 
			
		||||
            mpq bound = total / p.coeff() + monoid_max_no_mult(a_is_pos, p.var(), str);
 | 
			
		||||
            bool astrict = strict - static_cast<int>(str) > 0; 
 | 
			
		||||
            if (a_is_pos) {
 | 
			
		||||
                limit_j(j, bound, true, true, astrict);
 | 
			
		||||
                limit_j(p.var(), bound, true, true, astrict);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                limit_j(j, bound, false, false, astrict);
 | 
			
		||||
                limit_j(p.var(), bound, false, false, astrict);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void limit_monoid_u_from_below() {
 | 
			
		||||
        // we are going to limit from below the monoid m_column_of_u,
 | 
			
		||||
        // every other monoid is impossible to limit from below
 | 
			
		||||
        mpq u_coeff, a;
 | 
			
		||||
        mpq u_coeff;
 | 
			
		||||
        unsigned j;
 | 
			
		||||
        mpq bound = -m_rs.x;
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        bool strict = false;
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
        for (const auto& p : m_row) {
 | 
			
		||||
            j = p.var();
 | 
			
		||||
            if (j == static_cast<unsigned>(m_column_of_u)) {
 | 
			
		||||
                u_coeff = a;
 | 
			
		||||
                u_coeff = p.coeff();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
            bool str;
 | 
			
		||||
            bound -= monoid_max(a, j, str);
 | 
			
		||||
            bound -= monoid_max(p.coeff(), j, str);
 | 
			
		||||
            if (str)
 | 
			
		||||
                strict = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bound /= u_coeff;
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        if (numeric_traits<impq>::is_pos(u_coeff)) {
 | 
			
		||||
            limit_j(m_column_of_u, bound, true, true, strict);
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -252,19 +304,19 @@ public :
 | 
			
		|||
    void limit_monoid_l_from_above() {
 | 
			
		||||
        // we are going to limit from above the monoid m_column_of_l,
 | 
			
		||||
        // every other monoid is impossible to limit from above
 | 
			
		||||
        mpq l_coeff, a;
 | 
			
		||||
        mpq l_coeff;
 | 
			
		||||
        unsigned j;
 | 
			
		||||
        mpq bound = -m_rs.x;
 | 
			
		||||
        bool strict = false;
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
        while (m_it.next(a, j)) {
 | 
			
		||||
        for (const auto &p : m_row) {
 | 
			
		||||
            j = p.var();
 | 
			
		||||
            if (j == static_cast<unsigned>(m_column_of_l)) {
 | 
			
		||||
                l_coeff = a;
 | 
			
		||||
                l_coeff = p.coeff();
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            bool str;
 | 
			
		||||
            bound -= monoid_min(a, j, str);
 | 
			
		||||
            bound -= monoid_min(p.coeff(), j, str);
 | 
			
		||||
            if (str)
 | 
			
		||||
                strict = true;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -275,51 +327,51 @@ public :
 | 
			
		|||
            limit_j(m_column_of_l, bound, false, true, strict);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    // // it is the coefficent before the bounded column
 | 
			
		||||
    // void provide_evidence(bool coeff_is_pos) {
 | 
			
		||||
    //     /*
 | 
			
		||||
    //     auto & be = m_ibounds.back();
 | 
			
		||||
    //     bool low_bound = be.m_low_bound;
 | 
			
		||||
    //     bool lower_bound = be.m_lower_bound;
 | 
			
		||||
    //     if (!coeff_is_pos)
 | 
			
		||||
    //         low_bound = !low_bound;
 | 
			
		||||
    //     auto it = m_it.clone();
 | 
			
		||||
    //         lower_bound = !lower_bound;
 | 
			
		||||
    //     auto it = m_row.clone();
 | 
			
		||||
    //     mpq a; unsigned j;
 | 
			
		||||
    //     while (it->next(a, j)) {
 | 
			
		||||
    //         if (be.m_j == j) continue;
 | 
			
		||||
    //         SASSERT(bound_is_available(j, is_neg(a) ? low_bound : !low_bound));
 | 
			
		||||
    //         lp_assert(bound_is_available(j, is_neg(a) ? lower_bound : !lower_bound));
 | 
			
		||||
    //         be.m_vector_of_bound_signatures.emplace_back(a, j, numeric_traits<impq>::
 | 
			
		||||
    //                                                      is_neg(a)? low_bound: !low_bound);
 | 
			
		||||
    //                                                      is_neg(a)? lower_bound: !lower_bound);
 | 
			
		||||
    //     }
 | 
			
		||||
    //     delete it;
 | 
			
		||||
    //     */
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_low_bound, bool strict){
 | 
			
		||||
        m_bp.try_add_bound(u, j, is_low_bound, coeff_before_j_is_pos, m_row_or_term_index, strict);
 | 
			
		||||
    void limit_j(unsigned j, const mpq& u, bool coeff_before_j_is_pos, bool is_lower_bound, bool strict){
 | 
			
		||||
        m_bp.try_add_bound(u, j, is_lower_bound, coeff_before_j_is_pos, m_row_or_term_index, strict);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void advance_u(unsigned j) {
 | 
			
		||||
        if (m_column_of_u == -1)
 | 
			
		||||
            m_column_of_u = j;
 | 
			
		||||
        else
 | 
			
		||||
            m_column_of_u = -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void advance_l(unsigned j) {
 | 
			
		||||
        if (m_column_of_l == -1)
 | 
			
		||||
            m_column_of_l = j;
 | 
			
		||||
        else
 | 
			
		||||
            m_column_of_l = -2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void analyze_bound_on_var_on_coeff(int j, const mpq &a) {
 | 
			
		||||
        switch (m_bp.get_column_type(j)) {
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (numeric_traits<mpq>::is_pos(a))
 | 
			
		||||
                advance_u(j);
 | 
			
		||||
            else
 | 
			
		||||
            else 
 | 
			
		||||
                advance_l(j);
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
| 
						 | 
				
			
			@ -337,14 +389,16 @@ public :
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void analyze_row(linear_combination_iterator<mpq> &it,
 | 
			
		||||
    static void analyze_row(const C & row,
 | 
			
		||||
                            unsigned bj, // basis column for the row
 | 
			
		||||
                            const numeric_pair<mpq>& rs,
 | 
			
		||||
                            unsigned row_or_term_index,
 | 
			
		||||
                            lp_bound_propagator & bp
 | 
			
		||||
                            bound_propagator & bp
 | 
			
		||||
                            ) {
 | 
			
		||||
        bound_analyzer_on_row a(it, rs, row_or_term_index, bp);
 | 
			
		||||
        bound_analyzer_on_row a(row, bj, rs, row_or_term_index, bp);
 | 
			
		||||
        a.analyze();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										58
									
								
								src/util/lp/bound_propagator.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/util/lp/bound_propagator.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,58 @@
 | 
			
		|||
/*
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
  Author: Lev Nachmanson
 | 
			
		||||
*/
 | 
			
		||||
#include "util/lp/lar_solver.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
bound_propagator::bound_propagator(lar_solver & ls):
 | 
			
		||||
    m_lar_solver(ls) {}
 | 
			
		||||
column_type bound_propagator::get_column_type(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j];
 | 
			
		||||
}
 | 
			
		||||
const impq & bound_propagator::get_lower_bound(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_r_lower_bounds()[j];
 | 
			
		||||
}
 | 
			
		||||
const impq & bound_propagator::get_upper_bound(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j];
 | 
			
		||||
}
 | 
			
		||||
void bound_propagator::try_add_bound(mpq  v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
 | 
			
		||||
    j = m_lar_solver.adjust_column_index_to_term_index(j);    
 | 
			
		||||
    if (m_lar_solver.is_term(j)) {
 | 
			
		||||
        // lp treats terms as not having a free coefficient, restoring it below for the outside consumption
 | 
			
		||||
        v += m_lar_solver.get_term(j).m_v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lconstraint_kind kind = is_low? GE : LE;
 | 
			
		||||
    if (strict)
 | 
			
		||||
        kind = static_cast<lconstraint_kind>(kind / 2);
 | 
			
		||||
    
 | 
			
		||||
    if (!bound_is_interesting(j, kind, v))
 | 
			
		||||
        return;
 | 
			
		||||
     unsigned k; // index to ibounds
 | 
			
		||||
     if (is_low) {
 | 
			
		||||
         if (try_get_value(m_improved_lower_bounds, j, k)) {
 | 
			
		||||
             auto & found_bound = m_ibounds[k];
 | 
			
		||||
             if (v > found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict)) {
 | 
			
		||||
                 found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
 | 
			
		||||
                 TRACE("try_add_bound", m_lar_solver.print_implied_bound(found_bound, tout););
 | 
			
		||||
             }
 | 
			
		||||
         } else {
 | 
			
		||||
             m_improved_lower_bounds[j] = m_ibounds.size();
 | 
			
		||||
             m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
 | 
			
		||||
             TRACE("try_add_bound", m_lar_solver.print_implied_bound(m_ibounds.back(), tout););
 | 
			
		||||
         }
 | 
			
		||||
     } else { // the upper bound case
 | 
			
		||||
         if (try_get_value(m_improved_upper_bounds, j, k)) {
 | 
			
		||||
             auto & found_bound = m_ibounds[k];
 | 
			
		||||
             if (v < found_bound.m_bound || (v == found_bound.m_bound && found_bound.m_strict == false && strict)) {
 | 
			
		||||
                 found_bound = implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
 | 
			
		||||
                 TRACE("try_add_bound", m_lar_solver.print_implied_bound(found_bound, tout););
 | 
			
		||||
             }
 | 
			
		||||
         } else {
 | 
			
		||||
             m_improved_upper_bounds[j] = m_ibounds.size();
 | 
			
		||||
             m_ibounds.push_back(implied_bound(v, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
 | 
			
		||||
             TRACE("try_add_bound", m_lar_solver.print_implied_bound(m_ibounds.back(), tout););
 | 
			
		||||
        }
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								src/util/lp/bound_propagator.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/util/lp/bound_propagator.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,27 @@
 | 
			
		|||
/*
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
  Author: Lev Nachmanson
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/lp_settings.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
class lar_solver;
 | 
			
		||||
class bound_propagator {
 | 
			
		||||
    std::unordered_map<unsigned, unsigned> m_improved_lower_bounds; // these maps map a column index to the corresponding index in ibounds
 | 
			
		||||
    std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
 | 
			
		||||
    lar_solver & m_lar_solver;
 | 
			
		||||
public:
 | 
			
		||||
    vector<implied_bound> m_ibounds;
 | 
			
		||||
public:
 | 
			
		||||
    bound_propagator(lar_solver & ls);
 | 
			
		||||
    column_type get_column_type(unsigned) const;
 | 
			
		||||
    const impq & get_lower_bound(unsigned) const;
 | 
			
		||||
    const impq & get_upper_bound(unsigned) const;
 | 
			
		||||
    void try_add_bound(mpq  v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict);
 | 
			
		||||
    virtual bool bound_is_interesting(unsigned vi,
 | 
			
		||||
                                      lp::lconstraint_kind kind,
 | 
			
		||||
                                      const rational & bval) {return true;}
 | 
			
		||||
    unsigned number_of_found_bounds() const { return m_ibounds.size(); }
 | 
			
		||||
    virtual void consume(mpq const& v, lp::constraint_index j) = 0;
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -30,11 +30,11 @@ inline bool is_valid(unsigned j) { return static_cast<int>(j) >= 0;}
 | 
			
		|||
template <typename T>
 | 
			
		||||
class column_info {
 | 
			
		||||
    std::string m_name;
 | 
			
		||||
    bool        m_low_bound_is_set;
 | 
			
		||||
    bool        m_low_bound_is_strict;
 | 
			
		||||
    bool        m_lower_bound_is_set;
 | 
			
		||||
    bool        m_lower_bound_is_strict;
 | 
			
		||||
    bool        m_upper_bound_is_set;
 | 
			
		||||
    bool        m_upper_bound_is_strict;
 | 
			
		||||
    T           m_low_bound;
 | 
			
		||||
    T           m_lower_bound;
 | 
			
		||||
    T           m_upper_bound;
 | 
			
		||||
    T           m_fixed_value;
 | 
			
		||||
    bool        m_is_fixed;
 | 
			
		||||
| 
						 | 
				
			
			@ -43,11 +43,11 @@ class column_info {
 | 
			
		|||
public:
 | 
			
		||||
    bool operator==(const column_info & c) const {
 | 
			
		||||
        return m_name == c.m_name &&
 | 
			
		||||
            m_low_bound_is_set == c.m_low_bound_is_set &&
 | 
			
		||||
            m_low_bound_is_strict == c.m_low_bound_is_strict &&
 | 
			
		||||
            m_lower_bound_is_set == c.m_lower_bound_is_set &&
 | 
			
		||||
            m_lower_bound_is_strict == c.m_lower_bound_is_strict &&
 | 
			
		||||
            m_upper_bound_is_set == c.m_upper_bound_is_set&&
 | 
			
		||||
            m_upper_bound_is_strict == c.m_upper_bound_is_strict&&
 | 
			
		||||
            (!m_low_bound_is_set || m_low_bound == c.m_low_bound) &&
 | 
			
		||||
            (!m_lower_bound_is_set || m_lower_bound == c.m_low_bound) &&
 | 
			
		||||
            (!m_upper_bound_is_set || m_upper_bound == c.m_upper_bound) &&
 | 
			
		||||
            m_cost == c.m_cost &&
 | 
			
		||||
            m_is_fixed == c.m_is_fixed &&
 | 
			
		||||
| 
						 | 
				
			
			@ -60,8 +60,8 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
    // the default constructor
 | 
			
		||||
    column_info():
 | 
			
		||||
        m_low_bound_is_set(false),
 | 
			
		||||
        m_low_bound_is_strict(false),
 | 
			
		||||
        m_lower_bound_is_set(false),
 | 
			
		||||
        m_lower_bound_is_strict(false),
 | 
			
		||||
        m_upper_bound_is_set (false),
 | 
			
		||||
        m_upper_bound_is_strict (false),
 | 
			
		||||
        m_is_fixed(false),
 | 
			
		||||
| 
						 | 
				
			
			@ -70,8 +70,8 @@ public:
 | 
			
		|||
    {}
 | 
			
		||||
    
 | 
			
		||||
    column_info(unsigned column_index) :
 | 
			
		||||
        m_low_bound_is_set(false),
 | 
			
		||||
        m_low_bound_is_strict(false),
 | 
			
		||||
        m_lower_bound_is_set(false),
 | 
			
		||||
        m_lower_bound_is_strict(false),
 | 
			
		||||
        m_upper_bound_is_set (false),
 | 
			
		||||
        m_upper_bound_is_strict (false),
 | 
			
		||||
        m_is_fixed(false),
 | 
			
		||||
| 
						 | 
				
			
			@ -81,11 +81,11 @@ public:
 | 
			
		|||
 | 
			
		||||
    column_info(const column_info & ci) {
 | 
			
		||||
        m_name = ci.m_name;
 | 
			
		||||
        m_low_bound_is_set = ci.m_low_bound_is_set;
 | 
			
		||||
        m_low_bound_is_strict = ci.m_low_bound_is_strict;
 | 
			
		||||
        m_lower_bound_is_set = ci.m_lower_bound_is_set;
 | 
			
		||||
        m_lower_bound_is_strict = ci.m_lower_bound_is_strict;
 | 
			
		||||
        m_upper_bound_is_set = ci.m_upper_bound_is_set;
 | 
			
		||||
        m_upper_bound_is_strict = ci.m_upper_bound_is_strict;
 | 
			
		||||
        m_low_bound = ci.m_low_bound;
 | 
			
		||||
        m_lower_bound = ci.m_lower_bound;
 | 
			
		||||
        m_upper_bound = ci.m_upper_bound;
 | 
			
		||||
        m_cost = ci.m_cost;
 | 
			
		||||
        m_fixed_value = ci.m_fixed_value;
 | 
			
		||||
| 
						 | 
				
			
			@ -98,7 +98,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    column_type get_column_type() const {
 | 
			
		||||
        return m_is_fixed? column_type::fixed : (m_low_bound_is_set? (m_upper_bound_is_set? column_type::boxed : column_type::low_bound) : (m_upper_bound_is_set? column_type::upper_bound: column_type::free_column));
 | 
			
		||||
        return m_is_fixed? column_type::fixed : (m_lower_bound_is_set? (m_upper_bound_is_set? column_type::boxed : column_type::lower_bound) : (m_upper_bound_is_set? column_type::upper_bound: column_type::free_column));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    column_type get_column_type_no_flipping() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -106,25 +106,25 @@ public:
 | 
			
		|||
            return column_type::fixed;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (m_low_bound_is_set) {
 | 
			
		||||
            return m_upper_bound_is_set? column_type::boxed: column_type::low_bound;
 | 
			
		||||
        if (m_lower_bound_is_set) {
 | 
			
		||||
            return m_upper_bound_is_set? column_type::boxed: column_type::lower_bound;
 | 
			
		||||
        }
 | 
			
		||||
        // we are flipping the bounds!
 | 
			
		||||
        return m_upper_bound_is_set? column_type::upper_bound
 | 
			
		||||
            : column_type::free_column;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T get_low_bound() const {
 | 
			
		||||
        SASSERT(m_low_bound_is_set);
 | 
			
		||||
        return m_low_bound;
 | 
			
		||||
    T get_lower_bound() const {
 | 
			
		||||
        lp_assert(m_lower_bound_is_set);
 | 
			
		||||
        return m_lower_bound;
 | 
			
		||||
    }
 | 
			
		||||
    T get_upper_bound() const {
 | 
			
		||||
        SASSERT(m_upper_bound_is_set);
 | 
			
		||||
        lp_assert(m_upper_bound_is_set);
 | 
			
		||||
        return m_upper_bound;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool low_bound_is_set() const {
 | 
			
		||||
        return m_low_bound_is_set;
 | 
			
		||||
    bool lower_bound_is_set() const {
 | 
			
		||||
        return m_lower_bound_is_set;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool upper_bound_is_set() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -138,23 +138,23 @@ public:
 | 
			
		|||
        if (is_flipped()){
 | 
			
		||||
            return m_upper_bound;
 | 
			
		||||
        }
 | 
			
		||||
        return m_low_bound_is_set? m_low_bound : numeric_traits<T>::zero();
 | 
			
		||||
        return m_lower_bound_is_set? m_lower_bound : numeric_traits<T>::zero();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_flipped() {
 | 
			
		||||
        return m_upper_bound_is_set && !m_low_bound_is_set;
 | 
			
		||||
        return m_upper_bound_is_set && !m_lower_bound_is_set;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjusted_low_bound_is_set() {
 | 
			
		||||
        return !is_flipped()? low_bound_is_set(): upper_bound_is_set();
 | 
			
		||||
    bool adjusted_lower_bound_is_set() {
 | 
			
		||||
        return !is_flipped()? lower_bound_is_set(): upper_bound_is_set();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjusted_upper_bound_is_set() {
 | 
			
		||||
        return !is_flipped()? upper_bound_is_set(): low_bound_is_set();
 | 
			
		||||
        return !is_flipped()? upper_bound_is_set(): lower_bound_is_set();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    T  get_adjusted_upper_bound() {
 | 
			
		||||
        return get_upper_bound() - get_low_bound();
 | 
			
		||||
        return get_upper_bound() - get_lower_bound();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_fixed() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +162,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_free() {
 | 
			
		||||
        return !m_low_bound_is_set && !m_upper_bound_is_set;
 | 
			
		||||
        return !m_lower_bound_is_set && !m_upper_bound_is_set;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_fixed_value(T v) {
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +171,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    T get_fixed_value() const {
 | 
			
		||||
        SASSERT(m_is_fixed);
 | 
			
		||||
        lp_assert(m_is_fixed);
 | 
			
		||||
        return m_fixed_value;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -191,9 +191,9 @@ public:
 | 
			
		|||
        return m_name;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_low_bound(T const & l) {
 | 
			
		||||
        m_low_bound = l;
 | 
			
		||||
        m_low_bound_is_set = true;
 | 
			
		||||
    void set_lower_bound(T const & l) {
 | 
			
		||||
        m_lower_bound = l;
 | 
			
		||||
        m_lower_bound_is_set = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_upper_bound(T const & l) {
 | 
			
		||||
| 
						 | 
				
			
			@ -201,8 +201,8 @@ public:
 | 
			
		|||
        m_upper_bound_is_set = true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void unset_low_bound() {
 | 
			
		||||
        m_low_bound_is_set = false;
 | 
			
		||||
    void unset_lower_bound() {
 | 
			
		||||
        m_lower_bound_is_set = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void unset_upper_bound() {
 | 
			
		||||
| 
						 | 
				
			
			@ -213,8 +213,8 @@ public:
 | 
			
		|||
        m_is_fixed = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool low_bound_holds(T v) {
 | 
			
		||||
        return !low_bound_is_set() || v >= m_low_bound -T(0.0000001);
 | 
			
		||||
    bool lower_bound_holds(T v) {
 | 
			
		||||
        return !lower_bound_is_set() || v >= m_lower_bound -T(0.0000001);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool upper_bound_holds(T v) {
 | 
			
		||||
| 
						 | 
				
			
			@ -222,36 +222,36 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool bounds_hold(T v) {
 | 
			
		||||
        return low_bound_holds(v) && upper_bound_holds(v);
 | 
			
		||||
        return lower_bound_holds(v) && upper_bound_holds(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjusted_bounds_hold(T v) {
 | 
			
		||||
        return adjusted_low_bound_holds(v) && adjusted_upper_bound_holds(v);
 | 
			
		||||
        return adjusted_lower_bound_holds(v) && adjusted_upper_bound_holds(v);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjusted_low_bound_holds(T v) {
 | 
			
		||||
        return !adjusted_low_bound_is_set() || v >= -T(0.0000001);
 | 
			
		||||
    bool adjusted_lower_bound_holds(T v) {
 | 
			
		||||
        return !adjusted_lower_bound_is_set() || v >= -T(0.0000001);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjusted_upper_bound_holds(T v) {
 | 
			
		||||
        return !adjusted_upper_bound_is_set() || v <= get_adjusted_upper_bound() + T(0.000001);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_infeasible() {
 | 
			
		||||
        if ((!upper_bound_is_set()) || (!low_bound_is_set()))
 | 
			
		||||
        if ((!upper_bound_is_set()) || (!lower_bound_is_set()))
 | 
			
		||||
            return false;
 | 
			
		||||
        // ok, both bounds are set
 | 
			
		||||
        bool at_least_one_is_strict = upper_bound_is_strict() || low_bound_is_strict();
 | 
			
		||||
        bool at_least_one_is_strict = upper_bound_is_strict() || lower_bound_is_strict();
 | 
			
		||||
        if (!at_least_one_is_strict)
 | 
			
		||||
            return get_upper_bound() < get_low_bound();
 | 
			
		||||
            return get_upper_bound() < get_lower_bound();
 | 
			
		||||
        // at least on bound is strict
 | 
			
		||||
        return get_upper_bound() <= get_low_bound(); // the equality is impossible
 | 
			
		||||
        return get_upper_bound() <= get_lower_bound(); // the equality is impossible
 | 
			
		||||
    }
 | 
			
		||||
    bool low_bound_is_strict() const {
 | 
			
		||||
        return m_low_bound_is_strict;
 | 
			
		||||
    bool lower_bound_is_strict() const {
 | 
			
		||||
        return m_lower_bound_is_strict;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_low_bound_strict(bool val) {
 | 
			
		||||
        m_low_bound_is_strict = val;
 | 
			
		||||
    void set_lower_bound_strict(bool val) {
 | 
			
		||||
        m_lower_bound_is_strict = val;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool upper_bound_is_strict() const {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,31 +19,19 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
#include <string>
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
#include "util/lp/static_matrix.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
class column_namer {
 | 
			
		||||
public:
 | 
			
		||||
    virtual std::string get_column_name(unsigned j) const = 0;
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void print_linear_iterator(linear_combination_iterator<T>* it, std::ostream & out) const {
 | 
			
		||||
    void print_row(const row_strip<T> & row, std::ostream & out) const {
 | 
			
		||||
        vector<std::pair<T, unsigned>> coeff;
 | 
			
		||||
        T a;
 | 
			
		||||
        unsigned i;
 | 
			
		||||
        while (it->next(a, i)) {
 | 
			
		||||
            coeff.push_back(std::make_pair(a, i));
 | 
			
		||||
        for (auto & p : row) {
 | 
			
		||||
            coeff.push_back(std::make_pair(p.coeff(), p.var()));
 | 
			
		||||
        }
 | 
			
		||||
        print_linear_combination_of_column_indices(coeff, out);
 | 
			
		||||
    }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void print_linear_iterator_indices_only(linear_combination_iterator<T>* it, std::ostream & out) const {
 | 
			
		||||
        vector<std::pair<T, unsigned>> coeff;
 | 
			
		||||
        T a;
 | 
			
		||||
        unsigned i;
 | 
			
		||||
        while (it->next(a, i)) {
 | 
			
		||||
            coeff.emplace_back(a, i);
 | 
			
		||||
        }
 | 
			
		||||
        print_linear_combination_of_column_indices_only(coeff, out);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void print_linear_combination_of_column_indices_only(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -65,10 +53,34 @@ public:
 | 
			
		|||
            else if (val != numeric_traits<T>::one())
 | 
			
		||||
                out << T_to_string(val);
 | 
			
		||||
        
 | 
			
		||||
            out << "_" << it.second;
 | 
			
		||||
            out << "v" << it.second;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void print_linear_combination_of_column_indices_std(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
 | 
			
		||||
        bool first = true;
 | 
			
		||||
        for (const auto & it : coeffs) {
 | 
			
		||||
            auto val = it.first;
 | 
			
		||||
            if (first) {
 | 
			
		||||
                first = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (numeric_traits<T>::is_pos(val)) {
 | 
			
		||||
                    out << " + ";
 | 
			
		||||
                } else {
 | 
			
		||||
                    out << " - ";
 | 
			
		||||
                    val = -val;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            if (val == -numeric_traits<T>::one())
 | 
			
		||||
                out << " - ";
 | 
			
		||||
            else if (val != numeric_traits<T>::one())
 | 
			
		||||
                out << val;
 | 
			
		||||
        
 | 
			
		||||
            out << get_column_name(it.second);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void print_linear_combination_of_column_indices(const vector<std::pair<T, unsigned>> & coeffs, std::ostream & out) const {
 | 
			
		||||
        bool first = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										99
									
								
								src/util/lp/constraint.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/util/lp/constraint.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,99 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
namespace lp {
 | 
			
		||||
class constraint; // forward definition
 | 
			
		||||
struct constraint_hash {
 | 
			
		||||
    size_t operator() (const constraint* c) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct constraint_equal {
 | 
			
		||||
    bool operator() (const constraint * a, const constraint * b) const;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class constraint { // we only have less or equal for the inequality sign, which is enough for integral variables
 | 
			
		||||
    int                                              m_id;  
 | 
			
		||||
    bool                                             m_is_ineq;
 | 
			
		||||
    polynomial                                       m_poly;
 | 
			
		||||
    mpq                                              m_d; // the divider for the case of a divisibility constraint
 | 
			
		||||
    std::unordered_set<constraint_index>             m_assert_origins; // these indices come from the client and get collected during tightening
 | 
			
		||||
public :
 | 
			
		||||
    unsigned id() const { return m_id; }
 | 
			
		||||
    const polynomial & poly() const { return m_poly; }
 | 
			
		||||
    polynomial & poly() { return m_poly; }
 | 
			
		||||
    std::unordered_set<constraint_index> & assert_origins() { return m_assert_origins;}
 | 
			
		||||
    const std::unordered_set<constraint_index> & assert_origins() const { return m_assert_origins;}
 | 
			
		||||
    bool is_lemma() const { return !is_assert(); }
 | 
			
		||||
    bool is_assert() const { return m_assert_origins.size() == 1; }
 | 
			
		||||
    bool is_ineq() const { return m_is_ineq; }
 | 
			
		||||
    const mpq & divider() const { return m_d; }
 | 
			
		||||
public:
 | 
			
		||||
    constraint(
 | 
			
		||||
        unsigned id,
 | 
			
		||||
        constraint_index assert_origin,
 | 
			
		||||
        const polynomial & p,
 | 
			
		||||
        bool is_ineq):
 | 
			
		||||
        m_id(id),
 | 
			
		||||
        m_is_ineq(is_ineq),
 | 
			
		||||
        m_poly(p)
 | 
			
		||||
    { // creates an assert
 | 
			
		||||
        m_assert_origins.insert(assert_origin);
 | 
			
		||||
    }
 | 
			
		||||
    constraint(
 | 
			
		||||
        unsigned id,
 | 
			
		||||
        const std::unordered_set<constraint_index>& origins,
 | 
			
		||||
        const polynomial & p,
 | 
			
		||||
        bool is_ineq):
 | 
			
		||||
        m_id(id),
 | 
			
		||||
        m_is_ineq(is_ineq),
 | 
			
		||||
        m_poly(p),
 | 
			
		||||
        m_assert_origins(origins)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    constraint(
 | 
			
		||||
        unsigned id,
 | 
			
		||||
        const polynomial & p,
 | 
			
		||||
        bool is_ineq):
 | 
			
		||||
        m_id(id),
 | 
			
		||||
        m_is_ineq(is_ineq),
 | 
			
		||||
        m_poly(p) { // creates a lemma
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
public:
 | 
			
		||||
    constraint() {}
 | 
			
		||||
 | 
			
		||||
    const mpq & coeff(var_index j) const {
 | 
			
		||||
        return m_poly.coeff(j);
 | 
			
		||||
    }
 | 
			
		||||
    const vector<monomial>& coeffs() const { return m_poly.m_coeffs;}
 | 
			
		||||
 | 
			
		||||
    bool is_tight(unsigned j) const {
 | 
			
		||||
        const mpq & a = m_poly.coeff(j);
 | 
			
		||||
        return a == 1 || a == -1;
 | 
			
		||||
    }
 | 
			
		||||
    void add_predecessor(const constraint* p) {
 | 
			
		||||
        lp_assert(p != nullptr);
 | 
			
		||||
        for (auto m : p->assert_origins())
 | 
			
		||||
            m_assert_origins.insert(m); }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,8 +22,8 @@ Revision History:
 | 
			
		|||
namespace lp {
 | 
			
		||||
template <typename V>
 | 
			
		||||
struct conversion_helper {
 | 
			
		||||
    static V get_low_bound(const column_info<mpq> & ci) {
 | 
			
		||||
        return V(ci.get_low_bound(), ci.low_bound_is_strict()? 1 : 0);
 | 
			
		||||
    static V get_lower_bound(const column_info<mpq> & ci) {
 | 
			
		||||
        return V(ci.get_lower_bound(), ci.lower_bound_is_strict()? 1 : 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static V get_upper_bound(const column_info<mpq> & ci) {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,20 +37,20 @@ struct conversion_helper <double> {
 | 
			
		|||
        if (!ci.upper_bound_is_strict())
 | 
			
		||||
            return ci.get_upper_bound().get_double();
 | 
			
		||||
        double eps = 0.00001;
 | 
			
		||||
        if (!ci.low_bound_is_set())
 | 
			
		||||
        if (!ci.lower_bound_is_set())
 | 
			
		||||
            return ci.get_upper_bound().get_double() - eps;
 | 
			
		||||
        eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, 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_low_bound(const column_info<mpq> & ci) {
 | 
			
		||||
        if (!ci.low_bound_is_strict())
 | 
			
		||||
            return ci.get_low_bound().get_double();
 | 
			
		||||
    static double get_lower_bound(const column_info<mpq> & 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_low_bound().get_double() + eps;
 | 
			
		||||
        eps = std::min((ci.get_upper_bound() - ci.get_low_bound()).get_double() / 1000, eps);
 | 
			
		||||
        return ci.get_low_bound().get_double() + eps;
 | 
			
		||||
            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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/lp/core_solver_pretty_printer.hpp"
 | 
			
		||||
#include "util/lp/core_solver_pretty_printer_def.h"
 | 
			
		||||
template lp::core_solver_pretty_printer<double, double>::core_solver_pretty_printer(lp::lp_core_solver_base<double, double> &, std::ostream & out);
 | 
			
		||||
template void lp::core_solver_pretty_printer<double, double>::print();
 | 
			
		||||
template lp::core_solver_pretty_printer<double, double>::~core_solver_pretty_printer();
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ class core_solver_pretty_printer {
 | 
			
		|||
    std::string m_cost_title;
 | 
			
		||||
    std::string m_basis_heading_title;
 | 
			
		||||
    std::string m_x_title;
 | 
			
		||||
    std::string m_low_bounds_title;
 | 
			
		||||
    std::string m_lower_bounds_title;
 | 
			
		||||
    std::string m_upp_bounds_title;
 | 
			
		||||
    std::string m_exact_norm_title;
 | 
			
		||||
    std::string m_approx_norm_title;
 | 
			
		||||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void init_column_widths();
 | 
			
		||||
 | 
			
		||||
    void adjust_width_with_low_bound(unsigned column, unsigned & w);
 | 
			
		||||
    void adjust_width_with_lower_bound(unsigned column, unsigned & w);
 | 
			
		||||
    void adjust_width_with_upper_bound(unsigned column, unsigned & w);
 | 
			
		||||
 | 
			
		||||
    void adjust_width_with_bounds(unsigned column, unsigned & w);
 | 
			
		||||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void print_x();
 | 
			
		||||
 | 
			
		||||
    std::string get_low_bound_string(unsigned j);
 | 
			
		||||
    std::string get_lower_bound_string(unsigned j);
 | 
			
		||||
 | 
			
		||||
    std::string get_upp_bound_string(unsigned j);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ core_solver_pretty_printer<T, X>::core_solver_pretty_printer(lp_core_solver_base
 | 
			
		|||
    m_rs(ncols(), zero_of_type<X>()),
 | 
			
		||||
    m_w_buff(core_solver.m_w),
 | 
			
		||||
    m_ed_buff(core_solver.m_ed) {
 | 
			
		||||
    m_low_bounds_title = "low";
 | 
			
		||||
    m_lower_bounds_title = "low";
 | 
			
		||||
    m_upp_bounds_title = "upp";
 | 
			
		||||
    m_exact_norm_title = "exact cn";
 | 
			
		||||
    m_approx_norm_title = "approx cn";
 | 
			
		||||
| 
						 | 
				
			
			@ -105,6 +105,8 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_m_
 | 
			
		|||
                
 | 
			
		||||
            string name = m_core_solver.column_name(column);
 | 
			
		||||
            for (unsigned row = 0; row < nrows(); row ++) {
 | 
			
		||||
                m_A[row].resize(ncols(), "");
 | 
			
		||||
                m_signs[row].resize(ncols(),"");
 | 
			
		||||
                set_coeff(
 | 
			
		||||
                          m_A[row],
 | 
			
		||||
                          m_signs[row],
 | 
			
		||||
| 
						 | 
				
			
			@ -139,9 +141,9 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::init_co
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_low_bound(unsigned column, unsigned & w) {
 | 
			
		||||
    if (!m_core_solver.low_bounds_are_set()) return;
 | 
			
		||||
    w = std::max(w, (unsigned)T_to_string(m_core_solver.low_bound_value(column)).size());
 | 
			
		||||
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_lower_bound(unsigned column, unsigned & w) {
 | 
			
		||||
    if (!m_core_solver.lower_bounds_are_set()) return;
 | 
			
		||||
    w = std::max(w, (unsigned)T_to_string(m_core_solver.lower_bound_value(column)).size());
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_width_with_upper_bound(unsigned column, unsigned & w) {
 | 
			
		||||
    w = std::max(w, (unsigned)T_to_string(m_core_solver.upper_bound_value(column)).size());
 | 
			
		||||
| 
						 | 
				
			
			@ -151,11 +153,11 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_
 | 
			
		|||
    switch (m_core_solver.get_column_type(column)) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        adjust_width_with_low_bound(column, w);
 | 
			
		||||
        adjust_width_with_lower_bound(column, w);
 | 
			
		||||
        adjust_width_with_upper_bound(column, w);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        adjust_width_with_low_bound(column, w);
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        adjust_width_with_lower_bound(column, w);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        adjust_width_with_upper_bound(column, w);
 | 
			
		||||
| 
						 | 
				
			
			@ -163,7 +165,7 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::adjust_
 | 
			
		|||
    case column_type::free_column:
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -236,13 +238,13 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_x
 | 
			
		|||
    m_out << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> std::string core_solver_pretty_printer<T, X>::get_low_bound_string(unsigned j) {
 | 
			
		||||
template <typename T, typename X> std::string core_solver_pretty_printer<T, X>::get_lower_bound_string(unsigned j) {
 | 
			
		||||
    switch (m_core_solver.get_column_type(j)){
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
        if (m_core_solver.low_bounds_are_set())
 | 
			
		||||
            return T_to_string(m_core_solver.low_bound_value(j));
 | 
			
		||||
        if (m_core_solver.lower_bounds_are_set())
 | 
			
		||||
            return T_to_string(m_core_solver.lower_bound_value(j));
 | 
			
		||||
        else
 | 
			
		||||
            return std::string("0");
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -268,12 +270,12 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_l
 | 
			
		|||
    if (ncols() == 0) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    int blanks = m_title_width + 1 - static_cast<unsigned>(m_low_bounds_title.size());
 | 
			
		||||
    m_out << m_low_bounds_title;
 | 
			
		||||
    int blanks = m_title_width + 1 - static_cast<unsigned>(m_lower_bounds_title.size());
 | 
			
		||||
    m_out << m_lower_bounds_title;
 | 
			
		||||
    print_blanks(blanks, m_out);
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < ncols(); i++) {
 | 
			
		||||
        string s = get_low_bound_string(i);
 | 
			
		||||
        string s = get_lower_bound_string(i);
 | 
			
		||||
        int blanks = m_column_widths[i] - static_cast<unsigned>(s.size());
 | 
			
		||||
        print_blanks(blanks, m_out);
 | 
			
		||||
        m_out << s << "   "; // the column interval
 | 
			
		||||
| 
						 | 
				
			
			@ -372,7 +374,7 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_g
 | 
			
		|||
        unsigned width = m_column_widths[col];
 | 
			
		||||
        string s = row[col];
 | 
			
		||||
        int number_of_blanks = width - static_cast<unsigned>(s.size());
 | 
			
		||||
        SASSERT(number_of_blanks >= 0);
 | 
			
		||||
        lp_assert(number_of_blanks >= 0);
 | 
			
		||||
        print_blanks(number_of_blanks, m_out);
 | 
			
		||||
        m_out << s << ' ';
 | 
			
		||||
        if (col < row.size() - 1) {
 | 
			
		||||
| 
						 | 
				
			
			@ -383,7 +385,7 @@ template <typename T, typename X> void core_solver_pretty_printer<T, X>::print_g
 | 
			
		|||
 | 
			
		||||
    string rs = T_to_string(rst);
 | 
			
		||||
    int nb = m_rs_width - static_cast<int>(rs.size());
 | 
			
		||||
    SASSERT(nb >= 0);
 | 
			
		||||
    lp_assert(nb >= 0);
 | 
			
		||||
    print_blanks(nb + 1, m_out);
 | 
			
		||||
    m_out << rs << std::endl;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/lp_settings.h"
 | 
			
		||||
#include "util/lp/dense_matrix.hpp"
 | 
			
		||||
#include "util/lp/dense_matrix_def.h"
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
template lp::dense_matrix<double, double> lp::operator*<double, double>(lp::matrix<double, double>&, lp::matrix<double, double>&);
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +46,7 @@ public:
 | 
			
		|||
    dense_matrix(unsigned m, unsigned n);
 | 
			
		||||
 | 
			
		||||
    dense_matrix operator*=(matrix<T, X> const & a) {
 | 
			
		||||
        SASSERT(column_count() == a.row_count());
 | 
			
		||||
        lp_assert(column_count() == a.row_count());
 | 
			
		||||
        dense_matrix c(row_count(), a.column_count());
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i++) {
 | 
			
		||||
            for (unsigned j = 0; j < a.column_count(); j++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +100,7 @@ public:
 | 
			
		|||
    void swap_rows(unsigned a, unsigned b);
 | 
			
		||||
 | 
			
		||||
    void multiply_row_by_constant(unsigned row, T & t);
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
};
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
dense_matrix<T, X> operator* (matrix<T, X> & a, matrix<T, X> & b);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -23,7 +23,6 @@ Revision History:
 | 
			
		|||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/lp/dense_matrix.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T> void print_vector(const vector<T> & t, std::ostream & out);
 | 
			
		||||
template <typename T, typename X> dense_matrix<T, X>::dense_matrix(unsigned m, unsigned n) : m_m(m), m_n(n), m_values(m * n, numeric_traits<T>::zero()) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +184,7 @@ template <typename T, typename X> void dense_matrix<T, X>::multiply_row_by_const
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
dense_matrix<T, X> operator* (matrix<T, X> & a, matrix<T, X> & b){
 | 
			
		||||
    SASSERT(a.column_count() == b.row_count());
 | 
			
		||||
    lp_assert(a.column_count() == b.row_count());
 | 
			
		||||
    dense_matrix<T, X> ret(a.row_count(), b.column_count());
 | 
			
		||||
    for (unsigned i = 0; i < ret.m_m; i++)
 | 
			
		||||
        for (unsigned j = 0; j< ret.m_n; j++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1,334 +0,0 @@
 | 
			
		|||
/*
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
  Author: Lev Nachmanson
 | 
			
		||||
*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <map>
 | 
			
		||||
namespace lp {
 | 
			
		||||
// represents the set of disjoint intervals of integer number
 | 
			
		||||
struct disjoint_intervals {
 | 
			
		||||
    std::map<int, short> m_endpoints; // 0 means start, 1 means end, 2 means both - for a point interval
 | 
			
		||||
    bool m_empty;
 | 
			
		||||
    // constructors create an interval containing all integer numbers or an empty interval
 | 
			
		||||
    disjoint_intervals() : m_empty(false) {}
 | 
			
		||||
    disjoint_intervals(bool is_empty) : m_empty(is_empty) {}
 | 
			
		||||
 | 
			
		||||
    bool is_start(short x) const { return x == 0 || x == 2; }
 | 
			
		||||
    bool is_start(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return is_start(it->second);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_start(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return is_start(it->second);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_end(short x) const { return x == 1 || x == 2; }
 | 
			
		||||
    bool is_end(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return is_end(it->second);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_end(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return is_end(it->second);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int pos(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return it->first;
 | 
			
		||||
    }
 | 
			
		||||
    int pos(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return it->first;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int bound_kind(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return it->second;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int bound_kind(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return it->second;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_proper_start(short x) const { return x == 0; }
 | 
			
		||||
    bool is_proper_end(short x) const { return x == 1; }
 | 
			
		||||
    bool is_proper_end(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return is_proper_end(it->second);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_proper_end(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return is_proper_end(it->second);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_one_point_interval(short x) const { return x == 2; }
 | 
			
		||||
    bool is_one_point_interval(const std::map<int, short>::iterator & it) const {
 | 
			
		||||
        return is_one_point_interval(it->second);
 | 
			
		||||
    }
 | 
			
		||||
    bool is_one_point_interval(const std::map<int, short>::reverse_iterator & it) const {
 | 
			
		||||
        return is_one_point_interval(it->second);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    void erase(int x) {
 | 
			
		||||
        m_endpoints.erase(x);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void set_one_point_segment(int x) {
 | 
			
		||||
        m_endpoints[x] = 2;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_start(int x) {
 | 
			
		||||
        m_endpoints[x] = 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void set_end(int x) {
 | 
			
		||||
        m_endpoints[x] = 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void remove_all_endpoints_below(int x) {
 | 
			
		||||
        while (m_endpoints.begin() != m_endpoints.end() && m_endpoints.begin()->first < x)
 | 
			
		||||
            m_endpoints.erase(m_endpoints.begin());
 | 
			
		||||
    }
 | 
			
		||||
    // we intersect the existing set with the half open to the right interval
 | 
			
		||||
    void intersect_with_lower_bound(int x) {
 | 
			
		||||
        if (m_empty)
 | 
			
		||||
            return;
 | 
			
		||||
        if (m_endpoints.empty()) {
 | 
			
		||||
            set_start(x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bool pos_inf = has_pos_inf();
 | 
			
		||||
        auto it = m_endpoints.begin();
 | 
			
		||||
        while (it != m_endpoints.end() && pos(it) < x) {
 | 
			
		||||
            m_endpoints.erase(it);
 | 
			
		||||
            it = m_endpoints.begin();
 | 
			
		||||
        }
 | 
			
		||||
        if (m_endpoints.empty()) {
 | 
			
		||||
            if (!pos_inf) {
 | 
			
		||||
                m_empty = true;
 | 
			
		||||
                return;
 | 
			
		||||
            } 
 | 
			
		||||
            set_start(x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        lp_assert(pos(it) >= x);
 | 
			
		||||
        if (pos(it) == x) {
 | 
			
		||||
            if (is_proper_end(it))
 | 
			
		||||
                set_one_point_segment(x);			
 | 
			
		||||
        }
 | 
			
		||||
        else { // x(it) > x
 | 
			
		||||
            if (is_proper_end(it)) {
 | 
			
		||||
                set_start(x);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lp_assert(is_correct());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // we intersect the existing set with the half open interval
 | 
			
		||||
    void intersect_with_upper_bound(int x) {
 | 
			
		||||
        if (m_empty)
 | 
			
		||||
            return;
 | 
			
		||||
        if (m_endpoints.empty()) {
 | 
			
		||||
            set_end(x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bool neg_inf = has_neg_inf();
 | 
			
		||||
        auto it = m_endpoints.rbegin();
 | 
			
		||||
 | 
			
		||||
        while (!m_endpoints.empty() && pos(it) > x) {
 | 
			
		||||
            m_endpoints.erase(std::prev(m_endpoints.end()));
 | 
			
		||||
            it = m_endpoints.rbegin();
 | 
			
		||||
        }
 | 
			
		||||
        if (m_endpoints.empty()) {
 | 
			
		||||
            if (!neg_inf) {
 | 
			
		||||
                m_empty = true;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            set_end(x);
 | 
			
		||||
        }
 | 
			
		||||
        lp_assert(pos(it) <= x);
 | 
			
		||||
        if (pos(it) == x) {
 | 
			
		||||
            if (is_one_point_interval(it)) {} 
 | 
			
		||||
            else if (is_proper_end(it)) {}
 | 
			
		||||
            else {// is_proper_start(it->second)
 | 
			
		||||
                set_one_point_segment(x);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else { // pos(it) < x} 
 | 
			
		||||
            if (is_start(it))
 | 
			
		||||
                set_end(x);
 | 
			
		||||
        }
 | 
			
		||||
        lp_assert(is_correct());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool has_pos_inf() const {
 | 
			
		||||
        if (m_empty)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (m_endpoints.empty())
 | 
			
		||||
            return true;
 | 
			
		||||
        
 | 
			
		||||
        lp_assert(m_endpoints.rbegin() != m_endpoints.rend());
 | 
			
		||||
        return m_endpoints.rbegin()->second == 0;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool has_neg_inf() const {
 | 
			
		||||
        if (m_empty)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        if (m_endpoints.empty())
 | 
			
		||||
            return true;
 | 
			
		||||
        auto it = m_endpoints.begin();
 | 
			
		||||
        return is_proper_end(it->second);//m_endpoints.begin());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // we are intersecting
 | 
			
		||||
    void intersect_with_interval(int x, int y) {
 | 
			
		||||
        if (m_empty)
 | 
			
		||||
            return;
 | 
			
		||||
        lp_assert(x <= y);
 | 
			
		||||
        intersect_with_lower_bound(x);
 | 
			
		||||
        intersect_with_upper_bound(y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // add an intervar [x, inf]
 | 
			
		||||
    void unite_with_interval_x_pos_inf(int x) {
 | 
			
		||||
        if (m_empty) {
 | 
			
		||||
            set_start(x);
 | 
			
		||||
            m_empty = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        while (!m_endpoints.empty() && pos(m_endpoints.rbegin()) > x) {
 | 
			
		||||
            m_endpoints.erase(std::prev(m_endpoints.end()));
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (m_endpoints.empty()) {
 | 
			
		||||
            set_start(x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        auto it = m_endpoints.rbegin();
 | 
			
		||||
        lp_assert(pos(it) <= x);
 | 
			
		||||
        if (pos(it) == x) {
 | 
			
		||||
            if (is_end(it)) {
 | 
			
		||||
                m_endpoints.erase(x);
 | 
			
		||||
            } else {
 | 
			
		||||
                set_start(x);
 | 
			
		||||
            }
 | 
			
		||||
        } else if (pos(it) == x - 1 && is_end(it)) {
 | 
			
		||||
            m_endpoints.erase(x - 1); // closing the gap
 | 
			
		||||
        } else {
 | 
			
		||||
            if (!has_pos_inf())
 | 
			
		||||
                set_start(x);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // add an interval [-inf, x]
 | 
			
		||||
    void unite_with_interval_neg_inf_x(int x) {
 | 
			
		||||
        if (m_empty) {
 | 
			
		||||
            set_end(x);
 | 
			
		||||
            m_empty = false;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        auto it = m_endpoints.upper_bound(x);
 | 
			
		||||
        
 | 
			
		||||
        if (it == m_endpoints.end()) {
 | 
			
		||||
            bool pos_inf = has_pos_inf();
 | 
			
		||||
            m_endpoints.clear();
 | 
			
		||||
            // it could be the case where x is inside of the last infinite interval with pos inf
 | 
			
		||||
            if (!pos_inf)
 | 
			
		||||
                set_end(x);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        lp_assert(pos(it) > x);
 | 
			
		||||
        if (is_one_point_interval(pos(it))) {
 | 
			
		||||
            set_end(it->second);
 | 
			
		||||
        } else {
 | 
			
		||||
            if (is_start(it->second)) {
 | 
			
		||||
                set_end(x);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        while (!m_endpoints.empty() && m_endpoints.begin()->first < x) {
 | 
			
		||||
            m_endpoints.erase(m_endpoints.begin());
 | 
			
		||||
        }
 | 
			
		||||
        lp_assert(is_correct());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void unite_with_interval(int x, int y) {
 | 
			
		||||
        lp_assert(false); // not implemented
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_correct() const {
 | 
			
		||||
        if (m_empty) {
 | 
			
		||||
            if (m_endpoints.size() > 0) {
 | 
			
		||||
                std::cout << "is empty is true but m_endpoints.size() = " << m_endpoints.size() << std::endl;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        bool expect_end;
 | 
			
		||||
        bool prev = false;
 | 
			
		||||
        int prev_x;
 | 
			
		||||
        for (auto t : m_endpoints) {
 | 
			
		||||
            if (prev && (expect_end != t.second > 0)) {
 | 
			
		||||
                std::cout << "x = " << t.first << "\n";
 | 
			
		||||
                if (expect_end) {
 | 
			
		||||
                    std::cout << "expecting an interval end\n";
 | 
			
		||||
                } else {
 | 
			
		||||
                    std::cout << "expecting an interval start\n";
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (t.second == 2) {
 | 
			
		||||
                expect_end = false; // swallow a point interval
 | 
			
		||||
            } else {
 | 
			
		||||
                if (prev)
 | 
			
		||||
                    expect_end = !expect_end;
 | 
			
		||||
                else
 | 
			
		||||
                    expect_end = is_start(t.second);
 | 
			
		||||
            }
 | 
			
		||||
            if (prev) {
 | 
			
		||||
                if (t.first - prev_x <= 1) {
 | 
			
		||||
                    std::cout << "the sequence is not increasing or the gap is too small: " << prev_x << ", " << t.first << std::endl;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            } 
 | 
			
		||||
            prev = true;
 | 
			
		||||
            prev_x = t.first;
 | 
			
		||||
        }
 | 
			
		||||
            
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void print(std::ostream & out) const {
 | 
			
		||||
        if (m_empty) {
 | 
			
		||||
            out << "empty\n";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_endpoints.empty()){
 | 
			
		||||
            out << "[-oo,oo]\n";
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        bool first = true;
 | 
			
		||||
        for (auto t : m_endpoints) {
 | 
			
		||||
            if (first) {
 | 
			
		||||
                if (t.second == 1) {
 | 
			
		||||
                    out << "[-oo," << t.first << "]";
 | 
			
		||||
                }
 | 
			
		||||
                else if (t.second == 0)
 | 
			
		||||
                    out << "[" << t.first << ",";
 | 
			
		||||
                else if (t.second == 2)
 | 
			
		||||
                    out << "[" << t.first << "]";
 | 
			
		||||
                first = false;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (t.second==0)
 | 
			
		||||
                    out << "[" << t.first << ",";
 | 
			
		||||
                else if (t.second == 1)
 | 
			
		||||
                    out << t.first << "]";
 | 
			
		||||
                else if (t.second == 2)
 | 
			
		||||
                    out << "[" << t.first << "]";
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        if (has_pos_inf())
 | 
			
		||||
            out << "oo]";
 | 
			
		||||
        out << "\n";
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -20,7 +20,7 @@ Revision History:
 | 
			
		|||
#include <memory>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/lp/eta_matrix.hpp"
 | 
			
		||||
#include "util/lp/eta_matrix_def.h"
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
template double lp::eta_matrix<double, double>::get_elem(unsigned int, unsigned int) const;
 | 
			
		||||
template lp::mpq lp::eta_matrix<lp::mpq, lp::mpq>::get_elem(unsigned int, unsigned int) const;
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ public:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    void push_back(unsigned row_index, T val ) {
 | 
			
		||||
        SASSERT(row_index != m_column_index);
 | 
			
		||||
        lp_assert(row_index != m_column_index);
 | 
			
		||||
        m_column_vector.push_back(row_index, val);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -75,7 +75,7 @@ void eta_matrix<T, X>::apply_from_right(vector<T> & w) {
 | 
			
		|||
    }
 | 
			
		||||
    w[m_column_index] = t;
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    // SASSERT(vectors_are_equal<T>(clone_w, w, get_number_of_rows()));
 | 
			
		||||
    // lp_assert(vectors_are_equal<T>(clone_w, w, get_number_of_rows()));
 | 
			
		||||
    // delete clone_w;
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -115,8 +115,8 @@ void eta_matrix<T, X>::apply_from_right(indexed_vector<T> & w) {
 | 
			
		|||
    }
 | 
			
		||||
    
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    // SASSERT(w.is_OK());
 | 
			
		||||
    // SASSERT(vectors_are_equal<T>(wcopy, w.m_data));
 | 
			
		||||
    // lp_assert(w.is_OK());
 | 
			
		||||
    // lp_assert(vectors_are_equal<T>(wcopy, w.m_data));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
| 
						 | 
				
			
			@ -145,7 +145,7 @@ void eta_matrix<T, X>::conjugate_by_permutation(permutation_matrix<T, X> & p) {
 | 
			
		|||
        pair.first = p.get_rev(pair.first);
 | 
			
		||||
    }
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    // SASSERT(deb == *this);
 | 
			
		||||
    // lp_assert(deb == *this);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										32
									
								
								src/util/lp/explanation.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								src/util/lp/explanation.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,32 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
namespace lp {
 | 
			
		||||
struct explanation {
 | 
			
		||||
    void clear() { m_explanation.clear(); }
 | 
			
		||||
    vector<std::pair<mpq, constraint_index>> m_explanation;
 | 
			
		||||
    void push_justification(constraint_index j, const mpq& v) {
 | 
			
		||||
        m_explanation.push_back(std::make_pair(v, j));
 | 
			
		||||
    }
 | 
			
		||||
    void push_justification(constraint_index j) {
 | 
			
		||||
        m_explanation.push_back(std::make_pair(one_of_type<mpq>(), j));
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										259
									
								
								src/util/lp/general_matrix.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										259
									
								
								src/util/lp/general_matrix.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,259 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <functional>
 | 
			
		||||
namespace lp {
 | 
			
		||||
class general_matrix {
 | 
			
		||||
    // fields
 | 
			
		||||
    permutation_matrix<mpq, mpq>          m_row_permutation;
 | 
			
		||||
    permutation_matrix<mpq, mpq>          m_column_permutation;
 | 
			
		||||
    vector<vector<mpq>>                   m_data;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    unsigned adjust_row(unsigned row) const{
 | 
			
		||||
        return m_row_permutation[row];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void push_row(vector<mpq> & v) {
 | 
			
		||||
        m_data.push_back(v);
 | 
			
		||||
        m_row_permutation.resize(m_data.size());
 | 
			
		||||
        m_column_permutation.resize(v.size());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    unsigned row_count() const { return m_data.size(); }
 | 
			
		||||
    unsigned column_count() const { return m_data.size() > 0? m_data[0].size() : 0; }
 | 
			
		||||
 | 
			
		||||
    class ref_row {
 | 
			
		||||
        general_matrix& m_matrix;
 | 
			
		||||
        vector<mpq>& m_row_data;
 | 
			
		||||
    public:
 | 
			
		||||
        ref_row(general_matrix& m, vector<mpq>& row_data) : m_matrix(m), m_row_data(row_data) {}
 | 
			
		||||
        mpq & operator[](unsigned col) { return m_row_data[m_matrix.adjust_column(col)]; }
 | 
			
		||||
    };
 | 
			
		||||
    class ref_row_const {
 | 
			
		||||
        const general_matrix& m_matrix;
 | 
			
		||||
        const vector<mpq>& m_row_data;
 | 
			
		||||
    public:
 | 
			
		||||
        ref_row_const(const general_matrix& m, const vector<mpq>& row_data) : m_matrix(m), m_row_data(row_data) {}
 | 
			
		||||
        const mpq&  operator[](unsigned col) const { return m_row_data[m_matrix.adjust_column(col)]; }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    ref_row operator[](unsigned i) { return ref_row(*this, m_data[adjust_row(i)]); }
 | 
			
		||||
    ref_row_const operator[](unsigned i) const { return ref_row_const(*this, m_data[adjust_row(i)]); }
 | 
			
		||||
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    void print(std::ostream & out, unsigned blanks = 0) const {
 | 
			
		||||
        unsigned m = row_count();
 | 
			
		||||
        unsigned n = column_count();
 | 
			
		||||
        general_matrix g(m, n);
 | 
			
		||||
        for (unsigned i = 0; i < m; i++)
 | 
			
		||||
            for (unsigned j = 0; j < n; j++)
 | 
			
		||||
                g[i][j] = (*this)[i][j];
 | 
			
		||||
        print_matrix<mpq>(g.m_data, out, blanks);
 | 
			
		||||
    }
 | 
			
		||||
    void print(std::ostream & out, const char * ss) const {
 | 
			
		||||
        std::string s(ss);
 | 
			
		||||
        out << s;
 | 
			
		||||
        print(out, static_cast<unsigned>(s.size()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void print_submatrix(std::ostream & out, unsigned k, unsigned blanks = 0) const {
 | 
			
		||||
        general_matrix m(row_count() - k, column_count() - k);
 | 
			
		||||
        for (unsigned i = k; i < row_count(); i++) {
 | 
			
		||||
            for (unsigned j = k; j < column_count(); j++)
 | 
			
		||||
                m[i-k][j-k] = (*this)[i][j];
 | 
			
		||||
        }
 | 
			
		||||
        print_matrix<mpq>(m.m_data, out, blanks);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    void clear() { m_data.clear(); }
 | 
			
		||||
 | 
			
		||||
    bool row_is_initialized_correctly(const vector<mpq>& row) {
 | 
			
		||||
        lp_assert(row.size() == column_count());
 | 
			
		||||
        for (unsigned j = 0; j < row.size(); j ++)
 | 
			
		||||
            lp_assert(is_zero(row[j]));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    void init_row_from_container(int i, const T & c, std::function<unsigned (unsigned)> column_fix) {
 | 
			
		||||
        auto & row = m_data[adjust_row(i)];
 | 
			
		||||
        lp_assert(row_is_initialized_correctly(row));
 | 
			
		||||
        for (const auto & p : c) {
 | 
			
		||||
            unsigned j = adjust_column(column_fix(p.var()));
 | 
			
		||||
            row[j] = p.coeff();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void copy_column_to_indexed_vector(unsigned entering, indexed_vector<mpq> &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());
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i ++) {
 | 
			
		||||
             for (unsigned j = 0; j < m.column_count(); j++) {
 | 
			
		||||
                mpq a(0);
 | 
			
		||||
                for (unsigned k = 0; k < column_count(); k++)
 | 
			
		||||
                    a += ((*this)[i][k])*m[k][j];
 | 
			
		||||
                ret[i][j] = a;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool elements_are_equal(const general_matrix& m) const {
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i++)
 | 
			
		||||
            for (unsigned j = 0; j < column_count(); j++)
 | 
			
		||||
                if ( (*this)[i][j] != m[i][j])
 | 
			
		||||
                    return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool elements_are_equal_modulo(const general_matrix& m, const mpq & d) const {
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i++)
 | 
			
		||||
            for (unsigned j = 0; j < column_count(); j++)
 | 
			
		||||
                if (!is_zero(((*this)[i][j] - m[i][j]) % d)) 
 | 
			
		||||
                    return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator==(const general_matrix& m) const {
 | 
			
		||||
        return row_count() == m.row_count() && column_count() == m.column_count() && elements_are_equal(m);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator!=(const general_matrix& m) const {
 | 
			
		||||
        return !(*this == m);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool equal_modulo(const general_matrix& m, const mpq & d) const {
 | 
			
		||||
        return row_count() == m.row_count() && column_count() == m.column_count() && elements_are_equal_modulo(m, d);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    vector<mpq> operator*(const vector<mpq> & x) const {
 | 
			
		||||
        vector<mpq> r;
 | 
			
		||||
        lp_assert(x.size() == column_count());
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i++) {
 | 
			
		||||
            mpq v(0);
 | 
			
		||||
            for (unsigned j = 0; j < column_count(); j++) {
 | 
			
		||||
                v += (*this)[i][j] * x[j];
 | 
			
		||||
            }
 | 
			
		||||
            r.push_back(v);
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // bool create_upper_triangle(general_matrix& m, vector<mpq>& 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<mpq>& x, const vector<mpq>& 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);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void transpose_columns(unsigned j, unsigned k) {
 | 
			
		||||
        lp_assert(j != k);
 | 
			
		||||
        m_column_permutation.transpose_from_left(j, k);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    general_matrix(){}
 | 
			
		||||
    general_matrix(unsigned n) :
 | 
			
		||||
        m_row_permutation(n),
 | 
			
		||||
        m_column_permutation(n),
 | 
			
		||||
        m_data(n)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto& v : m_data){
 | 
			
		||||
            v.resize(n);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    general_matrix(unsigned m, unsigned n) :
 | 
			
		||||
        m_row_permutation(m),
 | 
			
		||||
        m_column_permutation(n),
 | 
			
		||||
        m_data(m) {
 | 
			
		||||
        for (auto& v : m_data){
 | 
			
		||||
            v.resize(n);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void shrink_to_rank(const svector<unsigned>& basis_rows) {
 | 
			
		||||
        if (basis_rows.size() == row_count()) return;
 | 
			
		||||
        vector<vector<mpq>> data; // todo : not efficient code
 | 
			
		||||
        for (unsigned i : basis_rows)
 | 
			
		||||
            data.push_back(m_data[i]);
 | 
			
		||||
        m_data = data;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // used for debug only
 | 
			
		||||
    general_matrix take_first_n_columns(unsigned n) const {
 | 
			
		||||
        lp_assert(n <= column_count());
 | 
			
		||||
        if (n == column_count())
 | 
			
		||||
            return *this;
 | 
			
		||||
        general_matrix ret(row_count(), n);
 | 
			
		||||
        for (unsigned i = 0; i < row_count(); i++)
 | 
			
		||||
            for (unsigned j = 0; j < n; j++)
 | 
			
		||||
                ret[i][j] = (*this)[i][j];
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
    inline
 | 
			
		||||
    friend vector<mpq> operator*(const vector<mpq> & f, const general_matrix& a) {
 | 
			
		||||
        vector<mpq> r(a.column_count());
 | 
			
		||||
        for (unsigned j = 0; j < a.column_count(); j ++) {
 | 
			
		||||
            mpq t = zero_of_type<mpq>();
 | 
			
		||||
            for (unsigned i = 0; i < a.row_count(); i++) {
 | 
			
		||||
                t += f[i] * a[i][j];
 | 
			
		||||
            }
 | 
			
		||||
            r[j] = t;
 | 
			
		||||
        }
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,54 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <utility>
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/numerics/mpq.h"
 | 
			
		||||
#ifdef __CLANG__
 | 
			
		||||
#pragma clang diagnostic push
 | 
			
		||||
#pragma clang diagnostic ignored "-Wmismatched-tags"
 | 
			
		||||
#endif
 | 
			
		||||
namespace std {
 | 
			
		||||
template<>
 | 
			
		||||
struct hash<lp::mpq> {
 | 
			
		||||
    inline size_t operator()(const lp::mpq & v) const {
 | 
			
		||||
        return v.hash();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <class T>
 | 
			
		||||
inline void hash_combine(std::size_t & seed, const T & v) {
 | 
			
		||||
    seed ^= std::hash<T>()(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
template<typename S, typename T> struct hash<pair<S, T>> {
 | 
			
		||||
    inline size_t operator()(const pair<S, T> & v) const {
 | 
			
		||||
        size_t seed = 0;
 | 
			
		||||
        hash_combine(seed, v.first);
 | 
			
		||||
        hash_combine(seed, v.second);
 | 
			
		||||
        return seed;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
#ifdef __CLANG__
 | 
			
		||||
#pragma clang diagnostic pop
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										623
									
								
								src/util/lp/hnf.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										623
									
								
								src/util/lp/hnf.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,623 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
    Creates the Hermite Normal Form of a matrix in place.
 | 
			
		||||
    We suppose that $A$ is an integral $m$ by $n$ matrix or rank $m$, where $n >= m$.
 | 
			
		||||
    The paragraph below is applicable to the usage of HNF.
 | 
			
		||||
We have $H = AU$ where $H$ is in Hermite Normal Form
 | 
			
		||||
and $U$ is a unimodular matrix. We do not have an explicit
 | 
			
		||||
 representation of $U$. For a given $i$ we need to find the $i$-th
 | 
			
		||||
    row of $U^{-1}$. 
 | 
			
		||||
Let $e_i$ be a vector of length $m$ with all elements equal to $0$ and
 | 
			
		||||
$1$ at $i$-th position. Then we need to find the row vector $e_iU^{-1}=t$. Noticing that $U^{-1} = H^{-1}A$, we have $e_iH^{-1}A=t$.
 | 
			
		||||
We find  $e_iH^{-1} = f$ by solving $e_i = fH$ and then $fA$ gives us $t$.
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/ext_gcd.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
namespace hnf_calc {
 | 
			
		||||
 | 
			
		||||
    // d = u * a + v * b and the sum of abs(u) + abs(v) is minimal, d is positive
 | 
			
		||||
inline
 | 
			
		||||
void extended_gcd_minimal_uv(const mpq & a, const mpq & b, mpq & d, mpq & u, mpq & v) {
 | 
			
		||||
    if (is_zero(a)) {
 | 
			
		||||
        u = zero_of_type<mpq>();
 | 
			
		||||
        v = one_of_type<mpq>();
 | 
			
		||||
        d = b;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (is_zero(b)) {
 | 
			
		||||
        u = one_of_type<mpq>();
 | 
			
		||||
        v = zero_of_type<mpq>();
 | 
			
		||||
        d = a;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
#if 1
 | 
			
		||||
    d = gcd(a, b, u, v);
 | 
			
		||||
#else
 | 
			
		||||
    extended_gcd(a, b, d, u, v);
 | 
			
		||||
#endif
 | 
			
		||||
    if (is_neg(d)) {
 | 
			
		||||
        d = -d;
 | 
			
		||||
        u = -u;
 | 
			
		||||
        v = -v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (d == a) {
 | 
			
		||||
        u = one_of_type<mpq>();
 | 
			
		||||
        v = zero_of_type<mpq>();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    if (d == -a) {
 | 
			
		||||
        u = - one_of_type<mpq>();
 | 
			
		||||
        v = zero_of_type<mpq>();
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    mpq a_over_d = abs(a) / d;
 | 
			
		||||
    mpq r;
 | 
			
		||||
        
 | 
			
		||||
    mpq k = machine_div_rem(v, a_over_d, r);
 | 
			
		||||
    if (is_neg(r)) {
 | 
			
		||||
        r += a_over_d;
 | 
			
		||||
        k -= one_of_type<mpq>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    lp_assert(v == k * a_over_d + r);
 | 
			
		||||
 | 
			
		||||
    if (is_pos(b)) {
 | 
			
		||||
        v = r - a_over_d; //   v -= (k + 1) * a_over_d;
 | 
			
		||||
        lp_assert(- a_over_d < v && v <= zero_of_type<mpq>());
 | 
			
		||||
 | 
			
		||||
        if (is_pos(a)) {
 | 
			
		||||
            u += (k + 1) * (b / d);
 | 
			
		||||
            lp_assert( one_of_type<mpq>() <= u && u <= abs(b)/d);
 | 
			
		||||
        } else {
 | 
			
		||||
            u -= (k + 1) * (b / d);
 | 
			
		||||
            lp_assert( one_of_type<mpq>() <= -u && -u <= abs(b)/d);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        v = r; // v -= k * a_over_d;
 | 
			
		||||
        lp_assert(- a_over_d < -v && -v <= zero_of_type<mpq>());
 | 
			
		||||
        if (is_pos(a)) {
 | 
			
		||||
            u += k * (b / d);
 | 
			
		||||
            lp_assert( one_of_type<mpq>() <= u && u <= abs(b)/d);
 | 
			
		||||
        } else {
 | 
			
		||||
            u -= k * (b / d);
 | 
			
		||||
            lp_assert( one_of_type<mpq>() <= -u && -u <= abs(b)/d);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    lp_assert(d == u * a + v * b);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename M> 
 | 
			
		||||
bool prepare_pivot_for_lower_triangle(M &m, unsigned r) {
 | 
			
		||||
    for (unsigned i = r; i < m.row_count(); i++) {
 | 
			
		||||
        for (unsigned j = r; j < m.column_count(); j++) {
 | 
			
		||||
            if (!is_zero(m[i][j])) {
 | 
			
		||||
                if (i != r) {
 | 
			
		||||
                    m.transpose_rows(i, r);
 | 
			
		||||
                }
 | 
			
		||||
                if (j != r) {
 | 
			
		||||
                    m.transpose_columns(j, r);
 | 
			
		||||
                }
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename M> 
 | 
			
		||||
void pivot_column_non_fractional(M &m, unsigned r, bool & overflow, const mpq & big_number) {
 | 
			
		||||
    lp_assert(!is_zero(m[r][r]));
 | 
			
		||||
    for (unsigned j = r + 1; j < m.column_count(); j++) {
 | 
			
		||||
        for (unsigned i = r + 1; i  < m.row_count(); i++) {            
 | 
			
		||||
            if (
 | 
			
		||||
                (m[i][j] = (r > 0) ? (m[r][r]*m[i][j] - m[i][r]*m[r][j]) / m[r-1][r-1] :
 | 
			
		||||
                                     (m[r][r]*m[i][j] - m[i][r]*m[r][j]))
 | 
			
		||||
                >= big_number) {
 | 
			
		||||
                overflow = true;
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            lp_assert(is_int(m[i][j]));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns the rank of the matrix
 | 
			
		||||
template <typename M> 
 | 
			
		||||
unsigned to_lower_triangle_non_fractional(M &m, bool & overflow, const mpq& big_number) {
 | 
			
		||||
    unsigned i = 0;
 | 
			
		||||
    for (; i < m.row_count(); i++) {
 | 
			
		||||
        if (!prepare_pivot_for_lower_triangle(m, i)) {
 | 
			
		||||
            return i;
 | 
			
		||||
        }
 | 
			
		||||
        pivot_column_non_fractional(m, i, overflow, big_number);
 | 
			
		||||
        if (overflow)
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    lp_assert(i == m.row_count());
 | 
			
		||||
    return i; 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// returns gcd of values below diagonal i,i
 | 
			
		||||
template <typename M>
 | 
			
		||||
mpq gcd_of_row_starting_from_diagonal(const M& m, unsigned i) {
 | 
			
		||||
    mpq g = zero_of_type<mpq>();
 | 
			
		||||
    unsigned j = i;
 | 
			
		||||
    for (; j < m.column_count() && is_zero(g); j++) {
 | 
			
		||||
        const auto & t = m[i][j];
 | 
			
		||||
        if (!is_zero(t))
 | 
			
		||||
            g = abs(t);
 | 
			
		||||
    }
 | 
			
		||||
    lp_assert(!is_zero(g));
 | 
			
		||||
    for (; j < m.column_count(); j++) {
 | 
			
		||||
        const auto & t = m[i][j];
 | 
			
		||||
        if (!is_zero(t))
 | 
			
		||||
            g = gcd(g, t);
 | 
			
		||||
    }
 | 
			
		||||
    return g;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// It fills "r" - the basic rows of m.
 | 
			
		||||
// The plan is to transform m to the lower triangular form by using non-fractional Gaussian Elimination by columns.
 | 
			
		||||
// Then the trailing after the diagonal elements of the following elements of the last non-zero row of the matrix,
 | 
			
		||||
// namely, m[r-1][r-1], m[r-1][r], ..., m[r-1]m[m.column_count() - 1] give the determinants of all minors of rank r.
 | 
			
		||||
// The gcd of these minors is the return value.
 | 
			
		||||
 
 | 
			
		||||
template <typename M> 
 | 
			
		||||
mpq determinant_of_rectangular_matrix(const M& m, svector<unsigned> & basis_rows, const mpq& big_number) {
 | 
			
		||||
    auto m_copy = m;
 | 
			
		||||
    bool overflow = false;
 | 
			
		||||
    unsigned rank = to_lower_triangle_non_fractional(m_copy, overflow, big_number);
 | 
			
		||||
    if (overflow)
 | 
			
		||||
        return big_number;
 | 
			
		||||
    if (rank == 0)
 | 
			
		||||
        return one_of_type<mpq>();
 | 
			
		||||
 | 
			
		||||
    for (unsigned i = 0; i < rank; i++) {
 | 
			
		||||
        basis_rows.push_back(m_copy.adjust_row(i));
 | 
			
		||||
    }
 | 
			
		||||
    TRACE("hnf_calc", tout << "basis_rows = "; print_vector(basis_rows, tout); m_copy.print(tout, "m_copy = "););
 | 
			
		||||
    return gcd_of_row_starting_from_diagonal(m_copy, rank - 1);
 | 
			
		||||
}
 | 
			
		||||
} // end of namespace hnf_calc
 | 
			
		||||
 | 
			
		||||
template <typename M> // M is the matrix type
 | 
			
		||||
class hnf {
 | 
			
		||||
    // fields
 | 
			
		||||
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    M            m_H;
 | 
			
		||||
    M            m_U;
 | 
			
		||||
    M            m_U_reverse;
 | 
			
		||||
    M            m_A_orig;
 | 
			
		||||
#endif
 | 
			
		||||
    M            m_W;
 | 
			
		||||
    vector<mpq>  m_buffer;
 | 
			
		||||
    unsigned     m_m;
 | 
			
		||||
    unsigned     m_n;
 | 
			
		||||
    mpq          m_d; // it is a positive number and a multiple of gcd of r-minors of m_A_orig, where r is the rank of m_A_orig
 | 
			
		||||
    //  we suppose that the rank of m_A is equal to row_count(), and that row_count() <= column_count(), that is m_A has the full rank
 | 
			
		||||
    unsigned     m_i;
 | 
			
		||||
    unsigned     m_j;
 | 
			
		||||
    mpq          m_R;
 | 
			
		||||
    mpq          m_half_R;
 | 
			
		||||
    mpq mod_R_balanced(const mpq & a) const {
 | 
			
		||||
       mpq t = a % m_R;
 | 
			
		||||
       return t > m_half_R? t - m_R : (t < - m_half_R? t + m_R : t);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    mpq mod_R(const mpq & a) const {
 | 
			
		||||
       mpq t = a % m_R;
 | 
			
		||||
       t = is_neg(t) ? t + m_R : t;       
 | 
			
		||||
       CTRACE("hnf", is_neg(t), tout << "a=" << a << ", m_R= " << m_R << std::endl;);
 | 
			
		||||
       return t;
 | 
			
		||||
           
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    void buffer_p_col_i_plus_q_col_j_H(const mpq & p, unsigned i, const mpq & q, unsigned j) {
 | 
			
		||||
        for (unsigned k = i; k < m_m; k++) {
 | 
			
		||||
            m_buffer[k] =  p * m_H[k][i] + q * m_H[k][j];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    bool zeros_in_column_W_above(unsigned i) {
 | 
			
		||||
        for (unsigned k = 0; k < i; k++)
 | 
			
		||||
            if (!is_zero(m_W[k][i]))
 | 
			
		||||
                return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void buffer_p_col_i_plus_q_col_j_W_modulo(const mpq & p, const mpq & q) {
 | 
			
		||||
        lp_assert(zeros_in_column_W_above(m_i));
 | 
			
		||||
        for (unsigned k = m_i; k < m_m; k++) {
 | 
			
		||||
            m_buffer[k] =  mod_R_balanced(mod_R_balanced(p * m_W[k][m_i]) + mod_R_balanced(q * m_W[k][m_j]));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    void buffer_p_col_i_plus_q_col_j_U(const mpq & p, unsigned i, const mpq & q, unsigned j) {
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_buffer[k] = p * m_U[k][i] + q * m_U[k][j];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void pivot_column_i_to_column_j_H(mpq u, unsigned i, mpq v, unsigned j) {
 | 
			
		||||
        lp_assert(is_zero(u * m_H[i][i] + v * m_H[i][j]));
 | 
			
		||||
        m_H[i][j] = zero_of_type<mpq>();
 | 
			
		||||
        for (unsigned k = i + 1; k < m_m; k ++)
 | 
			
		||||
            m_H[k][j] = u * m_H[k][i] + v * m_H[k][j];
 | 
			
		||||
                  
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    void pivot_column_i_to_column_j_W_modulo(mpq u, mpq v)  {
 | 
			
		||||
        lp_assert(is_zero((u * m_W[m_i][m_i] + v * m_W[m_i][m_j]) % m_R));
 | 
			
		||||
        m_W[m_i][m_j] = zero_of_type<mpq>();
 | 
			
		||||
        for (unsigned k = m_i + 1; k < m_m; k ++)
 | 
			
		||||
            m_W[k][m_j] = mod_R_balanced(mod_R_balanced(u * m_W[k][m_i]) + mod_R_balanced(v * m_W[k][m_j]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    void pivot_column_i_to_column_j_U(mpq u, unsigned i, mpq v, unsigned j) {
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k ++)
 | 
			
		||||
            m_U[k][j] = u * m_U[k][i] + v * m_U[k][j];
 | 
			
		||||
                  
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void copy_buffer_to_col_i_H(unsigned i) {
 | 
			
		||||
        for (unsigned k = i; k < m_m; k++) {
 | 
			
		||||
            m_H[k][i] = m_buffer[k];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    void copy_buffer_to_col_i_U(unsigned i) {
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++)
 | 
			
		||||
            m_U[k][i] = m_buffer[k];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // multiply by (a, b)
 | 
			
		||||
    //             (c, d)
 | 
			
		||||
    // from the left where i and j are the modified columns
 | 
			
		||||
    // the [i][i] = a, and [i][j] = b for the matrix we multiply by
 | 
			
		||||
   
 | 
			
		||||
    
 | 
			
		||||
    void multiply_U_reverse_from_left_by(unsigned i, unsigned j, const mpq & a, const mpq & b, const mpq & c, const mpq d) {
 | 
			
		||||
        // the new i-th row goes to the buffer
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_buffer[k] = a * m_U_reverse[i][k] + b * m_U_reverse[j][k];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // calculate the new j-th row in place
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_U_reverse[j][k] = c * m_U_reverse[i][k] + d * m_U_reverse[j][k];
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // copy the buffer into i-th row
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_U_reverse[i][k] = m_buffer[k];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void handle_column_ij_in_row_i(unsigned i, unsigned j) {
 | 
			
		||||
        lp_assert(is_correct_modulo());
 | 
			
		||||
        const mpq& aii = m_H[i][i];
 | 
			
		||||
        const mpq& aij = m_H[i][j];
 | 
			
		||||
        mpq p,q,r;
 | 
			
		||||
        extended_gcd(aii, aij, r, p, q);
 | 
			
		||||
        mpq aii_over_r = aii / r;
 | 
			
		||||
        mpq aij_over_r = aij / r;
 | 
			
		||||
        
 | 
			
		||||
        
 | 
			
		||||
        buffer_p_col_i_plus_q_col_j_H(p, i, q, j);
 | 
			
		||||
        pivot_column_i_to_column_j_H(- aij_over_r, i, aii_over_r, j);
 | 
			
		||||
        copy_buffer_to_col_i_H(i);
 | 
			
		||||
 | 
			
		||||
        
 | 
			
		||||
        buffer_p_col_i_plus_q_col_j_U(p, i, q, j);
 | 
			
		||||
        pivot_column_i_to_column_j_U(- aij_over_r, i, aii_over_r, j);
 | 
			
		||||
        copy_buffer_to_col_i_U(i);
 | 
			
		||||
 | 
			
		||||
        // U was multiplied from the right by (p, - aij_over_r)
 | 
			
		||||
        //                                    (q, aii_over_r  )
 | 
			
		||||
        // We need to multiply U_reverse by   (aii_over_r, aij_over_r)
 | 
			
		||||
        //                                    (-q        , p)
 | 
			
		||||
        // from the left
 | 
			
		||||
        
 | 
			
		||||
        multiply_U_reverse_from_left_by(i, j, aii_over_r, aij_over_r, -q, p);
 | 
			
		||||
        lp_assert(is_correct_modulo());
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    void switch_sign_for_column(unsigned i) {
 | 
			
		||||
        for (unsigned k = i; k < m_m; k++)
 | 
			
		||||
            m_H[k][i].neg();
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++)
 | 
			
		||||
            m_U[k][i].neg();
 | 
			
		||||
 | 
			
		||||
        // switch sign for the i-th row in the reverse m_U_reverse
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++)
 | 
			
		||||
            m_U_reverse[i][k].neg();
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void process_row_column(unsigned i, unsigned j){
 | 
			
		||||
        if (is_zero(m_H[i][j]))
 | 
			
		||||
            return;
 | 
			
		||||
        handle_column_ij_in_row_i(i, j);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void replace_column_j_by_j_minus_u_col_i_H(unsigned i, unsigned j, const mpq & u) {
 | 
			
		||||
        lp_assert(j < i);
 | 
			
		||||
        for (unsigned k = i; k < m_m; k++) {
 | 
			
		||||
            m_H[k][j] -= u * m_H[k][i];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    void replace_column_j_by_j_minus_u_col_i_U(unsigned i, unsigned j, const mpq & u) {
 | 
			
		||||
        
 | 
			
		||||
        lp_assert(j < i);
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_U[k][j] -= u * m_U[k][i];
 | 
			
		||||
        }
 | 
			
		||||
        // Here we multiply from m_U from the right by the matrix ( 1,  0)
 | 
			
		||||
        //                                                        ( -u, 1).
 | 
			
		||||
        // To adjust the reverse we multiply it from the left by (1, 0)
 | 
			
		||||
        //                                                       (u, 1)
 | 
			
		||||
 | 
			
		||||
        for (unsigned k = 0; k < m_n; k++) {
 | 
			
		||||
            m_U_reverse[i][k] += u * m_U_reverse[j][k];
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void work_on_columns_less_than_i_in_the_triangle(unsigned i) {
 | 
			
		||||
        const mpq & mii = m_H[i][i];
 | 
			
		||||
        if (is_zero(mii)) return;
 | 
			
		||||
        for (unsigned j = 0; j < i; j++) {
 | 
			
		||||
            const mpq & mij = m_H[i][j];
 | 
			
		||||
            if (!is_pos(mij) && - mij < mii)
 | 
			
		||||
                continue;
 | 
			
		||||
            mpq u = ceil(mij / mii);
 | 
			
		||||
            replace_column_j_by_j_minus_u_col_i_H(i, j, u);
 | 
			
		||||
            replace_column_j_by_j_minus_u_col_i_U(i, j, u);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void process_row(unsigned i) {
 | 
			
		||||
 | 
			
		||||
        lp_assert(is_correct_modulo());
 | 
			
		||||
        for (unsigned j = i + 1; j < m_n; j++) {
 | 
			
		||||
            process_row_column(i, j);
 | 
			
		||||
        }
 | 
			
		||||
        if (i >= m_n) {
 | 
			
		||||
            lp_assert(m_H == m_A_orig * m_U);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (is_neg(m_H[i][i]))
 | 
			
		||||
            switch_sign_for_column(i);
 | 
			
		||||
        work_on_columns_less_than_i_in_the_triangle(i);
 | 
			
		||||
        lp_assert(is_correct_modulo());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void calculate() {
 | 
			
		||||
        for (unsigned i = 0; i < m_m; i++) {
 | 
			
		||||
            process_row(i);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void prepare_U_and_U_reverse() {
 | 
			
		||||
        m_U = M(m_H.column_count());
 | 
			
		||||
        for (unsigned i = 0; i < m_U.column_count(); i++)
 | 
			
		||||
            m_U[i][i] = 1;
 | 
			
		||||
 | 
			
		||||
        m_U_reverse = m_U;
 | 
			
		||||
        
 | 
			
		||||
        lp_assert(m_H == m_A_orig * m_U);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool row_is_correct_form(unsigned i) const {
 | 
			
		||||
        if (i >= m_n)
 | 
			
		||||
            return true;
 | 
			
		||||
        const mpq& hii = m_H[i][i];
 | 
			
		||||
        if (is_neg(hii))
 | 
			
		||||
            return false;
 | 
			
		||||
        for (unsigned j = 0; j < i; j++) {
 | 
			
		||||
            const mpq & hij = m_H[i][j];
 | 
			
		||||
            if (is_pos(hij))
 | 
			
		||||
                return false;
 | 
			
		||||
            if (!is_zero(hii) && - hij >= hii)
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bool is_correct_form() const {
 | 
			
		||||
        for (unsigned i = 0; i < m_m; i++)
 | 
			
		||||
            if (!row_is_correct_form(i))
 | 
			
		||||
                return false;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_correct() const {
 | 
			
		||||
        return m_H == m_A_orig * m_U && is_unit_matrix(m_U * m_U_reverse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_correct_modulo() const {
 | 
			
		||||
        return m_H.equal_modulo(m_A_orig * m_U, m_d) && is_unit_matrix(m_U * m_U_reverse);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_correct_final() const {
 | 
			
		||||
        if (!is_correct()) {
 | 
			
		||||
            TRACE("hnf_calc",
 | 
			
		||||
                  tout << "m_H =            "; m_H.print(tout, 17);
 | 
			
		||||
                  tout << "\nm_A_orig * m_U = ";  (m_A_orig * m_U).print(tout, 17);
 | 
			
		||||
                  tout << "is_correct() does not hold" << std::endl;);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!is_correct_form()) {
 | 
			
		||||
            TRACE("hnf_calc", tout << "is_correct_form() does not hold" << std::endl;);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
public:
 | 
			
		||||
    const M& H() const { return m_H;}
 | 
			
		||||
    const M& U() const { return m_U;}
 | 
			
		||||
    const M& U_reverse() const { return m_U_reverse; }
 | 
			
		||||
private:
 | 
			
		||||
#endif
 | 
			
		||||
    void copy_buffer_to_col_i_W_modulo() {
 | 
			
		||||
        for (unsigned k = m_i; k < m_m; k++) {
 | 
			
		||||
            m_W[k][m_i] = m_buffer[k];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void replace_column_j_by_j_minus_u_col_i_W(unsigned j, const mpq & u) {
 | 
			
		||||
        lp_assert(j < m_i);
 | 
			
		||||
        for (unsigned k = m_i; k < m_m; k++) {
 | 
			
		||||
            m_W[k][j] -= u * m_W[k][m_i];
 | 
			
		||||
            //  m_W[k][j] = mod_R_balanced(m_W[k][j]);
 | 
			
		||||
        }
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    bool is_unit_matrix(const M& u) const {
 | 
			
		||||
        unsigned m = u.row_count();
 | 
			
		||||
        unsigned n = u.column_count();
 | 
			
		||||
        if (m != n) return false;
 | 
			
		||||
        for (unsigned i = 0; i < m; i ++)
 | 
			
		||||
            for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
                if (i == j) {
 | 
			
		||||
                    if (one_of_type<mpq>() != u[i][j])
 | 
			
		||||
                        return false;
 | 
			
		||||
                } else {
 | 
			
		||||
                    if (!is_zero(u[i][j]))
 | 
			
		||||
                        return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // follows Algorithm 2.4.8 of Henri Cohen's "A course on computational algebraic number theory",
 | 
			
		||||
    // with some changes related to that we create a low triangle matrix
 | 
			
		||||
    // with non-positive elements under the diagonal
 | 
			
		||||
    void process_column_in_row_modulo() {
 | 
			
		||||
        const mpq& aii = m_W[m_i][m_i];
 | 
			
		||||
        const mpq& aij = m_W[m_i][m_j];
 | 
			
		||||
        mpq d, p,q;
 | 
			
		||||
        hnf_calc::extended_gcd_minimal_uv(aii, aij, d, p, q);
 | 
			
		||||
        if (is_zero(d))
 | 
			
		||||
            return;
 | 
			
		||||
        mpq aii_over_d = mod_R(aii / d);
 | 
			
		||||
        mpq aij_over_d = mod_R(aij / d);
 | 
			
		||||
        buffer_p_col_i_plus_q_col_j_W_modulo(p, q);
 | 
			
		||||
        pivot_column_i_to_column_j_W_modulo(- aij_over_d, aii_over_d);
 | 
			
		||||
        copy_buffer_to_col_i_W_modulo();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fix_row_under_diagonal_W_modulo() {
 | 
			
		||||
        mpq d, u, v;
 | 
			
		||||
        if (is_zero(m_W[m_i][m_i])) {
 | 
			
		||||
            m_W[m_i][m_i] = m_R;
 | 
			
		||||
            u = one_of_type<mpq>();
 | 
			
		||||
            d = m_R;
 | 
			
		||||
        } else {
 | 
			
		||||
            hnf_calc::extended_gcd_minimal_uv(m_W[m_i][m_i], m_R, d, u, v);
 | 
			
		||||
        }
 | 
			
		||||
        auto & mii = m_W[m_i][m_i];
 | 
			
		||||
        mii *= u;
 | 
			
		||||
        mii = mod_R(mii);
 | 
			
		||||
        if (is_zero(mii))
 | 
			
		||||
            mii = d;
 | 
			
		||||
 | 
			
		||||
        lp_assert(is_pos(mii));
 | 
			
		||||
 | 
			
		||||
         // adjust column m_i
 | 
			
		||||
        for (unsigned k = m_i + 1; k < m_m; k++) {
 | 
			
		||||
            m_W[k][m_i] *= u;
 | 
			
		||||
            m_W[k][m_i] = mod_R_balanced(m_W[k][m_i]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        lp_assert(is_pos(mii));
 | 
			
		||||
        for (unsigned j = 0; j < m_i; j++) {
 | 
			
		||||
            const mpq & mij = m_W[m_i][j];
 | 
			
		||||
            if (!is_pos(mij) && - mij < mii)
 | 
			
		||||
                continue;
 | 
			
		||||
            mpq q = ceil(mij / mii);
 | 
			
		||||
            replace_column_j_by_j_minus_u_col_i_W(j, q);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    void process_row_modulo() {
 | 
			
		||||
        for (m_j = m_i + 1; m_j < m_n; m_j++) {
 | 
			
		||||
            process_column_in_row_modulo();
 | 
			
		||||
        }
 | 
			
		||||
        fix_row_under_diagonal_W_modulo();
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void calculate_by_modulo() {
 | 
			
		||||
        for (m_i = 0; m_i < m_m; m_i ++) {
 | 
			
		||||
            process_row_modulo();
 | 
			
		||||
            lp_assert(is_pos(m_W[m_i][m_i]));
 | 
			
		||||
            m_R /= m_W[m_i][m_i];
 | 
			
		||||
            lp_assert(is_int(m_R));
 | 
			
		||||
            m_half_R = floor(m_R / 2);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
public:
 | 
			
		||||
    hnf(M & A, const mpq & d) :
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
        m_H(A),
 | 
			
		||||
        m_A_orig(A),
 | 
			
		||||
#endif
 | 
			
		||||
        m_W(A),
 | 
			
		||||
        m_buffer(std::max(A.row_count(), A.column_count())),
 | 
			
		||||
        m_m(A.row_count()),
 | 
			
		||||
        m_n(A.column_count()),
 | 
			
		||||
        m_d(d),
 | 
			
		||||
        m_R(m_d),
 | 
			
		||||
        m_half_R(floor(m_R / 2))
 | 
			
		||||
    {
 | 
			
		||||
        if (m_m == 0 || m_n == 0 || is_zero(m_d))
 | 
			
		||||
            return;
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
        prepare_U_and_U_reverse();
 | 
			
		||||
        calculate();
 | 
			
		||||
        lp_assert(is_correct_final());
 | 
			
		||||
#endif
 | 
			
		||||
        calculate_by_modulo();
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
        CTRACE("hnf_calc", m_H != m_W,
 | 
			
		||||
               tout << "A = "; m_A_orig.print(tout, 4); tout << std::endl;
 | 
			
		||||
               tout << "H = "; m_H.print(tout, 4);  tout << std::endl;
 | 
			
		||||
               tout << "W = "; m_W.print(tout, 4);  tout << std::endl;);
 | 
			
		||||
        lp_assert (m_H == m_W);
 | 
			
		||||
#endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const M & W() const { return m_W; }
 | 
			
		||||
    
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										232
									
								
								src/util/lp/hnf_cutter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										232
									
								
								src/util/lp/hnf_cutter.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,232 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/lar_term.h"
 | 
			
		||||
#include "util/lp/hnf.h"
 | 
			
		||||
#include "util/lp/general_matrix.h"
 | 
			
		||||
#include "util/lp/var_register.h"
 | 
			
		||||
#include "util/lp/lia_move.h"
 | 
			
		||||
#include "util/lp/explanation.h"
 | 
			
		||||
 | 
			
		||||
namespace lp  {
 | 
			
		||||
class hnf_cutter {
 | 
			
		||||
    var_register               m_var_register;
 | 
			
		||||
    general_matrix             m_A;
 | 
			
		||||
    vector<const lar_term*>    m_terms;
 | 
			
		||||
    svector<constraint_index>  m_constraints_for_explanation;
 | 
			
		||||
    vector<mpq>                m_right_sides;
 | 
			
		||||
    lp_settings &              m_settings;
 | 
			
		||||
    mpq                        m_abs_max;
 | 
			
		||||
    bool                       m_overflow;
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
    const mpq & abs_max() const { return m_abs_max; }
 | 
			
		||||
    
 | 
			
		||||
    hnf_cutter(lp_settings & settings) : m_settings(settings),
 | 
			
		||||
                                         m_abs_max(zero_of_type<mpq>()) {}
 | 
			
		||||
 | 
			
		||||
    unsigned terms_count() const {
 | 
			
		||||
        return m_terms.size();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const vector<const lar_term*>& terms() const { return m_terms; }
 | 
			
		||||
    const svector<unsigned>& constraints_for_explanation() const {
 | 
			
		||||
        return m_constraints_for_explanation;
 | 
			
		||||
    }
 | 
			
		||||
    const vector<mpq> & right_sides() const { return m_right_sides; }
 | 
			
		||||
    void clear() {
 | 
			
		||||
        // m_A will be filled from scratch in init_matrix_A
 | 
			
		||||
        m_var_register.clear();
 | 
			
		||||
        m_terms.clear();
 | 
			
		||||
        m_constraints_for_explanation.clear();
 | 
			
		||||
        m_right_sides.clear();
 | 
			
		||||
        m_abs_max = zero_of_type<mpq>();
 | 
			
		||||
        m_overflow = false;
 | 
			
		||||
    }
 | 
			
		||||
    void add_term(const lar_term* t, const mpq &rs, constraint_index ci) {
 | 
			
		||||
        m_terms.push_back(t);
 | 
			
		||||
        m_right_sides.push_back(rs);
 | 
			
		||||
        m_constraints_for_explanation.push_back(ci);
 | 
			
		||||
        for (const auto &p : *t) {
 | 
			
		||||
            m_var_register.add_var(p.var());
 | 
			
		||||
            mpq t = abs(ceil(p.coeff()));
 | 
			
		||||
            if (t > m_abs_max)
 | 
			
		||||
                m_abs_max = t;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void print(std::ostream & out) {
 | 
			
		||||
        out << "terms = " << m_terms.size() << ", var = " << m_var_register.size() << std::endl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void initialize_row(unsigned i) {
 | 
			
		||||
        m_A.init_row_from_container(i, * m_terms[i], [this](unsigned j) { return m_var_register.add_var(j);});
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void init_matrix_A() {
 | 
			
		||||
        m_A = general_matrix(terms_count(), vars().size());
 | 
			
		||||
        for (unsigned i = 0; i < terms_count(); i++)
 | 
			
		||||
            initialize_row(i);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // todo: as we need only one row i with non integral b[i] need to optimize later
 | 
			
		||||
    void find_h_minus_1_b(const general_matrix& H, vector<mpq> & b) {
 | 
			
		||||
        // the solution will be put into b
 | 
			
		||||
        for (unsigned i = 0; i < H.row_count() ;i++) {
 | 
			
		||||
            for (unsigned j = 0; j < i; j++) {
 | 
			
		||||
                b[i] -= H[i][j]*b[j];
 | 
			
		||||
            }
 | 
			
		||||
            b[i] /= H[i][i];
 | 
			
		||||
            // consider return from here if b[i] is not an integer and return i
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    vector<mpq> create_b(const svector<unsigned> & basis_rows) {
 | 
			
		||||
        if (basis_rows.size() == m_right_sides.size())
 | 
			
		||||
            return m_right_sides;
 | 
			
		||||
        vector<mpq> b;
 | 
			
		||||
        for (unsigned i : basis_rows) {
 | 
			
		||||
            b.push_back(m_right_sides[i]);
 | 
			
		||||
        }
 | 
			
		||||
        return b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int find_cut_row_index(const vector<mpq> & b) {
 | 
			
		||||
        int ret = -1;
 | 
			
		||||
        int n = 0;
 | 
			
		||||
        for (int i = 0; i < static_cast<int>(b.size()); i++) {
 | 
			
		||||
            if (is_int(b[i])) continue;
 | 
			
		||||
            if (n == 0 ) {
 | 
			
		||||
                lp_assert(ret == -1);
 | 
			
		||||
                n = 1;
 | 
			
		||||
                ret = i;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (m_settings.random_next() % (++n) == 0) {
 | 
			
		||||
                    ret = i;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // fills e_i*H_minus_1
 | 
			
		||||
    void get_ei_H_minus_1(unsigned i, const general_matrix& H, vector<mpq> & row) {
 | 
			
		||||
        // we solve x = ei * H_min_1
 | 
			
		||||
        // or x * H = ei
 | 
			
		||||
        unsigned m = H.row_count();
 | 
			
		||||
        for (unsigned k = i + 1; k < m; k++) {
 | 
			
		||||
            row[k] = zero_of_type<mpq>();
 | 
			
		||||
        }
 | 
			
		||||
        row[i] = one_of_type<mpq>() / H[i][i];
 | 
			
		||||
        for(int k = i - 1; k >= 0; k--) {
 | 
			
		||||
            mpq t = zero_of_type<mpq>();
 | 
			
		||||
            for (unsigned l = k + 1; l <= i; l++) {
 | 
			
		||||
                t += H[l][k]*row[l];
 | 
			
		||||
            }
 | 
			
		||||
            row[k] = -t / H[k][k]; 
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // // test region
 | 
			
		||||
        // vector<mpq> ei(H.row_count(), zero_of_type<mpq>());
 | 
			
		||||
        // ei[i] = one_of_type<mpq>();
 | 
			
		||||
        // vector<mpq> pr = row * H;
 | 
			
		||||
        // pr.shrink(ei.size());
 | 
			
		||||
        // lp_assert(ei == pr);
 | 
			
		||||
        // // end test region
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fill_term(const vector<mpq> & row, lar_term& t) {
 | 
			
		||||
        for (unsigned j = 0; j < row.size(); j++) {
 | 
			
		||||
            if (!is_zero(row[j]))
 | 
			
		||||
                t.add_monomial(row[j], m_var_register.local_to_external(j));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    vector<mpq> transform_to_local_columns(const vector<impq> & x) const {
 | 
			
		||||
        vector<mpq> ret;
 | 
			
		||||
        for (unsigned j = 0; j < vars().size(); j++) {
 | 
			
		||||
            lp_assert(is_zero(x[m_var_register.local_to_external(j)].y));
 | 
			
		||||
            ret.push_back(x[m_var_register.local_to_external(j)].x);
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
    void shrink_explanation(const svector<unsigned>& basis_rows) {
 | 
			
		||||
        svector<unsigned> new_expl;
 | 
			
		||||
        for (unsigned i : basis_rows) {
 | 
			
		||||
            new_expl.push_back(m_constraints_for_explanation[i]);
 | 
			
		||||
        }
 | 
			
		||||
        m_constraints_for_explanation = new_expl;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool overflow() const { return m_overflow; }
 | 
			
		||||
    
 | 
			
		||||
    lia_move create_cut(lar_term& t, mpq& k, explanation& ex, bool & upper
 | 
			
		||||
                        #ifdef Z3DEBUG
 | 
			
		||||
                        ,
 | 
			
		||||
                        const vector<mpq> & x0
 | 
			
		||||
                        #endif
 | 
			
		||||
                        ) {
 | 
			
		||||
        // we suppose that x0 has at least one non integer element 
 | 
			
		||||
        init_matrix_A();
 | 
			
		||||
        svector<unsigned> basis_rows;
 | 
			
		||||
        mpq big_number = m_abs_max.expt(3);
 | 
			
		||||
        mpq d = hnf_calc::determinant_of_rectangular_matrix(m_A, basis_rows, big_number);
 | 
			
		||||
        
 | 
			
		||||
        //        std::cout << "max = " << m_abs_max << ", d = " << d << ", d/max = " << ceil (d /m_abs_max) << std::endl;
 | 
			
		||||
        //std::cout << "max cube " << m_abs_max * m_abs_max * m_abs_max << std::endl;
 | 
			
		||||
 | 
			
		||||
        if (d >= big_number) {
 | 
			
		||||
            return lia_move::undef;
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        if (m_settings.get_cancel_flag())
 | 
			
		||||
            return lia_move::undef;
 | 
			
		||||
        if (basis_rows.size() < m_A.row_count()) {
 | 
			
		||||
            m_A.shrink_to_rank(basis_rows);
 | 
			
		||||
            shrink_explanation(basis_rows);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        hnf<general_matrix> h(m_A, d);
 | 
			
		||||
        //  general_matrix A_orig = m_A;
 | 
			
		||||
        
 | 
			
		||||
        vector<mpq> b = create_b(basis_rows);
 | 
			
		||||
        lp_assert(m_A * x0 == b);
 | 
			
		||||
        // vector<mpq> bcopy = b;
 | 
			
		||||
        find_h_minus_1_b(h.W(), b);
 | 
			
		||||
        // lp_assert(bcopy == h.W().take_first_n_columns(b.size()) * b);
 | 
			
		||||
        int cut_row = find_cut_row_index(b);
 | 
			
		||||
        if (cut_row == -1)
 | 
			
		||||
            return lia_move::undef;
 | 
			
		||||
        // the matrix is not square - we can get
 | 
			
		||||
        // all integers in b's projection
 | 
			
		||||
        
 | 
			
		||||
        vector<mpq> row(m_A.column_count());
 | 
			
		||||
        get_ei_H_minus_1(cut_row, h.W(), row);
 | 
			
		||||
        vector<mpq> f = row * m_A;
 | 
			
		||||
        fill_term(f, t);
 | 
			
		||||
        k = floor(b[cut_row]);
 | 
			
		||||
        upper = true;
 | 
			
		||||
        return lia_move::cut;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    svector<unsigned> vars() const { return m_var_register.vars(); }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -24,34 +24,34 @@ namespace lp {
 | 
			
		|||
struct implied_bound {
 | 
			
		||||
    mpq m_bound;
 | 
			
		||||
    unsigned m_j; // the column for which the bound has been found
 | 
			
		||||
    bool m_is_low_bound;
 | 
			
		||||
    bool m_is_lower_bound;
 | 
			
		||||
    bool m_coeff_before_j_is_pos;
 | 
			
		||||
    unsigned m_row_or_term_index;
 | 
			
		||||
    bool m_strict;
 | 
			
		||||
    
 | 
			
		||||
    lconstraint_kind kind() const {
 | 
			
		||||
        lconstraint_kind k = m_is_low_bound? GE : LE;
 | 
			
		||||
        lconstraint_kind k = m_is_lower_bound? GE : LE;
 | 
			
		||||
        if (m_strict)
 | 
			
		||||
            k = static_cast<lconstraint_kind>(k / 2);
 | 
			
		||||
        return k;
 | 
			
		||||
    }
 | 
			
		||||
    bool operator==(const implied_bound & o) const {
 | 
			
		||||
        return m_j == o.m_j && m_is_low_bound == o.m_is_low_bound && m_bound == o.m_bound &&
 | 
			
		||||
        return m_j == o.m_j && m_is_lower_bound == o.m_is_lower_bound && m_bound == o.m_bound &&
 | 
			
		||||
            m_coeff_before_j_is_pos == o.m_coeff_before_j_is_pos &&
 | 
			
		||||
            m_row_or_term_index == o.m_row_or_term_index && m_strict == o.m_strict;
 | 
			
		||||
    }
 | 
			
		||||
    implied_bound(){}
 | 
			
		||||
    implied_bound(const mpq & a,
 | 
			
		||||
                  unsigned j,
 | 
			
		||||
                  bool low_bound,
 | 
			
		||||
                  bool lower_bound,
 | 
			
		||||
                  bool coeff_before_j_is_pos,
 | 
			
		||||
                  unsigned row_or_term_index,
 | 
			
		||||
                  bool strict):
 | 
			
		||||
        m_bound(a),
 | 
			
		||||
        m_j(j),
 | 
			
		||||
        m_is_low_bound(low_bound),
 | 
			
		||||
        m_is_lower_bound(lower_bound),
 | 
			
		||||
        m_coeff_before_j_is_pos(coeff_before_j_is_pos),
 | 
			
		||||
        m_row_or_term_index(row_or_term_index),
 | 
			
		||||
        m_strict(strict) {}
 | 
			
		||||
        m_strict(strict) {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -18,7 +18,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include "util/lp/indexed_vector.hpp"
 | 
			
		||||
#include "util/lp/indexed_vector_def.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template void indexed_vector<double>::clear();
 | 
			
		||||
template void indexed_vector<double>::clear_all();
 | 
			
		||||
| 
						 | 
				
			
			@ -42,11 +42,12 @@ template void lp::indexed_vector<double>::print(std::basic_ostream<char,struct s
 | 
			
		|||
template void lp::indexed_vector<lp::numeric_pair<lp::mpq> >::print(std::ostream&);
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
template void lp::print_vector<double>(vector<double> const&, std::ostream&);
 | 
			
		||||
template void lp::print_vector<unsigned int>(vector<unsigned int> const&, std::ostream&);
 | 
			
		||||
template void lp::print_vector<std::string>(vector<std::string> const&, std::ostream&);
 | 
			
		||||
template void lp::print_vector<lp::numeric_pair<lp::mpq> >(vector<lp::numeric_pair<lp::mpq>> const&, std::ostream&);
 | 
			
		||||
// template void lp::print_vector<double, vectro>(vector<double> const&, std::ostream&);
 | 
			
		||||
// template void lp::print_vector<unsigned int>(vector<unsigned int> const&, std::ostream&);
 | 
			
		||||
// template void lp::print_vector<std::string>(vector<std::string> const&, std::ostream&);
 | 
			
		||||
// template void lp::print_vector<lp::numeric_pair<lp::mpq> >(vector<lp::numeric_pair<lp::mpq>> const&, std::ostream&);
 | 
			
		||||
template void lp::indexed_vector<double>::resize(unsigned int);
 | 
			
		||||
template void lp::print_vector< lp::mpq>(vector< lp::mpq> const &, std::basic_ostream<char, std::char_traits<char> > &);
 | 
			
		||||
template void lp::print_vector<std::pair<lp::mpq, unsigned int> >(vector<std::pair<lp::mpq, unsigned int>> const&, std::ostream&);
 | 
			
		||||
// template void lp::print_vector< lp::mpq>(vector< lp::mpq> const &, std::basic_ostream<char, std::char_traits<char> > &);
 | 
			
		||||
// template void lp::print_vector<std::pair<lp::mpq, unsigned int> >(vector<std::pair<lp::mpq, unsigned int>> const&, std::ostream&);
 | 
			
		||||
template void lp::indexed_vector<lp::numeric_pair<lp::mpq> >::erase_from_index(unsigned int);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -28,11 +28,9 @@ Revision History:
 | 
			
		|||
#include <unordered_set>
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
template <typename T> void print_vector(const vector<T> & t, std::ostream & out);
 | 
			
		||||
template <typename T> void print_vector(const buffer<T> & t, std::ostream & out);
 | 
			
		||||
template <typename T> void print_sparse_vector(const vector<T> & t, std::ostream & out);
 | 
			
		||||
 | 
			
		||||
void print_vector(const vector<mpq> & t, std::ostream & out);
 | 
			
		||||
void print_vector_as_doubles(const vector<mpq> & t, std::ostream & out);
 | 
			
		||||
template <typename T>
 | 
			
		||||
class indexed_vector {
 | 
			
		||||
public:
 | 
			
		||||
| 
						 | 
				
			
			@ -90,16 +88,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void set_value(const T& value, unsigned index);
 | 
			
		||||
    void set_value_as_in_dictionary(unsigned index) {
 | 
			
		||||
        SASSERT(index < m_data.size());
 | 
			
		||||
        T & loc = m_data[index];
 | 
			
		||||
        if (is_zero(loc)) {
 | 
			
		||||
            m_index.push_back(index);
 | 
			
		||||
            loc = one_of_type<T>(); // use as a characteristic function
 | 
			
		||||
        } 
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    void clear();
 | 
			
		||||
    void clear_all();
 | 
			
		||||
    const T& operator[] (unsigned i) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -175,6 +164,55 @@ public:
 | 
			
		|||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct ival {
 | 
			
		||||
        unsigned m_var;
 | 
			
		||||
        const T & m_coeff;
 | 
			
		||||
        ival(unsigned var, const T & val) : m_var(var), m_coeff(val) {
 | 
			
		||||
        }
 | 
			
		||||
        unsigned var() const { return m_var;}
 | 
			
		||||
        const T & coeff() const { return m_coeff; }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    struct const_iterator {
 | 
			
		||||
            // fields
 | 
			
		||||
        const unsigned *m_i;
 | 
			
		||||
        const indexed_vector& m_v;
 | 
			
		||||
        
 | 
			
		||||
        //typedefs
 | 
			
		||||
            
 | 
			
		||||
            
 | 
			
		||||
        typedef const_iterator self_type;
 | 
			
		||||
        typedef ival value_type;
 | 
			
		||||
        typedef const ival reference;
 | 
			
		||||
        //        typedef const column_cell* pointer;
 | 
			
		||||
        typedef int difference_type;
 | 
			
		||||
        typedef std::forward_iterator_tag iterator_category;
 | 
			
		||||
 | 
			
		||||
        reference operator*() const {
 | 
			
		||||
            return ival(*m_i, m_v[*m_i]);
 | 
			
		||||
        }        
 | 
			
		||||
        self_type operator++() {  self_type i = *this; m_i++; return i;  }
 | 
			
		||||
        self_type operator++(int) { m_i++; return *this; }
 | 
			
		||||
 | 
			
		||||
        const_iterator(const unsigned* it, const indexed_vector& v) :
 | 
			
		||||
            m_i(it),
 | 
			
		||||
            m_v(v)
 | 
			
		||||
        {}
 | 
			
		||||
        bool operator==(const self_type &other) const {
 | 
			
		||||
            return m_i == other.m_i;
 | 
			
		||||
        }
 | 
			
		||||
        bool operator!=(const self_type &other) const { return !(*this == other); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const_iterator begin() const {
 | 
			
		||||
        return const_iterator(m_index.begin(), *this);
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    const_iterator end() const {
 | 
			
		||||
        return const_iterator(m_index.end(), *this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    bool is_OK() const;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,21 +22,6 @@ Revision History:
 | 
			
		|||
#include "util/lp/lp_settings.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void print_vector(const vector<T> & t, std::ostream & out) {
 | 
			
		||||
    for (unsigned i = 0; i < t.size(); i++)
 | 
			
		||||
        out << t[i] << " ";
 | 
			
		||||
    out << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void print_vector(const buffer<T> & t, std::ostream & out) {
 | 
			
		||||
    for (unsigned i = 0; i < t.size(); i++)
 | 
			
		||||
        out << t[i] << " ";
 | 
			
		||||
    out << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void print_sparse_vector(const vector<T> & t, std::ostream & out) {
 | 
			
		||||
    for (unsigned i = 0; i < t.size(); i++) {
 | 
			
		||||
| 
						 | 
				
			
			@ -46,7 +31,7 @@ void print_sparse_vector(const vector<T> & t, std::ostream & out) {
 | 
			
		|||
    out << std::endl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void print_vector(const vector<mpq> & t, std::ostream & out) {
 | 
			
		||||
void print_vector_as_doubles(const vector<mpq> & t, std::ostream & out) {
 | 
			
		||||
    for (unsigned i = 0; i < t.size(); i++)
 | 
			
		||||
        out << t[i].get_double() << std::setprecision(3) << " ";
 | 
			
		||||
    out << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -56,13 +41,13 @@ template <typename T>
 | 
			
		|||
void indexed_vector<T>::resize(unsigned data_size) {
 | 
			
		||||
    clear();
 | 
			
		||||
    m_data.resize(data_size, numeric_traits<T>::zero());
 | 
			
		||||
    SASSERT(is_OK());
 | 
			
		||||
    lp_assert(is_OK());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T>
 | 
			
		||||
void indexed_vector<T>::set_value(const T& value, unsigned index) {
 | 
			
		||||
    m_data[index] = value;
 | 
			
		||||
    SASSERT(std::find(m_index.begin(), m_index.end(), index) == m_index.end());
 | 
			
		||||
    lp_assert(std::find(m_index.begin(), m_index.end(), index) == m_index.end());
 | 
			
		||||
    m_index.push_back(index);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										45
									
								
								src/util/lp/indexer_of_constraints.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/util/lp/indexer_of_constraints.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,45 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
class indexer_of_constraints {
 | 
			
		||||
    binary_heap_priority_queue<unsigned> 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; }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,591 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
 | 
			
		||||
// here we are inside lp::lar_solver class
 | 
			
		||||
 | 
			
		||||
bool strategy_is_undecided() const {
 | 
			
		||||
    return m_settings.simplex_strategy() == simplex_strategy_enum::undecided;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var_index add_var(unsigned ext_j) {
 | 
			
		||||
    var_index i;
 | 
			
		||||
    SASSERT (ext_j < m_terms_start_index); 
 | 
			
		||||
 | 
			
		||||
    if (ext_j >= m_terms_start_index)
 | 
			
		||||
        throw 0; // todo : what is the right way to exit?
 | 
			
		||||
            
 | 
			
		||||
    if (try_get_val(m_ext_vars_to_columns, ext_j, i)) {
 | 
			
		||||
        return i;
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(m_vars_to_ul_pairs.size() == A_r().column_count());
 | 
			
		||||
    i = A_r().column_count();
 | 
			
		||||
    m_vars_to_ul_pairs.push_back (ul_pair(static_cast<unsigned>(-1)));
 | 
			
		||||
    add_non_basic_var_to_core_fields(ext_j);
 | 
			
		||||
    SASSERT(sizes_are_correct());
 | 
			
		||||
    return i;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void register_new_ext_var_index(unsigned ext_v) {
 | 
			
		||||
    SASSERT(!contains(m_ext_vars_to_columns, ext_v));
 | 
			
		||||
    unsigned j = static_cast<unsigned>(m_ext_vars_to_columns.size());
 | 
			
		||||
    m_ext_vars_to_columns[ext_v] = j;
 | 
			
		||||
    SASSERT(m_columns_to_ext_vars_or_term_indices.size() == j);
 | 
			
		||||
    m_columns_to_ext_vars_or_term_indices.push_back(ext_v);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_non_basic_var_to_core_fields(unsigned ext_j) {
 | 
			
		||||
    register_new_ext_var_index(ext_j);
 | 
			
		||||
    m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
 | 
			
		||||
    m_columns_with_changed_bound.increase_size_by_one();
 | 
			
		||||
    add_new_var_to_core_fields_for_mpq(false);
 | 
			
		||||
    if (use_lu())
 | 
			
		||||
        add_new_var_to_core_fields_for_doubles(false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_new_var_to_core_fields_for_doubles(bool register_in_basis) {
 | 
			
		||||
    unsigned j = A_d().column_count();
 | 
			
		||||
    A_d().add_column();
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j);
 | 
			
		||||
    //        SASSERT(m_mpq_lar_core_solver.m_d_low_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_low_bounds.resize(j + 1);
 | 
			
		||||
    m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
 | 
			
		||||
    SASSERT(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<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
 | 
			
		||||
        m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_new_var_to_core_fields_for_mpq(bool register_in_basis) {
 | 
			
		||||
    unsigned j = A_r().column_count();
 | 
			
		||||
    A_r().add_column();
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_r_x.size() == j);
 | 
			
		||||
    //        SASSERT(m_mpq_lar_core_solver.m_r_low_bounds.size() == j && m_mpq_lar_core_solver.m_r_upper_bounds.size() == j);  // restore later
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_x.resize(j + 1);
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_low_bounds.increase_size_by_one();
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_upper_bounds.increase_size_by_one();
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_solver.m_inf_set.increase_size_by_one();
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_solver.m_costs.resize(j + 1);
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_solver.m_d.resize(j + 1);
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_r_heading.size() == j); // as A().column_count() on the entry to the method
 | 
			
		||||
    if (register_in_basis) {
 | 
			
		||||
        A_r().add_row();
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_heading.push_back(m_mpq_lar_core_solver.m_r_basis.size());
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_basis.push_back(j);
 | 
			
		||||
        if (m_settings.bound_propagation())
 | 
			
		||||
            m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
 | 
			
		||||
    } else {
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_heading.push_back(- static_cast<int>(m_mpq_lar_core_solver.m_r_nbasis.size()) - 1);
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_nbasis.push_back(j);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var_index add_term_undecided(const vector<std::pair<mpq, var_index>> & coeffs,
 | 
			
		||||
                             const mpq &m_v) {
 | 
			
		||||
    m_terms.push_back(new lar_term(coeffs, m_v));
 | 
			
		||||
    m_orig_terms.push_back(new lar_term(coeffs, m_v));
 | 
			
		||||
    return m_terms_start_index +  m_terms.size() - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// terms
 | 
			
		||||
var_index add_term(const vector<std::pair<mpq, var_index>> & coeffs,
 | 
			
		||||
                   const mpq &m_v) {
 | 
			
		||||
    if (strategy_is_undecided())
 | 
			
		||||
        return add_term_undecided(coeffs, m_v);
 | 
			
		||||
 | 
			
		||||
    m_terms.push_back(new lar_term(coeffs, m_v));
 | 
			
		||||
    m_orig_terms.push_back(new lar_term(coeffs, m_v));
 | 
			
		||||
    unsigned adjusted_term_index = m_terms.size() - 1;
 | 
			
		||||
    var_index ret = m_terms_start_index + adjusted_term_index;
 | 
			
		||||
    if (use_tableau() && !coeffs.empty()) {
 | 
			
		||||
        add_row_for_term(m_orig_terms.back(), ret);
 | 
			
		||||
        if (m_settings.bound_propagation())
 | 
			
		||||
            m_rows_with_changed_bounds.insert(A_r().row_count() - 1);
 | 
			
		||||
    } 
 | 
			
		||||
    SASSERT(m_ext_vars_to_columns.size() == A_r().column_count());
 | 
			
		||||
    return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_row_for_term(const lar_term * term, unsigned term_ext_index) {
 | 
			
		||||
    SASSERT(sizes_are_correct());
 | 
			
		||||
    add_row_from_term_no_constraint(term, term_ext_index);
 | 
			
		||||
    SASSERT(sizes_are_correct());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_row_from_term_no_constraint(const lar_term * term, unsigned term_ext_index) {
 | 
			
		||||
    register_new_ext_var_index(term_ext_index);
 | 
			
		||||
    // j will be a new variable
 | 
			
		||||
    unsigned j = A_r().column_count();
 | 
			
		||||
    ul_pair ul(j);
 | 
			
		||||
    m_vars_to_ul_pairs.push_back(ul);
 | 
			
		||||
    add_basic_var_to_core_fields();
 | 
			
		||||
    if (use_tableau()) {
 | 
			
		||||
        auto it = iterator_on_term_with_basis_var(*term, j);
 | 
			
		||||
        A_r().fill_last_row_with_pivoting(it,
 | 
			
		||||
                                          m_mpq_lar_core_solver.m_r_solver.m_basis_heading);
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_solver.m_b.resize(A_r().column_count(), zero_of_type<mpq>());
 | 
			
		||||
    } else {
 | 
			
		||||
        fill_last_row_of_A_r(A_r(), term);
 | 
			
		||||
    }
 | 
			
		||||
    m_mpq_lar_core_solver.m_r_x[j] = get_basic_var_value_from_row_directly(A_r().row_count() - 1);
 | 
			
		||||
    if (use_lu())
 | 
			
		||||
        fill_last_row_of_A_d(A_d(), term);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_basic_var_to_core_fields() {
 | 
			
		||||
    bool use_lu = m_mpq_lar_core_solver.need_to_presolve_with_double_solver();
 | 
			
		||||
    SASSERT(!use_lu || A_r().column_count() == A_d().column_count());
 | 
			
		||||
    m_mpq_lar_core_solver.m_column_types.push_back(column_type::free_column);
 | 
			
		||||
    m_columns_with_changed_bound.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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
constraint_index add_var_bound(var_index j, lconstraint_kind kind, const mpq & right_side)  {
 | 
			
		||||
    constraint_index ci = m_constraints.size();
 | 
			
		||||
    if (!is_term(j)) { // j is a var
 | 
			
		||||
        auto vc = new lar_var_constraint(j, kind, right_side);
 | 
			
		||||
        m_constraints.push_back(vc);
 | 
			
		||||
        update_column_type_and_bound(j, kind, right_side, ci);
 | 
			
		||||
    } else {
 | 
			
		||||
        add_var_bound_on_constraint_for_term(j, kind, right_side, ci);
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(sizes_are_correct());
 | 
			
		||||
    return ci;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_index) {
 | 
			
		||||
    switch(m_mpq_lar_core_solver.m_column_types[j]) {
 | 
			
		||||
    case column_type::free_column:
 | 
			
		||||
        update_free_column_type_and_bound(j, kind, right_side, constr_index);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        update_boxed_column_type_and_bound(j, kind, right_side, constr_index);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        update_low_bound_column_type_and_bound(j, kind, right_side, constr_index);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        update_upper_bound_column_type_and_bound(j, kind, right_side, constr_index);
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
        update_fixed_column_type_and_bound(j, kind, right_side, constr_index);
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false); // cannot be here
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void add_var_bound_on_constraint_for_term(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
 | 
			
		||||
    SASSERT(is_term(j));
 | 
			
		||||
    unsigned adjusted_term_index = adjust_term_index(j);
 | 
			
		||||
    unsigned term_j;
 | 
			
		||||
    if (try_get_val(m_ext_vars_to_columns, j, term_j)) {
 | 
			
		||||
        mpq rs = right_side - m_orig_terms[adjusted_term_index]->m_v;
 | 
			
		||||
        m_constraints.push_back(new lar_term_constraint(m_orig_terms[adjusted_term_index], kind, right_side));
 | 
			
		||||
        update_column_type_and_bound(term_j, kind, rs, ci);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        add_constraint_from_term_and_create_new_column_row(j, m_orig_terms[adjusted_term_index], kind, right_side);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void add_constraint_from_term_and_create_new_column_row(unsigned term_j, const lar_term* term,
 | 
			
		||||
                                                        lconstraint_kind kind, const mpq & right_side) {
 | 
			
		||||
 | 
			
		||||
    add_row_from_term_no_constraint(term, term_j);
 | 
			
		||||
    unsigned j = A_r().column_count() - 1;
 | 
			
		||||
    update_column_type_and_bound(j, kind, right_side - term->m_v, m_constraints.size());
 | 
			
		||||
    m_constraints.push_back(new lar_term_constraint(term, kind, right_side));
 | 
			
		||||
    SASSERT(A_r().column_count() == m_mpq_lar_core_solver.m_r_solver.m_costs.size());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void decide_on_strategy_and_adjust_initial_state() {
 | 
			
		||||
    SASSERT(strategy_is_undecided());
 | 
			
		||||
    if (m_vars_to_ul_pairs.size() > m_settings.column_number_threshold_for_using_lu_in_lar_solver) {
 | 
			
		||||
        m_settings.simplex_strategy() = simplex_strategy_enum::lu;
 | 
			
		||||
    } else {
 | 
			
		||||
        m_settings.simplex_strategy() = simplex_strategy_enum::tableau_rows; // todo: when to switch to tableau_costs?
 | 
			
		||||
    }
 | 
			
		||||
    adjust_initial_state();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void 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;
 | 
			
		||||
    case simplex_strategy_enum::tableau_costs:
 | 
			
		||||
        SASSERT(false); // not implemented
 | 
			
		||||
    case simplex_strategy_enum::undecided:
 | 
			
		||||
        adjust_initial_state_for_tableau_rows();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void 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_low_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();
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_d_x.size() == j);
 | 
			
		||||
    //        SASSERT(m_mpq_lar_core_solver.m_d_low_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_low_bounds.resize(j + 1);
 | 
			
		||||
    m_mpq_lar_core_solver.m_d_upper_bounds.resize(j + 1);
 | 
			
		||||
    SASSERT(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<int>(m_mpq_lar_core_solver.m_d_nbasis.size()) - 1);
 | 
			
		||||
        m_mpq_lar_core_solver.m_d_nbasis.push_back(j);
 | 
			
		||||
        }*/
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void adjust_initial_state_for_tableau_rows() {
 | 
			
		||||
    for (unsigned j = 0; j < m_terms.size(); j++) {
 | 
			
		||||
        if (contains(m_ext_vars_to_columns, j + m_terms_start_index))
 | 
			
		||||
            continue;
 | 
			
		||||
        add_row_from_term_no_constraint(m_terms[j], j + m_terms_start_index);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// this fills the last row of A_d and sets the basis column: -1 in the last column of the row
 | 
			
		||||
void fill_last_row_of_A_d(static_matrix<double, double> & A, const lar_term* ls) {
 | 
			
		||||
    SASSERT(A.row_count() > 0);
 | 
			
		||||
    SASSERT(A.column_count() > 0);
 | 
			
		||||
    unsigned last_row = A.row_count() - 1;
 | 
			
		||||
    SASSERT(A.m_rows[last_row].empty());
 | 
			
		||||
 | 
			
		||||
    for (auto & t : ls->m_coeffs) {
 | 
			
		||||
        SASSERT(!is_zero(t.second));
 | 
			
		||||
        var_index j = t.first;
 | 
			
		||||
        A.set(last_row, j, - t.second.get_double());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned basis_j = A.column_count() - 1;
 | 
			
		||||
    A.set(last_row, basis_j, - 1 );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update_free_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index constr_ind) {
 | 
			
		||||
    mpq y_of_bound(0);
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    case LT:
 | 
			
		||||
        y_of_bound = -1;
 | 
			
		||||
    case LE:
 | 
			
		||||
        m_mpq_lar_core_solver.m_column_types[j] = column_type::upper_bound;
 | 
			
		||||
        SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
 | 
			
		||||
        SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
 | 
			
		||||
        {
 | 
			
		||||
            auto up = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
 | 
			
		||||
        }
 | 
			
		||||
        set_upper_bound_witness(j, constr_ind);
 | 
			
		||||
        break;
 | 
			
		||||
    case GT:
 | 
			
		||||
        y_of_bound = 1;
 | 
			
		||||
    case GE:
 | 
			
		||||
        m_mpq_lar_core_solver.m_column_types[j] = column_type::low_bound;
 | 
			
		||||
        SASSERT(m_mpq_lar_core_solver.m_r_upper_bounds.size() > j);
 | 
			
		||||
        {
 | 
			
		||||
            auto low = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
 | 
			
		||||
        }
 | 
			
		||||
        set_low_bound_witness(j, constr_ind);
 | 
			
		||||
        break;
 | 
			
		||||
    case EQ:
 | 
			
		||||
        m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
        m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
 | 
			
		||||
        set_upper_bound_witness(j, constr_ind);
 | 
			
		||||
        set_low_bound_witness(j, constr_ind);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
    m_columns_with_changed_bound.insert(j);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update_upper_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::upper_bound);
 | 
			
		||||
    mpq y_of_bound(0);
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    case LT:
 | 
			
		||||
        y_of_bound = -1;
 | 
			
		||||
    case LE:
 | 
			
		||||
        {
 | 
			
		||||
            auto up = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            if (up < m_mpq_lar_core_solver.m_r_upper_bounds()[j]) {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case GT:
 | 
			
		||||
        y_of_bound = 1;
 | 
			
		||||
    case GE:            
 | 
			
		||||
        m_mpq_lar_core_solver.m_column_types[j] = column_type::boxed;
 | 
			
		||||
        {
 | 
			
		||||
            auto low = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
 | 
			
		||||
            set_low_bound_witness(j, ci);
 | 
			
		||||
            m_columns_with_changed_bound.insert(j);
 | 
			
		||||
            if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
            } else {
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
 | 
			
		||||
            }                     
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case EQ:
 | 
			
		||||
        {
 | 
			
		||||
            auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
 | 
			
		||||
            if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
            } else {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
void update_boxed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
 | 
			
		||||
    SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::boxed && m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
 | 
			
		||||
    mpq y_of_bound(0);
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    case LT:
 | 
			
		||||
        y_of_bound = -1;
 | 
			
		||||
    case LE:
 | 
			
		||||
        {
 | 
			
		||||
            auto up = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            if (up < m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                SASSERT(false);
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
            } else {
 | 
			
		||||
                if (m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j])
 | 
			
		||||
                    m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
            }                    
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case GT:
 | 
			
		||||
        y_of_bound = 1;
 | 
			
		||||
    case GE:            
 | 
			
		||||
        {
 | 
			
		||||
            auto low = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
            }
 | 
			
		||||
            if (low > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
            } else if ( low == m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case EQ:
 | 
			
		||||
        {
 | 
			
		||||
            auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
 | 
			
		||||
            if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_upper_bound_witness(j, ci);                    
 | 
			
		||||
            } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_low_bound_witness(j, ci);                    
 | 
			
		||||
            } else {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
void update_low_bound_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
 | 
			
		||||
    SASSERT(m_mpq_lar_core_solver.m_column_types()[j] == column_type::low_bound);
 | 
			
		||||
    mpq y_of_bound(0);
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    case LT:
 | 
			
		||||
        y_of_bound = -1;
 | 
			
		||||
    case LE:
 | 
			
		||||
        {
 | 
			
		||||
            auto up = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            m_mpq_lar_core_solver.m_r_upper_bounds[j] = up;
 | 
			
		||||
            set_upper_bound_witness(j, ci);
 | 
			
		||||
            m_columns_with_changed_bound.insert(j);
 | 
			
		||||
 | 
			
		||||
            if (up < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
            } else {
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = m_mpq_lar_core_solver.m_r_low_bounds()[j] < m_mpq_lar_core_solver.m_r_upper_bounds()[j]? column_type::boxed : column_type::fixed;
 | 
			
		||||
            }                    
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case GT:
 | 
			
		||||
        y_of_bound = 1;
 | 
			
		||||
    case GE:            
 | 
			
		||||
        {
 | 
			
		||||
            auto low = numeric_pair<mpq>(right_side, y_of_bound);
 | 
			
		||||
            if (low > m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_low_bounds[j] = low;
 | 
			
		||||
                m_columns_with_changed_bound.insert(j);
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case EQ:
 | 
			
		||||
        {
 | 
			
		||||
            auto v = numeric_pair<mpq>(right_side, zero_of_type<mpq>());
 | 
			
		||||
            if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_upper_bound_witness(j, ci);                    
 | 
			
		||||
            } else {
 | 
			
		||||
                m_mpq_lar_core_solver.m_r_low_bounds[j] = m_mpq_lar_core_solver.m_r_upper_bounds[j] = v;
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
                m_mpq_lar_core_solver.m_column_types[j] = column_type::fixed;
 | 
			
		||||
            }
 | 
			
		||||
            m_columns_with_changed_bound.insert(j);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void update_fixed_column_type_and_bound(var_index j, lconstraint_kind kind, const mpq & right_side, constraint_index ci) {
 | 
			
		||||
    SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_column_types()[j] == column_type::fixed && m_mpq_lar_core_solver.m_r_low_bounds()[j] == m_mpq_lar_core_solver.m_r_upper_bounds()[j]));
 | 
			
		||||
    SASSERT(m_status == INFEASIBLE || (m_mpq_lar_core_solver.m_r_low_bounds()[j].y.is_zero() && m_mpq_lar_core_solver.m_r_upper_bounds()[j].y.is_zero()));
 | 
			
		||||
    auto v = numeric_pair<mpq>(right_side, mpq(0));
 | 
			
		||||
        
 | 
			
		||||
    mpq y_of_bound(0);
 | 
			
		||||
    switch (kind) {
 | 
			
		||||
    case LT:
 | 
			
		||||
        if (v <= m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
            m_status = INFEASIBLE;
 | 
			
		||||
            m_infeasible_column_index = j;
 | 
			
		||||
            set_upper_bound_witness(j, ci);
 | 
			
		||||
        }                   
 | 
			
		||||
        break;
 | 
			
		||||
    case LE:
 | 
			
		||||
        {
 | 
			
		||||
            if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_upper_bound_witness(j, ci);
 | 
			
		||||
            }                   
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case GT:
 | 
			
		||||
        {
 | 
			
		||||
            if (v >= m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index =j;
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case GE:            
 | 
			
		||||
        {
 | 
			
		||||
            if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_low_bound_witness(j, ci);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case EQ:
 | 
			
		||||
        {
 | 
			
		||||
            if (v < m_mpq_lar_core_solver.m_r_low_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_upper_bound_witness(j, ci);                    
 | 
			
		||||
            } else if (v > m_mpq_lar_core_solver.m_r_upper_bounds[j]) {
 | 
			
		||||
                m_status = INFEASIBLE;
 | 
			
		||||
                m_infeasible_column_index = j;
 | 
			
		||||
                set_low_bound_witness(j, ci);                    
 | 
			
		||||
            } 
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
                
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +35,7 @@ public:
 | 
			
		|||
        return m_data[j] >= 0;
 | 
			
		||||
    }
 | 
			
		||||
    void insert(unsigned j) {
 | 
			
		||||
        SASSERT(j < m_data.size());
 | 
			
		||||
        lp_assert(j < m_data.size());
 | 
			
		||||
        if (contains(j)) return;
 | 
			
		||||
        m_data[j] = m_index.size();
 | 
			
		||||
        m_index.push_back(j);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										1294
									
								
								src/util/lp/int_solver.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1294
									
								
								src/util/lp/int_solver.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										166
									
								
								src/util/lp/int_solver.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								src/util/lp/int_solver.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,166 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/lp_settings.h"
 | 
			
		||||
#include "util/lp/static_matrix.h"
 | 
			
		||||
#include "util/lp/int_set.h"
 | 
			
		||||
#include "util/lp/lar_term.h"
 | 
			
		||||
#include "util/lp/lar_constraints.h"
 | 
			
		||||
#include "util/lp/hnf_cutter.h"
 | 
			
		||||
#include "util/lp/lia_move.h"
 | 
			
		||||
#include "util/lp/explanation.h"
 | 
			
		||||
 | 
			
		||||
namespace lp {
 | 
			
		||||
class lar_solver;
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
struct lp_constraint;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class int_solver {
 | 
			
		||||
public:
 | 
			
		||||
    // fields
 | 
			
		||||
    lar_solver          *m_lar_solver;
 | 
			
		||||
    unsigned            m_number_of_calls;
 | 
			
		||||
    lar_term            *m_t; // the term to return in the cut
 | 
			
		||||
    mpq                 *m_k; // the right side of the cut
 | 
			
		||||
    explanation         *m_ex; // the conflict explanation
 | 
			
		||||
    bool                *m_upper; // we have a cut m_t*x <= k if m_upper is true nad m_t*x >= k otherwise
 | 
			
		||||
    hnf_cutter          m_hnf_cutter;
 | 
			
		||||
    // methods
 | 
			
		||||
    int_solver(lar_solver* lp);
 | 
			
		||||
 | 
			
		||||
    // main function to check that the solution provided by lar_solver is valid for integral values,
 | 
			
		||||
    // or provide a way of how it can be adjusted.
 | 
			
		||||
    lia_move check(lar_term& t, mpq& k, explanation& ex, bool & upper);
 | 
			
		||||
    lia_move check_(lar_term& t, mpq& k, explanation& ex, bool & upper);
 | 
			
		||||
    bool move_non_basic_column_to_bounds(unsigned j);
 | 
			
		||||
    lia_move check_wrapper(lar_term& t, mpq& k, explanation& ex);    
 | 
			
		||||
    bool is_base(unsigned j) const;
 | 
			
		||||
    
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
    // how to tighten bounds for integer variables.
 | 
			
		||||
 | 
			
		||||
    bool gcd_test_for_row(static_matrix<mpq, numeric_pair<mpq>> & A, unsigned i); 
 | 
			
		||||
    
 | 
			
		||||
    // gcd test
 | 
			
		||||
    // 5*x + 3*y + 6*z = 5
 | 
			
		||||
    // suppose x is fixed at 2.
 | 
			
		||||
    // so we have 10 + 3(y + 2z) = 5
 | 
			
		||||
    //             5 = -3(y + 2z)
 | 
			
		||||
    // this is unsolvable because 5/3 is not an integer.
 | 
			
		||||
    // so we create a lemma that rules out this condition.
 | 
			
		||||
    // 
 | 
			
		||||
    bool gcd_test(); // returns false in case of failure. Creates a theory lemma in case of failure.
 | 
			
		||||
 | 
			
		||||
    bool branch(const lp_constraint<mpq, mpq> & new_inequality);
 | 
			
		||||
    bool ext_gcd_test(const row_strip<mpq>& row,
 | 
			
		||||
                      mpq const & least_coeff, 
 | 
			
		||||
                      mpq const & lcm_den,
 | 
			
		||||
                      mpq const & consts);
 | 
			
		||||
    void fill_explanation_from_fixed_columns(const row_strip<mpq> & row);
 | 
			
		||||
    void add_to_explanation_from_fixed_or_boxed_column(unsigned j);
 | 
			
		||||
    lia_move patch_nbasic_columns();
 | 
			
		||||
    bool get_freedom_interval_for_column(unsigned j, bool & inf_l, impq & l, bool & inf_u, impq & u, mpq & m);
 | 
			
		||||
    const impq & lower_bound(unsigned j) const;
 | 
			
		||||
    const impq & upper_bound(unsigned j) const;
 | 
			
		||||
    bool is_int(unsigned j) const;
 | 
			
		||||
    bool is_real(unsigned j) const;
 | 
			
		||||
    bool is_boxed(unsigned j) const;
 | 
			
		||||
    bool is_fixed(unsigned j) const;
 | 
			
		||||
    bool is_free(unsigned j) const;
 | 
			
		||||
    bool value_is_int(unsigned j) const;
 | 
			
		||||
    void set_value_for_nbasic_column(unsigned j, const impq & new_val);
 | 
			
		||||
    void set_value_for_nbasic_column_ignore_old_values(unsigned j, const impq & new_val);
 | 
			
		||||
    bool non_basic_columns_are_at_bounds() const;
 | 
			
		||||
    bool is_feasible() const;
 | 
			
		||||
    const impq & get_value(unsigned j) const;
 | 
			
		||||
    bool column_is_int_inf(unsigned j) const;
 | 
			
		||||
    void trace_inf_rows() const;
 | 
			
		||||
    lia_move branch_or_sat();
 | 
			
		||||
    int find_any_inf_int_column_basis_first();
 | 
			
		||||
    int find_inf_int_base_column();
 | 
			
		||||
    int find_inf_int_boxed_base_column_with_smallest_range(unsigned&);
 | 
			
		||||
    int get_kth_inf_int(unsigned) const;
 | 
			
		||||
    lp_settings& settings();
 | 
			
		||||
    const lp_settings& settings() const;
 | 
			
		||||
    bool move_non_basic_columns_to_bounds();
 | 
			
		||||
    void branch_infeasible_int_var(unsigned);
 | 
			
		||||
    lia_move mk_gomory_cut(unsigned inf_col, const row_strip<mpq>& row);
 | 
			
		||||
    lia_move report_conflict_from_gomory_cut();
 | 
			
		||||
    void adjust_term_and_k_for_some_ints_case_gomory(mpq& lcm_den);
 | 
			
		||||
    lia_move proceed_with_gomory_cut(unsigned j);
 | 
			
		||||
    int find_free_var_in_gomory_row(const row_strip<mpq>& );
 | 
			
		||||
    bool is_gomory_cut_target(const row_strip<mpq>&);
 | 
			
		||||
    bool at_bound(unsigned j) const;
 | 
			
		||||
    bool at_low(unsigned j) const;
 | 
			
		||||
    bool at_upper(unsigned j) const;
 | 
			
		||||
    bool has_low(unsigned j) const;
 | 
			
		||||
    bool has_upper(unsigned j) const;
 | 
			
		||||
    unsigned row_of_basic_column(unsigned j) const;
 | 
			
		||||
    inline static bool is_rational(const impq & n) {
 | 
			
		||||
        return is_zero(n.y);  
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    void display_column(std::ostream & out, unsigned j) const;
 | 
			
		||||
    inline static
 | 
			
		||||
    mpq fractional_part(const impq & n) {
 | 
			
		||||
        lp_assert(is_rational(n));
 | 
			
		||||
        return n.x - floor(n.x);
 | 
			
		||||
    }
 | 
			
		||||
private:
 | 
			
		||||
    void real_case_in_gomory_cut(const mpq & a, unsigned x_j, const mpq& f_0, const mpq& one_minus_f_0);
 | 
			
		||||
    void int_case_in_gomory_cut(const mpq & a, unsigned x_j, mpq & lcm_den, const mpq& f_0, const mpq& one_minus_f_0);
 | 
			
		||||
    constraint_index column_upper_bound_constraint(unsigned j) const;
 | 
			
		||||
    constraint_index column_lower_bound_constraint(unsigned j) const;
 | 
			
		||||
    void display_row_info(std::ostream & out, unsigned row_index) const;
 | 
			
		||||
    void gomory_cut_adjust_t_and_k(vector<std::pair<mpq, unsigned>> & pol, lar_term & t, mpq &k, bool num_ints, mpq &lcm_den);
 | 
			
		||||
    bool current_solution_is_inf_on_cut() const;
 | 
			
		||||
public:
 | 
			
		||||
    bool shift_var(unsigned j, unsigned range);
 | 
			
		||||
private:
 | 
			
		||||
    unsigned random();
 | 
			
		||||
    bool has_inf_int() const;
 | 
			
		||||
    lia_move create_branch_on_column(int j);
 | 
			
		||||
public:
 | 
			
		||||
    bool is_term(unsigned j) const;
 | 
			
		||||
    bool left_branch_is_more_narrow_than_right(unsigned);
 | 
			
		||||
    lia_move find_cube();
 | 
			
		||||
    bool tighten_terms_for_cube();
 | 
			
		||||
    bool tighten_term_for_cube(unsigned);
 | 
			
		||||
    unsigned column_count() const;
 | 
			
		||||
    bool all_columns_are_bounded() const;
 | 
			
		||||
    impq get_cube_delta_for_term(const lar_term&) const;
 | 
			
		||||
    void find_feasible_solution();
 | 
			
		||||
    int find_inf_int_nbasis_column() const;
 | 
			
		||||
    lia_move run_gcd_test();
 | 
			
		||||
    lia_move gomory_cut();
 | 
			
		||||
    lia_move hnf_cut();
 | 
			
		||||
    lia_move make_hnf_cut();
 | 
			
		||||
    bool init_terms_for_hnf_cut();
 | 
			
		||||
    bool hnf_matrix_is_empty() const;
 | 
			
		||||
    void try_add_term_to_A_for_hnf(unsigned term_index);
 | 
			
		||||
    bool hnf_has_var_with_non_integral_value() const;
 | 
			
		||||
    bool hnf_cutter_is_full() const;
 | 
			
		||||
    void patch_nbasic_column(unsigned j, bool patch_only_int_vals);
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,65 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
#include "util/lp/static_matrix.h"
 | 
			
		||||
#include "util/lp/lar_term.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
struct iterator_on_column:linear_combination_iterator<T> {
 | 
			
		||||
    const vector<column_cell>& m_column; // the offset in term coeffs
 | 
			
		||||
    const static_matrix<T, X> & m_A;
 | 
			
		||||
    int m_i; // the initial offset in the column
 | 
			
		||||
    unsigned size() const override { return m_column.size(); }
 | 
			
		||||
    iterator_on_column(const vector<column_cell>& column, const static_matrix<T,X> & A) // the offset in term coeffs
 | 
			
		||||
        :
 | 
			
		||||
        m_column(column),
 | 
			
		||||
        m_A(A),
 | 
			
		||||
        m_i(-1) {}
 | 
			
		||||
    
 | 
			
		||||
    bool next(mpq & a, unsigned & i) override {
 | 
			
		||||
        if (++m_i >= static_cast<int>(m_column.size()))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        const column_cell& c = m_column[m_i];
 | 
			
		||||
        a = m_A.get_val(c);
 | 
			
		||||
        i = c.m_i;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool next(unsigned & i) override {
 | 
			
		||||
        if (++m_i >= static_cast<int>(m_column.size()))
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        const column_cell& c = m_column[m_i];
 | 
			
		||||
        i = c.m_i;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void reset() override {
 | 
			
		||||
        m_i = -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    linear_combination_iterator<mpq> * clone() override {
 | 
			
		||||
        iterator_on_column * r = new iterator_on_column(m_column, m_A);
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,53 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct iterator_on_indexed_vector:linear_combination_iterator<T> {
 | 
			
		||||
    const indexed_vector<T> & m_v;
 | 
			
		||||
    unsigned m_offset;
 | 
			
		||||
    iterator_on_indexed_vector(const indexed_vector<T> & v) :
 | 
			
		||||
        m_v(v),
 | 
			
		||||
        m_offset(0)
 | 
			
		||||
    {}
 | 
			
		||||
    unsigned size() const override { return m_v.m_index.size(); }
 | 
			
		||||
    bool next(T & a, unsigned & i) override {
 | 
			
		||||
        if (m_offset >= m_v.m_index.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        i = m_v.m_index[m_offset++];
 | 
			
		||||
        a = m_v.m_data[i];
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bool next(unsigned & i) override {
 | 
			
		||||
        if (m_offset >= m_v.m_index.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        i = m_v.m_index[m_offset++];
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    void reset() override {
 | 
			
		||||
        m_offset = 0;
 | 
			
		||||
    }
 | 
			
		||||
    linear_combination_iterator<T>* clone() override {
 | 
			
		||||
        return new iterator_on_indexed_vector(m_v);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,59 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/iterator_on_indexed_vector.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct iterator_on_pivot_row:linear_combination_iterator<T> {
 | 
			
		||||
    bool m_basis_returned;
 | 
			
		||||
    const indexed_vector<T> & m_v;
 | 
			
		||||
    unsigned m_basis_j;
 | 
			
		||||
    iterator_on_indexed_vector<T> m_it;
 | 
			
		||||
    unsigned size() const override { return m_it.size(); }
 | 
			
		||||
    iterator_on_pivot_row(const indexed_vector<T> & v, unsigned basis_j) :
 | 
			
		||||
        m_basis_returned(false),
 | 
			
		||||
        m_v(v), m_basis_j(basis_j), m_it(v) {}
 | 
			
		||||
    bool next(T & a, unsigned & i) override {
 | 
			
		||||
        if (m_basis_returned == false) {
 | 
			
		||||
            m_basis_returned = true;
 | 
			
		||||
            a = one_of_type<T>();
 | 
			
		||||
            i = m_basis_j;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return m_it.next(a, i);
 | 
			
		||||
    }
 | 
			
		||||
    bool next(unsigned & i) override {
 | 
			
		||||
        if (m_basis_returned == false) {
 | 
			
		||||
            m_basis_returned = true;
 | 
			
		||||
            i = m_basis_j;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        return m_it.next(i);
 | 
			
		||||
    }
 | 
			
		||||
    void reset() override {
 | 
			
		||||
        m_basis_returned = false;
 | 
			
		||||
        m_it.reset();
 | 
			
		||||
    }
 | 
			
		||||
    linear_combination_iterator<T> * clone() override {
 | 
			
		||||
        iterator_on_pivot_row * r = new iterator_on_pivot_row(m_v, m_basis_j);
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,52 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct iterator_on_row:linear_combination_iterator<T> {
 | 
			
		||||
    const vector<row_cell<T>> & m_row;
 | 
			
		||||
    unsigned m_i; // offset
 | 
			
		||||
    iterator_on_row(const vector<row_cell<T>> & row) : m_row(row), m_i(0)
 | 
			
		||||
    {}
 | 
			
		||||
    unsigned size() const override { return m_row.size(); }
 | 
			
		||||
    bool next(T & a, unsigned & i) override {
 | 
			
		||||
        if (m_i == m_row.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        auto &c = m_row[m_i++];
 | 
			
		||||
        i = c.m_j;
 | 
			
		||||
        a = c.get_val();
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    bool next(unsigned & i) override {
 | 
			
		||||
        if (m_i == m_row.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        auto &c = m_row[m_i++];
 | 
			
		||||
        i = c.m_j;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    void reset() override {
 | 
			
		||||
        m_i = 0;
 | 
			
		||||
    }
 | 
			
		||||
    linear_combination_iterator<T>* clone() override {
 | 
			
		||||
        return new iterator_on_row(m_row);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,72 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/linear_combination_iterator.h"
 | 
			
		||||
#include "util/lp/numeric_pair.h"
 | 
			
		||||
#include "util/lp/lar_term.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
struct iterator_on_term_with_basis_var:linear_combination_iterator<mpq> {
 | 
			
		||||
    const lar_term & m_term;
 | 
			
		||||
    std::unordered_map<unsigned, mpq>::const_iterator m_i; // the offset in term coeffs
 | 
			
		||||
    bool             m_term_j_returned;
 | 
			
		||||
    unsigned         m_term_j;
 | 
			
		||||
    unsigned size() const override {return static_cast<unsigned>(m_term.m_coeffs.size() + 1);}
 | 
			
		||||
    iterator_on_term_with_basis_var(const lar_term & t, unsigned term_j) :
 | 
			
		||||
        m_term(t),
 | 
			
		||||
        m_i(t.m_coeffs.begin()),
 | 
			
		||||
        m_term_j_returned(false),
 | 
			
		||||
        m_term_j(term_j) {}
 | 
			
		||||
 | 
			
		||||
    bool next(mpq & a, unsigned & i) override {
 | 
			
		||||
        if (m_term_j_returned == false) {
 | 
			
		||||
            m_term_j_returned = true;
 | 
			
		||||
            a = - one_of_type<mpq>();
 | 
			
		||||
            i = m_term_j;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_i == m_term.m_coeffs.end())
 | 
			
		||||
            return false;
 | 
			
		||||
        i = m_i->first;
 | 
			
		||||
        a = m_i->second;
 | 
			
		||||
        m_i++;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    bool next(unsigned & i) override {
 | 
			
		||||
        if (m_term_j_returned == false) {
 | 
			
		||||
            m_term_j_returned = true;
 | 
			
		||||
            i = m_term_j;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        if (m_i == m_term.m_coeffs.end())
 | 
			
		||||
            return false;
 | 
			
		||||
        i = m_i->first;
 | 
			
		||||
        m_i++;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    void reset() override {
 | 
			
		||||
        m_term_j_returned = false;
 | 
			
		||||
        m_i = m_term.m_coeffs.begin();
 | 
			
		||||
    }
 | 
			
		||||
    linear_combination_iterator<mpq> * clone() override {
 | 
			
		||||
        iterator_on_term_with_basis_var * r = new iterator_on_term_with_basis_var(m_term, m_term_j);
 | 
			
		||||
        return r;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -40,12 +40,11 @@ inline std::string lconstraint_kind_string(lconstraint_kind t) {
 | 
			
		|||
    case GT: return std::string(">");
 | 
			
		||||
    case EQ: return std::string("=");
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return std::string(); // it is unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class lar_base_constraint {
 | 
			
		||||
public:
 | 
			
		||||
struct lar_base_constraint {
 | 
			
		||||
    lconstraint_kind m_kind;
 | 
			
		||||
    mpq m_right_side;
 | 
			
		||||
    virtual vector<std::pair<mpq, var_index>> get_left_side_coefficients() const = 0;
 | 
			
		||||
| 
						 | 
				
			
			@ -88,7 +87,7 @@ public:
 | 
			
		|||
        :  lar_base_constraint(kind, right_side), m_coeffs(left_side) {}
 | 
			
		||||
    
 | 
			
		||||
    lar_constraint(const lar_base_constraint & c) {
 | 
			
		||||
        SASSERT(false); // should not be called : todo!
 | 
			
		||||
        lp_assert(false); // should not be called : todo!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    unsigned size() const override {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,4 +22,4 @@ Revision History:
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lar_core_solver.hpp"
 | 
			
		||||
#include "util/lp/lar_core_solver_def.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -26,12 +26,9 @@ Revision History:
 | 
			
		|||
#include "util/lp/indexed_vector.h"
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.h"
 | 
			
		||||
#include "util/lp/breakpoint.h"
 | 
			
		||||
#include "util/lp/stacked_unordered_set.h"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver.h"
 | 
			
		||||
#include "util/lp/stacked_vector.h"
 | 
			
		||||
#include "util/lp/lar_solution_signature.h"
 | 
			
		||||
#include "util/lp/iterator_on_column.h"
 | 
			
		||||
#include "util/lp/iterator_on_indexed_vector.h"
 | 
			
		||||
#include "util/lp/stacked_value.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -50,7 +47,7 @@ public:
 | 
			
		|||
    stacked_vector<column_type> m_column_types;
 | 
			
		||||
    // r - solver fields, for rational numbers
 | 
			
		||||
    vector<numeric_pair<mpq>> m_r_x; // the solution
 | 
			
		||||
    stacked_vector<numeric_pair<mpq>> m_r_low_bounds;
 | 
			
		||||
    stacked_vector<numeric_pair<mpq>> m_r_lower_bounds;
 | 
			
		||||
    stacked_vector<numeric_pair<mpq>> m_r_upper_bounds;
 | 
			
		||||
    static_matrix<mpq, numeric_pair<mpq>> m_r_A;
 | 
			
		||||
    stacked_vector<unsigned> m_r_pushed_basis;
 | 
			
		||||
| 
						 | 
				
			
			@ -62,7 +59,7 @@ public:
 | 
			
		|||
    
 | 
			
		||||
    // d - solver fields, for doubles
 | 
			
		||||
    vector<double> m_d_x; // the solution in doubles
 | 
			
		||||
    vector<double> m_d_low_bounds;
 | 
			
		||||
    vector<double> m_d_lower_bounds;
 | 
			
		||||
    vector<double> m_d_upper_bounds;
 | 
			
		||||
    static_matrix<double, double> m_d_A;
 | 
			
		||||
    stacked_vector<unsigned> m_d_pushed_basis;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,11 +152,11 @@ public:
 | 
			
		|||
 | 
			
		||||
    void fill_evidence(unsigned row);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	unsigned get_number_of_non_ints() const;
 | 
			
		||||
 | 
			
		||||
    void solve();
 | 
			
		||||
 | 
			
		||||
    bool low_bounds_are_set() const { return true; }
 | 
			
		||||
    bool lower_bounds_are_set() const { return true; }
 | 
			
		||||
 | 
			
		||||
    const indexed_vector<mpq> & get_pivot_row() const {
 | 
			
		||||
        return m_r_solver.m_pivot_row;
 | 
			
		||||
| 
						 | 
				
			
			@ -183,16 +180,16 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void push() {
 | 
			
		||||
        SASSERT(m_r_solver.basis_heading_is_correct());
 | 
			
		||||
        SASSERT(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct());
 | 
			
		||||
        SASSERT(m_column_types.size() == m_r_A.column_count());
 | 
			
		||||
        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();
 | 
			
		||||
        m_column_types.push();
 | 
			
		||||
        // rational
 | 
			
		||||
        if (!settings().use_tableau()) 
 | 
			
		||||
            m_r_A.push();
 | 
			
		||||
        m_r_low_bounds.push();
 | 
			
		||||
        m_r_lower_bounds.push();
 | 
			
		||||
        m_r_upper_bounds.push();
 | 
			
		||||
        if (!settings().use_tableau()) {
 | 
			
		||||
            push_vector(m_r_pushed_basis, m_r_basis);
 | 
			
		||||
| 
						 | 
				
			
			@ -207,7 +204,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    template <typename K> 
 | 
			
		||||
    void push_vector(stacked_vector<K> & pushed_vector, const vector<K> & vector) {
 | 
			
		||||
        SASSERT(pushed_vector.size() <= vector.size());
 | 
			
		||||
        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]);
 | 
			
		||||
| 
						 | 
				
			
			@ -234,7 +231,7 @@ public:
 | 
			
		|||
        // rationals
 | 
			
		||||
        if (!settings().use_tableau()) 
 | 
			
		||||
            m_r_A.pop(k);
 | 
			
		||||
        m_r_low_bounds.pop(k);
 | 
			
		||||
        m_r_lower_bounds.pop(k);
 | 
			
		||||
        m_r_upper_bounds.pop(k);
 | 
			
		||||
        m_column_types.pop(k);
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -257,8 +254,8 @@ public:
 | 
			
		|||
        pop_basis(k);
 | 
			
		||||
        m_stacked_simplex_strategy.pop(k);
 | 
			
		||||
        settings().simplex_strategy() = m_stacked_simplex_strategy;
 | 
			
		||||
        SASSERT(m_r_solver.basis_heading_is_correct());
 | 
			
		||||
        SASSERT(!need_to_presolve_with_double_solver() || m_d_solver.basis_heading_is_correct());
 | 
			
		||||
        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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -276,11 +273,11 @@ public:
 | 
			
		|||
    bool update_xj_and_get_delta(unsigned j, non_basic_column_value_position pos_type, numeric_pair<mpq> & delta) {
 | 
			
		||||
        auto & x = m_r_x[j];
 | 
			
		||||
        switch (pos_type) {
 | 
			
		||||
        case at_low_bound:
 | 
			
		||||
            if (x == m_r_solver.m_low_bounds[j])
 | 
			
		||||
        case at_lower_bound:
 | 
			
		||||
            if (x == m_r_solver.m_lower_bounds[j])
 | 
			
		||||
                return false;
 | 
			
		||||
            delta = m_r_solver.m_low_bounds[j] - x;
 | 
			
		||||
            m_r_solver.m_x[j] = m_r_solver.m_low_bounds[j];
 | 
			
		||||
            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:
 | 
			
		||||
| 
						 | 
				
			
			@ -300,30 +297,30 @@ public:
 | 
			
		|||
                delta = m_r_solver.m_upper_bounds[j] - x;
 | 
			
		||||
                x = m_r_solver.m_upper_bounds[j];
 | 
			
		||||
                break;
 | 
			
		||||
            case column_type::low_bound:
 | 
			
		||||
                delta = m_r_solver.m_low_bounds[j] - x;
 | 
			
		||||
                x = m_r_solver.m_low_bounds[j];
 | 
			
		||||
            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_low_bounds[j] - x;
 | 
			
		||||
                    x = m_r_solver.m_low_bounds[j];
 | 
			
		||||
                    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_low_bounds[j] - x;
 | 
			
		||||
                x = m_r_solver.m_low_bounds[j];
 | 
			
		||||
                delta = m_r_solver.m_lower_bounds[j] - x;
 | 
			
		||||
                x = m_r_solver.m_lower_bounds[j];
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                SASSERT(false);
 | 
			
		||||
                lp_assert(false);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_unreachable();
 | 
			
		||||
        }
 | 
			
		||||
        m_r_solver.remove_column_from_inf_set(j);
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -332,7 +329,7 @@ public:
 | 
			
		|||
    
 | 
			
		||||
    
 | 
			
		||||
    void prepare_solver_x_with_signature_tableau(const lar_solution_signature & signature) {
 | 
			
		||||
        SASSERT(m_r_solver.inf_set_is_correct());
 | 
			
		||||
        lp_assert(m_r_solver.inf_set_is_correct());
 | 
			
		||||
        for (auto &t : signature) {
 | 
			
		||||
            unsigned j = t.first;
 | 
			
		||||
            if (m_r_heading[j] >= 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -344,12 +341,11 @@ public:
 | 
			
		|||
            for (const auto & cc : m_r_solver.m_A.m_columns[j]){
 | 
			
		||||
                unsigned i = cc.m_i;
 | 
			
		||||
                unsigned jb = m_r_solver.m_basis[i];
 | 
			
		||||
                m_r_solver.m_x[jb] -= delta * m_r_solver.m_A.get_val(cc);
 | 
			
		||||
                m_r_solver.update_column_in_inf_set(jb);
 | 
			
		||||
                m_r_solver.update_x_with_delta_and_track_feasibility(jb, - delta * m_r_solver.m_A.get_val(cc));
 | 
			
		||||
            }
 | 
			
		||||
            SASSERT(m_r_solver.A_mult_x_is_off() == false);
 | 
			
		||||
            CASSERT("A_off", m_r_solver.A_mult_x_is_off() == false);
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(m_r_solver.inf_set_is_correct());
 | 
			
		||||
        lp_assert(m_r_solver.inf_set_is_correct());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -357,11 +353,11 @@ public:
 | 
			
		|||
    void prepare_solver_x_with_signature(const lar_solution_signature & signature, lp_primal_core_solver<L,K> & s) {
 | 
			
		||||
        for (auto &t : signature) {
 | 
			
		||||
            unsigned j = t.first;
 | 
			
		||||
            SASSERT(m_r_heading[j] < 0);
 | 
			
		||||
            lp_assert(m_r_heading[j] < 0);
 | 
			
		||||
            auto pos_type = t.second;
 | 
			
		||||
            switch (pos_type) {
 | 
			
		||||
            case at_low_bound:
 | 
			
		||||
                s.m_x[j] = s.m_low_bounds[j];
 | 
			
		||||
            case at_lower_bound:
 | 
			
		||||
                s.m_x[j] = s.m_lower_bounds[j];
 | 
			
		||||
                break;
 | 
			
		||||
            case at_fixed:
 | 
			
		||||
            case at_upper_bound:
 | 
			
		||||
| 
						 | 
				
			
			@ -374,33 +370,33 @@ public:
 | 
			
		|||
            case not_at_bound:
 | 
			
		||||
                  switch (m_column_types[j]) {
 | 
			
		||||
                  case column_type::free_column:
 | 
			
		||||
                      SASSERT(false); // unreachable
 | 
			
		||||
                      lp_assert(false); // unreachable
 | 
			
		||||
                  case column_type::upper_bound:
 | 
			
		||||
                      s.m_x[j] = s.m_upper_bounds[j];
 | 
			
		||||
                      break;
 | 
			
		||||
                  case column_type::low_bound:
 | 
			
		||||
                      s.m_x[j] = s.m_low_bounds[j];
 | 
			
		||||
                  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_low_bounds[j];
 | 
			
		||||
                          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_low_bounds[j];
 | 
			
		||||
                      s.m_x[j] = s.m_lower_bounds[j];
 | 
			
		||||
                      break;
 | 
			
		||||
                  default:
 | 
			
		||||
                      SASSERT(false);
 | 
			
		||||
                      lp_assert(false);
 | 
			
		||||
                  }
 | 
			
		||||
                  break;
 | 
			
		||||
            default:
 | 
			
		||||
                SASSERT(false);
 | 
			
		||||
                lp_unreachable();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SASSERT(is_zero_vector(s.m_b));
 | 
			
		||||
        lp_assert(is_zero_vector(s.m_b));
 | 
			
		||||
        s.solve_Ax_eq_b();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -433,7 +429,7 @@ public:
 | 
			
		|||
            // the queues of delayed indices
 | 
			
		||||
            std::queue<unsigned> entr_q, leav_q;
 | 
			
		||||
            auto * l = cs.m_factorization;
 | 
			
		||||
            SASSERT(l->get_status() == LU_status::OK);
 | 
			
		||||
            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];
 | 
			
		||||
| 
						 | 
				
			
			@ -461,8 +457,8 @@ public:
 | 
			
		|||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                SASSERT(cs.m_basis_heading[entering] < 0);
 | 
			
		||||
                SASSERT(cs.m_basis_heading[leaving] >= 0);
 | 
			
		||||
                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<L>(), w, cs.m_basis_heading[leaving]);
 | 
			
		||||
| 
						 | 
				
			
			@ -486,7 +482,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void solve_on_signature_tableau(const lar_solution_signature & signature, const vector<unsigned> & changes_of_basis) {
 | 
			
		||||
        r_basis_is_OK();
 | 
			
		||||
        SASSERT(settings().use_tableau());
 | 
			
		||||
        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
 | 
			
		||||
| 
						 | 
				
			
			@ -505,10 +501,10 @@ public:
 | 
			
		|||
                return;
 | 
			
		||||
            m_r_solver.stop_tracing_basis_changes();
 | 
			
		||||
            // and now catch up in the double solver
 | 
			
		||||
            SASSERT(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2);
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(r_basis_is_OK());
 | 
			
		||||
        lp_assert(r_basis_is_OK());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool adjust_x_of_column(unsigned j) {
 | 
			
		||||
| 
						 | 
				
			
			@ -522,16 +518,16 @@ public:
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        m_r_solver.snap_column_to_bound_tableau(j);
 | 
			
		||||
        SASSERT(m_r_solver.column_is_feasible(j));
 | 
			
		||||
        lp_assert(m_r_solver.column_is_feasible(j));
 | 
			
		||||
        m_r_solver.m_inf_set.erase(j);
 | 
			
		||||
        */
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    bool catch_up_in_lu_tableau(const vector<unsigned> & trace_of_basis_change, const vector<int> & basis_heading) {
 | 
			
		||||
        SASSERT(r_basis_is_OK());
 | 
			
		||||
        lp_assert(r_basis_is_OK());
 | 
			
		||||
        // the queues of delayed indices
 | 
			
		||||
        std::queue<unsigned> entr_q, leav_q;
 | 
			
		||||
        for (unsigned i = 0; i < trace_of_basis_change.size(); i+= 2) {
 | 
			
		||||
| 
						 | 
				
			
			@ -561,8 +557,8 @@ public:
 | 
			
		|||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            SASSERT(m_r_solver.m_basis_heading[entering] < 0);
 | 
			
		||||
            SASSERT(m_r_solver.m_basis_heading[leaving] >= 0);
 | 
			
		||||
            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
 | 
			
		||||
| 
						 | 
				
			
			@ -572,12 +568,12 @@ public:
 | 
			
		|||
#endif
 | 
			
		||||
                    m_r_solver.pivot_column_tableau(leaving, m_r_solver.m_basis_heading[leaving]);
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
                SASSERT(t);
 | 
			
		||||
                lp_assert(t);
 | 
			
		||||
#endif 
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(r_basis_is_OK());
 | 
			
		||||
        lp_assert(r_basis_is_OK());
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -587,14 +583,14 @@ public:
 | 
			
		|||
        if (!m_r_solver.m_settings.use_tableau())
 | 
			
		||||
            return true;
 | 
			
		||||
        for (unsigned j : m_r_solver.m_basis) {
 | 
			
		||||
            SASSERT(m_r_solver.m_A.m_columns[j].size() == 1);
 | 
			
		||||
            SASSERT(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type<mpq>());
 | 
			
		||||
            lp_assert(m_r_solver.m_A.m_columns[j].size() == 1);
 | 
			
		||||
            lp_assert(m_r_solver.m_A.get_val(m_r_solver.m_A.m_columns[j][0]) == one_of_type<mpq>());
 | 
			
		||||
        }
 | 
			
		||||
        for (unsigned j =0; j < m_r_solver.m_basis_heading.size(); j++) {
 | 
			
		||||
            if (m_r_solver.m_basis_heading[j] >= 0) continue;
 | 
			
		||||
            if (m_r_solver.m_column_types[j] == column_type::fixed) continue;
 | 
			
		||||
            SASSERT(static_cast<unsigned>(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size());
 | 
			
		||||
            SASSERT( m_r_solver.m_basis_heading[j] <= -1);
 | 
			
		||||
            lp_assert(static_cast<unsigned>(- m_r_solver.m_basis_heading[j] - 1) < m_r_solver.m_column_types.size());
 | 
			
		||||
            lp_assert( m_r_solver.m_basis_heading[j] <= -1);
 | 
			
		||||
        }
 | 
			
		||||
#endif
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -614,7 +610,6 @@ public:
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        if (no_r_lu()) { // it is the case where m_d_solver gives a degenerated basis, we need to roll back
 | 
			
		||||
            //            std::cout << "no_r_lu" << std::endl;
 | 
			
		||||
            catch_up_in_lu_in_reverse(changes_of_basis, m_r_solver);
 | 
			
		||||
            m_r_solver.find_feasible_solution();
 | 
			
		||||
            m_d_basis = m_r_basis;
 | 
			
		||||
| 
						 | 
				
			
			@ -630,7 +625,7 @@ public:
 | 
			
		|||
                return;
 | 
			
		||||
            m_r_solver.stop_tracing_basis_changes();
 | 
			
		||||
            // and now catch up in the double solver
 | 
			
		||||
            SASSERT(m_r_solver.total_iterations() >= m_r_solver.m_trace_of_basis_change_vector.size() /2);
 | 
			
		||||
            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);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -656,7 +651,7 @@ public:
 | 
			
		|||
    template <typename L, typename K>
 | 
			
		||||
    void extract_signature_from_lp_core_solver(const lp_primal_core_solver<L, K> & solver, lar_solution_signature & signature) {
 | 
			
		||||
        signature.clear();
 | 
			
		||||
        SASSERT(signature.size() == 0);
 | 
			
		||||
        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);
 | 
			
		||||
| 
						 | 
				
			
			@ -666,27 +661,27 @@ public:
 | 
			
		|||
 | 
			
		||||
    void get_bounds_for_double_solver() {
 | 
			
		||||
        unsigned n = m_n();
 | 
			
		||||
        m_d_low_bounds.resize(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 (low_bound_is_set(j)) {
 | 
			
		||||
                const auto & lb = m_r_solver.m_low_bounds[j];
 | 
			
		||||
                m_d_low_bounds[j] = lb.x.get_double() + delta * lb.y.get_double();
 | 
			
		||||
            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();
 | 
			
		||||
                SASSERT(!low_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_low_bounds[j]));
 | 
			
		||||
                lp_assert(!lower_bound_is_set(j) || (m_d_upper_bounds[j] >= m_d_lower_bounds[j]));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void scale_problem_for_doubles(
 | 
			
		||||
                        static_matrix<double, double>& A,        
 | 
			
		||||
                        vector<double> & low_bounds,
 | 
			
		||||
                        vector<double> & lower_bounds,
 | 
			
		||||
                        vector<double> & upper_bounds) {
 | 
			
		||||
        vector<double> column_scale_vector;
 | 
			
		||||
        vector<double> right_side_vector(A.column_count());
 | 
			
		||||
| 
						 | 
				
			
			@ -706,8 +701,8 @@ public:
 | 
			
		|||
                if (m_r_solver.column_has_upper_bound(j)) {
 | 
			
		||||
                    upper_bounds[j] /= column_scale_vector[j];
 | 
			
		||||
                }
 | 
			
		||||
                if (m_r_solver.column_has_low_bound(j)) {
 | 
			
		||||
                    low_bounds[j] /= column_scale_vector[j];
 | 
			
		||||
                if (m_r_solver.column_has_lower_bound(j)) {
 | 
			
		||||
                    lower_bounds[j] /= column_scale_vector[j];
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -734,17 +729,17 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    bool low_bound_is_set(unsigned j) const {
 | 
			
		||||
    bool lower_bound_is_set(unsigned j) const {
 | 
			
		||||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            return false;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -752,27 +747,27 @@ public:
 | 
			
		|||
    bool upper_bound_is_set(unsigned j) const {
 | 
			
		||||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            return false;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void update_delta(mpq& delta, numeric_pair<mpq> const& l, numeric_pair<mpq> const& u) const {
 | 
			
		||||
        SASSERT(l <= u);
 | 
			
		||||
        lp_assert(l <= u);
 | 
			
		||||
        if (l.x < u.x && l.y > u.y) {
 | 
			
		||||
            mpq delta1 = (u.x - l.x) / (l.y - u.y);
 | 
			
		||||
            if (delta1 < delta) {
 | 
			
		||||
                delta = delta1;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(l.x + delta * l.y <= u.x + delta * u.y);
 | 
			
		||||
        lp_assert(l.x + delta * l.y <= u.x + delta * u.y);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -781,8 +776,7 @@ public:
 | 
			
		|||
        for (unsigned j = 0; j < m_r_A.column_count(); j++ ) {
 | 
			
		||||
            if (m_column_types()[j] != column_type::boxed)
 | 
			
		||||
                continue;
 | 
			
		||||
            update_delta(delta, m_r_low_bounds[j], m_r_upper_bounds[j]);
 | 
			
		||||
 | 
			
		||||
            update_delta(delta, m_r_lower_bounds[j], m_r_upper_bounds[j]);
 | 
			
		||||
        }
 | 
			
		||||
        return delta;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -791,8 +785,8 @@ public:
 | 
			
		|||
    mpq find_delta_for_strict_bounds(const mpq & initial_delta) const{
 | 
			
		||||
        mpq delta = initial_delta;
 | 
			
		||||
        for (unsigned j = 0; j < m_r_A.column_count(); j++ ) {
 | 
			
		||||
            if (low_bound_is_set(j))
 | 
			
		||||
                update_delta(delta, m_r_low_bounds[j], m_r_x[j]);
 | 
			
		||||
            if (lower_bound_is_set(j))
 | 
			
		||||
                update_delta(delta, m_r_lower_bounds[j], m_r_x[j]);
 | 
			
		||||
            if (upper_bound_is_set(j))
 | 
			
		||||
                update_delta(delta, m_r_x[j], m_r_upper_bounds[j]);
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -803,14 +797,38 @@ public:
 | 
			
		|||
        m_r_solver.init_column_row_non_zeroes();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    linear_combination_iterator<mpq> * get_column_iterator(unsigned j) {
 | 
			
		||||
        if (settings().use_tableau()) {
 | 
			
		||||
            return new iterator_on_column<mpq, numeric_pair<mpq>>(m_r_solver.m_A.m_columns[j], m_r_solver.m_A);
 | 
			
		||||
        } else {
 | 
			
		||||
            m_r_solver.solve_Bd(j);
 | 
			
		||||
            return new iterator_on_indexed_vector<mpq>(m_r_solver.m_ed);
 | 
			
		||||
    bool column_is_fixed(unsigned j) const {
 | 
			
		||||
        return m_column_types()[j] == column_type::fixed ||
 | 
			
		||||
            ( m_column_types()[j] == column_type::boxed &&
 | 
			
		||||
              m_r_solver.m_lower_bounds[j] == m_r_solver.m_upper_bounds[j]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const impq & lower_bound(unsigned j) const {
 | 
			
		||||
        lp_assert(m_column_types()[j] == column_type::fixed ||
 | 
			
		||||
                    m_column_types()[j] == column_type::boxed ||
 | 
			
		||||
                    m_column_types()[j] == column_type::lower_bound);
 | 
			
		||||
        return m_r_lower_bounds[j];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const impq & upper_bound(unsigned j) const {
 | 
			
		||||
        lp_assert(m_column_types()[j] == column_type::fixed ||
 | 
			
		||||
                    m_column_types()[j] == column_type::boxed ||
 | 
			
		||||
                    m_column_types()[j] == column_type::upper_bound);
 | 
			
		||||
        return m_r_upper_bounds[j];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
    const bool column_is_bounded(unsigned j) const {
 | 
			
		||||
        switch(m_column_types()[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            return true;
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    const vector<unsigned>& r_basis() const { return m_r_basis; }
 | 
			
		||||
    const vector<unsigned>& r_nbasis() const { return m_r_nbasis; }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -54,7 +54,7 @@ lar_core_solver::lar_core_solver(
 | 
			
		|||
                    m_r_heading,
 | 
			
		||||
                    m_costs_dummy,
 | 
			
		||||
                    m_column_types(),
 | 
			
		||||
                    m_r_low_bounds(),
 | 
			
		||||
                    m_r_lower_bounds(),
 | 
			
		||||
                    m_r_upper_bounds(),
 | 
			
		||||
                    settings,
 | 
			
		||||
               column_names),
 | 
			
		||||
| 
						 | 
				
			
			@ -66,15 +66,15 @@ lar_core_solver::lar_core_solver(
 | 
			
		|||
                    m_d_heading,
 | 
			
		||||
                    m_d_costs_dummy,
 | 
			
		||||
                    m_column_types(),
 | 
			
		||||
                    m_d_low_bounds,
 | 
			
		||||
                    m_d_lower_bounds,
 | 
			
		||||
                    m_d_upper_bounds,
 | 
			
		||||
                    settings,
 | 
			
		||||
                    column_names){}
 | 
			
		||||
 | 
			
		||||
void lar_core_solver::init_costs(bool first_time) {
 | 
			
		||||
    SASSERT(false); // should not be called
 | 
			
		||||
    // SASSERT(this->m_x.size() >= this->m_n());
 | 
			
		||||
    // SASSERT(this->m_column_types.size() >= this->m_n());
 | 
			
		||||
    lp_assert(false); // should not be called
 | 
			
		||||
    // lp_assert(this->m_x.size() >= this->m_n());
 | 
			
		||||
    // lp_assert(this->m_column_types.size() >= this->m_n());
 | 
			
		||||
    // if (first_time)
 | 
			
		||||
    //     this->m_costs.resize(this->m_n());
 | 
			
		||||
    // X inf = this->m_infeasibility;
 | 
			
		||||
| 
						 | 
				
			
			@ -84,7 +84,7 @@ void lar_core_solver::init_costs(bool first_time) {
 | 
			
		|||
    // if (!(first_time || inf >= this->m_infeasibility)) {
 | 
			
		||||
    //     LP_OUT(this->m_settings, "iter = " << this->total_iterations() << std::endl);
 | 
			
		||||
    //     LP_OUT(this->m_settings, "inf was " << T_to_string(inf) << " and now " << T_to_string(this->m_infeasibility) << std::endl);
 | 
			
		||||
    //     SASSERT(false);
 | 
			
		||||
    //     lp_assert(false);
 | 
			
		||||
    // }
 | 
			
		||||
    // if (inf == this->m_infeasibility)
 | 
			
		||||
    //     this->m_iters_with_no_cost_growing++;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,17 +108,17 @@ void lar_core_solver::init_cost_for_column(unsigned j) {
 | 
			
		|||
        if (x > this->m_upper_bounds[j]) {
 | 
			
		||||
            this->m_costs[j] = 1;
 | 
			
		||||
            this->m_infeasibility += x - this->m_upper_bounds[j];
 | 
			
		||||
        } else if (x < this->m_low_bounds[j]) {
 | 
			
		||||
            this->m_infeasibility += this->m_low_bounds[j] - x;
 | 
			
		||||
        } else if (x < this->m_lower_bounds[j]) {
 | 
			
		||||
            this->m_infeasibility += this->m_lower_bounds[j] - x;
 | 
			
		||||
            this->m_costs[j] = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
            this->m_costs[j] = numeric_traits<T>::zero();
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case low_bound:
 | 
			
		||||
        if (x < this->m_low_bounds[j]) {
 | 
			
		||||
    case lower_bound:
 | 
			
		||||
        if (x < this->m_lower_bounds[j]) {
 | 
			
		||||
            this->m_costs[j] = -1;
 | 
			
		||||
            this->m_infeasibility += this->m_low_bounds[j] - x;
 | 
			
		||||
            this->m_infeasibility += this->m_lower_bounds[j] - x;
 | 
			
		||||
        } else {
 | 
			
		||||
            this->m_costs[j] = numeric_traits<T>::zero();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +135,7 @@ void lar_core_solver::init_cost_for_column(unsigned j) {
 | 
			
		|||
        this->m_costs[j] = numeric_traits<T>::zero();
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
        }*/
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +154,7 @@ int lar_core_solver::column_is_out_of_bounds(unsigned j) {
 | 
			
		|||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    case low_bound:
 | 
			
		||||
    case lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(j)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -168,30 +168,14 @@ int lar_core_solver::column_is_out_of_bounds(unsigned j) {
 | 
			
		|||
        return 0;
 | 
			
		||||
        break;
 | 
			
		||||
        }*/
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_assert(false);
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void lar_core_solver::calculate_pivot_row(unsigned i) {
 | 
			
		||||
    SASSERT(!m_r_solver.use_tableau());
 | 
			
		||||
    SASSERT(m_r_solver.m_pivot_row.is_OK());
 | 
			
		||||
    m_r_solver.m_pivot_row_of_B_1.clear();
 | 
			
		||||
    m_r_solver.m_pivot_row_of_B_1.resize(m_r_solver.m_m());
 | 
			
		||||
    m_r_solver.m_pivot_row.clear();
 | 
			
		||||
    m_r_solver.m_pivot_row.resize(m_r_solver.m_n());
 | 
			
		||||
    if (m_r_solver.m_settings.use_tableau()) {
 | 
			
		||||
        unsigned basis_j = m_r_solver.m_basis[i];
 | 
			
		||||
        for (auto & c : m_r_solver.m_A.m_rows[i]) {
 | 
			
		||||
            if (c.m_j != basis_j)
 | 
			
		||||
                m_r_solver.m_pivot_row.set_value(c.get_val(), c.m_j);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    m_r_solver.calculate_pivot_row_of_B_1(i);
 | 
			
		||||
    m_r_solver.calculate_pivot_row_when_pivot_row_of_B1_is_ready(i);
 | 
			
		||||
    m_r_solver.calculate_pivot_row(i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -238,7 +222,7 @@ void lar_core_solver::calculate_pivot_row(unsigned i) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
void lar_core_solver::fill_not_improvable_zero_sum_from_inf_row() {
 | 
			
		||||
    SASSERT(m_r_solver.A_mult_x_is_off() == false);
 | 
			
		||||
    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();
 | 
			
		||||
| 
						 | 
				
			
			@ -271,34 +255,44 @@ void lar_core_solver::fill_not_improvable_zero_sum() {
 | 
			
		|||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
unsigned lar_core_solver::get_number_of_non_ints() const {
 | 
			
		||||
	unsigned n = 0;
 | 
			
		||||
	for (auto & x : m_r_solver.m_x) {
 | 
			
		||||
		if (x.is_int() == false)
 | 
			
		||||
			n++;
 | 
			
		||||
	}
 | 
			
		||||
	return n;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void lar_core_solver::solve() {
 | 
			
		||||
    SASSERT(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
    SASSERT(m_r_solver.inf_set_is_correct());
 | 
			
		||||
    if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) {
 | 
			
		||||
        m_r_solver.set_status(OPTIMAL);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
    lp_assert(m_r_solver.inf_set_is_correct());
 | 
			
		||||
	TRACE("find_feas_stats", tout << "infeasibles = " << m_r_solver.m_inf_set.size() << ", int_infs = " << get_number_of_non_ints() << std::endl;);
 | 
			
		||||
	if (m_r_solver.current_x_is_feasible() && m_r_solver.m_look_for_feasible_solution_only) {
 | 
			
		||||
		m_r_solver.set_status(lp_status::OPTIMAL);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
    ++settings().st().m_need_to_solve_inf;
 | 
			
		||||
    SASSERT(!m_r_solver.A_mult_x_is_off());
 | 
			
		||||
    SASSERT((!settings().use_tableau()) || r_basis_is_OK());
 | 
			
		||||
    CASSERT("A_off", !m_r_solver.A_mult_x_is_off());
 | 
			
		||||
    lp_assert((!settings().use_tableau()) || r_basis_is_OK());
 | 
			
		||||
    if (need_to_presolve_with_double_solver()) {
 | 
			
		||||
        prefix_d();
 | 
			
		||||
        lar_solution_signature solution_signature;
 | 
			
		||||
        vector<unsigned> changes_of_basis = find_solution_signature_with_doubles(solution_signature);
 | 
			
		||||
        if (m_d_solver.get_status() == TIME_EXHAUSTED) {
 | 
			
		||||
            m_r_solver.set_status(TIME_EXHAUSTED);
 | 
			
		||||
        if (m_d_solver.get_status() == lp_status::TIME_EXHAUSTED) {
 | 
			
		||||
            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);
 | 
			
		||||
        SASSERT(!settings().use_tableau() || r_basis_is_OK());
 | 
			
		||||
 | 
			
		||||
        lp_assert(!settings().use_tableau() || r_basis_is_OK());
 | 
			
		||||
    } else {
 | 
			
		||||
        if (!settings().use_tableau()) {
 | 
			
		||||
            bool snapped = m_r_solver.snap_non_basic_x_to_bound();   
 | 
			
		||||
            SASSERT(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
            lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
            if (snapped)
 | 
			
		||||
                m_r_solver.solve_Ax_eq_b();
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -306,16 +300,16 @@ void lar_core_solver::solve() {
 | 
			
		|||
            m_r_solver.find_feasible_solution();
 | 
			
		||||
        else
 | 
			
		||||
            m_r_solver.solve();
 | 
			
		||||
        SASSERT(!settings().use_tableau() || r_basis_is_OK());
 | 
			
		||||
        lp_assert(!settings().use_tableau() || r_basis_is_OK());
 | 
			
		||||
    }
 | 
			
		||||
    if (m_r_solver.get_status() == INFEASIBLE) {
 | 
			
		||||
    if (m_r_solver.get_status() == lp_status::INFEASIBLE) {
 | 
			
		||||
        fill_not_improvable_zero_sum();
 | 
			
		||||
    } else if (m_r_solver.get_status() != UNBOUNDED) {
 | 
			
		||||
        m_r_solver.set_status(OPTIMAL);
 | 
			
		||||
    } else if (m_r_solver.get_status() != lp_status::UNBOUNDED) {
 | 
			
		||||
        m_r_solver.set_status(lp_status::OPTIMAL);
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(r_basis_is_OK());
 | 
			
		||||
    SASSERT(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
    SASSERT(m_r_solver.inf_set_is_correct());
 | 
			
		||||
    lp_assert(r_basis_is_OK());
 | 
			
		||||
    lp_assert(m_r_solver.non_basic_columns_are_set_correctly());
 | 
			
		||||
    lp_assert(m_r_solver.inf_set_is_correct());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2286
									
								
								src/util/lp/lar_solver.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										2286
									
								
								src/util/lp/lar_solver.cpp
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										13
									
								
								src/util/lp/lar_solver_instances.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								src/util/lp/lar_solver_instances.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
/*
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
  Author: Lev Nachmanson
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#include "util/lp/lar_solver.cpp"
 | 
			
		||||
 | 
			
		||||
template void  lp::lar_solver::copy_from_mpq_matrix<double,double>(class lp::static_matrix<double,double> &);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1,22 +1,22 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
  Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
  Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
  <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
  Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
  <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
  Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
  Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
  Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
  --*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/indexed_vector.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
| 
						 | 
				
			
			@ -25,7 +25,7 @@ struct lar_term {
 | 
			
		|||
    std::unordered_map<unsigned, mpq> m_coeffs;
 | 
			
		||||
    mpq m_v;
 | 
			
		||||
    lar_term() {}
 | 
			
		||||
    void add_to_map(unsigned j, const mpq& c) {
 | 
			
		||||
    void add_monomial(const mpq& c, unsigned j) {
 | 
			
		||||
        auto it = m_coeffs.find(j);
 | 
			
		||||
        if (it == m_coeffs.end()) {
 | 
			
		||||
            m_coeffs.emplace(j, c);
 | 
			
		||||
| 
						 | 
				
			
			@ -36,6 +36,10 @@ struct lar_term {
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool is_empty() const {
 | 
			
		||||
        return m_coeffs.size() == 0 && is_zero(m_v);
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    unsigned size() const { return static_cast<unsigned>(m_coeffs.size()); }
 | 
			
		||||
    
 | 
			
		||||
    const std::unordered_map<unsigned, mpq> & coeffs() const {
 | 
			
		||||
| 
						 | 
				
			
			@ -45,7 +49,7 @@ struct lar_term {
 | 
			
		|||
    lar_term(const vector<std::pair<mpq, unsigned>>& coeffs,
 | 
			
		||||
             const mpq & v) : m_v(v) {
 | 
			
		||||
        for (const auto & p : coeffs) {
 | 
			
		||||
            add_to_map(p.second, p.first);
 | 
			
		||||
            add_monomial(p.first, p.second);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    bool operator==(const lar_term & a) const {  return false; } // take care not to create identical terms
 | 
			
		||||
| 
						 | 
				
			
			@ -67,7 +71,7 @@ struct lar_term {
 | 
			
		|||
        if (it == m_coeffs.end()) return;
 | 
			
		||||
        const mpq & b = it->second;
 | 
			
		||||
        for (unsigned it_j :li.m_index) {
 | 
			
		||||
            add_to_map(it_j, - b * li.m_data[it_j]);
 | 
			
		||||
            add_monomial(- b * li.m_data[it_j], it_j);
 | 
			
		||||
        }
 | 
			
		||||
        m_coeffs.erase(it);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -75,5 +79,61 @@ struct lar_term {
 | 
			
		|||
    bool contains(unsigned j) const {
 | 
			
		||||
        return m_coeffs.find(j) != m_coeffs.end();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void negate() {
 | 
			
		||||
        for (auto & t : m_coeffs)
 | 
			
		||||
            t.second.neg();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename T>
 | 
			
		||||
    T apply(const vector<T>& x) const {
 | 
			
		||||
        T ret = T(m_v);
 | 
			
		||||
        for (const auto & t : m_coeffs) {
 | 
			
		||||
            ret += t.second * x[t.first];
 | 
			
		||||
        }
 | 
			
		||||
        return ret;
 | 
			
		||||
    }
 | 
			
		||||
   
 | 
			
		||||
    void clear() {
 | 
			
		||||
        m_coeffs.clear();
 | 
			
		||||
        m_v = zero_of_type<mpq>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    struct ival {
 | 
			
		||||
        unsigned m_var;
 | 
			
		||||
        const mpq & m_coeff;
 | 
			
		||||
        ival(unsigned var, const mpq & val) : m_var(var), m_coeff(val) {
 | 
			
		||||
        }
 | 
			
		||||
        unsigned var() const { return m_var;}
 | 
			
		||||
        const mpq & coeff() const { return m_coeff; }
 | 
			
		||||
    };
 | 
			
		||||
    
 | 
			
		||||
    struct const_iterator {
 | 
			
		||||
        //fields
 | 
			
		||||
        std::unordered_map<unsigned, mpq>::const_iterator m_it;
 | 
			
		||||
 | 
			
		||||
        typedef const_iterator self_type;
 | 
			
		||||
        typedef ival value_type;
 | 
			
		||||
        typedef ival reference;
 | 
			
		||||
        //        typedef std::pair<const unsigned, mpq>* pointer;
 | 
			
		||||
        typedef int difference_type;
 | 
			
		||||
        typedef std::forward_iterator_tag iterator_category;
 | 
			
		||||
 | 
			
		||||
        reference operator*() const {
 | 
			
		||||
            return ival(m_it->first, m_it->second);
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        self_type operator++() {  self_type i = *this; m_it++; return i;  }
 | 
			
		||||
        self_type operator++(int) { m_it++; return *this; }
 | 
			
		||||
 | 
			
		||||
        const_iterator(std::unordered_map<unsigned, mpq>::const_iterator it) : m_it(it) {}
 | 
			
		||||
        bool operator==(const self_type &other) const {
 | 
			
		||||
            return m_it == other.m_it;
 | 
			
		||||
        }
 | 
			
		||||
        bool operator!=(const self_type &other) const { return !(*this == other); }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const_iterator begin() const { return m_coeffs.begin();}
 | 
			
		||||
    const_iterator end() const { return m_coeffs.end(); }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										31
									
								
								src/util/lp/lia_move.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/util/lp/lia_move.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,31 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
    Nikolaj Bjorner (nbjorner)
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
namespace lp {
 | 
			
		||||
enum class lia_move {
 | 
			
		||||
    sat,
 | 
			
		||||
    branch,
 | 
			
		||||
    cut,
 | 
			
		||||
    conflict,
 | 
			
		||||
    continue_with_check,
 | 
			
		||||
    undef,
 | 
			
		||||
    unsat
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,65 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct linear_combination_iterator {
 | 
			
		||||
    virtual bool next(T & a, unsigned & i) = 0;
 | 
			
		||||
    virtual bool next(unsigned & i) = 0;
 | 
			
		||||
    virtual void reset() = 0;
 | 
			
		||||
    virtual linear_combination_iterator * clone() = 0;
 | 
			
		||||
    virtual ~linear_combination_iterator(){}
 | 
			
		||||
    virtual unsigned size() const = 0;
 | 
			
		||||
};
 | 
			
		||||
template <typename T>
 | 
			
		||||
struct linear_combination_iterator_on_vector : linear_combination_iterator<T> {
 | 
			
		||||
    vector<std::pair<T, unsigned>> & m_vector;
 | 
			
		||||
    int m_offset;
 | 
			
		||||
    bool next(T & a, unsigned & i) {
 | 
			
		||||
        if(m_offset >= m_vector.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        auto & p = m_vector[m_offset];
 | 
			
		||||
        a = p.first;
 | 
			
		||||
        i = p.second;
 | 
			
		||||
        m_offset++;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool next(unsigned & i) {
 | 
			
		||||
        if(m_offset >= m_vector.size())
 | 
			
		||||
            return false;
 | 
			
		||||
        auto & p = m_vector[m_offset];
 | 
			
		||||
        i = p.second;
 | 
			
		||||
        m_offset++;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void reset() {m_offset = 0;}
 | 
			
		||||
    linear_combination_iterator<T> * clone() {
 | 
			
		||||
        return new linear_combination_iterator_on_vector(m_vector);
 | 
			
		||||
    }
 | 
			
		||||
    linear_combination_iterator_on_vector(vector<std::pair<T, unsigned>> & vec):
 | 
			
		||||
        m_vector(vec),
 | 
			
		||||
        m_offset(0)
 | 
			
		||||
    {}
 | 
			
		||||
    unsigned size() const { return m_vector.size(); }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,67 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/lar_solver.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
    lp_bound_propagator::lp_bound_propagator(lar_solver & ls):
 | 
			
		||||
    m_lar_solver(ls) {}
 | 
			
		||||
column_type lp_bound_propagator::get_column_type(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_column_types()[j];
 | 
			
		||||
}
 | 
			
		||||
const impq & lp_bound_propagator::get_low_bound(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_r_low_bounds()[j];
 | 
			
		||||
}
 | 
			
		||||
const impq & lp_bound_propagator::get_upper_bound(unsigned j) const {
 | 
			
		||||
    return m_lar_solver.m_mpq_lar_core_solver.m_r_upper_bounds()[j];
 | 
			
		||||
}
 | 
			
		||||
void lp_bound_propagator::try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict) {
 | 
			
		||||
    unsigned term_j = m_lar_solver.adjust_column_index_to_term_index(j);
 | 
			
		||||
    mpq w = v;
 | 
			
		||||
    if (term_j != j) {
 | 
			
		||||
        j = term_j;
 | 
			
		||||
        w += m_lar_solver.get_term(term_j).m_v; // when terms are turned into the columns they "lose" the right side, at this moment they aquire it back
 | 
			
		||||
    }
 | 
			
		||||
    lconstraint_kind kind = is_low? GE : LE;
 | 
			
		||||
    if (strict)
 | 
			
		||||
        kind = static_cast<lconstraint_kind>(kind / 2);
 | 
			
		||||
 | 
			
		||||
    if (!bound_is_interesting(j, kind, w))
 | 
			
		||||
        return;
 | 
			
		||||
     unsigned k; // index to ibounds
 | 
			
		||||
     if (is_low) {
 | 
			
		||||
         if (try_get_val(m_improved_low_bounds, j, k)) {
 | 
			
		||||
             auto & found_bound = m_ibounds[k];
 | 
			
		||||
             if (w > found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict))
 | 
			
		||||
                 found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
 | 
			
		||||
         } else {
 | 
			
		||||
             m_improved_low_bounds[j] = m_ibounds.size();
 | 
			
		||||
             m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
 | 
			
		||||
         }
 | 
			
		||||
     } else { // the upper bound case
 | 
			
		||||
         if (try_get_val(m_improved_upper_bounds, j, k)) {
 | 
			
		||||
             auto & found_bound = m_ibounds[k];
 | 
			
		||||
             if (w < found_bound.m_bound || (w == found_bound.m_bound && found_bound.m_strict == false && strict))
 | 
			
		||||
                 found_bound = implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict);
 | 
			
		||||
         } else {
 | 
			
		||||
             m_improved_upper_bounds[j] = m_ibounds.size();
 | 
			
		||||
             m_ibounds.push_back(implied_bound(w, j, is_low, coeff_before_j_is_pos, row_or_term_index, strict));
 | 
			
		||||
        }
 | 
			
		||||
     }
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,42 +0,0 @@
 | 
			
		|||
/*++
 | 
			
		||||
Copyright (c) 2017 Microsoft Corporation
 | 
			
		||||
 | 
			
		||||
Module Name:
 | 
			
		||||
 | 
			
		||||
    <name>
 | 
			
		||||
 | 
			
		||||
Abstract:
 | 
			
		||||
 | 
			
		||||
    <abstract>
 | 
			
		||||
 | 
			
		||||
Author:
 | 
			
		||||
 | 
			
		||||
    Lev Nachmanson (levnach)
 | 
			
		||||
 | 
			
		||||
Revision History:
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#pragma once
 | 
			
		||||
#include "util/lp/lp_settings.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
class lar_solver;
 | 
			
		||||
class lp_bound_propagator {
 | 
			
		||||
    std::unordered_map<unsigned, unsigned> m_improved_low_bounds; // these maps map a column index to the corresponding index in ibounds
 | 
			
		||||
    std::unordered_map<unsigned, unsigned> m_improved_upper_bounds;
 | 
			
		||||
    lar_solver & m_lar_solver;
 | 
			
		||||
public:
 | 
			
		||||
    vector<implied_bound> m_ibounds;
 | 
			
		||||
public:
 | 
			
		||||
    lp_bound_propagator(lar_solver & ls);
 | 
			
		||||
    column_type get_column_type(unsigned) const;
 | 
			
		||||
    const impq & get_low_bound(unsigned) const;
 | 
			
		||||
    const impq & get_upper_bound(unsigned) const;
 | 
			
		||||
    void try_add_bound(const mpq & v, unsigned j, bool is_low, bool coeff_before_j_is_pos, unsigned row_or_term_index, bool strict);
 | 
			
		||||
    virtual bool bound_is_interesting(unsigned vi,
 | 
			
		||||
                                      lp::lconstraint_kind kind,
 | 
			
		||||
                                      const rational & bval) {return true;}
 | 
			
		||||
    unsigned number_of_found_bounds() const { return m_ibounds.size(); }
 | 
			
		||||
    virtual void consume(mpq const& v, unsigned j) { std::cout << "doh\n"; }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ Revision History:
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lp_core_solver_base.hpp"
 | 
			
		||||
#include "util/lp/lp_core_solver_base_def.h"
 | 
			
		||||
template bool lp::lp_core_solver_base<double, double>::A_mult_x_is_off() const;
 | 
			
		||||
template bool lp::lp_core_solver_base<double, double>::A_mult_x_is_off_on_index(const vector<unsigned> &) const;
 | 
			
		||||
template bool lp::lp_core_solver_base<double, double>::basis_heading_is_correct() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -144,3 +144,5 @@ template bool lp::lp_core_solver_base<lp::mpq, lp::mpq>::inf_set_is_correct() co
 | 
			
		|||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::infeasibility_costs_are_correct() const;
 | 
			
		||||
template bool lp::lp_core_solver_base<lp::mpq, lp::mpq >::infeasibility_costs_are_correct() const;
 | 
			
		||||
template bool lp::lp_core_solver_base<double, double >::infeasibility_costs_are_correct() const;
 | 
			
		||||
template void lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::calculate_pivot_row(unsigned int);
 | 
			
		||||
template bool lp::lp_core_solver_base<lp::mpq, lp::numeric_pair<lp::mpq> >::remove_from_basis(unsigned int);
 | 
			
		||||
| 
						 | 
				
			
			@ -28,6 +28,7 @@ Revision History:
 | 
			
		|||
#include "util/lp/lu.h"
 | 
			
		||||
#include "util/lp/permutation_matrix.h"
 | 
			
		||||
#include "util/lp/column_namer.h"
 | 
			
		||||
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> // X represents the type of the x variable and the bounds
 | 
			
		||||
| 
						 | 
				
			
			@ -38,7 +39,17 @@ class lp_core_solver_base {
 | 
			
		|||
private:
 | 
			
		||||
    lp_status m_status;
 | 
			
		||||
public:
 | 
			
		||||
    bool current_x_is_feasible() const { return m_inf_set.size() == 0; }
 | 
			
		||||
    bool current_x_is_feasible() const {
 | 
			
		||||
        TRACE("feas",
 | 
			
		||||
              if (m_inf_set.size()) {
 | 
			
		||||
                  tout << "column " << m_inf_set.m_index[0] << " is infeasible" << std::endl;
 | 
			
		||||
                  print_column_info(m_inf_set.m_index[0], tout);
 | 
			
		||||
              } else {
 | 
			
		||||
                  tout << "x is feasible\n";
 | 
			
		||||
              }
 | 
			
		||||
              );
 | 
			
		||||
        return m_inf_set.size() == 0;
 | 
			
		||||
    }
 | 
			
		||||
    bool current_x_is_infeasible() const { return m_inf_set.size() != 0; }
 | 
			
		||||
    int_set m_inf_set;
 | 
			
		||||
    bool m_using_infeas_costs;
 | 
			
		||||
| 
						 | 
				
			
			@ -58,13 +69,13 @@ public:
 | 
			
		|||
    lp_settings &         m_settings;
 | 
			
		||||
    vector<T>             m_y; // the buffer for yB = cb
 | 
			
		||||
    // a device that is able to solve Bx=c, xB=d, and change the basis
 | 
			
		||||
    lu<T, X> *            m_factorization;
 | 
			
		||||
    lu<static_matrix<T, X>> *            m_factorization;
 | 
			
		||||
    const column_namer &  m_column_names;
 | 
			
		||||
    indexed_vector<T>     m_w; // the vector featuring in 24.3 of the Chvatal book
 | 
			
		||||
    vector<T>             m_d; // the vector of reduced costs
 | 
			
		||||
    indexed_vector<T>     m_ed; // the solution of B*m_ed = a
 | 
			
		||||
    const vector<column_type> & m_column_types;
 | 
			
		||||
    const vector<X> &     m_low_bounds;
 | 
			
		||||
    const vector<X> &     m_lower_bounds;
 | 
			
		||||
    const vector<X> &     m_upper_bounds;
 | 
			
		||||
    vector<T>             m_column_norms; // the approximate squares of column norms that help choosing a profitable column
 | 
			
		||||
    vector<X>             m_copy_of_xB;
 | 
			
		||||
| 
						 | 
				
			
			@ -74,6 +85,7 @@ public:
 | 
			
		|||
    bool                  m_tracing_basis_changes;
 | 
			
		||||
    int_set*              m_pivoted_rows;
 | 
			
		||||
    bool                  m_look_for_feasible_solution_only;
 | 
			
		||||
 | 
			
		||||
    void start_tracing_basis_changes() {
 | 
			
		||||
        m_trace_of_basis_change_vector.resize(0);
 | 
			
		||||
        m_tracing_basis_changes = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -108,7 +120,7 @@ public:
 | 
			
		|||
                        lp_settings & settings,
 | 
			
		||||
                        const column_namer& column_names,
 | 
			
		||||
                        const vector<column_type> & column_types,
 | 
			
		||||
                        const vector<X> & low_bound_values,
 | 
			
		||||
                        const vector<X> & lower_bound_values,
 | 
			
		||||
                        const vector<X> & upper_bound_values);
 | 
			
		||||
 | 
			
		||||
    void allocate_basis_heading();
 | 
			
		||||
| 
						 | 
				
			
			@ -197,11 +209,11 @@ public:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
    bool need_to_pivot_to_basis_tableau() const {
 | 
			
		||||
        SASSERT(m_A.is_correct());
 | 
			
		||||
        lp_assert(m_A.is_correct());
 | 
			
		||||
        unsigned m = m_A.row_count();
 | 
			
		||||
        for (unsigned i = 0; i < m; i++) {
 | 
			
		||||
            unsigned bj = m_basis[i];
 | 
			
		||||
            SASSERT(m_A.m_columns[bj].size() > 0);
 | 
			
		||||
            lp_assert(m_A.m_columns[bj].size() > 0);
 | 
			
		||||
            if (m_A.m_columns[bj].size() > 1 || m_A.get_val(m_A.m_columns[bj][0]) != one_of_type<mpq>()) return true;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -210,10 +222,9 @@ public:
 | 
			
		|||
    bool reduced_costs_are_correct_tableau() const {
 | 
			
		||||
        if (m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
 | 
			
		||||
            return true;
 | 
			
		||||
        SASSERT(m_A.is_correct());
 | 
			
		||||
        lp_assert(m_A.is_correct());
 | 
			
		||||
        if (m_using_infeas_costs) {
 | 
			
		||||
            if (infeasibility_costs_are_correct() == false) {
 | 
			
		||||
                std::cout << "infeasibility_costs_are_correct() does not hold" << std::endl;
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -222,9 +233,6 @@ public:
 | 
			
		|||
        for (unsigned j = 0; j < n; j++) {
 | 
			
		||||
            if (m_basis_heading[j] >= 0) {
 | 
			
		||||
                if (!is_zero(m_d[j])) {
 | 
			
		||||
                    
 | 
			
		||||
                    std::cout << "case a\n";
 | 
			
		||||
                    print_column_info(j, std::cout);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -233,8 +241,6 @@ public:
 | 
			
		|||
                    d -= this->m_costs[this->m_basis[cc.m_i]] * this->m_A.get_val(cc);
 | 
			
		||||
                }
 | 
			
		||||
                if (m_d[j] != d) {
 | 
			
		||||
                    std::cout << "case b\n";
 | 
			
		||||
                    print_column_info(j, std::cout);
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -253,14 +259,14 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool x_below_low_bound(unsigned p) const {
 | 
			
		||||
        return below_bound(m_x[p], m_low_bounds[p]);
 | 
			
		||||
        return below_bound(m_x[p], m_lower_bounds[p]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool infeasibility_costs_are_correct() const;
 | 
			
		||||
    bool infeasibility_cost_is_correct_for_column(unsigned j) const;
 | 
			
		||||
    
 | 
			
		||||
    bool x_above_low_bound(unsigned p) const {
 | 
			
		||||
        return above_bound(m_x[p], m_low_bounds[p]);
 | 
			
		||||
    bool x_above_lower_bound(unsigned p) const {
 | 
			
		||||
        return above_bound(m_x[p], m_lower_bounds[p]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool x_below_upper_bound(unsigned p) const {
 | 
			
		||||
| 
						 | 
				
			
			@ -271,15 +277,15 @@ public:
 | 
			
		|||
    bool x_above_upper_bound(unsigned p) const {
 | 
			
		||||
        return above_bound(m_x[p], m_upper_bounds[p]);
 | 
			
		||||
    }
 | 
			
		||||
    bool x_is_at_low_bound(unsigned j) const {
 | 
			
		||||
        return at_bound(m_x[j], m_low_bounds[j]);
 | 
			
		||||
    bool x_is_at_lower_bound(unsigned j) const {
 | 
			
		||||
        return at_bound(m_x[j], m_lower_bounds[j]);
 | 
			
		||||
    }
 | 
			
		||||
    bool x_is_at_upper_bound(unsigned j) const {
 | 
			
		||||
        return at_bound(m_x[j], m_upper_bounds[j]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool x_is_at_bound(unsigned j) const {
 | 
			
		||||
        return x_is_at_low_bound(j) || x_is_at_upper_bound(j);
 | 
			
		||||
        return x_is_at_lower_bound(j) || x_is_at_upper_bound(j);
 | 
			
		||||
    }
 | 
			
		||||
    bool column_is_feasible(unsigned j) const;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -318,8 +324,8 @@ public:
 | 
			
		|||
    void fill_reduced_costs_from_m_y_by_rows();
 | 
			
		||||
 | 
			
		||||
    void copy_rs_to_xB(vector<X> & rs);
 | 
			
		||||
    virtual bool low_bounds_are_set() const { return false; }
 | 
			
		||||
    X low_bound_value(unsigned j) const { return m_low_bounds[j]; }
 | 
			
		||||
    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]; }
 | 
			
		||||
 | 
			
		||||
    column_type get_column_type(unsigned j) const {return m_column_types[j]; }
 | 
			
		||||
| 
						 | 
				
			
			@ -329,7 +335,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    X bound_span(unsigned j) const {
 | 
			
		||||
        return m_upper_bounds[j] - m_low_bounds[j];
 | 
			
		||||
        return m_upper_bounds[j] - m_lower_bounds[j];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    std::string column_name(unsigned column) const;
 | 
			
		||||
| 
						 | 
				
			
			@ -357,21 +363,21 @@ public:
 | 
			
		|||
        case column_type::fixed:
 | 
			
		||||
            if (x_is_at_bound(j))
 | 
			
		||||
                break;
 | 
			
		||||
            m_x[j] = m_low_bounds[j];
 | 
			
		||||
            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_low_bounds[j];
 | 
			
		||||
                m_x[j] = m_lower_bounds[j];
 | 
			
		||||
            else
 | 
			
		||||
                m_x[j] = m_upper_bounds[j];
 | 
			
		||||
            return true;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            if (x_is_at_low_bound(j))
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (x_is_at_lower_bound(j))
 | 
			
		||||
                break;
 | 
			
		||||
            m_x[j] = m_low_bounds[j];
 | 
			
		||||
            m_x[j] = m_lower_bounds[j];
 | 
			
		||||
            return true;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            if (x_is_at_upper_bound(j))
 | 
			
		||||
| 
						 | 
				
			
			@ -385,50 +391,47 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    bool make_column_feasible(unsigned j, numeric_pair<mpq> & delta) {
 | 
			
		||||
        SASSERT(m_basis_heading[j] < 0);
 | 
			
		||||
        bool ret = false;
 | 
			
		||||
        lp_assert(m_basis_heading[j] < 0);
 | 
			
		||||
        auto & x = m_x[j];
 | 
			
		||||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
            SASSERT(m_low_bounds[j] == m_upper_bounds[j]);
 | 
			
		||||
            if (x != m_low_bounds[j]) {
 | 
			
		||||
                delta = m_low_bounds[j] - x;
 | 
			
		||||
                x = m_low_bounds[j];
 | 
			
		||||
                return true;
 | 
			
		||||
            lp_assert(m_lower_bounds[j] == m_upper_bounds[j]);
 | 
			
		||||
            if (x != m_lower_bounds[j]) {
 | 
			
		||||
                delta = m_lower_bounds[j] - x;
 | 
			
		||||
                ret = true;;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            if (x < m_low_bounds[j]) {
 | 
			
		||||
                delta = m_low_bounds[j] - x;
 | 
			
		||||
                x = m_low_bounds[j];
 | 
			
		||||
                return true;
 | 
			
		||||
            if (x < m_lower_bounds[j]) {
 | 
			
		||||
                delta = m_lower_bounds[j] - x;
 | 
			
		||||
                ret = true;;
 | 
			
		||||
            }
 | 
			
		||||
            if (x > m_upper_bounds[j]) {
 | 
			
		||||
                delta = m_upper_bounds[j] - x;
 | 
			
		||||
                x = m_upper_bounds[j];
 | 
			
		||||
                return true;
 | 
			
		||||
                ret = true;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            if (x < m_low_bounds[j]) {
 | 
			
		||||
                delta = m_low_bounds[j] - x;
 | 
			
		||||
                x = m_low_bounds[j];
 | 
			
		||||
                return true;
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (x < m_lower_bounds[j]) {
 | 
			
		||||
                delta = m_lower_bounds[j] - x;
 | 
			
		||||
                ret = true;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            if (x > m_upper_bounds[j]) {
 | 
			
		||||
                delta = m_upper_bounds[j] - x;
 | 
			
		||||
                x = m_upper_bounds[j];
 | 
			
		||||
                return true;
 | 
			
		||||
                ret = true;
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
        if (ret)
 | 
			
		||||
            add_delta_to_x_and_call_tracker(j, delta);
 | 
			
		||||
 | 
			
		||||
        return ret;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -444,6 +447,8 @@ public:
 | 
			
		|||
    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);
 | 
			
		||||
    bool pivot_column_general(unsigned j, unsigned j_basic, indexed_vector<T> & w);
 | 
			
		||||
    bool pivot_for_tableau_on_basis();
 | 
			
		||||
    bool pivot_row_for_tableau_on_basis(unsigned row);
 | 
			
		||||
    void init_basic_part_of_basis_heading() {
 | 
			
		||||
| 
						 | 
				
			
			@ -473,7 +478,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void change_basis_unconditionally(unsigned entering, unsigned leaving) {
 | 
			
		||||
        SASSERT(m_basis_heading[entering] < 0);
 | 
			
		||||
        lp_assert(m_basis_heading[entering] < 0);
 | 
			
		||||
        int place_in_non_basis = -1 - m_basis_heading[entering];
 | 
			
		||||
        if (static_cast<unsigned>(place_in_non_basis) >= m_nbasis.size()) {
 | 
			
		||||
              // entering variable in not in m_nbasis, we need to put it back;
 | 
			
		||||
| 
						 | 
				
			
			@ -492,7 +497,8 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
    
 | 
			
		||||
    void change_basis(unsigned entering, unsigned leaving) {
 | 
			
		||||
        SASSERT(m_basis_heading[entering] < 0);
 | 
			
		||||
        lp_assert(m_basis_heading[entering] < 0);
 | 
			
		||||
		lp_assert(m_basis_heading[leaving] >= 0);
 | 
			
		||||
        
 | 
			
		||||
        int place_in_basis =  m_basis_heading[leaving];
 | 
			
		||||
        int place_in_non_basis = - m_basis_heading[entering] - 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -522,8 +528,8 @@ public:
 | 
			
		|||
            if (!this->x_is_at_bound(j))
 | 
			
		||||
                return false;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            if (!this->x_is_at_low_bound(j))
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (!this->x_is_at_lower_bound(j))
 | 
			
		||||
                return false;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
| 
						 | 
				
			
			@ -533,7 +539,7 @@ public:
 | 
			
		|||
        case column_type::free_column:
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -541,7 +547,6 @@ public:
 | 
			
		|||
    bool non_basic_columns_are_set_correctly() const {
 | 
			
		||||
        for (unsigned j : this->m_nbasis)
 | 
			
		||||
            if (!column_is_feasible(j)) {
 | 
			
		||||
                print_column_info(j, std::cout);
 | 
			
		||||
                return false;
 | 
			
		||||
            }
 | 
			
		||||
        return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -552,10 +557,10 @@ public:
 | 
			
		|||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            out << "(" << m_low_bounds[j] << ", " << m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
            out << "(" << m_lower_bounds[j] << ", " << m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            out << m_low_bounds[j] << std::endl;
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            out << m_lower_bounds[j] << std::endl;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            out << m_upper_bounds[j] << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -566,36 +571,38 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void print_column_info(unsigned j, std::ostream & out) const {
 | 
			
		||||
        out << "column_index = " << j << ", name = "<< column_name(j) << " type = " << column_type_to_string(m_column_types[j]) << std::endl;
 | 
			
		||||
        out << "j = " << j << ", name = "<< column_name(j);
 | 
			
		||||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            out << "(" << m_low_bounds[j] << ", " << m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
            out << " [" << m_lower_bounds[j] << ", " << m_upper_bounds[j] << "]";
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            out << m_low_bounds[j] << std::endl;
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            out << " [" << m_lower_bounds[j] << "," << "oo" << "]";
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            out << m_upper_bounds[j] << std::endl;
 | 
			
		||||
            out << " [-oo, " << m_upper_bounds[j] << ']';
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
            out << " [-oo, oo]";
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        std::cout << "basis heading = " << m_basis_heading[j] << std::endl;
 | 
			
		||||
        std::cout << "x = " << m_x[j] << std::endl;
 | 
			
		||||
        /*
 | 
			
		||||
        std::cout << "cost = " << m_costs[j] << std::endl;
 | 
			
		||||
        std:: cout << "m_d = " << m_d[j] << std::endl;*/
 | 
			
		||||
        //        out << "basis heading = " << m_basis_heading[j] << std::endl;
 | 
			
		||||
        out << " x =                " << m_x[j];
 | 
			
		||||
        if (m_basis_heading[j] >= 0)
 | 
			
		||||
            out << " base\n";
 | 
			
		||||
        else
 | 
			
		||||
            out << " nbas\n";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool column_is_free(unsigned j) { return this->m_column_type[j] == free; }
 | 
			
		||||
    bool column_is_free(unsigned j) const { return this->m_column_type[j] == free; }
 | 
			
		||||
 | 
			
		||||
    bool column_has_upper_bound(unsigned j) {
 | 
			
		||||
    bool column_has_upper_bound(unsigned j) const {
 | 
			
		||||
        switch(m_column_types[j]) {
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            return false;
 | 
			
		||||
        default:
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -605,13 +612,13 @@ public:
 | 
			
		|||
    bool bounds_for_boxed_are_set_correctly() const {
 | 
			
		||||
        for (unsigned j = 0; j < m_column_types.size(); j++) {
 | 
			
		||||
            if (m_column_types[j] != column_type::boxed) continue;
 | 
			
		||||
            if (m_low_bounds[j] > m_upper_bounds[j])
 | 
			
		||||
            if (m_lower_bounds[j] > m_upper_bounds[j])
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    bool column_has_low_bound(unsigned j) {
 | 
			
		||||
    bool column_has_lower_bound(unsigned j) const {
 | 
			
		||||
        switch(m_column_types[j]) {
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
| 
						 | 
				
			
			@ -671,26 +678,43 @@ public:
 | 
			
		|||
        return m_inf_set.contains(j);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void update_column_in_inf_set(unsigned j) {
 | 
			
		||||
        if (column_is_feasible(j)) {
 | 
			
		||||
            m_inf_set.erase(j);
 | 
			
		||||
        } else {
 | 
			
		||||
            m_inf_set.insert(j);
 | 
			
		||||
        }
 | 
			
		||||
    void update_x_with_feasibility_tracking(unsigned j, const X & v) {
 | 
			
		||||
        m_x[j] = v;
 | 
			
		||||
        track_column_feasibility(j);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void update_x_with_delta_and_track_feasibility(unsigned j, const X & del) {
 | 
			
		||||
        m_x[j] += del;
 | 
			
		||||
        track_column_feasibility(j);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void update_x_and_call_tracker(unsigned j, const X & v) {
 | 
			
		||||
        m_x[j] = v;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void add_delta_to_x_and_call_tracker(unsigned j, const X & delta) {
 | 
			
		||||
        m_x[j] += delta;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    void track_column_feasibility(unsigned j) {
 | 
			
		||||
        if (column_is_feasible(j))
 | 
			
		||||
            remove_column_from_inf_set(j);
 | 
			
		||||
        else
 | 
			
		||||
            insert_column_into_inf_set(j);
 | 
			
		||||
    }
 | 
			
		||||
    void insert_column_into_inf_set(unsigned j) {
 | 
			
		||||
        m_inf_set.insert(j);
 | 
			
		||||
        SASSERT(!column_is_feasible(j));
 | 
			
		||||
        lp_assert(!column_is_feasible(j));
 | 
			
		||||
    }
 | 
			
		||||
    void remove_column_from_inf_set(unsigned j) {
 | 
			
		||||
        m_inf_set.erase(j);
 | 
			
		||||
        SASSERT(column_is_feasible(j));
 | 
			
		||||
        lp_assert(column_is_feasible(j));
 | 
			
		||||
    }
 | 
			
		||||
    bool costs_on_nbasis_are_zeros() const {
 | 
			
		||||
        SASSERT(this->basis_heading_is_correct());
 | 
			
		||||
        lp_assert(this->basis_heading_is_correct());
 | 
			
		||||
        for (unsigned j = 0; j < this->m_n(); j++) {
 | 
			
		||||
            if (this->m_basis_heading[j] < 0)
 | 
			
		||||
                SASSERT(is_zero(this->m_costs[j]));
 | 
			
		||||
                lp_assert(is_zero(this->m_costs[j]));
 | 
			
		||||
        }
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -701,5 +725,10 @@ public:
 | 
			
		|||
    const unsigned & iters_with_no_cost_growing() const {
 | 
			
		||||
        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];
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -35,11 +35,11 @@ lp_core_solver_base(static_matrix<T, X> & A,
 | 
			
		|||
                    lp_settings & settings,
 | 
			
		||||
                    const column_namer& column_names,
 | 
			
		||||
                    const vector<column_type> & column_types,
 | 
			
		||||
                    const vector<X> & low_bound_values,
 | 
			
		||||
                    const vector<X> & lower_bound_values,
 | 
			
		||||
                    const vector<X> & upper_bound_values):
 | 
			
		||||
    m_total_iterations(0),
 | 
			
		||||
    m_iters_with_no_cost_growing(0),
 | 
			
		||||
    m_status(FEASIBLE),
 | 
			
		||||
    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()),
 | 
			
		||||
| 
						 | 
				
			
			@ -59,7 +59,7 @@ lp_core_solver_base(static_matrix<T, X> & A,
 | 
			
		|||
    m_d(m_n()),
 | 
			
		||||
    m_ed(m_m()),
 | 
			
		||||
    m_column_types(column_types),
 | 
			
		||||
    m_low_bounds(low_bound_values),
 | 
			
		||||
    m_lower_bounds(lower_bound_values),
 | 
			
		||||
    m_upper_bounds(upper_bound_values),
 | 
			
		||||
    m_column_norms(m_n()),
 | 
			
		||||
    m_copy_of_xB(m_m()),
 | 
			
		||||
| 
						 | 
				
			
			@ -68,7 +68,7 @@ lp_core_solver_base(static_matrix<T, X> & A,
 | 
			
		|||
    m_tracing_basis_changes(false),
 | 
			
		||||
    m_pivoted_rows(nullptr),
 | 
			
		||||
    m_look_for_feasible_solution_only(false) {
 | 
			
		||||
    SASSERT(bounds_for_boxed_are_set_correctly());    
 | 
			
		||||
    lp_assert(bounds_for_boxed_are_set_correctly());    
 | 
			
		||||
    init();
 | 
			
		||||
    init_basis_heading_and_non_basic_columns_vector();
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -76,7 +76,7 @@ lp_core_solver_base(static_matrix<T, X> & A,
 | 
			
		|||
template <typename T, typename X> void lp_core_solver_base<T, X>::
 | 
			
		||||
allocate_basis_heading() { // the rest of initilization will be handled by the factorization class
 | 
			
		||||
    init_basis_heading_and_non_basic_columns_vector();
 | 
			
		||||
    SASSERT(basis_heading_is_correct());
 | 
			
		||||
    lp_assert(basis_heading_is_correct());
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X> void lp_core_solver_base<T, X>::
 | 
			
		||||
init() {    
 | 
			
		||||
| 
						 | 
				
			
			@ -142,7 +142,7 @@ solve_yB(vector<T> & y) {
 | 
			
		|||
//     }
 | 
			
		||||
// }
 | 
			
		||||
template <typename T, typename X> void lp_core_solver_base<T, X>::solve_Bd(unsigned entering, indexed_vector<T> & column) {
 | 
			
		||||
    SASSERT(!m_settings.use_tableau());
 | 
			
		||||
    lp_assert(!m_settings.use_tableau());
 | 
			
		||||
    if (m_factorization == nullptr) {
 | 
			
		||||
        init_factorization(m_factorization, m_A, m_basis, m_settings);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -152,19 +152,19 @@ template <typename T, typename X> void lp_core_solver_base<T, X>::solve_Bd(unsig
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> void lp_core_solver_base<T, X>::
 | 
			
		||||
solve_Bd(unsigned entering) {
 | 
			
		||||
    SASSERT(m_ed.is_OK());
 | 
			
		||||
    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();
 | 
			
		||||
    SASSERT(m_ed.is_OK());
 | 
			
		||||
    SASSERT(m_w.is_OK());
 | 
			
		||||
    lp_assert(m_ed.is_OK());
 | 
			
		||||
    lp_assert(m_w.is_OK());
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    // auto B = get_B(*m_factorization, m_basis);
 | 
			
		||||
    // vector<T>  a(m_m());
 | 
			
		||||
    // m_A.copy_column_to_vector(entering, a);
 | 
			
		||||
    // vector<T> cd(m_ed.m_data);
 | 
			
		||||
    // B.apply_from_left(cd, m_settings);
 | 
			
		||||
    // SASSERT(vectors_are_equal(cd , a));
 | 
			
		||||
    // lp_assert(vectors_are_equal(cd , a));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -223,16 +223,11 @@ restore_m_ed(T * buffer) {
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
A_mult_x_is_off() const {
 | 
			
		||||
    SASSERT(m_x.size() == m_A.column_count());
 | 
			
		||||
    lp_assert(m_x.size() == m_A.column_count());
 | 
			
		||||
    if (numeric_traits<T>::precise()) {
 | 
			
		||||
        for (unsigned i = 0; i < m_m(); i++) {
 | 
			
		||||
		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<X>::zero()) {
 | 
			
		||||
                std::cout << "precise x is off (";
 | 
			
		||||
                std::cout << "m_b[" << i << "] = " << m_b[i] << " ";
 | 
			
		||||
                std::cout << "left side = " << m_A.dot_product_with_row(i, m_x) << ' ';
 | 
			
		||||
                std::cout << "delta = " << delta << ' ';
 | 
			
		||||
                std::cout << "iters = " << total_iterations() << ")" << std::endl;
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -259,17 +254,12 @@ A_mult_x_is_off() const {
 | 
			
		|||
}
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
A_mult_x_is_off_on_index(const vector<unsigned> & index) const {
 | 
			
		||||
    SASSERT(m_x.size() == m_A.column_count());
 | 
			
		||||
    lp_assert(m_x.size() == m_A.column_count());
 | 
			
		||||
    if (numeric_traits<T>::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<X>::zero()) {
 | 
			
		||||
            // std::cout << "x is off (";
 | 
			
		||||
            // std::cout << "m_b[" << i  << "] = " << m_b[i] << " ";
 | 
			
		||||
            // std::cout << "left side = " << m_A.dot_product_with_row(i, m_x) << ' ';
 | 
			
		||||
            // std::cout << "delta = " << delta << ' ';
 | 
			
		||||
            // std::cout << "iters = " << total_iterations() << ")" << std::endl;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -299,13 +289,13 @@ A_mult_x_is_off_on_index(const vector<unsigned> & index) const {
 | 
			
		|||
// from page 182 of Istvan Maros's book
 | 
			
		||||
template <typename T, typename X> void lp_core_solver_base<T, X>::
 | 
			
		||||
calculate_pivot_row_of_B_1(unsigned pivot_row) {
 | 
			
		||||
    SASSERT(! use_tableau());
 | 
			
		||||
    SASSERT(m_pivot_row_of_B_1.is_OK());
 | 
			
		||||
    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<T>::one(), pivot_row);
 | 
			
		||||
    SASSERT(m_pivot_row_of_B_1.is_OK());
 | 
			
		||||
    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);
 | 
			
		||||
    SASSERT(m_pivot_row_of_B_1.is_OK());
 | 
			
		||||
    lp_assert(m_pivot_row_of_B_1.is_OK());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -391,15 +381,15 @@ 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_low_bounds[j];
 | 
			
		||||
            m_x[j] = m_d[j] < 0? m_upper_bounds[j]: m_lower_bounds[j];
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            m_x[j] = m_low_bounds[j];
 | 
			
		||||
            SASSERT(column_is_dual_feasible(j));
 | 
			
		||||
        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];
 | 
			
		||||
            SASSERT(column_is_dual_feasible(j));
 | 
			
		||||
            lp_assert(column_is_dual_feasible(j));
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -411,21 +401,18 @@ column_is_dual_feasible(unsigned j) const {
 | 
			
		|||
    switch (m_column_types[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        return (x_is_at_low_bound(j) && d_is_not_negative(j)) ||
 | 
			
		||||
        return (x_is_at_lower_bound(j) && d_is_not_negative(j)) ||
 | 
			
		||||
            (x_is_at_upper_bound(j) && d_is_not_positive(j));
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        return x_is_at_low_bound(j) && d_is_not_negative(j);
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        return x_is_at_lower_bound(j) && d_is_not_negative(j);
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        LP_OUT(m_settings,  "upper_bound type should be switched to low_bound" << std::endl);
 | 
			
		||||
        SASSERT(false); // impossible case
 | 
			
		||||
        lp_assert(false); // impossible case
 | 
			
		||||
    case column_type::free_column:
 | 
			
		||||
        return numeric_traits<X>::is_zero(m_d[j]);
 | 
			
		||||
    default:
 | 
			
		||||
        LP_OUT(m_settings,  "column = " << j << std::endl);
 | 
			
		||||
        LP_OUT(m_settings,  "unexpected column type = " << column_type_to_string(m_column_types[j]) << std::endl);
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
| 
						 | 
				
			
			@ -484,14 +471,14 @@ template <typename T, typename X> bool lp_core_solver_base<T, X>::column_is_feas
 | 
			
		|||
    case column_type::boxed:
 | 
			
		||||
        if (this->above_bound(x, this->m_upper_bounds[j])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else if (this->below_bound(x, this->m_low_bounds[j])) {
 | 
			
		||||
        } else if (this->below_bound(x, this->m_lower_bounds[j])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        if (this->below_bound(x, this->m_low_bounds[j])) {
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->below_bound(x, this->m_lower_bounds[j])) {
 | 
			
		||||
            return false;
 | 
			
		||||
        } else {
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -508,7 +495,7 @@ template <typename T, typename X> bool lp_core_solver_base<T, X>::column_is_feas
 | 
			
		|||
        return true;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    return false; // it is unreachable
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -530,9 +517,6 @@ template <typename T, typename X> bool lp_core_solver_base<T, X>::inf_set_is_cor
 | 
			
		|||
        bool is_feas = column_is_feasible(j);
 | 
			
		||||
    
 | 
			
		||||
        if (is_feas == belongs_to_set) {
 | 
			
		||||
            print_column_info(j, std::cout);
 | 
			
		||||
            std::cout << "belongs_to_set = " << belongs_to_set << std::endl;
 | 
			
		||||
            std::cout <<( is_feas? "feas":"inf") << std::endl;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -549,7 +533,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) {
 | 
			
		|||
            if (!find_x_by_solving()) {
 | 
			
		||||
                restore_x(entering, tt);
 | 
			
		||||
                if(A_mult_x_is_off()) {
 | 
			
		||||
                    m_status = FLOATING_POINT_ERROR;
 | 
			
		||||
                    m_status = lp_status::FLOATING_POINT_ERROR;
 | 
			
		||||
                    m_iters_with_no_cost_growing++;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
| 
						 | 
				
			
			@ -559,7 +543,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) {
 | 
			
		|||
                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 = FLOATING_POINT_ERROR;
 | 
			
		||||
                    m_status = lp_status::FLOATING_POINT_ERROR;
 | 
			
		||||
                    return false;
 | 
			
		||||
                }
 | 
			
		||||
                return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -581,19 +565,19 @@ update_basis_and_x(int entering, int leaving, X const & tt) {
 | 
			
		|||
    init_lu();
 | 
			
		||||
    if (m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
        if (m_look_for_feasible_solution_only && !precise()) {
 | 
			
		||||
            m_status = UNSTABLE;
 | 
			
		||||
            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 == FLOATING_POINT_ERROR)
 | 
			
		||||
        if (m_status == lp_status::FLOATING_POINT_ERROR)
 | 
			
		||||
            return false;
 | 
			
		||||
        SASSERT(!A_mult_x_is_off());
 | 
			
		||||
        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 = UNSTABLE;
 | 
			
		||||
        m_status = lp_status::UNSTABLE;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -602,7 +586,7 @@ update_basis_and_x(int entering, int leaving, X const & tt) {
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise());
 | 
			
		||||
    int pivot_index = -1;
 | 
			
		||||
    auto & row = m_A.m_rows[pivot_row];
 | 
			
		||||
    unsigned size = row.size();
 | 
			
		||||
| 
						 | 
				
			
			@ -629,7 +613,7 @@ divide_row_by_pivot(unsigned pivot_row, unsigned pivot_col) {
 | 
			
		|||
}
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
pivot_column_tableau(unsigned j, unsigned piv_row_index) {
 | 
			
		||||
    if (!divide_row_by_pivot(piv_row_index, j))
 | 
			
		||||
	if (!divide_row_by_pivot(piv_row_index, j))
 | 
			
		||||
        return false;
 | 
			
		||||
    auto &column = m_A.m_columns[j];
 | 
			
		||||
    int pivot_col_cell_index = -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -643,7 +627,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) {
 | 
			
		|||
        return false;
 | 
			
		||||
        
 | 
			
		||||
    if (pivot_col_cell_index != 0) {
 | 
			
		||||
        SASSERT(column.size() > 1);
 | 
			
		||||
        lp_assert(column.size() > 1);
 | 
			
		||||
        // swap the pivot column cell with the head cell
 | 
			
		||||
        auto c = column[0];
 | 
			
		||||
        column[0]  = column[pivot_col_cell_index];
 | 
			
		||||
| 
						 | 
				
			
			@ -654,7 +638,7 @@ pivot_column_tableau(unsigned j, unsigned piv_row_index) {
 | 
			
		|||
    }
 | 
			
		||||
    while (column.size() > 1) {
 | 
			
		||||
        auto & c = column.back();
 | 
			
		||||
        SASSERT(c.m_i != piv_row_index);
 | 
			
		||||
        lp_assert(c.m_i != piv_row_index);
 | 
			
		||||
        if(! m_A.pivot_row_to_row_given_cell(piv_row_index, c, j)) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -702,7 +686,7 @@ non_basis_is_correctly_represented_in_heading() const {
 | 
			
		|||
    }
 | 
			
		||||
    for (unsigned j = 0; j < m_A.column_count(); j++) {
 | 
			
		||||
        if (m_basis_heading[j] >= 0) {
 | 
			
		||||
            SASSERT(static_cast<unsigned>(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j);
 | 
			
		||||
            lp_assert(static_cast<unsigned>(m_basis_heading[j]) < m_A.row_count() && m_basis[m_basis_heading[j]] == j);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -710,26 +694,22 @@ non_basis_is_correctly_represented_in_heading() const {
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::
 | 
			
		||||
    basis_heading_is_correct() const {
 | 
			
		||||
    SASSERT(m_basis_heading.size() == m_A.column_count());
 | 
			
		||||
    SASSERT(m_basis.size() == m_A.row_count());
 | 
			
		||||
    SASSERT(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller
 | 
			
		||||
    lp_assert(m_basis_heading.size() == m_A.column_count());
 | 
			
		||||
    lp_assert(m_basis.size() == m_A.row_count());
 | 
			
		||||
    lp_assert(m_nbasis.size() <= m_A.column_count() - m_A.row_count()); // for the dual the size of non basis can be smaller
 | 
			
		||||
    if (!basis_has_no_doubles()) {
 | 
			
		||||
        //        std::cout << "basis_has_no_doubles" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!non_basis_has_no_doubles()) {
 | 
			
		||||
        // std::cout << "non_basis_has_no_doubles" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!basis_is_correctly_represented_in_heading()) {
 | 
			
		||||
        // std::cout << "basis_is_correctly_represented_in_heading" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!non_basis_is_correctly_represented_in_heading()) {
 | 
			
		||||
        // std::cout << "non_basis_is_correctly_represented_in_heading" << std::endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -856,12 +836,12 @@ solve_Ax_eq_b() {
 | 
			
		|||
template <typename T, typename X> void lp_core_solver_base<T, X>::
 | 
			
		||||
snap_non_basic_x_to_bound_and_free_to_zeroes() {
 | 
			
		||||
    for (unsigned j : non_basis()) {
 | 
			
		||||
        SASSERT(j < m_x.size());
 | 
			
		||||
        lp_assert(j < m_x.size());
 | 
			
		||||
        switch (m_column_types[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            m_x[j] = m_low_bounds[j];
 | 
			
		||||
        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];
 | 
			
		||||
| 
						 | 
				
			
			@ -894,23 +874,23 @@ template <typename T, typename X> non_basic_column_value_position lp_core_solver
 | 
			
		|||
get_non_basic_column_value_position(unsigned j) const {
 | 
			
		||||
    switch (m_column_types[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
        return x_is_at_low_bound(j)? at_fixed : not_at_bound;
 | 
			
		||||
        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_low_bound(j)? at_low_bound :(
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        return x_is_at_low_bound(j)? at_low_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:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    return at_low_bound;
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return at_lower_bound;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_core_solver_base<T, X>::init_lu() {
 | 
			
		||||
| 
						 | 
				
			
			@ -938,59 +918,80 @@ template <typename T, typename X>  void lp_core_solver_base<T, X>::transpose_row
 | 
			
		|||
    transpose_basis(i, j);
 | 
			
		||||
    m_A.transpose_rows(i, j);
 | 
			
		||||
}
 | 
			
		||||
// j is the new basic column, j_basic - the leaving column
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::pivot_column_general(unsigned j, unsigned j_basic, indexed_vector<T> & w) {
 | 
			
		||||
	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<T>(), 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
 | 
			
		||||
		if (pivot_column_tableau(j, row_index))
 | 
			
		||||
			change_basis(j, j_basic);
 | 
			
		||||
		else return false;
 | 
			
		||||
	}
 | 
			
		||||
	return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>  void lp_core_solver_base<T, X>::pivot_fixed_vars_from_basis() {
 | 
			
		||||
    // run over basis and non-basis at the same time
 | 
			
		||||
    indexed_vector<T> w(m_basis.size()); // the buffer
 | 
			
		||||
    unsigned i = 0; // points to basis
 | 
			
		||||
    unsigned j = 0; // points to nonbasis
 | 
			
		||||
    for (; i < m_basis.size() && j < m_nbasis.size(); i++) {
 | 
			
		||||
        unsigned ii = m_basis[i];
 | 
			
		||||
        unsigned jj;
 | 
			
		||||
    for (; i < m_basis.size(); i++) {
 | 
			
		||||
        unsigned basic_j = m_basis[i];
 | 
			
		||||
 | 
			
		||||
        if (get_column_type(ii) != column_type::fixed) continue;
 | 
			
		||||
        while (j < m_nbasis.size()) {
 | 
			
		||||
            for (; j < m_nbasis.size(); j++) {
 | 
			
		||||
                jj = m_nbasis[j];
 | 
			
		||||
                if (get_column_type(jj) != column_type::fixed)
 | 
			
		||||
        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;
 | 
			
		||||
            }
 | 
			
		||||
            if (j >= m_nbasis.size())
 | 
			
		||||
                break;
 | 
			
		||||
            j++;
 | 
			
		||||
            if (m_factorization->need_to_refactor()) {
 | 
			
		||||
                change_basis(jj, ii);
 | 
			
		||||
                init_lu();
 | 
			
		||||
            } else {
 | 
			
		||||
                m_factorization->prepare_entering(jj, w); // to init vector w
 | 
			
		||||
                m_factorization->replace_column(zero_of_type<T>(), w, m_basis_heading[ii]);
 | 
			
		||||
                change_basis(jj, ii);
 | 
			
		||||
            }
 | 
			
		||||
            if (m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                change_basis(ii, jj);
 | 
			
		||||
                init_lu();
 | 
			
		||||
            } else {
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(m_factorization->get_status()== LU_status::OK);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_core_solver_base<T, X>::remove_from_basis(unsigned basic_j) {
 | 
			
		||||
    indexed_vector<T> 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 <typename T, typename X> bool 
 | 
			
		||||
lp_core_solver_base<T, X>::infeasibility_costs_are_correct() const {
 | 
			
		||||
    if (! this->m_using_infeas_costs)
 | 
			
		||||
        return true;
 | 
			
		||||
    SASSERT(costs_on_nbasis_are_zeros());
 | 
			
		||||
    lp_assert(costs_on_nbasis_are_zeros());
 | 
			
		||||
    for (unsigned j :this->m_basis) {
 | 
			
		||||
        if (!infeasibility_cost_is_correct_for_column(j)) {
 | 
			
		||||
            std::cout << "infeasibility_cost_is_correct_for_column does not hold\n";
 | 
			
		||||
            print_column_info(j, std::cout);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        if (!is_zero(m_d[j])) {
 | 
			
		||||
            std::cout << "m_d is not zero\n";
 | 
			
		||||
            print_column_info(j, std::cout);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1012,7 +1013,7 @@ lp_core_solver_base<T, X>::infeasibility_cost_is_correct_for_column(unsigned j)
 | 
			
		|||
        }
 | 
			
		||||
        return is_zero(this->m_costs[j]);
 | 
			
		||||
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(j)) {
 | 
			
		||||
            return this->m_costs[j] == -r;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -1026,9 +1027,31 @@ lp_core_solver_base<T, X>::infeasibility_cost_is_correct_for_column(unsigned j)
 | 
			
		|||
    case column_type::free_column:
 | 
			
		||||
        return is_zero(this->m_costs[j]);
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
void lp_core_solver_base<T, X>::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.m_j != basic_j)
 | 
			
		||||
                m_pivot_row.set_value(c.get_val(), c.m_j);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    calculate_pivot_row_of_B_1(i);
 | 
			
		||||
    calculate_pivot_row_when_pivot_row_of_B1_is_ready(i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ Revision History:
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lp_dual_core_solver.hpp"
 | 
			
		||||
#include "util/lp/lp_dual_core_solver_def.h"
 | 
			
		||||
template void lp::lp_dual_core_solver<lp::mpq, lp::mpq>::start_with_initial_basis_and_make_it_dual_feasible();
 | 
			
		||||
template void lp::lp_dual_core_solver<lp::mpq, lp::mpq>::solve();
 | 
			
		||||
template lp::lp_dual_core_solver<double, double>::lp_dual_core_solver(lp::static_matrix<double, double>&, vector<bool>&,
 | 
			
		||||
| 
						 | 
				
			
			@ -56,7 +56,7 @@ public:
 | 
			
		|||
                        vector<int> & heading,
 | 
			
		||||
                        vector<T> & costs,
 | 
			
		||||
                        vector<column_type> & column_type_array,
 | 
			
		||||
                        vector<X> & low_bound_values,
 | 
			
		||||
                        vector<X> & lower_bound_values,
 | 
			
		||||
                        vector<X> & upper_bound_values,
 | 
			
		||||
                        lp_settings & settings,
 | 
			
		||||
                        const column_namer & column_names):
 | 
			
		||||
| 
						 | 
				
			
			@ -70,7 +70,7 @@ public:
 | 
			
		|||
                                  settings,
 | 
			
		||||
                                  column_names,
 | 
			
		||||
                                  column_type_array,
 | 
			
		||||
                                  low_bound_values,
 | 
			
		||||
                                  lower_bound_values,
 | 
			
		||||
                                  upper_bound_values),
 | 
			
		||||
        m_can_enter_basis(can_enter_basis),
 | 
			
		||||
        m_a_wave(this->m_m()),
 | 
			
		||||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    bool done();
 | 
			
		||||
 | 
			
		||||
    T get_edge_steepness_for_low_bound(unsigned p);
 | 
			
		||||
    T get_edge_steepness_for_lower_bound(unsigned p);
 | 
			
		||||
 | 
			
		||||
    T get_edge_steepness_for_upper_bound(unsigned p);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -174,7 +174,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    // 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_low_bound(j)? this->bound_span(j): - this->bound_span(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();
 | 
			
		||||
| 
						 | 
				
			
			@ -207,6 +207,6 @@ public:
 | 
			
		|||
 | 
			
		||||
    void solve();
 | 
			
		||||
 | 
			
		||||
    bool low_bounds_are_set() const override { return true; }
 | 
			
		||||
    bool lower_bounds_are_set() const override { return true; }
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::restore_non_ba
 | 
			
		|||
    while (j--) {
 | 
			
		||||
        if (this->m_basis_heading[j] >= 0 ) continue;
 | 
			
		||||
        if (m_can_enter_basis[j]) {
 | 
			
		||||
            SASSERT(std::find(nb.begin(), nb.end(), j) == nb.end());
 | 
			
		||||
            lp_assert(std::find(nb.begin(), nb.end(), j) == nb.end());
 | 
			
		||||
            nb.push_back(j);
 | 
			
		||||
            this->m_basis_heading[j] = - static_cast<int>(nb.size());
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -97,25 +97,25 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::start_with_ini
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_dual_core_solver<T, X>::done() {
 | 
			
		||||
    if (this->get_status() == OPTIMAL) {
 | 
			
		||||
    if (this->get_status() == lp_status::OPTIMAL) {
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->total_iterations() > this->m_settings.max_total_number_of_iterations) { // debug !!!!
 | 
			
		||||
        this->set_status(ITERATIONS_EXHAUSTED);
 | 
			
		||||
        this->set_status(lp_status::ITERATIONS_EXHAUSTED);
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false; // todo, need to be more cases
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> T lp_dual_core_solver<T, X>::get_edge_steepness_for_low_bound(unsigned p) {
 | 
			
		||||
    SASSERT(this->m_basis_heading[p] >= 0 && static_cast<unsigned>(this->m_basis_heading[p]) < this->m_m());
 | 
			
		||||
    T del = this->m_x[p] - this->m_low_bounds[p];
 | 
			
		||||
template <typename T, typename X> T lp_dual_core_solver<T, X>::get_edge_steepness_for_lower_bound(unsigned p) {
 | 
			
		||||
    lp_assert(this->m_basis_heading[p] >= 0 && static_cast<unsigned>(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 <typename T, typename X> T lp_dual_core_solver<T, X>::get_edge_steepness_for_upper_bound(unsigned p) {
 | 
			
		||||
    SASSERT(this->m_basis_heading[p] >= 0 && static_cast<unsigned>(this->m_basis_heading[p]) < this->m_m());
 | 
			
		||||
    lp_assert(this->m_basis_heading[p] >= 0 && static_cast<unsigned>(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]];
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +127,7 @@ template <typename T, typename X> T lp_dual_core_solver<T, X>::pricing_for_row(u
 | 
			
		|||
    case column_type::fixed:
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        if (this->x_below_low_bound(p)) {
 | 
			
		||||
            T del =  get_edge_steepness_for_low_bound(p);
 | 
			
		||||
            T del =  get_edge_steepness_for_lower_bound(p);
 | 
			
		||||
            return del;
 | 
			
		||||
        }
 | 
			
		||||
        if (this->x_above_upper_bound(p)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -135,9 +135,9 @@ template <typename T, typename X> T lp_dual_core_solver<T, X>::pricing_for_row(u
 | 
			
		|||
            return del;
 | 
			
		||||
        }
 | 
			
		||||
        return numeric_traits<T>::zero();
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(p)) {
 | 
			
		||||
            T del =  get_edge_steepness_for_low_bound(p);
 | 
			
		||||
            T del =  get_edge_steepness_for_lower_bound(p);
 | 
			
		||||
            return del;
 | 
			
		||||
        }
 | 
			
		||||
        return numeric_traits<T>::zero();
 | 
			
		||||
| 
						 | 
				
			
			@ -150,12 +150,12 @@ template <typename T, typename X> T lp_dual_core_solver<T, X>::pricing_for_row(u
 | 
			
		|||
        return numeric_traits<T>::zero();
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::free_column:
 | 
			
		||||
        SASSERT(numeric_traits<T>::is_zero(this->m_d[p]));
 | 
			
		||||
        lp_assert(numeric_traits<T>::is_zero(this->m_d[p]));
 | 
			
		||||
        return numeric_traits<T>::zero();
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return numeric_traits<T>::zero();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -185,8 +185,8 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::pricing_loop(u
 | 
			
		|||
        }
 | 
			
		||||
    } while (i != initial_offset_in_rows && rows_left);
 | 
			
		||||
    if (m_r == -1) {
 | 
			
		||||
        if (this->get_status() != UNSTABLE) {
 | 
			
		||||
            this->set_status(OPTIMAL);
 | 
			
		||||
        if (this->get_status() != lp_status::UNSTABLE) {
 | 
			
		||||
            this->set_status(lp_status::OPTIMAL);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        m_p = this->m_basis[m_r];
 | 
			
		||||
| 
						 | 
				
			
			@ -196,10 +196,10 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::pricing_loop(u
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        // failure in advance_on_known_p
 | 
			
		||||
        if (this->get_status() == FLOATING_POINT_ERROR) {
 | 
			
		||||
        if (this->get_status() == lp_status::FLOATING_POINT_ERROR) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        this->set_status(UNSTABLE);
 | 
			
		||||
        this->set_status(lp_status::UNSTABLE);
 | 
			
		||||
        m_forbidden_rows.insert(m_r);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -224,9 +224,9 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::advance_on_kno
 | 
			
		|||
    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
 | 
			
		||||
        SASSERT(false); // not implemented yet
 | 
			
		||||
        lp_unreachable(); // not implemented yet
 | 
			
		||||
    } else {
 | 
			
		||||
        SASSERT(pivot_compare_result == 1);
 | 
			
		||||
        lp_assert(pivot_compare_result == 1);
 | 
			
		||||
        this->init_lu();
 | 
			
		||||
    }
 | 
			
		||||
    DSE_FTran();
 | 
			
		||||
| 
						 | 
				
			
			@ -243,38 +243,38 @@ template <typename T, typename X> int lp_dual_core_solver<T, X>::define_sign_of_
 | 
			
		|||
        if (this->x_above_upper_bound(m_p)) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(m_p)) {
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        if (this->x_above_upper_bound(m_p)) {
 | 
			
		||||
            return 1;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_dual_core_solver<T, X>::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::low_bound:
 | 
			
		||||
        SASSERT(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_low_bounds[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:
 | 
			
		||||
        SASSERT(this->m_settings.abs_val_is_smaller_than_harris_tolerance(this->m_x[j] - this->m_upper_bounds[j]));
 | 
			
		||||
        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 low_bound = this->x_is_at_low_bound(j);
 | 
			
		||||
            bool lower_bound = this->x_is_at_lower_bound(j);
 | 
			
		||||
            bool grawing = m_sign_of_alpha_r * this->m_pivot_row[j] > 0;
 | 
			
		||||
            return low_bound == grawing;
 | 
			
		||||
            return lower_bound == grawing;
 | 
			
		||||
        }
 | 
			
		||||
    case column_type::fixed: // is always dual feasible so we ingore it
 | 
			
		||||
        return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -302,28 +302,28 @@ template <typename T, typename X> T lp_dual_core_solver<T, X>::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_low_bounds[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];
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(m_p)) {
 | 
			
		||||
            return this->m_x[m_p] - this->m_low_bounds[m_p];
 | 
			
		||||
            return this->m_x[m_p] - this->m_lower_bounds[m_p];
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        if (this->x_above_upper_bound(m_p)) {
 | 
			
		||||
            return get_edge_steepness_for_upper_bound(m_p);
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
        return this->m_x[m_p] - this->m_upper_bounds[m_p];
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return zero_of_type<T>();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -370,11 +370,11 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::update_betas()
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> void lp_dual_core_solver<T, X>::apply_flips() {
 | 
			
		||||
    for (unsigned j : m_flipped_boxed) {
 | 
			
		||||
        SASSERT(this->x_is_at_bound(j));
 | 
			
		||||
        if (this->x_is_at_low_bound(j)) {
 | 
			
		||||
        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_low_bounds[j];
 | 
			
		||||
            this->m_x[j] = this->m_lower_bounds[j];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -382,17 +382,17 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::apply_flips()
 | 
			
		|||
template <typename T, typename X> void lp_dual_core_solver<T, X>::snap_xN_column_to_bounds(unsigned j) {
 | 
			
		||||
    switch (this->m_column_type[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
        this->m_x[j] = this->m_low_bounds[j];
 | 
			
		||||
        this->m_x[j] = this->m_lower_bounds[j];
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        if (this->x_is_at_low_bound(j)) {
 | 
			
		||||
            this->m_x[j] = this->m_low_bounds[j];
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        this->m_x[j] = this->m_low_bounds[j];
 | 
			
		||||
    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];
 | 
			
		||||
| 
						 | 
				
			
			@ -400,7 +400,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::snap_xN_column
 | 
			
		|||
    case column_type::free_column:
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -456,15 +456,15 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::basis_change_a
 | 
			
		|||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SASSERT(d_is_correct());
 | 
			
		||||
    lp_assert(d_is_correct());
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_core_solver<T, X>::recover_leaving() {
 | 
			
		||||
    switch (m_entering_boundary_position) {
 | 
			
		||||
    case at_low_bound:
 | 
			
		||||
    case at_lower_bound:
 | 
			
		||||
    case at_fixed:
 | 
			
		||||
        this->m_x[m_q] = this->m_low_bounds[m_q];
 | 
			
		||||
        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];
 | 
			
		||||
| 
						 | 
				
			
			@ -472,7 +472,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::recover_leavin
 | 
			
		|||
    case free_of_bounds:
 | 
			
		||||
        this->m_x[m_q] = zero_of_type<X>();
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -481,12 +481,12 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::revert_to_prev
 | 
			
		|||
    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(FLOATING_POINT_ERROR); // complete failure
 | 
			
		||||
        this->set_status(lp_status::FLOATING_POINT_ERROR); // complete failure
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    recover_leaving();
 | 
			
		||||
    if (!this->find_x_by_solving()) {
 | 
			
		||||
        this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
        this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    recalculate_xB_and_d();
 | 
			
		||||
| 
						 | 
				
			
			@ -497,23 +497,23 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::revert_to_prev
 | 
			
		|||
template <typename T, typename X> bool lp_dual_core_solver<T, X>::snap_runaway_nonbasic_column(unsigned j) {
 | 
			
		||||
    switch (this->m_column_types[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        if (!this->x_is_at_low_bound(j)) {
 | 
			
		||||
            this->m_x[j] = this->m_low_bounds[j];
 | 
			
		||||
    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_low_bound = abs(this->m_low_bounds[j] - this->m_x[j]) < abs(this->m_upper_bounds[j] - this->m_x[j]);
 | 
			
		||||
            if (closer_to_low_bound) {
 | 
			
		||||
                if (!this->x_is_at_low_bound(j)) {
 | 
			
		||||
                    this->m_x[j] = this->m_low_bounds[j];
 | 
			
		||||
            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_low_bounds[j];
 | 
			
		||||
                    this->m_x[j] = this->m_lower_bounds[j];
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -535,12 +535,6 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::snap_runaway_n
 | 
			
		|||
template <typename T, typename X> bool lp_dual_core_solver<T, X>::problem_is_dual_feasible() const {
 | 
			
		||||
    for (unsigned j : this->non_basis()){
 | 
			
		||||
        if (!this->column_is_dual_feasible(j)) {
 | 
			
		||||
            // std::cout << "column " << j << " is not dual feasible" << std::endl;
 | 
			
		||||
            // std::cout << "m_d[" << j << "] = " << this->m_d[j] << std::endl;
 | 
			
		||||
            // std::cout << "x[" << j << "] = " << this->m_x[j] << std::endl;
 | 
			
		||||
            // std::cout << "type = " << column_type_to_string(this->m_column_type[j]) << std::endl;
 | 
			
		||||
            // std::cout << "bounds = " << this->m_low_bounds[j] << "," << this->m_upper_bounds[j] << std::endl;
 | 
			
		||||
            // std::cout << "total_iterations = " << this->total_iterations() << std::endl;
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -566,10 +560,10 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::delta_keeps_th
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_core_solver<T, X>::set_status_to_tentative_dual_unbounded_or_dual_unbounded() {
 | 
			
		||||
    if (this->get_status() == TENTATIVE_DUAL_UNBOUNDED) {
 | 
			
		||||
        this->set_status(DUAL_UNBOUNDED);
 | 
			
		||||
    if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) {
 | 
			
		||||
        this->set_status(lp_status::DUAL_UNBOUNDED);
 | 
			
		||||
    } else {
 | 
			
		||||
        this->set_status(TENTATIVE_DUAL_UNBOUNDED);
 | 
			
		||||
        this->set_status(lp_status::TENTATIVE_DUAL_UNBOUNDED);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -599,10 +593,10 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::tight_breakpoi
 | 
			
		|||
template <typename T, typename X> T lp_dual_core_solver<T, X>::calculate_harris_delta_on_breakpoint_set() {
 | 
			
		||||
    bool first_time = true;
 | 
			
		||||
    T ret = zero_of_type<T>();
 | 
			
		||||
    SASSERT(m_breakpoint_set.size() > 0);
 | 
			
		||||
    lp_assert(m_breakpoint_set.size() > 0);
 | 
			
		||||
    for (auto j : m_breakpoint_set) {
 | 
			
		||||
        T t;
 | 
			
		||||
        if (this->x_is_at_low_bound(j)) {
 | 
			
		||||
        if (this->x_is_at_lower_bound(j)) {
 | 
			
		||||
            t = abs((std::max(this->m_d[j], numeric_traits<T>::zero()) + m_harris_tolerance) / this->m_pivot_row[j]);
 | 
			
		||||
        } else {
 | 
			
		||||
            t = abs((std::min(this->m_d[j], numeric_traits<T>::zero()) - m_harris_tolerance) / this->m_pivot_row[j]);
 | 
			
		||||
| 
						 | 
				
			
			@ -620,7 +614,7 @@ template <typename T, typename X> T lp_dual_core_solver<T, X>::calculate_harris_
 | 
			
		|||
template <typename T, typename X> void lp_dual_core_solver<T, X>::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_low_bound(j)) {
 | 
			
		||||
        if (this->x_is_at_lower_bound(j)) {
 | 
			
		||||
            if (abs(std::max(this->m_d[j], numeric_traits<T>::zero()) / this->m_pivot_row[j]) <= harris_delta){
 | 
			
		||||
                m_tight_set.insert(j);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -648,7 +642,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::find_q_on_tigh
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    m_tight_set.erase(m_q);
 | 
			
		||||
    SASSERT(m_q != -1);
 | 
			
		||||
    lp_assert(m_q != -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_core_solver<T, X>::find_q_and_tight_set() {
 | 
			
		||||
| 
						 | 
				
			
			@ -675,7 +669,7 @@ template <typename T, typename X> bool lp_dual_core_solver<T, X>::ratio_test() {
 | 
			
		|||
            set_status_to_tentative_dual_unbounded_or_dual_unbounded();
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        this->set_status(FEASIBLE);
 | 
			
		||||
        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;
 | 
			
		||||
| 
						 | 
				
			
			@ -731,19 +725,19 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::update_xb_afte
 | 
			
		|||
template <typename T, typename X> void lp_dual_core_solver<T, X>::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() == TENTATIVE_DUAL_UNBOUNDED) {
 | 
			
		||||
    if (this->get_status() == lp_status::TENTATIVE_DUAL_UNBOUNDED) {
 | 
			
		||||
        number_of_rows_to_try = this->m_m();
 | 
			
		||||
    } else {
 | 
			
		||||
        this->set_status(FEASIBLE);
 | 
			
		||||
        this->set_status(lp_status::FEASIBLE);
 | 
			
		||||
    }
 | 
			
		||||
    pricing_loop(number_of_rows_to_try, offset_in_rows);
 | 
			
		||||
    SASSERT(problem_is_dual_feasible());
 | 
			
		||||
    lp_assert(problem_is_dual_feasible());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_core_solver<T, X>::solve() { // see the page 35
 | 
			
		||||
    SASSERT(d_is_correct());
 | 
			
		||||
    SASSERT(problem_is_dual_feasible());
 | 
			
		||||
    SASSERT(this->basis_heading_is_correct());
 | 
			
		||||
    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 {
 | 
			
		||||
| 
						 | 
				
			
			@ -751,7 +745,7 @@ template <typename T, typename X> void lp_dual_core_solver<T, X>::solve() { // s
 | 
			
		|||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        one_iteration();
 | 
			
		||||
    } while (this->get_status() != FLOATING_POINT_ERROR && this->get_status() != DUAL_UNBOUNDED && this->get_status() != OPTIMAL &&
 | 
			
		||||
    } 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
 | 
			
		||||
             && this->total_iterations() <= this->m_settings.max_total_number_of_iterations);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -17,7 +17,7 @@ Revision History:
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
--*/
 | 
			
		||||
#include "util/lp/lp_dual_simplex.hpp"
 | 
			
		||||
#include "util/lp/lp_dual_simplex_def.h"
 | 
			
		||||
template lp::mpq lp::lp_dual_simplex<lp::mpq, lp::mpq>::get_current_cost() const;
 | 
			
		||||
template void lp::lp_dual_simplex<lp::mpq, lp::mpq>::find_maximal_solution();
 | 
			
		||||
template double lp::lp_dual_simplex<double, double>::get_current_cost() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -28,7 +28,7 @@ template <typename T, typename X>
 | 
			
		|||
class lp_dual_simplex: public lp_solver<T, X> {
 | 
			
		||||
    lp_dual_core_solver<T, X> * m_core_solver;
 | 
			
		||||
    vector<T> m_b_copy;
 | 
			
		||||
    vector<T> m_low_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<T> 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<column_type> m_column_types_of_core_solver;
 | 
			
		||||
    vector<column_type> m_column_types_of_logicals;
 | 
			
		||||
    vector<bool>  m_can_enter_basis;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -22,61 +22,61 @@ namespace lp{
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::decide_on_status_after_stage1() {
 | 
			
		||||
    switch (m_core_solver->get_status()) {
 | 
			
		||||
    case OPTIMAL:
 | 
			
		||||
    case lp_status::OPTIMAL:
 | 
			
		||||
        if (this->m_settings.abs_val_is_smaller_than_artificial_tolerance(m_core_solver->get_cost())) {
 | 
			
		||||
            this->m_status = FEASIBLE;
 | 
			
		||||
            this->m_status = lp_status::FEASIBLE;
 | 
			
		||||
        } else {
 | 
			
		||||
            this->m_status = UNBOUNDED;
 | 
			
		||||
            this->m_status = lp_status::UNBOUNDED;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case DUAL_UNBOUNDED:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
    case ITERATIONS_EXHAUSTED:
 | 
			
		||||
        this->m_status = ITERATIONS_EXHAUSTED;
 | 
			
		||||
    case lp_status::DUAL_UNBOUNDED:
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case lp_status::ITERATIONS_EXHAUSTED:
 | 
			
		||||
        this->m_status = lp_status::ITERATIONS_EXHAUSTED;
 | 
			
		||||
        break;
 | 
			
		||||
    case TIME_EXHAUSTED:
 | 
			
		||||
        this->m_status = TIME_EXHAUSTED;
 | 
			
		||||
    case lp_status::TIME_EXHAUSTED:
 | 
			
		||||
        this->m_status = lp_status::TIME_EXHAUSTED;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLOATING_POINT_ERROR:
 | 
			
		||||
        this->m_status = FLOATING_POINT_ERROR;
 | 
			
		||||
    case lp_status::FLOATING_POINT_ERROR:
 | 
			
		||||
        this->m_status = lp_status::FLOATING_POINT_ERROR;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::fix_logical_for_stage2(unsigned j) {
 | 
			
		||||
    SASSERT(j >= this->number_of_core_structurals());
 | 
			
		||||
    lp_assert(j >= this->number_of_core_structurals());
 | 
			
		||||
    switch (m_column_types_of_logicals[j - this->number_of_core_structurals()]) {
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        m_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        m_column_types_of_core_solver[j] = column_type::low_bound;
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        m_lower_bounds[j] = numeric_traits<T>::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_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_upper_bounds[j] = m_lower_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        m_column_types_of_core_solver[j] = column_type::fixed;
 | 
			
		||||
        m_can_enter_basis[j] = false;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::fix_structural_for_stage2(unsigned j) {
 | 
			
		||||
    column_info<T> * 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::low_bound:
 | 
			
		||||
        m_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        m_column_types_of_core_solver[j] = column_type::low_bound;
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        m_lower_bounds[j] = numeric_traits<T>::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:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        this->m_upper_bounds[j] = ci->get_adjusted_upper_bound() / this->m_column_scale[j];
 | 
			
		||||
        m_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        m_lower_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        m_column_types_of_core_solver[j] = column_type::boxed;
 | 
			
		||||
        m_can_enter_basis[j] = true;
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +85,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fix_structural_for
 | 
			
		|||
        m_column_types_of_core_solver[j] = column_type::free_column;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    //    T cost_was = this->m_costs[j];
 | 
			
		||||
    this->set_scaled_cost(j);
 | 
			
		||||
| 
						 | 
				
			
			@ -114,23 +114,23 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::solve_for_stage2()
 | 
			
		|||
    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(FEASIBLE);
 | 
			
		||||
    m_core_solver->set_status(lp_status::FEASIBLE);
 | 
			
		||||
    m_core_solver->solve();
 | 
			
		||||
    switch (m_core_solver->get_status()) {
 | 
			
		||||
    case OPTIMAL:
 | 
			
		||||
        this->m_status = OPTIMAL;
 | 
			
		||||
    case lp_status::OPTIMAL:
 | 
			
		||||
        this->m_status = lp_status::OPTIMAL;
 | 
			
		||||
        break;
 | 
			
		||||
    case DUAL_UNBOUNDED:
 | 
			
		||||
        this->m_status = INFEASIBLE;
 | 
			
		||||
    case lp_status::DUAL_UNBOUNDED:
 | 
			
		||||
        this->m_status = lp_status::INFEASIBLE;
 | 
			
		||||
        break;
 | 
			
		||||
    case TIME_EXHAUSTED:
 | 
			
		||||
        this->m_status = TIME_EXHAUSTED;
 | 
			
		||||
    case lp_status::TIME_EXHAUSTED:
 | 
			
		||||
        this->m_status = lp_status::TIME_EXHAUSTED;
 | 
			
		||||
        break;
 | 
			
		||||
    case FLOATING_POINT_ERROR:
 | 
			
		||||
        this->m_status = FLOATING_POINT_ERROR;
 | 
			
		||||
    case lp_status::FLOATING_POINT_ERROR:
 | 
			
		||||
        this->m_status = lp_status::FLOATING_POINT_ERROR;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        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);
 | 
			
		||||
| 
						 | 
				
			
			@ -144,7 +144,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_x_with_zeros(
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::stage1() {
 | 
			
		||||
    SASSERT(m_core_solver == nullptr);
 | 
			
		||||
    lp_assert(m_core_solver == nullptr);
 | 
			
		||||
    this->m_x.resize(this->m_A->column_count(), numeric_traits<T>::zero());
 | 
			
		||||
    if (this->m_settings.get_message_ostream() != nullptr)
 | 
			
		||||
        this->print_statistics_on_A(*this->m_settings.get_message_ostream());
 | 
			
		||||
| 
						 | 
				
			
			@ -158,7 +158,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::stage1() {
 | 
			
		|||
                                                  this->m_heading,
 | 
			
		||||
                                                  this->m_costs,
 | 
			
		||||
                                                  this->m_column_types_of_core_solver,
 | 
			
		||||
                                                  this->m_low_bounds,
 | 
			
		||||
                                                  this->m_lower_bounds,
 | 
			
		||||
                                                  this->m_upper_bounds,
 | 
			
		||||
                                                  this->m_settings,
 | 
			
		||||
                                                  *this);
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +166,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::stage1() {
 | 
			
		|||
    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(OPTIMAL);
 | 
			
		||||
        m_core_solver->set_status(lp_status::OPTIMAL);
 | 
			
		||||
        m_core_solver->set_total_iterations(0);
 | 
			
		||||
    } else {
 | 
			
		||||
        m_core_solver->solve();
 | 
			
		||||
| 
						 | 
				
			
			@ -192,7 +192,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_first_stage_s
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> column_type lp_dual_simplex<T, X>::get_column_type(unsigned j) {
 | 
			
		||||
    SASSERT(j < this->m_A->column_count());
 | 
			
		||||
    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()];
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -201,12 +201,12 @@ template <typename T, typename X> column_type lp_dual_simplex<T, X>::get_column_
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::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
 | 
			
		||||
    SASSERT(this->m_core_solver_columns_to_external_columns.find(j) !=
 | 
			
		||||
    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];
 | 
			
		||||
    SASSERT(this->m_map_from_var_index_to_column_info.find(jj) != this->m_map_from_var_index_to_column_info.end());
 | 
			
		||||
    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<T> * ci = this->m_map_from_var_index_to_column_info[jj];
 | 
			
		||||
    switch (ci->get_column_type()) {
 | 
			
		||||
    case column_type::upper_bound: {
 | 
			
		||||
| 
						 | 
				
			
			@ -216,10 +216,10 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_bounds_
 | 
			
		|||
        throw_exception(s.str());
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    case column_type::low_bound: {
 | 
			
		||||
    case column_type::lower_bound: {
 | 
			
		||||
        m_can_enter_basis[j] = true;
 | 
			
		||||
        this->set_scaled_cost(j);
 | 
			
		||||
        this->m_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_lower_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_upper_bounds[j] =numeric_traits<T>::one();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -227,30 +227,30 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_bounds_
 | 
			
		|||
        m_can_enter_basis[j] = true;
 | 
			
		||||
        this->set_scaled_cost(j);
 | 
			
		||||
        this->m_upper_bounds[j] = free_bound;
 | 
			
		||||
        this->m_low_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<T>::zero();
 | 
			
		||||
        this->m_upper_bounds[j] = this->m_low_bounds[j] =  numeric_traits<T>::zero(); // is it needed?
 | 
			
		||||
        this->m_upper_bounds[j] = this->m_lower_bounds[j] =  numeric_traits<T>::zero(); // is it needed?
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
    m_column_types_of_core_solver[j] = column_type::boxed;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_bounds_types_and_can_enter_basis_for_the_first_stage_solver_logical_column(unsigned j) {
 | 
			
		||||
    this->m_costs[j] = 0;
 | 
			
		||||
    SASSERT(get_column_type(j) != column_type::upper_bound);
 | 
			
		||||
    if ((m_can_enter_basis[j] = (get_column_type(j) == column_type::low_bound))) {
 | 
			
		||||
    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_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_lower_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_upper_bounds[j] = numeric_traits<T>::one();
 | 
			
		||||
    } else {
 | 
			
		||||
        m_column_types_of_core_solver[j] = column_type::fixed;
 | 
			
		||||
        this->m_low_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_lower_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
        this->m_upper_bounds[j] = numeric_traits<T>::zero();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -269,7 +269,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_costs_and_bou
 | 
			
		|||
template <typename T, typename X> void lp_dual_simplex<T, X>::fill_first_stage_solver_fields_for_row_slack_and_artificial(unsigned row,
 | 
			
		||||
                                                                                                                          unsigned & slack_var,
 | 
			
		||||
                                                                                                                          unsigned & artificial) {
 | 
			
		||||
    SASSERT(row < this->row_count());
 | 
			
		||||
    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];
 | 
			
		||||
| 
						 | 
				
			
			@ -283,7 +283,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_first_stage_s
 | 
			
		|||
        break;
 | 
			
		||||
 | 
			
		||||
    case Greater_or_equal:
 | 
			
		||||
        set_type_for_logical(slack_var, column_type::low_bound);
 | 
			
		||||
        set_type_for_logical(slack_var, column_type::lower_bound);
 | 
			
		||||
        (*this->m_A)(row, slack_var) = - numeric_traits<T>::one();
 | 
			
		||||
        if (rs > 0) {
 | 
			
		||||
            // adding one artificial
 | 
			
		||||
| 
						 | 
				
			
			@ -301,7 +301,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::fill_first_stage_s
 | 
			
		|||
        break;
 | 
			
		||||
    case Less_or_equal:
 | 
			
		||||
        // introduce a non-negative slack variable
 | 
			
		||||
        set_type_for_logical(slack_var, column_type::low_bound);
 | 
			
		||||
        set_type_for_logical(slack_var, column_type::lower_bound);
 | 
			
		||||
        (*this->m_A)(row, slack_var) = numeric_traits<T>::one();
 | 
			
		||||
        if (rs < 0) {
 | 
			
		||||
            // adding one artificial
 | 
			
		||||
| 
						 | 
				
			
			@ -328,7 +328,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::augment_matrix_A_a
 | 
			
		|||
    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_low_bounds.resize(n);
 | 
			
		||||
    this->m_lower_bounds.resize(n);
 | 
			
		||||
    m_can_enter_basis.resize(n);
 | 
			
		||||
    this->m_basis.resize(this->m_A->row_count());
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -351,7 +351,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::find_maximal_solut
 | 
			
		|||
    this->flip_costs(); // do it for now, todo ( remove the flipping)
 | 
			
		||||
 | 
			
		||||
    this->cleanup();
 | 
			
		||||
    if (this->m_status == INFEASIBLE) {
 | 
			
		||||
    if (this->m_status == lp_status::INFEASIBLE) {
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    this->fill_matrix_A_and_init_right_side();
 | 
			
		||||
| 
						 | 
				
			
			@ -361,7 +361,7 @@ template <typename T, typename X> void lp_dual_simplex<T, X>::find_maximal_solut
 | 
			
		|||
    fill_first_stage_solver_fields();
 | 
			
		||||
    copy_m_b_aside_and_set_it_to_zeros();
 | 
			
		||||
    stage1();
 | 
			
		||||
    if (this->m_status == FEASIBLE) {
 | 
			
		||||
    if (this->m_status == lp_status::FEASIBLE) {
 | 
			
		||||
        stage2();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -23,8 +23,8 @@ Revision History:
 | 
			
		|||
#include "util/vector.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lar_solver.h"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver.hpp"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver_tableau.h"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver_def.h"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver_tableau_def.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
template void lp_primal_core_solver<double, double>::find_feasible_solution();
 | 
			
		||||
| 
						 | 
				
			
			@ -37,10 +37,9 @@ Revision History:
 | 
			
		|||
#include "util/lp/breakpoint.h"
 | 
			
		||||
#include "util/lp/binary_heap_priority_queue.h"
 | 
			
		||||
#include "util/lp/int_set.h"
 | 
			
		||||
#include "util/lp/iterator_on_row.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
 | 
			
		||||
// This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x )
 | 
			
		||||
// 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 <typename T, typename X>
 | 
			
		||||
class lp_primal_core_solver:public lp_core_solver_base<T, X> {
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +84,7 @@ public:
 | 
			
		|||
    //     unsigned len = 100000000; 
 | 
			
		||||
    //     for (unsigned j : this->m_inf_set.m_index) {
 | 
			
		||||
    //         int i = this->m_basis_heading[j];
 | 
			
		||||
    //         SASSERT(i >= 0);
 | 
			
		||||
    //         lp_assert(i >= 0);
 | 
			
		||||
    //         unsigned row_len = this->m_A.m_rows[i].size();
 | 
			
		||||
    //         if (row_len < len) {
 | 
			
		||||
    //             choices.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -113,52 +112,52 @@ public:
 | 
			
		|||
    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
 | 
			
		||||
        SASSERT(this->m_basis_heading[j] < 0);
 | 
			
		||||
        SASSERT(this->column_is_feasible(j));
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (sign < 0)
 | 
			
		||||
                return true;
 | 
			
		||||
            return !this->x_is_at_low_bound(j);
 | 
			
		||||
            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_low_bound(j);
 | 
			
		||||
                return !this->x_is_at_lower_bound(j);
 | 
			
		||||
            return !this->x_is_at_upper_bound(j);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        SASSERT(false); // cannot be here
 | 
			
		||||
        lp_assert(false); // cannot be here
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    bool needs_to_grow(unsigned bj) const {
 | 
			
		||||
        SASSERT(!this->column_is_feasible(bj));
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            return this-> x_below_low_bound(bj);
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false); // unreachable
 | 
			
		||||
        lp_assert(false); // unreachable
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    int inf_sign_of_column(unsigned bj) const {
 | 
			
		||||
        SASSERT(!this->column_is_feasible(bj));
 | 
			
		||||
        lp_assert(!this->column_is_feasible(bj));
 | 
			
		||||
        switch(this->m_column_types[bj]) {
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
            return 0;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            return 1;
 | 
			
		||||
        case column_type::fixed: 
 | 
			
		||||
        case column_type::boxed:            
 | 
			
		||||
| 
						 | 
				
			
			@ -166,7 +165,7 @@ public:
 | 
			
		|||
        default:
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false); // unreachable
 | 
			
		||||
        lp_assert(false); // unreachable
 | 
			
		||||
        return 0;
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -174,15 +173,15 @@ public:
 | 
			
		|||
 | 
			
		||||
    bool monoid_can_decrease(const row_cell<T> & rc) const {
 | 
			
		||||
        unsigned j = rc.m_j;
 | 
			
		||||
        SASSERT(this->column_is_feasible(j));
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (is_pos(rc.get_val())) {
 | 
			
		||||
                return this->x_above_low_bound(j);
 | 
			
		||||
                return this->x_above_lower_bound(j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -194,28 +193,28 @@ public:
 | 
			
		|||
            return this->x_below_upper_bound(j);
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            if (is_pos(rc.get_val())) {
 | 
			
		||||
                return this->x_above_low_bound(j);
 | 
			
		||||
                return this->x_above_lower_bound(j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this->x_below_upper_bound(j);
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false); // unreachable
 | 
			
		||||
        lp_assert(false); // unreachable
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool monoid_can_increase(const row_cell<T> & rc) const {
 | 
			
		||||
        unsigned j = rc.m_j;
 | 
			
		||||
        SASSERT(this->column_is_feasible(j));
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (is_neg(rc.get_val())) {
 | 
			
		||||
                return this->x_above_low_bound(j);
 | 
			
		||||
                return this->x_above_lower_bound(j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
| 
						 | 
				
			
			@ -227,14 +226,14 @@ public:
 | 
			
		|||
            return this->x_below_upper_bound(j);
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            if (is_neg(rc.get_val())) {
 | 
			
		||||
                return this->x_above_low_bound(j);
 | 
			
		||||
                return this->x_above_lower_bound(j);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return this->x_below_upper_bound(j);
 | 
			
		||||
        default:
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
        SASSERT(false); // unreachable
 | 
			
		||||
        lp_assert(false); // unreachable
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -344,24 +343,24 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        SASSERT(m < 0 && this->m_column_types[j] == column_type::upper_bound);
 | 
			
		||||
        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_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        SASSERT(m < 0 && this->m_column_types[j] == column_type::low_bound);
 | 
			
		||||
        limit_inf_on_bound_m_neg(m, this->m_x[j], this->m_low_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_low_bound(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        SASSERT(m > 0 && this->m_column_types[j] == column_type::low_bound);
 | 
			
		||||
        limit_inf_on_low_bound_m_pos(m, this->m_x[j], this->m_low_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) {
 | 
			
		||||
        SASSERT(m > 0 && this->m_column_types[j] == column_type::upper_bound);
 | 
			
		||||
        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);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -370,7 +369,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void get_bound_on_variable_and_update_leaving_precisely(unsigned j, vector<unsigned> & leavings, T m, X & t, T & abs_of_d_of_leaving);
 | 
			
		||||
 | 
			
		||||
    vector<T> m_low_bounds_dummy; // needed for the base class only
 | 
			
		||||
    vector<T> m_lower_bounds_dummy; // needed for the base class only
 | 
			
		||||
 | 
			
		||||
    X get_max_bound(vector<X> & b);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -403,7 +402,7 @@ public:
 | 
			
		|||
    bool need_to_switch_costs() const {
 | 
			
		||||
        if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
 | 
			
		||||
            return false;
 | 
			
		||||
        //        SASSERT(calc_current_x_is_feasible() == current_x_is_feasible());
 | 
			
		||||
        //        lp_assert(calc_current_x_is_feasible() == current_x_is_feasible());
 | 
			
		||||
        return this->current_x_is_feasible() == this->m_using_infeas_costs;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +419,7 @@ public:
 | 
			
		|||
    // returns the number of iterations
 | 
			
		||||
    unsigned solve();
 | 
			
		||||
 | 
			
		||||
    lu<T, X> * factorization() {return this->m_factorization;}
 | 
			
		||||
    lu<static_matrix<T, X>> * factorization() {return this->m_factorization;}
 | 
			
		||||
 | 
			
		||||
    void delete_factorization();
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -445,7 +444,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void advance_on_entering_and_leaving_tableau_rows(int entering, int leaving, const X &theta ) {
 | 
			
		||||
        this->update_basis_and_x_tableau(entering, leaving, theta);
 | 
			
		||||
        this->update_column_in_inf_set(entering);
 | 
			
		||||
        this->track_column_feasibility(entering);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -458,23 +457,23 @@ public:
 | 
			
		|||
        if (j == -1)
 | 
			
		||||
            return -1;
 | 
			
		||||
 | 
			
		||||
        SASSERT(!this->column_is_feasible(j));
 | 
			
		||||
        lp_assert(!this->column_is_feasible(j));
 | 
			
		||||
        switch (this->m_column_types[j]) {
 | 
			
		||||
        case column_type::fixed:
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            new_val_for_leaving = this->m_upper_bounds[j];
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
            new_val_for_leaving = this->m_low_bounds[j];
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            new_val_for_leaving = this->m_lower_bounds[j];
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            if (this->x_above_upper_bound(j))
 | 
			
		||||
                new_val_for_leaving = this->m_upper_bounds[j];
 | 
			
		||||
            else
 | 
			
		||||
                new_val_for_leaving = this->m_low_bounds[j];
 | 
			
		||||
                new_val_for_leaving = this->m_lower_bounds[j];
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
            new_val_for_leaving = numeric_traits<T>::zero(); // does not matter
 | 
			
		||||
        }
 | 
			
		||||
        return j;
 | 
			
		||||
| 
						 | 
				
			
			@ -484,7 +483,7 @@ public:
 | 
			
		|||
        X new_val_for_leaving;
 | 
			
		||||
        int leaving = find_leaving_tableau_rows(new_val_for_leaving);
 | 
			
		||||
        if (leaving == -1) {
 | 
			
		||||
            this->set_status(OPTIMAL);
 | 
			
		||||
            this->set_status(lp_status::OPTIMAL);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -500,14 +499,14 @@ public:
 | 
			
		|||
        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(INFEASIBLE);
 | 
			
		||||
            this->set_status(lp_status::INFEASIBLE);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        X theta = (this->m_x[leaving] - new_val_for_leaving) / a_ent;
 | 
			
		||||
        advance_on_entering_and_leaving_tableau_rows(entering, leaving, theta );
 | 
			
		||||
        SASSERT(this->m_x[leaving] == new_val_for_leaving);
 | 
			
		||||
        lp_assert(this->m_x[leaving] == new_val_for_leaving);
 | 
			
		||||
        if (this->current_x_is_feasible())
 | 
			
		||||
            this->set_status(OPTIMAL);
 | 
			
		||||
            this->set_status(lp_status::OPTIMAL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void fill_breakpoints_array(unsigned entering);
 | 
			
		||||
| 
						 | 
				
			
			@ -522,30 +521,30 @@ public:
 | 
			
		|||
    void update_basis_and_x_with_comparison(unsigned entering, unsigned leaving, X delta);
 | 
			
		||||
 | 
			
		||||
    void decide_on_status_when_cannot_find_entering() {
 | 
			
		||||
        SASSERT(!need_to_switch_costs());
 | 
			
		||||
        this->set_status(this->current_x_is_feasible()? OPTIMAL: INFEASIBLE);
 | 
			
		||||
        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(unsigned j, const T & m, X & theta) {
 | 
			
		||||
    //     SASSERT(m < 0);
 | 
			
		||||
    //     SASSERT(this->m_column_type[j] == low_bound || this->m_column_type[j] == boxed);
 | 
			
		||||
    //     const X & eps = harris_eps_for_bound(this->m_low_bounds[j]);
 | 
			
		||||
    //     if (this->above_bound(this->m_x[j], this->m_low_bounds[j])) {
 | 
			
		||||
    //         theta = std::min((this->m_low_bounds[j] -this->m_x[j] - eps) / m, 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<X>()) theta = zero_of_type<X>();
 | 
			
		||||
    //     }
 | 
			
		||||
    // }
 | 
			
		||||
 | 
			
		||||
    void limit_theta_on_basis_column_for_feas_case_m_neg_no_check(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        SASSERT(m < 0);
 | 
			
		||||
        const X& eps = harris_eps_for_bound(this->m_low_bounds[j]);
 | 
			
		||||
        limit_theta((this->m_low_bounds[j] - this->m_x[j] - eps) / m, theta, 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<X>()) theta = zero_of_type<X>();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool limit_inf_on_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) {
 | 
			
		||||
        // x gets smaller
 | 
			
		||||
        SASSERT(m < 0);
 | 
			
		||||
        lp_assert(m < 0);
 | 
			
		||||
        if (numeric_traits<T>::precise()) {
 | 
			
		||||
            if (this->below_bound(x, bound)) return false;
 | 
			
		||||
            if (this->above_bound(x, bound)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -569,7 +568,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    bool limit_inf_on_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) {
 | 
			
		||||
        // x gets larger
 | 
			
		||||
        SASSERT(m > 0);
 | 
			
		||||
        lp_assert(m > 0);
 | 
			
		||||
        if (numeric_traits<T>::precise()) {
 | 
			
		||||
            if (this->above_bound(x, bound)) return false;
 | 
			
		||||
            if (this->below_bound(x, bound)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -591,17 +590,17 @@ public:
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void limit_inf_on_low_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) {
 | 
			
		||||
    void limit_inf_on_lower_bound_m_pos(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) {
 | 
			
		||||
        if (numeric_traits<T>::precise()) {
 | 
			
		||||
            // x gets larger
 | 
			
		||||
            SASSERT(m > 0);
 | 
			
		||||
            lp_assert(m > 0);
 | 
			
		||||
            if (this->below_bound(x, bound)) {
 | 
			
		||||
                limit_theta((bound - x) / m, theta, unlimited);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            // x gets larger
 | 
			
		||||
            SASSERT(m > 0);
 | 
			
		||||
            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);
 | 
			
		||||
| 
						 | 
				
			
			@ -611,7 +610,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void limit_inf_on_upper_bound_m_neg(const T & m, const X & x, const X & bound, X & theta, bool & unlimited) {
 | 
			
		||||
        // x gets smaller
 | 
			
		||||
        SASSERT(m < 0);
 | 
			
		||||
        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);
 | 
			
		||||
| 
						 | 
				
			
			@ -619,9 +618,9 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void limit_theta_on_basis_column_for_inf_case_m_pos_boxed(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        //        SASSERT(m > 0 && this->m_column_type[j] == column_type::boxed);
 | 
			
		||||
        //        lp_assert(m > 0 && this->m_column_type[j] == column_type::boxed);
 | 
			
		||||
        const X & x = this->m_x[j];
 | 
			
		||||
        const X & lbound = this->m_low_bounds[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]);
 | 
			
		||||
| 
						 | 
				
			
			@ -639,14 +638,14 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void limit_theta_on_basis_column_for_inf_case_m_neg_boxed(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        //  SASSERT(m < 0 && this->m_column_type[j] == column_type::boxed);
 | 
			
		||||
        //  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_low_bounds[j];
 | 
			
		||||
            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);
 | 
			
		||||
| 
						 | 
				
			
			@ -657,7 +656,7 @@ public:
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    void limit_theta_on_basis_column_for_feas_case_m_pos(unsigned j, const T & m, X & theta, bool & unlimited) {
 | 
			
		||||
        SASSERT(m > 0);
 | 
			
		||||
        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);
 | 
			
		||||
| 
						 | 
				
			
			@ -669,7 +668,7 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    void limit_theta_on_basis_column_for_feas_case_m_pos_no_check(unsigned j, const T & m, X & theta, bool & unlimited ) {
 | 
			
		||||
        SASSERT(m > 0);
 | 
			
		||||
        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<X>()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -679,7 +678,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    // 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_low_bounds[j]- harris_feasibility_tolerance ( if m < 0 )
 | 
			
		||||
    // x[j] + t * m >=  this->m_lower_bounds[j]- harris_feasibility_tolerance ( if m < 0 )
 | 
			
		||||
    // or
 | 
			
		||||
    // x[j] + t * m <= this->m_upper_bounds[j] + harris_feasibility_tolerance ( if m > 0)
 | 
			
		||||
    void limit_theta_on_basis_column(unsigned j, T m, X & theta, bool & unlimited) {
 | 
			
		||||
| 
						 | 
				
			
			@ -696,15 +695,15 @@ public:
 | 
			
		|||
                    limit_theta_on_basis_column_for_inf_case_m_neg_upper_bound(j, m, theta, unlimited);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        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_low_bound(j, m, theta, unlimited);
 | 
			
		||||
                    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_low_bound(j, m, theta, unlimited);
 | 
			
		||||
                    limit_theta_on_basis_column_for_inf_case_m_pos_lower_bound(j, m, theta, unlimited);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
            // case fixed:
 | 
			
		||||
| 
						 | 
				
			
			@ -735,7 +734,7 @@ public:
 | 
			
		|||
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_unreachable();
 | 
			
		||||
        }
 | 
			
		||||
        if (!unlimited && theta < zero_of_type<X>()) {
 | 
			
		||||
            theta = zero_of_type<X>();
 | 
			
		||||
| 
						 | 
				
			
			@ -770,7 +769,7 @@ public:
 | 
			
		|||
 | 
			
		||||
    void init_reduced_costs();
 | 
			
		||||
 | 
			
		||||
    bool low_bounds_are_set() const override { return true; }
 | 
			
		||||
    bool lower_bounds_are_set() const override { return true; }
 | 
			
		||||
 | 
			
		||||
    int advance_on_sorted_breakpoints(unsigned entering, X & t);
 | 
			
		||||
    
 | 
			
		||||
| 
						 | 
				
			
			@ -794,7 +793,7 @@ public:
 | 
			
		|||
            if (this->m_basis_heading[j] < 0)
 | 
			
		||||
                continue;
 | 
			
		||||
            if (!this->column_is_feasible(j))
 | 
			
		||||
                this->m_inf_set.insert(j);
 | 
			
		||||
                this->insert_column_into_inf_set(j);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -807,7 +806,7 @@ public:
 | 
			
		|||
            if (this->x_above_upper_bound(j))
 | 
			
		||||
                return 1;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            if (this->x_below_low_bound(j))
 | 
			
		||||
                return -1;
 | 
			
		||||
            break;
 | 
			
		||||
| 
						 | 
				
			
			@ -818,7 +817,7 @@ public:
 | 
			
		|||
        case column_type::free_column:
 | 
			
		||||
            return 0;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -842,18 +841,18 @@ public:
 | 
			
		|||
        case column_type::fixed:
 | 
			
		||||
            return 0;
 | 
			
		||||
        case column_type::boxed:
 | 
			
		||||
            if (this->x_is_at_low_bound(j))
 | 
			
		||||
            if (this->x_is_at_lower_bound(j))
 | 
			
		||||
                return 1;
 | 
			
		||||
            return -1;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            return 1;
 | 
			
		||||
            break;
 | 
			
		||||
        case column_type::upper_bound:
 | 
			
		||||
            return -1;
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            SASSERT(false);
 | 
			
		||||
            lp_assert(false);
 | 
			
		||||
        }
 | 
			
		||||
        return 0;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -879,7 +878,7 @@ public:
 | 
			
		|||
 | 
			
		||||
// 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) {
 | 
			
		||||
        SASSERT(this->m_basis_heading[j] >= 0);
 | 
			
		||||
        lp_assert(this->m_basis_heading[j] >= 0);
 | 
			
		||||
        unsigned i = static_cast<unsigned>(this->m_basis_heading[j]);
 | 
			
		||||
        for (const row_cell<T> & rc : this->m_A.m_rows[i]) {
 | 
			
		||||
            unsigned k = rc.m_j;
 | 
			
		||||
| 
						 | 
				
			
			@ -906,7 +905,7 @@ public:
 | 
			
		|||
                          vector<int> & heading,
 | 
			
		||||
                          vector<T> & costs,
 | 
			
		||||
                          const vector<column_type> & column_type_array,
 | 
			
		||||
                          const vector<X> & low_bound_values,
 | 
			
		||||
                          const vector<X> & lower_bound_values,
 | 
			
		||||
                          const vector<X> & upper_bound_values,
 | 
			
		||||
                          lp_settings & settings,
 | 
			
		||||
                          const column_namer& column_names):
 | 
			
		||||
| 
						 | 
				
			
			@ -919,7 +918,7 @@ public:
 | 
			
		|||
                                  settings,
 | 
			
		||||
                                  column_names,
 | 
			
		||||
                                  column_type_array,
 | 
			
		||||
                                  low_bound_values,
 | 
			
		||||
                                  lower_bound_values,
 | 
			
		||||
                                  upper_bound_values),
 | 
			
		||||
        m_beta(A.row_count()),
 | 
			
		||||
        m_epsilon_of_reduced_cost(T(1)/T(10000000)),
 | 
			
		||||
| 
						 | 
				
			
			@ -930,7 +929,7 @@ public:
 | 
			
		|||
        } else {
 | 
			
		||||
            m_converted_harris_eps = zero_of_type<T>();
 | 
			
		||||
        }
 | 
			
		||||
        this->set_status(UNKNOWN);
 | 
			
		||||
        this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // constructor
 | 
			
		||||
| 
						 | 
				
			
			@ -954,12 +953,12 @@ public:
 | 
			
		|||
                                  settings,
 | 
			
		||||
                                  column_names,
 | 
			
		||||
                                  column_type_array,
 | 
			
		||||
                                  m_low_bounds_dummy,
 | 
			
		||||
                                  m_lower_bounds_dummy,
 | 
			
		||||
                                  upper_bound_values),
 | 
			
		||||
        m_beta(A.row_count()),
 | 
			
		||||
        m_converted_harris_eps(convert_struct<T, double>::convert(this->m_settings.harris_feasibility_tolerance)) {
 | 
			
		||||
        SASSERT(initial_x_is_correct());
 | 
			
		||||
        m_low_bounds_dummy.resize(A.column_count(), zero_of_type<T>());
 | 
			
		||||
        lp_assert(initial_x_is_correct());
 | 
			
		||||
        m_lower_bounds_dummy.resize(A.column_count(), zero_of_type<T>());
 | 
			
		||||
        m_enter_price_eps = numeric_traits<T>::precise() ? numeric_traits<T>::zero() : T(1e-5);
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
        // check_correctness();
 | 
			
		||||
| 
						 | 
				
			
			@ -972,7 +971,7 @@ public:
 | 
			
		|||
            basis_set.insert(this->m_basis[i]);
 | 
			
		||||
        }
 | 
			
		||||
        for (unsigned j = 0; j < this->m_n(); j++) {
 | 
			
		||||
            if (this->column_has_low_bound(j) && this->m_x[j] < numeric_traits<T>::zero()) {
 | 
			
		||||
            if (this->column_has_lower_bound(j) && this->m_x[j] < numeric_traits<T>::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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -983,7 +982,7 @@ public:
 | 
			
		|||
            }
 | 
			
		||||
 | 
			
		||||
            if (basis_set.find(j) != basis_set.end()) continue;
 | 
			
		||||
            if (this->m_column_types[j] == column_type::low_bound)  {
 | 
			
		||||
            if (this->m_column_types[j] == column_type::lower_bound)  {
 | 
			
		||||
                if (numeric_traits<T>::zero() != this->m_x[j]) {
 | 
			
		||||
                    LP_OUT(this->m_settings, "only low bound is set for " << j << " but low bound value " << numeric_traits<T>::zero() << " is not equal to " << this->m_x[j] << std::endl);
 | 
			
		||||
                    return false;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -25,12 +25,12 @@ Revision History:
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "util/lp/lp_primal_core_solver.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
// This core solver solves (Ax=b, low_bound_values \leq x \leq upper_bound_values, maximize costs*x )
 | 
			
		||||
// 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 <typename T, typename X>
 | 
			
		||||
void lp_primal_core_solver<T, X>::sort_non_basis_rational() {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert(numeric_traits<T>::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);
 | 
			
		||||
| 
						 | 
				
			
			@ -84,12 +84,12 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_on_breakpoin
 | 
			
		|||
    bool ret;
 | 
			
		||||
    const T & d = this->m_d[j];
 | 
			
		||||
    switch (this->m_column_types[j]) {
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        SASSERT(this->x_is_at_low_bound(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:
 | 
			
		||||
        SASSERT(this->x_is_at_upper_bound(j));
 | 
			
		||||
        lp_assert(this->x_is_at_upper_bound(j));
 | 
			
		||||
        ret = d > m_epsilon_of_reduced_cost;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
| 
						 | 
				
			
			@ -97,16 +97,16 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_on_breakpoin
 | 
			
		|||
        break;
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        {
 | 
			
		||||
            bool low_bound = this->x_is_at_low_bound(j);
 | 
			
		||||
            SASSERT(low_bound || this->x_is_at_upper_bound(j));
 | 
			
		||||
            ret = (low_bound && d < -m_epsilon_of_reduced_cost) || ((!low_bound) && d > m_epsilon_of_reduced_cost);
 | 
			
		||||
            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:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
        ret = false;
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -125,7 +125,7 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis(unsign
 | 
			
		|||
        if (dj > m_epsilon_of_reduced_cost || dj < -m_epsilon_of_reduced_cost)
 | 
			
		||||
            return true;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (dj > m_epsilon_of_reduced_cost) return true;;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
| 
						 | 
				
			
			@ -137,19 +137,19 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis(unsign
 | 
			
		|||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (dj < - m_epsilon_of_reduced_cost) {
 | 
			
		||||
            if (this->m_x[j] > this->m_low_bounds[j] + this->bound_span(j)/2)
 | 
			
		||||
            if (this->m_x[j] > this->m_lower_bounds[j] + this->bound_span(j)/2)
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis_precise(unsigned j) const {
 | 
			
		||||
    SASSERT (numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert (numeric_traits<T>::precise());
 | 
			
		||||
    if (this->m_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];
 | 
			
		||||
| 
						 | 
				
			
			@ -159,9 +159,9 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis_precis
 | 
			
		|||
        if (!is_zero(dj))
 | 
			
		||||
            return true;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (dj > zero_of_type<T>()) return true;
 | 
			
		||||
        if (dj < 0 && this->m_x[j] > this->m_low_bounds[j]){
 | 
			
		||||
        if (dj < 0 && this->m_x[j] > this->m_lower_bounds[j]){
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
| 
						 | 
				
			
			@ -177,12 +177,12 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis_precis
 | 
			
		|||
                return true;
 | 
			
		||||
            break;
 | 
			
		||||
        } else if (dj < zero_of_type<T>()) {
 | 
			
		||||
            if (this->m_x[j] > this->m_low_bounds[j])
 | 
			
		||||
            if (this->m_x[j] > this->m_lower_bounds[j])
 | 
			
		||||
                return true;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
| 
						 | 
				
			
			@ -190,7 +190,7 @@ bool lp_primal_core_solver<T, X>::column_is_benefitial_for_entering_basis_precis
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
int lp_primal_core_solver<T, X>::choose_entering_column_presize(unsigned number_of_benefitial_columns_to_go_over) { // at this moment m_y = cB * B(-1)
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise());
 | 
			
		||||
    if (number_of_benefitial_columns_to_go_over == 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    if (this->m_basis_sort_counter == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -274,7 +274,7 @@ int lp_primal_core_solver<T, X>::choose_entering_column(unsigned number_of_benef
 | 
			
		|||
template <typename T, typename X> int lp_primal_core_solver<T, X>::advance_on_sorted_breakpoints(unsigned entering, X &t) {
 | 
			
		||||
    T slope_at_entering = this->m_d[entering];
 | 
			
		||||
    breakpoint<X> * last_bp = nullptr;
 | 
			
		||||
    SASSERT(m_breakpoint_indices_queue.is_empty()==false);
 | 
			
		||||
    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<X> *b = &m_breakpoints[bi];
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +289,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::advance_on_so
 | 
			
		|||
            }
 | 
			
		||||
        }        
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT (last_bp != nullptr);
 | 
			
		||||
    lp_assert (last_bp != nullptr);
 | 
			
		||||
    t = last_bp->m_delta;
 | 
			
		||||
    return last_bp->m_j;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -297,13 +297,13 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::advance_on_so
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X> int
 | 
			
		||||
lp_primal_core_solver<T, X>::find_leaving_and_t_with_breakpoints(unsigned entering, X & t){
 | 
			
		||||
    SASSERT(this->precise() == false);
 | 
			
		||||
    lp_assert(this->precise() == false);
 | 
			
		||||
    fill_breakpoints_array(entering);
 | 
			
		||||
    return advance_on_sorted_breakpoints(entering, t);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_primal_core_solver<T, X>::get_harris_theta(X & theta) {
 | 
			
		||||
    SASSERT(this->m_ed.is_OK());
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -360,13 +360,13 @@ template <typename T, typename X> bool lp_primal_core_solver<T, X>::try_jump_to_
 | 
			
		|||
            if (m_sign_of_entering_delta > 0) {
 | 
			
		||||
                t = this->m_upper_bounds[entering] - this->m_x[entering];
 | 
			
		||||
                if (unlimited || t <= theta){
 | 
			
		||||
                    SASSERT(t >= zero_of_type<X>());
 | 
			
		||||
                    lp_assert(t >= zero_of_type<X>());
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            } else { // m_sign_of_entering_delta == -1
 | 
			
		||||
                t = this->m_x[entering] - this->m_low_bounds[entering];
 | 
			
		||||
                t = this->m_x[entering] - this->m_lower_bounds[entering];
 | 
			
		||||
                if (unlimited || t <= theta) {
 | 
			
		||||
                    SASSERT(t >= zero_of_type<X>());
 | 
			
		||||
                    lp_assert(t >= zero_of_type<X>());
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -375,16 +375,16 @@ template <typename T, typename X> bool lp_primal_core_solver<T, X>::try_jump_to_
 | 
			
		|||
        if (m_sign_of_entering_delta > 0) {
 | 
			
		||||
            t = this->m_upper_bounds[entering] - this->m_x[entering];
 | 
			
		||||
            if (unlimited || t <= theta){
 | 
			
		||||
                SASSERT(t >= zero_of_type<X>());
 | 
			
		||||
                lp_assert(t >= zero_of_type<X>());
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return false;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (m_sign_of_entering_delta < 0) {
 | 
			
		||||
                t = this->m_x[entering] - this->m_low_bounds[entering];
 | 
			
		||||
                t = this->m_x[entering] - this->m_lower_bounds[entering];
 | 
			
		||||
                if (unlimited || t <= theta) {
 | 
			
		||||
                    SASSERT(t >= zero_of_type<X>());
 | 
			
		||||
                    lp_assert(t >= zero_of_type<X>());
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -404,7 +404,7 @@ try_jump_to_another_bound_on_entering_unlimited(unsigned entering, X & t ) {
 | 
			
		|||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
     // m_sign_of_entering_delta == -1
 | 
			
		||||
    t = this->m_x[entering] - this->m_low_bounds[entering];
 | 
			
		||||
    t = this->m_x[entering] - this->m_lower_bounds[entering];
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -420,7 +420,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
 | 
			
		|||
    do {
 | 
			
		||||
        unsigned i = this->m_ed.m_index[k];
 | 
			
		||||
        const T & ed = this->m_ed[i];
 | 
			
		||||
        SASSERT(!numeric_traits<T>::is_zero(ed));
 | 
			
		||||
        lp_assert(!numeric_traits<T>::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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -439,7 +439,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
 | 
			
		|||
    while (k != initial_k) {
 | 
			
		||||
        unsigned i = this->m_ed.m_index[k];
 | 
			
		||||
        const T & ed = this->m_ed[i];
 | 
			
		||||
        SASSERT(!numeric_traits<T>::is_zero(ed));
 | 
			
		||||
        lp_assert(!numeric_traits<T>::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);
 | 
			
		||||
| 
						 | 
				
			
			@ -479,7 +479,7 @@ template <typename T, typename X>    int lp_primal_core_solver<T, X>::find_leavi
 | 
			
		|||
        return find_leaving_and_t_with_breakpoints(entering, t);
 | 
			
		||||
    X theta;
 | 
			
		||||
    bool unlimited = get_harris_theta(theta);
 | 
			
		||||
    SASSERT(unlimited || theta >= zero_of_type<X>());
 | 
			
		||||
    lp_assert(unlimited || theta >= zero_of_type<X>());
 | 
			
		||||
    if (try_jump_to_another_bound_on_entering(entering, theta, t, unlimited)) return entering;
 | 
			
		||||
    if (unlimited)
 | 
			
		||||
        return -1;
 | 
			
		||||
| 
						 | 
				
			
			@ -489,7 +489,7 @@ template <typename T, typename X>    int lp_primal_core_solver<T, X>::find_leavi
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
// m is the multiplier. updating t in a way that holds the following
 | 
			
		||||
// x[j] + t * m >= m_low_bounds[j] ( if m < 0 )
 | 
			
		||||
// x[j] + t * m >= m_lower_bounds[j] ( if m < 0 )
 | 
			
		||||
// or
 | 
			
		||||
// x[j] + t * m <= this->m_upper_bounds[j] ( if m > 0)
 | 
			
		||||
template <typename T, typename X> void
 | 
			
		||||
| 
						 | 
				
			
			@ -501,7 +501,7 @@ lp_primal_core_solver<T, X>::get_bound_on_variable_and_update_leaving_precisely(
 | 
			
		|||
            return;
 | 
			
		||||
        default:break;
 | 
			
		||||
        }
 | 
			
		||||
        X tt = - (this->m_low_bounds[j] - this->m_x[j]) / m;
 | 
			
		||||
        X tt = - (this->m_lower_bounds[j] - this->m_x[j]) / m;
 | 
			
		||||
        if (numeric_traits<X>::is_neg(tt))
 | 
			
		||||
            tt = zero_of_type<X>();
 | 
			
		||||
        if (leavings.size() == 0 || tt < t || (tt == t && m > abs_of_d_of_leaving)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -516,7 +516,7 @@ lp_primal_core_solver<T, X>::get_bound_on_variable_and_update_leaving_precisely(
 | 
			
		|||
    } else if (m < 0){
 | 
			
		||||
        switch (this->m_column_types[j]) { // check that j has an upper bound
 | 
			
		||||
        case column_type::free_column:
 | 
			
		||||
        case column_type::low_bound:
 | 
			
		||||
        case column_type::lower_bound:
 | 
			
		||||
            return;
 | 
			
		||||
        default:break;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -548,7 +548,7 @@ template <typename T, typename X>    X lp_primal_core_solver<T, X>::get_max_boun
 | 
			
		|||
template <typename T, typename X>   void lp_primal_core_solver<T, X>::check_Ax_equal_b() {
 | 
			
		||||
    dense_matrix<T, X> d(this->m_A);
 | 
			
		||||
    T * ls = d.apply_from_left_with_different_dims(this->m_x);
 | 
			
		||||
    SASSERT(vectors_are_equal<T>(ls, this->m_b, this->m_m()));
 | 
			
		||||
    lp_assert(vectors_are_equal<T>(ls, this->m_b, this->m_m()));
 | 
			
		||||
    delete [] ls;
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::check_the_bounds() {
 | 
			
		||||
| 
						 | 
				
			
			@ -558,8 +558,8 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::check_the
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::check_bound(unsigned i) {
 | 
			
		||||
    SASSERT (!(this->column_has_low_bound(i) && (numeric_traits<T>::zero() > this->m_x[i])));
 | 
			
		||||
    SASSERT (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i])));
 | 
			
		||||
    lp_assert (!(this->column_has_lower_bound(i) && (numeric_traits<T>::zero() > this->m_x[i])));
 | 
			
		||||
    lp_assert (!(this->column_has_upper_bound(i) && (this->m_upper_bounds[i] < this->m_x[i])));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::check_correctness() {
 | 
			
		||||
| 
						 | 
				
			
			@ -575,8 +575,8 @@ void lp_primal_core_solver<T, X>::update_reduced_costs_from_pivot_row(unsigned e
 | 
			
		|||
    // the basis heading has changed already
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    auto & basis_heading = this->m_basis_heading;
 | 
			
		||||
    SASSERT(basis_heading[entering] >= 0 && static_cast<unsigned>(basis_heading[entering]) < this->m_m());
 | 
			
		||||
    SASSERT(basis_heading[leaving] < 0);
 | 
			
		||||
    lp_assert(basis_heading[entering] >= 0 && static_cast<unsigned>(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;
 | 
			
		||||
| 
						 | 
				
			
			@ -599,7 +599,7 @@ void lp_primal_core_solver<T, X>::update_reduced_costs_from_pivot_row(unsigned e
 | 
			
		|||
template <typename T, typename X>    int lp_primal_core_solver<T, X>::refresh_reduced_cost_at_entering_and_check_that_it_is_off(unsigned entering) {
 | 
			
		||||
    if (numeric_traits<T>::precise()) return 0;
 | 
			
		||||
    T reduced_at_entering_was = this->m_d[entering];  // can benefit from going over non-zeros of m_ed
 | 
			
		||||
    SASSERT(abs(reduced_at_entering_was) > m_epsilon_of_reduced_cost);
 | 
			
		||||
    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];
 | 
			
		||||
| 
						 | 
				
			
			@ -634,7 +634,7 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::backup_an
 | 
			
		|||
        m_costs_backup = this->m_costs;
 | 
			
		||||
    } else {
 | 
			
		||||
        T cost_max = std::max(max_abs_in_vector(this->m_costs), T(1));
 | 
			
		||||
        SASSERT(m_costs_backup.size() == 0);
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -664,16 +664,16 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::init_run(
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::calc_working_vector_beta_for_column_norms(){
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise() == false);
 | 
			
		||||
    SASSERT(this->m_ed.is_OK());
 | 
			
		||||
    SASSERT(m_beta.is_OK());
 | 
			
		||||
    lp_assert(numeric_traits<T>::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);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving(int entering, X & t) {
 | 
			
		||||
    SASSERT(!this->A_mult_x_is_off() );
 | 
			
		||||
    CASSERT("A_off", !this->A_mult_x_is_off() );
 | 
			
		||||
    this->update_x(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();
 | 
			
		||||
| 
						 | 
				
			
			@ -685,7 +685,7 @@ void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving(int entering
 | 
			
		|||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (this->m_using_infeas_costs) {
 | 
			
		||||
        SASSERT(is_zero(this->m_costs[entering])); 
 | 
			
		||||
        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())
 | 
			
		||||
| 
						 | 
				
			
			@ -698,10 +698,10 @@ void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving(int entering
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_entering_and_leaving(int entering, int leaving, X & t) {
 | 
			
		||||
    SASSERT(entering >= 0 && m_non_basis_list.back() == static_cast<unsigned>(entering));
 | 
			
		||||
    SASSERT(this->m_using_infeas_costs || t >= zero_of_type<X>());
 | 
			
		||||
    SASSERT(leaving >= 0 && entering >= 0);
 | 
			
		||||
    SASSERT(entering != leaving || !is_zero(t)); // otherwise nothing changes
 | 
			
		||||
    lp_assert(entering >= 0 && m_non_basis_list.back() == static_cast<unsigned>(entering));
 | 
			
		||||
    lp_assert(this->m_using_infeas_costs || t >= zero_of_type<X>());
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -713,14 +713,14 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
    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(UNSTABLE);
 | 
			
		||||
        this->set_status(lp_status::UNSTABLE);
 | 
			
		||||
        this->iters_with_no_cost_growing()++;
 | 
			
		||||
        return;
 | 
			
		||||
    } else {
 | 
			
		||||
        SASSERT(pivot_compare_result == 1);
 | 
			
		||||
        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(UNSTABLE);
 | 
			
		||||
            this->set_status(lp_status::UNSTABLE);
 | 
			
		||||
            this->iters_with_no_cost_growing()++;
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -732,10 +732,10 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
            t = -t;
 | 
			
		||||
    }
 | 
			
		||||
    if (!this->update_basis_and_x(entering, leaving, t)) {
 | 
			
		||||
        if (this->get_status() == FLOATING_POINT_ERROR)
 | 
			
		||||
        if (this->get_status() == lp_status::FLOATING_POINT_ERROR)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this->m_look_for_feasible_solution_only) {
 | 
			
		||||
            this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
            this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        init_reduced_costs();
 | 
			
		||||
| 
						 | 
				
			
			@ -748,7 +748,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    if (this->current_x_is_feasible()) {
 | 
			
		||||
        this->set_status(FEASIBLE);
 | 
			
		||||
        this->set_status(lp_status::FEASIBLE);
 | 
			
		||||
        if (this->m_look_for_feasible_solution_only)
 | 
			
		||||
            return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -761,7 +761,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
    }  else {
 | 
			
		||||
        update_reduced_costs_from_pivot_row(entering, leaving);
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(!need_to_switch_costs());
 | 
			
		||||
    lp_assert(!need_to_switch_costs());
 | 
			
		||||
    std::list<unsigned>::iterator it = m_non_basis_list.end();
 | 
			
		||||
    it--;
 | 
			
		||||
    * it = static_cast<unsigned>(leaving);
 | 
			
		||||
| 
						 | 
				
			
			@ -769,13 +769,13 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_entering_precise(int entering) {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise());
 | 
			
		||||
    SASSERT(entering > -1);
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert(entering > -1);
 | 
			
		||||
    this->solve_Bd(entering);
 | 
			
		||||
    X t;
 | 
			
		||||
    int leaving = find_leaving_and_t_precise(entering, t);
 | 
			
		||||
    if (leaving == -1) {
 | 
			
		||||
        this->set_status(UNBOUNDED);
 | 
			
		||||
        this->set_status(lp_status::UNBOUNDED);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    advance_on_entering_and_leaving(entering, leaving, t);
 | 
			
		||||
| 
						 | 
				
			
			@ -786,12 +786,12 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_e
 | 
			
		|||
        advance_on_entering_precise(entering);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(entering > -1);
 | 
			
		||||
    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(FLOATING_POINT_ERROR);
 | 
			
		||||
            this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -806,7 +806,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_e
 | 
			
		|||
    int leaving = find_leaving_and_t(entering, t);
 | 
			
		||||
    if (leaving == -1){
 | 
			
		||||
        if (!this->current_x_is_feasible()) {
 | 
			
		||||
            SASSERT(!numeric_traits<T>::precise()); // we cannot have unbounded with inf costs
 | 
			
		||||
            lp_assert(!numeric_traits<T>::precise()); // we cannot have unbounded with inf costs
 | 
			
		||||
               
 | 
			
		||||
            // if (m_look_for_feasible_solution_only) {
 | 
			
		||||
            //     this->m_status = INFEASIBLE;
 | 
			
		||||
| 
						 | 
				
			
			@ -814,19 +814,19 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_e
 | 
			
		|||
            //  }
 | 
			
		||||
            
 | 
			
		||||
                
 | 
			
		||||
            if (this->get_status() == UNSTABLE) {
 | 
			
		||||
                this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
            if (this->get_status() == lp_status::UNSTABLE) {
 | 
			
		||||
                this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
            init_infeasibility_costs();
 | 
			
		||||
            this->set_status(UNSTABLE);
 | 
			
		||||
            this->set_status(lp_status::UNSTABLE);
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        if (this->get_status() == TENTATIVE_UNBOUNDED) {
 | 
			
		||||
            this->set_status(UNBOUNDED);
 | 
			
		||||
        if (this->get_status() == lp_status::TENTATIVE_UNBOUNDED) {
 | 
			
		||||
            this->set_status(lp_status::UNBOUNDED);
 | 
			
		||||
        } else {
 | 
			
		||||
            this->set_status(TENTATIVE_UNBOUNDED);
 | 
			
		||||
            this->set_status(lp_status::TENTATIVE_UNBOUNDED);
 | 
			
		||||
        }
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -840,7 +840,7 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::push_forw
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>  unsigned lp_primal_core_solver<T, X>::get_number_of_non_basic_column_to_try_for_enter() {
 | 
			
		||||
    unsigned ret = static_cast<unsigned>(this->m_nbasis.size());
 | 
			
		||||
    if (this->get_status() == TENTATIVE_UNBOUNDED)
 | 
			
		||||
    if (this->get_status() == lp_status::TENTATIVE_UNBOUNDED)
 | 
			
		||||
        return ret; // we really need to find entering with a large reduced cost
 | 
			
		||||
    if (ret > 300) {
 | 
			
		||||
        ret = (unsigned)(ret * this->m_settings.percent_of_entering_to_check / 100);
 | 
			
		||||
| 
						 | 
				
			
			@ -864,15 +864,15 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::print_column
 | 
			
		|||
template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve() {
 | 
			
		||||
    if (numeric_traits<T>::precise() && this->m_settings.use_tableau())
 | 
			
		||||
        return solve_with_tableau();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    init_run();
 | 
			
		||||
    if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) {
 | 
			
		||||
        this->set_status(FEASIBLE);
 | 
			
		||||
        this->set_status(lp_status::FEASIBLE);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    if ((!numeric_traits<T>::precise()) && this->A_mult_x_is_off()) {
 | 
			
		||||
        this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
        this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
    do {
 | 
			
		||||
| 
						 | 
				
			
			@ -880,10 +880,11 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
            return this->total_iterations();
 | 
			
		||||
        }
 | 
			
		||||
        one_iteration();
 | 
			
		||||
        SASSERT(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros());
 | 
			
		||||
 | 
			
		||||
        lp_assert(!this->m_using_infeas_costs || this->costs_on_nbasis_are_zeros());
 | 
			
		||||
        switch (this->get_status()) {
 | 
			
		||||
        case OPTIMAL:  // double check that we are at optimum
 | 
			
		||||
        case INFEASIBLE:
 | 
			
		||||
        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;
 | 
			
		||||
            if (!numeric_traits<T>::precise()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -892,7 +893,7 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
                this->init_lu();
 | 
			
		||||
                
 | 
			
		||||
                if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                    this->set_status (FLOATING_POINT_ERROR);
 | 
			
		||||
                    this->set_status (lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                init_reduced_costs();
 | 
			
		||||
| 
						 | 
				
			
			@ -900,7 +901,7 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
                    decide_on_status_when_cannot_find_entering();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                this->set_status(UNKNOWN);
 | 
			
		||||
                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();
 | 
			
		||||
| 
						 | 
				
			
			@ -908,31 +909,31 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
                        decide_on_status_when_cannot_find_entering();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    this->set_status(UNKNOWN);
 | 
			
		||||
                    this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case TENTATIVE_UNBOUNDED:
 | 
			
		||||
        case lp_status::TENTATIVE_UNBOUNDED:
 | 
			
		||||
            this->init_lu();
 | 
			
		||||
            if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
                this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            init_reduced_costs();
 | 
			
		||||
            break;
 | 
			
		||||
        case UNBOUNDED:
 | 
			
		||||
        case lp_status::UNBOUNDED:
 | 
			
		||||
            if (this->current_x_is_infeasible()) {
 | 
			
		||||
                init_reduced_costs();
 | 
			
		||||
                this->set_status(UNKNOWN);
 | 
			
		||||
                this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case UNSTABLE:
 | 
			
		||||
            SASSERT(! (numeric_traits<T>::precise()));
 | 
			
		||||
        case lp_status::UNSTABLE:
 | 
			
		||||
            lp_assert(! (numeric_traits<T>::precise()));
 | 
			
		||||
            this->init_lu();
 | 
			
		||||
            if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
                this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            init_reduced_costs();
 | 
			
		||||
| 
						 | 
				
			
			@ -941,13 +942,13 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
        default:
 | 
			
		||||
            break; // do nothing
 | 
			
		||||
        }
 | 
			
		||||
    } while (this->get_status() != FLOATING_POINT_ERROR
 | 
			
		||||
    } while (this->get_status() != lp_status::FLOATING_POINT_ERROR
 | 
			
		||||
             &&
 | 
			
		||||
             this->get_status() != UNBOUNDED
 | 
			
		||||
             this->get_status() != lp_status::UNBOUNDED
 | 
			
		||||
             &&
 | 
			
		||||
             this->get_status() != OPTIMAL
 | 
			
		||||
             this->get_status() != lp_status::OPTIMAL
 | 
			
		||||
             &&
 | 
			
		||||
             this->get_status() != INFEASIBLE
 | 
			
		||||
             this->get_status() != lp_status::INFEASIBLE
 | 
			
		||||
             &&
 | 
			
		||||
             this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
 | 
			
		||||
             &&
 | 
			
		||||
| 
						 | 
				
			
			@ -955,7 +956,7 @@ template <typename T, typename X> unsigned lp_primal_core_solver<T, X>::solve()
 | 
			
		|||
             &&
 | 
			
		||||
             !(this->current_x_is_feasible() && this->m_look_for_feasible_solution_only));
 | 
			
		||||
 | 
			
		||||
    SASSERT(this->get_status() == FLOATING_POINT_ERROR
 | 
			
		||||
    lp_assert(this->get_status() == lp_status::FLOATING_POINT_ERROR
 | 
			
		||||
                ||
 | 
			
		||||
                this->current_x_is_feasible() == false
 | 
			
		||||
                ||
 | 
			
		||||
| 
						 | 
				
			
			@ -972,7 +973,7 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::delete_fa
 | 
			
		|||
 | 
			
		||||
// according to Swietanowski, " A new steepest edge approximation for the simplex method for linear programming"
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_column_norms() {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise() == false);
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise() == false);
 | 
			
		||||
    for (unsigned j = 0; j < this->m_n(); j++) {
 | 
			
		||||
        this->m_column_norms[j] = T(static_cast<int>(this->m_A.m_columns[j].size() + 1)) 
 | 
			
		||||
            
 | 
			
		||||
| 
						 | 
				
			
			@ -982,7 +983,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::init_column_
 | 
			
		|||
 | 
			
		||||
// debug only
 | 
			
		||||
template <typename T, typename X> T lp_primal_core_solver<T, X>::calculate_column_norm_exactly(unsigned j) {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise() == false);
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise() == false);
 | 
			
		||||
    indexed_vector<T> w(this->m_m());
 | 
			
		||||
    this->m_A.copy_column_to_vector(j, w);
 | 
			
		||||
    vector<T> d(this->m_m());
 | 
			
		||||
| 
						 | 
				
			
			@ -994,8 +995,8 @@ template <typename T, typename X> T lp_primal_core_solver<T, X>::calculate_colum
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::update_or_init_column_norms(unsigned entering, unsigned leaving) {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise() == false);
 | 
			
		||||
    SASSERT(m_column_norm_update_counter <= this->m_settings.column_norms_update_frequency);
 | 
			
		||||
    lp_assert(numeric_traits<T>::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();
 | 
			
		||||
| 
						 | 
				
			
			@ -1007,7 +1008,7 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::update_or
 | 
			
		|||
 | 
			
		||||
// following Swietanowski - A new steepest ...
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::update_column_norms(unsigned entering, unsigned leaving) {
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise() == false);
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise() == false);
 | 
			
		||||
    T pivot = this->m_pivot_row[entering];
 | 
			
		||||
    T g_ent = calculate_norm_of_entering_exactly() / pivot / pivot;
 | 
			
		||||
    if (!numeric_traits<T>::precise()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1042,8 +1043,8 @@ template <typename T, typename X>    T lp_primal_core_solver<T, X>::calculate_no
 | 
			
		|||
// calling it stage1 is too cryptic
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::find_feasible_solution() {
 | 
			
		||||
    this->m_look_for_feasible_solution_only = true;
 | 
			
		||||
    SASSERT(this->non_basic_columns_are_set_correctly());
 | 
			
		||||
    this->set_status(UNKNOWN);
 | 
			
		||||
    lp_assert(this->non_basic_columns_are_set_correctly());
 | 
			
		||||
    this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
    solve();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,15 +1088,15 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::fill_breakpo
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_primal_core_solver<T, X>::done() {
 | 
			
		||||
    if (this->get_status() == OPTIMAL || this->get_status() == FLOATING_POINT_ERROR) return true;
 | 
			
		||||
    if (this->get_status() == INFEASIBLE) {
 | 
			
		||||
    if (this->get_status() == lp_status::OPTIMAL || this->get_status() == lp_status::FLOATING_POINT_ERROR) 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->get_status() = ITERATIONS_EXHAUSTED; return true;
 | 
			
		||||
        this->get_status() = lp_status::ITERATIONS_EXHAUSTED; return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (this->total_iterations() >= this->m_settings.max_total_number_of_iterations) {
 | 
			
		||||
        this->get_status() = ITERATIONS_EXHAUSTED; return true;
 | 
			
		||||
        this->get_status() = lp_status::ITERATIONS_EXHAUSTED; return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1110,8 +1111,8 @@ void lp_primal_core_solver<T, X>::init_infeasibility_costs_for_changed_basis_onl
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
void lp_primal_core_solver<T, X>::init_infeasibility_costs() {
 | 
			
		||||
    SASSERT(this->m_x.size() >= this->m_n());
 | 
			
		||||
    SASSERT(this->m_column_types.size() >= this->m_n());
 | 
			
		||||
    lp_assert(this->m_x.size() >= this->m_n());
 | 
			
		||||
    lp_assert(this->m_column_types.size() >= this->m_n());
 | 
			
		||||
    for (unsigned j = this->m_n(); j--;)
 | 
			
		||||
        init_infeasibility_cost_for_column(j);
 | 
			
		||||
    this->m_using_infeas_costs = true;
 | 
			
		||||
| 
						 | 
				
			
			@ -1135,7 +1136,7 @@ lp_primal_core_solver<T, X>::get_infeasibility_cost_for_column(unsigned j) const
 | 
			
		|||
            ret = numeric_traits<T>::zero();
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(j)) {
 | 
			
		||||
            ret = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1153,7 +1154,7 @@ lp_primal_core_solver<T, X>::get_infeasibility_cost_for_column(unsigned j) const
 | 
			
		|||
        ret = numeric_traits<T>::zero();
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        ret = numeric_traits<T>::zero(); // does not matter
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -1189,7 +1190,7 @@ lp_primal_core_solver<T, X>::init_infeasibility_cost_for_column(unsigned j) {
 | 
			
		|||
            this->m_costs[j] = numeric_traits<T>::zero();
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        if (this->x_below_low_bound(j)) {
 | 
			
		||||
            this->m_costs[j] = -1;
 | 
			
		||||
        } else {
 | 
			
		||||
| 
						 | 
				
			
			@ -1207,14 +1208,14 @@ lp_primal_core_solver<T, X>::init_infeasibility_cost_for_column(unsigned j) {
 | 
			
		|||
        this->m_costs[j] = numeric_traits<T>::zero();
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    if (numeric_traits<T>::is_zero(this->m_costs[j])) {
 | 
			
		||||
        this->m_inf_set.erase(j);
 | 
			
		||||
        this->remove_column_from_inf_set(j);
 | 
			
		||||
    } else {
 | 
			
		||||
        this->m_inf_set.insert(j);
 | 
			
		||||
        this->insert_column_into_inf_set(j);
 | 
			
		||||
    }
 | 
			
		||||
    if (!this->m_settings.use_breakpoints_in_feasibility_search) {
 | 
			
		||||
        this->m_costs[j] = - this->m_costs[j];
 | 
			
		||||
| 
						 | 
				
			
			@ -1227,18 +1228,18 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::print_column
 | 
			
		|||
    switch (this->m_column_type[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        out <<  "( " << this->m_low_bounds[j] << " " << this->m_x[j] << " " << this->m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
        out <<  "( " << this->m_lower_bounds[j] << " " << this->m_x[j] << " " << this->m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        out <<  "( _"  << this->m_x[j] << " " << this->m_upper_bounds[j] << ")" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        out <<  "( " << this->m_low_bounds[j] << " " << this->m_x[j] << " " << "_ )" << std::endl;
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        out <<  "( " << this->m_lower_bounds[j] << " " << this->m_x[j] << " " << "_ )" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::free_column:
 | 
			
		||||
        out << "( _" << this->m_x[j] << "_)" << std::endl;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1277,7 +1278,7 @@ template <typename T, typename X> std::string lp_primal_core_solver<T, X>::break
 | 
			
		|||
    case upper_break: return "upper_break";
 | 
			
		||||
    case fixed_break: return "fixed_break";
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
    return "type is not found";
 | 
			
		||||
| 
						 | 
				
			
			@ -1290,7 +1291,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::print_breakp
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
void lp_primal_core_solver<T, X>::init_reduced_costs() {
 | 
			
		||||
    SASSERT(!this->use_tableau());
 | 
			
		||||
    lp_assert(!this->use_tableau());
 | 
			
		||||
    if (this->current_x_is_infeasible() && !this->m_using_infeas_costs) {
 | 
			
		||||
        init_infeasibility_costs();
 | 
			
		||||
    } else if (this->current_x_is_feasible() && this->m_using_infeas_costs) {
 | 
			
		||||
| 
						 | 
				
			
			@ -1305,12 +1306,12 @@ void lp_primal_core_solver<T, X>::init_reduced_costs() {
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::change_slope_on_breakpoint(unsigned entering, breakpoint<X> * b, T & slope_at_entering) {
 | 
			
		||||
    if (b->m_j == entering) {
 | 
			
		||||
        SASSERT(b->m_type != fixed_break && (!is_zero(b->m_delta)));
 | 
			
		||||
        lp_assert(b->m_type != fixed_break && (!is_zero(b->m_delta)));
 | 
			
		||||
        slope_at_entering += m_sign_of_entering_delta;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SASSERT(this->m_basis_heading[b->m_j] >= 0);
 | 
			
		||||
    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<T>::is_zero(d)) return;
 | 
			
		||||
| 
						 | 
				
			
			@ -1329,27 +1330,27 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::change_sl
 | 
			
		|||
        slope_at_entering += delta;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X>    void lp_primal_core_solver<T, X>::try_add_breakpoint_in_row(unsigned i) {
 | 
			
		||||
    SASSERT(i < this->m_m());
 | 
			
		||||
    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_low_bounds[j]);
 | 
			
		||||
        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_low_bounds[j]);
 | 
			
		||||
        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::low_bound:
 | 
			
		||||
        try_add_breakpoint(j, x, d, low_break, this->m_low_bounds[j]);
 | 
			
		||||
    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]);
 | 
			
		||||
| 
						 | 
				
			
			@ -1357,7 +1358,7 @@ template <typename T, typename X>    void lp_primal_core_solver<T, X>::try_add_b
 | 
			
		|||
    case column_type::free_column:
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1369,10 +1370,10 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::print_bound_
 | 
			
		|||
    switch (this->m_column_types[j]) {
 | 
			
		||||
    case column_type::fixed:
 | 
			
		||||
    case column_type::boxed:
 | 
			
		||||
        out << "[" << this->m_low_bounds[j] << "," << this->m_upper_bounds[j] << "]" << std::endl;
 | 
			
		||||
        out << "[" << this->m_lower_bounds[j] << "," << this->m_upper_bounds[j] << "]" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::low_bound:
 | 
			
		||||
        out << "[" << this->m_low_bounds[j] << ", inf" << std::endl;
 | 
			
		||||
    case column_type::lower_bound:
 | 
			
		||||
        out << "[" << this->m_lower_bounds[j] << ", inf" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    case column_type::upper_bound:
 | 
			
		||||
        out << "inf ," << this->m_upper_bounds[j] << "]" << std::endl;
 | 
			
		||||
| 
						 | 
				
			
			@ -1381,7 +1382,7 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::print_bound_
 | 
			
		|||
        out << "inf, inf" << std::endl;
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_assert(false);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -28,14 +28,14 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::one_iteratio
 | 
			
		|||
    else {
 | 
			
		||||
        advance_on_entering_tableau(entering);
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(this->inf_set_is_correct());
 | 
			
		||||
    lp_assert(this->inf_set_is_correct());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::advance_on_entering_tableau(int entering) {
 | 
			
		||||
    X t;
 | 
			
		||||
    int leaving = find_leaving_and_t_tableau(entering, t);
 | 
			
		||||
    if (leaving == -1) {
 | 
			
		||||
        this->set_status(UNBOUNDED);
 | 
			
		||||
        this->set_status(lp_status::UNBOUNDED);
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    advance_on_entering_and_leaving_tableau(entering, leaving, t);
 | 
			
		||||
| 
						 | 
				
			
			@ -52,7 +52,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::choose_enteri
 | 
			
		|||
    //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();
 | 
			
		||||
    
 | 
			
		||||
    SASSERT(numeric_traits<T>::precise());
 | 
			
		||||
    lp_assert(numeric_traits<T>::precise());
 | 
			
		||||
    if (number_of_benefitial_columns_to_go_over == 0)
 | 
			
		||||
        return -1;
 | 
			
		||||
    if (this->m_basis_sort_counter == 0) {
 | 
			
		||||
| 
						 | 
				
			
			@ -100,25 +100,26 @@ template <typename T, typename X>
 | 
			
		|||
unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		||||
    init_run_tableau();
 | 
			
		||||
    if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only) {
 | 
			
		||||
        this->set_status(FEASIBLE);
 | 
			
		||||
        this->set_status(lp_status::FEASIBLE);
 | 
			
		||||
        return 0;
 | 
			
		||||
    }
 | 
			
		||||
        
 | 
			
		||||
    if ((!numeric_traits<T>::precise()) && this->A_mult_x_is_off()) {
 | 
			
		||||
        this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
        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->m_using_infeas_costs? "inf t" : "feas t"), * this->m_settings.get_message_ostream())) {
 | 
			
		||||
            return this->total_iterations();
 | 
			
		||||
        }
 | 
			
		||||
        if (this->m_settings.use_tableau_rows())
 | 
			
		||||
        if (this->m_settings.use_tableau_rows()) {
 | 
			
		||||
            one_iteration_tableau_rows();
 | 
			
		||||
        }
 | 
			
		||||
        else 
 | 
			
		||||
            one_iteration_tableau();
 | 
			
		||||
        switch (this->get_status()) {
 | 
			
		||||
        case OPTIMAL:  // double check that we are at optimum
 | 
			
		||||
        case INFEASIBLE:
 | 
			
		||||
        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;
 | 
			
		||||
            if (!numeric_traits<T>::precise()) {
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +128,7 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
                this->init_lu();
 | 
			
		||||
                
 | 
			
		||||
                if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                    this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
                    this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                init_reduced_costs();
 | 
			
		||||
| 
						 | 
				
			
			@ -135,7 +136,7 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
                    decide_on_status_when_cannot_find_entering();
 | 
			
		||||
                    break;
 | 
			
		||||
                }
 | 
			
		||||
                this->set_status(UNKNOWN);
 | 
			
		||||
                this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
            } else { // precise case
 | 
			
		||||
                if ((!this->infeasibility_costs_are_correct())) {
 | 
			
		||||
                    init_reduced_costs_tableau(); // forcing recalc
 | 
			
		||||
| 
						 | 
				
			
			@ -143,31 +144,31 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
                        decide_on_status_when_cannot_find_entering();
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                    this->set_status(UNKNOWN);
 | 
			
		||||
                    this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
        case TENTATIVE_UNBOUNDED:
 | 
			
		||||
        case lp_status::TENTATIVE_UNBOUNDED:
 | 
			
		||||
            this->init_lu();
 | 
			
		||||
            if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
                this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
                
 | 
			
		||||
            init_reduced_costs();
 | 
			
		||||
            break;
 | 
			
		||||
        case UNBOUNDED:
 | 
			
		||||
        case lp_status::UNBOUNDED:
 | 
			
		||||
            if (this->current_x_is_infeasible()) {
 | 
			
		||||
                init_reduced_costs();
 | 
			
		||||
                this->set_status(UNKNOWN);
 | 
			
		||||
                this->set_status(lp_status::UNKNOWN);
 | 
			
		||||
            }
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case UNSTABLE:
 | 
			
		||||
            SASSERT(! (numeric_traits<T>::precise()));
 | 
			
		||||
        case lp_status::UNSTABLE:
 | 
			
		||||
            lp_assert(! (numeric_traits<T>::precise()));
 | 
			
		||||
            this->init_lu();
 | 
			
		||||
            if (this->m_factorization->get_status() != LU_status::OK) {
 | 
			
		||||
                this->set_status(FLOATING_POINT_ERROR);
 | 
			
		||||
                this->set_status(lp_status::FLOATING_POINT_ERROR);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            init_reduced_costs();
 | 
			
		||||
| 
						 | 
				
			
			@ -176,13 +177,13 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
        default:
 | 
			
		||||
            break; // do nothing
 | 
			
		||||
        }
 | 
			
		||||
	} while (this->get_status() != FLOATING_POINT_ERROR
 | 
			
		||||
    } while (this->get_status() != lp_status::FLOATING_POINT_ERROR
 | 
			
		||||
		&&
 | 
			
		||||
		this->get_status() != UNBOUNDED
 | 
			
		||||
             this->get_status() != lp_status::UNBOUNDED
 | 
			
		||||
		&&
 | 
			
		||||
		this->get_status() != OPTIMAL
 | 
			
		||||
             this->get_status() != lp_status::OPTIMAL
 | 
			
		||||
		&&
 | 
			
		||||
		this->get_status() != INFEASIBLE
 | 
			
		||||
             this->get_status() != lp_status::INFEASIBLE
 | 
			
		||||
		&&
 | 
			
		||||
		this->iters_with_no_cost_growing() <= this->m_settings.max_number_of_iterations_with_no_improvements
 | 
			
		||||
		&&
 | 
			
		||||
| 
						 | 
				
			
			@ -193,13 +194,13 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
		this->m_settings.get_cancel_flag() == false);
 | 
			
		||||
	
 | 
			
		||||
	if (this->m_settings.get_cancel_flag()) {
 | 
			
		||||
            this->set_status(CANCELLED);
 | 
			
		||||
        this->set_status(lp_status::CANCELLED);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	SASSERT(
 | 
			
		||||
            this->get_status() == FLOATING_POINT_ERROR
 | 
			
		||||
	lp_assert(
 | 
			
		||||
            this->get_status() == lp_status::FLOATING_POINT_ERROR
 | 
			
		||||
            ||
 | 
			
		||||
            this->get_status() == CANCELLED
 | 
			
		||||
            this->get_status() == lp_status::CANCELLED
 | 
			
		||||
            ||
 | 
			
		||||
            this->current_x_is_feasible() == false
 | 
			
		||||
            ||
 | 
			
		||||
| 
						 | 
				
			
			@ -208,13 +209,13 @@ unsigned lp_primal_core_solver<T, X>::solve_with_tableau() {
 | 
			
		|||
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_entering_and_leaving_tableau(int entering, int leaving, X & t) {
 | 
			
		||||
    SASSERT(this->A_mult_x_is_off() == false);
 | 
			
		||||
    SASSERT(leaving >= 0 && entering >= 0);
 | 
			
		||||
    SASSERT((this->m_settings.simplex_strategy() ==
 | 
			
		||||
    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) ||
 | 
			
		||||
                m_non_basis_list.back() == static_cast<unsigned>(entering));
 | 
			
		||||
    SASSERT(this->m_using_infeas_costs || !is_neg(t));
 | 
			
		||||
    SASSERT(entering != leaving || !is_zero(t)); // otherwise nothing changes
 | 
			
		||||
    lp_assert(this->m_using_infeas_costs || !is_neg(t));
 | 
			
		||||
    lp_assert(entering != leaving || !is_zero(t)); // otherwise nothing changes
 | 
			
		||||
    if (entering == leaving) {
 | 
			
		||||
        advance_on_entering_equal_leaving_tableau(entering, t);
 | 
			
		||||
        return;
 | 
			
		||||
| 
						 | 
				
			
			@ -225,7 +226,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
                t = -t;
 | 
			
		||||
        }
 | 
			
		||||
        this->update_basis_and_x_tableau(entering, leaving, t);
 | 
			
		||||
        SASSERT(this->A_mult_x_is_off() == false);
 | 
			
		||||
        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]);
 | 
			
		||||
| 
						 | 
				
			
			@ -240,7 +241,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
            this->init_reduced_costs_tableau();
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
        SASSERT(!need_to_switch_costs());
 | 
			
		||||
        lp_assert(!need_to_switch_costs());
 | 
			
		||||
        std::list<unsigned>::iterator it = m_non_basis_list.end();
 | 
			
		||||
        it--;
 | 
			
		||||
        * it = static_cast<unsigned>(leaving);
 | 
			
		||||
| 
						 | 
				
			
			@ -249,7 +250,7 @@ template <typename T, typename X>void lp_primal_core_solver<T, X>::advance_on_en
 | 
			
		|||
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
void lp_primal_core_solver<T, X>::advance_on_entering_equal_leaving_tableau(int entering, X & t) {
 | 
			
		||||
    SASSERT(!this->A_mult_x_is_off() );
 | 
			
		||||
    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;
 | 
			
		||||
| 
						 | 
				
			
			@ -270,7 +271,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
 | 
			
		|||
        const column_cell & c = col[k];
 | 
			
		||||
        unsigned i = c.m_i;
 | 
			
		||||
        const T & ed = this->m_A.get_val(c);
 | 
			
		||||
        SASSERT(!numeric_traits<T>::is_zero(ed));
 | 
			
		||||
        lp_assert(!numeric_traits<T>::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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -289,7 +290,7 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
 | 
			
		|||
        const column_cell & c = col[k];
 | 
			
		||||
        unsigned i = c.m_i;
 | 
			
		||||
        const T & ed = this->m_A.get_val(c);
 | 
			
		||||
         SASSERT(!numeric_traits<T>::is_zero(ed));
 | 
			
		||||
         lp_assert(!numeric_traits<T>::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);
 | 
			
		||||
| 
						 | 
				
			
			@ -321,13 +322,12 @@ template <typename T, typename X> int lp_primal_core_solver<T, X>::find_leaving_
 | 
			
		|||
    return m_leaving_candidates[k];
 | 
			
		||||
}
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tableau() {
 | 
			
		||||
        //        print_matrix(&(this->m_A), std::cout);
 | 
			
		||||
        SASSERT(this->A_mult_x_is_off() == false);
 | 
			
		||||
        SASSERT(basis_columns_are_set_correctly());
 | 
			
		||||
    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);
 | 
			
		||||
        this->iters_with_no_cost_growing() = 0;
 | 
			
		||||
        SASSERT(this->inf_set_is_correct());
 | 
			
		||||
		lp_assert(this->inf_set_is_correct());
 | 
			
		||||
        if (this->current_x_is_feasible() && this->m_look_for_feasible_solution_only)
 | 
			
		||||
            return;
 | 
			
		||||
        if (this->m_settings.backup_costs)
 | 
			
		||||
| 
						 | 
				
			
			@ -341,13 +341,13 @@ template <typename T, typename X> void lp_primal_core_solver<T, X>::init_run_tab
 | 
			
		|||
        }
 | 
			
		||||
        if (this->m_settings.simplex_strategy() == simplex_strategy_enum::tableau_rows)
 | 
			
		||||
            init_tableau_rows();
 | 
			
		||||
        SASSERT(this->reduced_costs_are_correct_tableau());
 | 
			
		||||
        SASSERT(!this->need_to_pivot_to_basis_tableau());
 | 
			
		||||
        lp_assert(this->reduced_costs_are_correct_tableau());
 | 
			
		||||
        lp_assert(!this->need_to_pivot_to_basis_tableau());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> bool lp_primal_core_solver<T, X>::
 | 
			
		||||
update_basis_and_x_tableau(int entering, int leaving, X const & tt) {
 | 
			
		||||
    SASSERT(this->use_tableau());
 | 
			
		||||
    lp_assert(this->use_tableau());
 | 
			
		||||
    update_x_tableau(entering, tt);
 | 
			
		||||
    this->pivot_column_tableau(entering, this->m_basis_heading[leaving]);
 | 
			
		||||
    this->change_basis(entering, leaving);
 | 
			
		||||
| 
						 | 
				
			
			@ -355,36 +355,34 @@ update_basis_and_x_tableau(int entering, int leaving, X const & tt) {
 | 
			
		|||
}
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::
 | 
			
		||||
update_x_tableau(unsigned entering, const X& delta) {
 | 
			
		||||
    this->add_delta_to_x_and_call_tracker(entering, delta);
 | 
			
		||||
    if (!this->m_using_infeas_costs) {
 | 
			
		||||
        this->m_x[entering] += delta;
 | 
			
		||||
        for (const auto & c : this->m_A.m_columns[entering]) {
 | 
			
		||||
            unsigned i = c.m_i;
 | 
			
		||||
            this->m_x[this->m_basis[i]] -= delta * this->m_A.get_val(c);
 | 
			
		||||
            this->update_column_in_inf_set(this->m_basis[i]);
 | 
			
		||||
            this->update_x_with_delta_and_track_feasibility(this->m_basis[i], -  delta * this->m_A.get_val(c));
 | 
			
		||||
        }
 | 
			
		||||
    } else { // m_using_infeas_costs == true
 | 
			
		||||
        this->m_x[entering] += delta;
 | 
			
		||||
        SASSERT(this->column_is_feasible(entering));
 | 
			
		||||
        SASSERT(this->m_costs[entering] == zero_of_type<T>());
 | 
			
		||||
        lp_assert(this->column_is_feasible(entering));
 | 
			
		||||
        lp_assert(this->m_costs[entering] == zero_of_type<T>());
 | 
			
		||||
        // m_d[entering] can change because of the cost change for basic columns.
 | 
			
		||||
        for (const auto & c : this->m_A.m_columns[entering]) {
 | 
			
		||||
            unsigned i = c.m_i;
 | 
			
		||||
            unsigned j = this->m_basis[i];
 | 
			
		||||
            this->m_x[j] -= delta * this->m_A.get_val(c);
 | 
			
		||||
            this->add_delta_to_x_and_call_tracker(j, -delta * this->m_A.get_val(c));
 | 
			
		||||
            update_inf_cost_for_column_tableau(j);
 | 
			
		||||
            if (is_zero(this->m_costs[j]))
 | 
			
		||||
                this->m_inf_set.erase(j);
 | 
			
		||||
                this->remove_column_from_inf_set(j);
 | 
			
		||||
            else
 | 
			
		||||
                this->m_inf_set.insert(j);
 | 
			
		||||
                this->insert_column_into_inf_set(j);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(this->A_mult_x_is_off() == false);
 | 
			
		||||
    CASSERT("A_off", this->A_mult_x_is_off() == false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_primal_core_solver<T, X>::
 | 
			
		||||
update_inf_cost_for_column_tableau(unsigned j) {
 | 
			
		||||
    SASSERT(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows);
 | 
			
		||||
    SASSERT(this->m_using_infeas_costs);
 | 
			
		||||
    lp_assert(this->m_settings.simplex_strategy() != simplex_strategy_enum::tableau_rows);
 | 
			
		||||
    lp_assert(this->m_using_infeas_costs);
 | 
			
		||||
    T new_cost = get_infeasibility_cost_for_column(j);
 | 
			
		||||
    T delta = this->m_costs[j] - new_cost;
 | 
			
		||||
    if (is_zero(delta))
 | 
			
		||||
| 
						 | 
				
			
			@ -22,7 +22,7 @@ Revision History:
 | 
			
		|||
#include <string>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include <functional>
 | 
			
		||||
#include "util/lp/lp_primal_simplex.hpp"
 | 
			
		||||
#include "util/lp/lp_primal_simplex_def.h"
 | 
			
		||||
template bool lp::lp_primal_simplex<double, double>::bounds_hold(std::unordered_map<std::string, double, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, double> > > const&);
 | 
			
		||||
template bool lp::lp_primal_simplex<double, double>::row_constraints_hold(std::unordered_map<std::string, double, std::hash<std::string>, std::equal_to<std::string>, std::allocator<std::pair<std::string const, double> > > const&);
 | 
			
		||||
template double lp::lp_primal_simplex<double, double>::get_current_cost() const;
 | 
			
		||||
| 
						 | 
				
			
			@ -26,12 +26,11 @@ Revision History:
 | 
			
		|||
#include "util/lp/column_info.h"
 | 
			
		||||
#include "util/lp/lp_primal_core_solver.h"
 | 
			
		||||
#include "util/lp/lp_solver.h"
 | 
			
		||||
#include "util/lp/iterator_on_row.h"
 | 
			
		||||
namespace lp {
 | 
			
		||||
template <typename T, typename X>
 | 
			
		||||
class lp_primal_simplex: public lp_solver<T, X> {
 | 
			
		||||
    lp_primal_core_solver<T, X> * m_core_solver;
 | 
			
		||||
    vector<X> m_low_bounds;
 | 
			
		||||
    vector<X> m_lower_bounds;
 | 
			
		||||
private:
 | 
			
		||||
    unsigned original_rows() { return this->m_external_rows_to_core_solver_rows.size(); }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -76,14 +76,14 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::fill_costs_and_x
 | 
			
		|||
                                                                                                                int row,
 | 
			
		||||
                                                                                                                unsigned & slack_var,
 | 
			
		||||
                                                                                                                unsigned & artificial) {
 | 
			
		||||
    SASSERT(row >= 0 && row < this->row_count());
 | 
			
		||||
    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<T>::one();
 | 
			
		||||
    switch (constraint.m_relation) {
 | 
			
		||||
    case Equal: // no slack variable here
 | 
			
		||||
        this->m_column_types[artificial] = column_type::low_bound;
 | 
			
		||||
        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) {
 | 
			
		||||
| 
						 | 
				
			
			@ -97,13 +97,13 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::fill_costs_and_x
 | 
			
		|||
        break;
 | 
			
		||||
 | 
			
		||||
    case Greater_or_equal:
 | 
			
		||||
        this->m_column_types[slack_var] = column_type::low_bound;
 | 
			
		||||
        this->m_column_types[slack_var] = column_type::lower_bound;
 | 
			
		||||
        (*this->m_A)(row, slack_var) = - numeric_traits<T>::one();
 | 
			
		||||
 | 
			
		||||
        if (rs > 0) {
 | 
			
		||||
            SASSERT(numeric_traits<T>::is_zero(this->m_x[slack_var]));
 | 
			
		||||
            lp_assert(numeric_traits<T>::is_zero(this->m_x[slack_var]));
 | 
			
		||||
            // adding one artificial
 | 
			
		||||
            this->m_column_types[artificial] = column_type::low_bound;
 | 
			
		||||
            this->m_column_types[artificial] = column_type::lower_bound;
 | 
			
		||||
            (*this->m_A)(row, artificial) = numeric_traits<T>::one();
 | 
			
		||||
            this->m_costs[artificial] = artificial_cost;
 | 
			
		||||
            this->m_basis[row] = artificial;
 | 
			
		||||
| 
						 | 
				
			
			@ -118,13 +118,13 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::fill_costs_and_x
 | 
			
		|||
        break;
 | 
			
		||||
    case Less_or_equal:
 | 
			
		||||
        // introduce a non-negative slack variable
 | 
			
		||||
        this->m_column_types[slack_var] = column_type::low_bound;
 | 
			
		||||
        this->m_column_types[slack_var] = column_type::lower_bound;
 | 
			
		||||
        (*this->m_A)(row, slack_var) = numeric_traits<T>::one();
 | 
			
		||||
 | 
			
		||||
        if (rs < 0) {
 | 
			
		||||
            // adding one artificial
 | 
			
		||||
            SASSERT(numeric_traits<T>::is_zero(this->m_x[slack_var]));
 | 
			
		||||
            this->m_column_types[artificial] = column_type::low_bound;
 | 
			
		||||
            lp_assert(numeric_traits<T>::is_zero(this->m_x[slack_var]));
 | 
			
		||||
            this->m_column_types[artificial] = column_type::lower_bound;
 | 
			
		||||
            (*this->m_A)(row, artificial) = - numeric_traits<T>::one();
 | 
			
		||||
            this->m_costs[artificial] = artificial_cost;
 | 
			
		||||
            this->m_x[artificial] = - rs;
 | 
			
		||||
| 
						 | 
				
			
			@ -192,12 +192,12 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::fill_A_x_and_bas
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_primal_simplex<T, X>::fill_A_x_and_basis_for_stage_one_total_inf_for_row(unsigned row) {
 | 
			
		||||
    SASSERT(row < this->row_count());
 | 
			
		||||
    lp_assert(row < this->row_count());
 | 
			
		||||
    auto ext_row_it = this->m_core_solver_rows_to_external_rows.find(row);
 | 
			
		||||
    SASSERT(ext_row_it != this->m_core_solver_rows_to_external_rows.end());
 | 
			
		||||
    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);
 | 
			
		||||
    SASSERT(constr_it != this->m_constraints.end());
 | 
			
		||||
    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();
 | 
			
		||||
| 
						 | 
				
			
			@ -208,34 +208,34 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::fill_A_x_and_bas
 | 
			
		|||
        this->m_x[j] = this->m_b[row];
 | 
			
		||||
        (*this->m_A)(row, j) = numeric_traits<T>::one();
 | 
			
		||||
        this->m_column_types[j] = column_type::fixed;
 | 
			
		||||
        this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type<X>();
 | 
			
		||||
        this->m_upper_bounds[j] = m_lower_bounds[j] = zero_of_type<X>();
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case Greater_or_equal:
 | 
			
		||||
        this->m_x[j] = - this->m_b[row];
 | 
			
		||||
        (*this->m_A)(row, j) = - numeric_traits<T>::one();
 | 
			
		||||
        this->m_column_types[j] = column_type::low_bound;
 | 
			
		||||
        this->m_column_types[j] = column_type::lower_bound;
 | 
			
		||||
        this->m_upper_bounds[j] = zero_of_type<X>();
 | 
			
		||||
        break;
 | 
			
		||||
    case Less_or_equal:
 | 
			
		||||
        this->m_x[j] = this->m_b[row];
 | 
			
		||||
        (*this->m_A)(row, j) = numeric_traits<T>::one();
 | 
			
		||||
        this->m_column_types[j] = column_type::low_bound;
 | 
			
		||||
        this->m_upper_bounds[j] = m_low_bounds[j] = zero_of_type<X>();
 | 
			
		||||
        this->m_column_types[j] = column_type::lower_bound;
 | 
			
		||||
        this->m_upper_bounds[j] = m_lower_bounds[j] = zero_of_type<X>();
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        SASSERT(false);
 | 
			
		||||
        lp_unreachable();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename T, typename X> void lp_primal_simplex<T, X>::solve_with_total_inf() {
 | 
			
		||||
    int total_vars = this->m_A->column_count() + this->row_count();
 | 
			
		||||
    if (total_vars == 0) {
 | 
			
		||||
        this->m_status = OPTIMAL;
 | 
			
		||||
        this->m_status = lp_status::OPTIMAL;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
    m_low_bounds.clear();
 | 
			
		||||
    m_low_bounds.resize(total_vars, zero_of_type<X>());  // low bounds are shifted ot zero
 | 
			
		||||
    m_lower_bounds.clear();
 | 
			
		||||
    m_lower_bounds.resize(total_vars, zero_of_type<X>());  // low bounds are shifted ot zero
 | 
			
		||||
    this->m_x.resize(total_vars, numeric_traits<T>::zero());
 | 
			
		||||
    this->m_basis.resize(this->row_count());
 | 
			
		||||
    this->m_costs.clear();
 | 
			
		||||
| 
						 | 
				
			
			@ -253,7 +253,7 @@ template <typename T, typename X> void lp_primal_simplex<T, X>::solve_with_total
 | 
			
		|||
                                                    this->m_heading,
 | 
			
		||||
                                                    this->m_costs,
 | 
			
		||||
                                                    this->m_column_types,
 | 
			
		||||
                                                    m_low_bounds,
 | 
			
		||||
                                                    m_lower_bounds,
 | 
			
		||||
                                                    this->m_upper_bounds,
 | 
			
		||||
                                                    this->m_settings, *this);
 | 
			
		||||
    m_core_solver->solve();
 | 
			
		||||
| 
						 | 
				
			
			@ -278,7 +278,6 @@ template <typename T, typename X> bool lp_primal_simplex<T, X>::bounds_hold(std:
 | 
			
		|||
        }
 | 
			
		||||
 | 
			
		||||
        if (!it.second->bounds_hold(sol_it->second)) {
 | 
			
		||||
            //            std::cout << "bounds do not hold for " << it.second->get_name() << std::endl;
 | 
			
		||||
            it.second->bounds_hold(sol_it->second);
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -296,10 +295,10 @@ template <typename T, typename X> T lp_primal_simplex<T, X>::get_row_value(unsig
 | 
			
		|||
    T ret = numeric_traits<T>::zero();
 | 
			
		||||
    for (auto & pair : it->second) {
 | 
			
		||||
        auto cit = this->m_map_from_var_index_to_column_info.find(pair.first);
 | 
			
		||||
        SASSERT(cit != this->m_map_from_var_index_to_column_info.end());
 | 
			
		||||
        lp_assert(cit != this->m_map_from_var_index_to_column_info.end());
 | 
			
		||||
        column_info<T> * ci = cit->second;
 | 
			
		||||
        auto sol_it = solution.find(ci->get_name());
 | 
			
		||||
        SASSERT(sol_it != solution.end());
 | 
			
		||||
        lp_assert(sol_it != solution.end());
 | 
			
		||||
        T column_val = sol_it->second;
 | 
			
		||||
        if (out != nullptr) {
 | 
			
		||||
            (*out) << pair.second << "(" << ci->get_name() << "=" << column_val << ") ";
 | 
			
		||||
| 
						 | 
				
			
			@ -344,7 +343,7 @@ template <typename T, typename X> bool lp_primal_simplex<T, X>::row_constraint_h
 | 
			
		|||
        }
 | 
			
		||||
        return true;;
 | 
			
		||||
    }
 | 
			
		||||
    SASSERT(false);
 | 
			
		||||
    lp_unreachable();
 | 
			
		||||
    return false; // it is unreachable
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -19,7 +19,7 @@ Revision History:
 | 
			
		|||
--*/
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include "util/vector.h"
 | 
			
		||||
#include "util/lp/lp_settings.hpp"
 | 
			
		||||
#include "util/lp/lp_settings_def.h"
 | 
			
		||||
template bool lp::vectors_are_equal<double>(vector<double> const&, vector<double> const&);
 | 
			
		||||
template bool lp::vectors_are_equal<lp::mpq>(vector<lp::mpq > const&, vector<lp::mpq> const&);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -31,13 +31,16 @@ namespace lp {
 | 
			
		|||
typedef unsigned var_index;
 | 
			
		||||
typedef unsigned constraint_index;
 | 
			
		||||
typedef unsigned row_index;
 | 
			
		||||
 | 
			
		||||
typedef vector<std::pair<mpq, constraint_index>> explanation_t;
 | 
			
		||||
 | 
			
		||||
enum class column_type  {
 | 
			
		||||
    free_column = 0,
 | 
			
		||||
        low_bound = 1,
 | 
			
		||||
        upper_bound = 2,
 | 
			
		||||
        boxed = 3,
 | 
			
		||||
        fixed = 4
 | 
			
		||||
        };
 | 
			
		||||
    lower_bound = 1,
 | 
			
		||||
    upper_bound = 2,
 | 
			
		||||
    boxed = 3,
 | 
			
		||||
    fixed = 4
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class simplex_strategy_enum {
 | 
			
		||||
    undecided = 3,
 | 
			
		||||
| 
						 | 
				
			
			@ -48,7 +51,7 @@ enum class simplex_strategy_enum {
 | 
			
		|||
 | 
			
		||||
std::string column_type_to_string(column_type t);
 | 
			
		||||
 | 
			
		||||
enum lp_status {
 | 
			
		||||
enum class lp_status {
 | 
			
		||||
    UNKNOWN,
 | 
			
		||||
    INFEASIBLE,
 | 
			
		||||
    TENTATIVE_UNBOUNDED,
 | 
			
		||||
| 
						 | 
				
			
			@ -81,7 +84,7 @@ 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_low_bound, at_upper_bound, at_fixed, free_of_bounds, not_at_bound };
 | 
			
		||||
enum non_basic_column_value_position { at_lower_bound, at_upper_bound, at_fixed, free_of_bounds, not_at_bound };
 | 
			
		||||
 | 
			
		||||
template <typename X> bool is_epsilon_small(const X & v, const double& eps);    // forward definition
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -91,11 +94,22 @@ public:
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
struct stats {
 | 
			
		||||
    unsigned m_make_feasible;
 | 
			
		||||
    unsigned m_total_iterations;
 | 
			
		||||
    unsigned m_iters_with_no_cost_growing;
 | 
			
		||||
    unsigned m_num_factorizations;
 | 
			
		||||
    unsigned m_num_of_implied_bounds;
 | 
			
		||||
    unsigned m_need_to_solve_inf;
 | 
			
		||||
    unsigned m_max_cols;
 | 
			
		||||
    unsigned m_max_rows;
 | 
			
		||||
    unsigned m_gcd_calls;
 | 
			
		||||
    unsigned m_gcd_conflicts;
 | 
			
		||||
    unsigned m_cube_calls;
 | 
			
		||||
    unsigned m_cube_success;
 | 
			
		||||
    unsigned m_patches;
 | 
			
		||||
    unsigned m_patches_success;
 | 
			
		||||
    unsigned m_hnf_cutter_calls;
 | 
			
		||||
    unsigned m_hnf_cuts;
 | 
			
		||||
    stats() { reset(); }
 | 
			
		||||
    void reset() { memset(this, 0, sizeof(*this)); }
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -115,53 +129,76 @@ private:
 | 
			
		|||
    };
 | 
			
		||||
 | 
			
		||||
    default_lp_resource_limit m_default_resource_limit;
 | 
			
		||||
    lp_resource_limit* m_resource_limit;
 | 
			
		||||
    lp_resource_limit*        m_resource_limit;
 | 
			
		||||
    // used for debug output
 | 
			
		||||
    std::ostream* m_debug_out;
 | 
			
		||||
    std::ostream*             m_debug_out;
 | 
			
		||||
    // used for messages, for example, the computation progress messages
 | 
			
		||||
    std::ostream* m_message_out;
 | 
			
		||||
    std::ostream*             m_message_out;
 | 
			
		||||
 | 
			
		||||
    stats  m_stats;
 | 
			
		||||
    random_gen m_rand;
 | 
			
		||||
    stats                     m_stats;
 | 
			
		||||
    random_gen                m_rand;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    unsigned reps_in_scaler;
 | 
			
		||||
    unsigned      reps_in_scaler;
 | 
			
		||||
    // when the absolute value of an element is less than pivot_epsilon
 | 
			
		||||
    // in pivoting, we treat it as a zero
 | 
			
		||||
    double pivot_epsilon;
 | 
			
		||||
    double        pivot_epsilon;
 | 
			
		||||
    // see Chatal, page 115
 | 
			
		||||
    double positive_price_epsilon;
 | 
			
		||||
    double        positive_price_epsilon;
 | 
			
		||||
    // a quatation "if some choice of the entering vairable 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;
 | 
			
		||||
    int c_partial_pivoting; // this is the constant c from page 410
 | 
			
		||||
    unsigned depth_of_rook_search;
 | 
			
		||||
    bool using_partial_pivoting;
 | 
			
		||||
    double        entering_diag_epsilon;
 | 
			
		||||
    int           c_partial_pivoting; // this is the constant c from page 410
 | 
			
		||||
    unsigned      depth_of_rook_search;
 | 
			
		||||
    bool          using_partial_pivoting;
 | 
			
		||||
    // dissertation of Achim Koberstein
 | 
			
		||||
    // if Bx - b is different at any component more that refactor_epsilon then we refactor
 | 
			
		||||
    double refactor_tolerance;
 | 
			
		||||
    double pivot_tolerance;
 | 
			
		||||
    double zero_tolerance;
 | 
			
		||||
    double drop_tolerance;
 | 
			
		||||
    double tolerance_for_artificials;
 | 
			
		||||
    double can_be_taken_to_basis_tolerance;
 | 
			
		||||
    double       refactor_tolerance;
 | 
			
		||||
    double       pivot_tolerance;
 | 
			
		||||
    double       zero_tolerance;
 | 
			
		||||
    double       drop_tolerance;
 | 
			
		||||
    double       tolerance_for_artificials;
 | 
			
		||||
    double       can_be_taken_to_basis_tolerance;
 | 
			
		||||
 | 
			
		||||
    unsigned percent_of_entering_to_check; // we try to find a profitable column in a percentage of the columns
 | 
			
		||||
    bool use_scaling;
 | 
			
		||||
    double scaling_maximum;
 | 
			
		||||
    double scaling_minimum;
 | 
			
		||||
    double harris_feasibility_tolerance; // page 179 of Istvan Maros
 | 
			
		||||
    double ignore_epsilon_of_harris;
 | 
			
		||||
    unsigned max_number_of_iterations_with_no_improvements;
 | 
			
		||||
    unsigned max_total_number_of_iterations;
 | 
			
		||||
    double time_limit; // the maximum time limit of the total run time in seconds
 | 
			
		||||
    unsigned     percent_of_entering_to_check; // we try to find a profitable column in a percentage of the columns
 | 
			
		||||
    bool         use_scaling;
 | 
			
		||||
    double       scaling_maximum;
 | 
			
		||||
    double       scaling_minimum;
 | 
			
		||||
    double       harris_feasibility_tolerance; // page 179 of Istvan Maros
 | 
			
		||||
    double       ignore_epsilon_of_harris;
 | 
			
		||||
    unsigned     max_number_of_iterations_with_no_improvements;
 | 
			
		||||
    unsigned     max_total_number_of_iterations;
 | 
			
		||||
    double       time_limit; // the maximum time limit of the total run time in seconds
 | 
			
		||||
    // dual section
 | 
			
		||||
    double dual_feasibility_tolerance; // // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
    double primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
    double relative_primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
 | 
			
		||||
    bool m_bound_propagation;
 | 
			
		||||
    double       dual_feasibility_tolerance; // // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
    double       primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
    double       relative_primal_feasibility_tolerance; // page 71 of the PhD thesis of Achim Koberstein
 | 
			
		||||
    // end of dual section
 | 
			
		||||
    bool                   m_bound_propagation;
 | 
			
		||||
    bool                   presolve_with_double_solver_for_lar;
 | 
			
		||||
    simplex_strategy_enum  m_simplex_strategy;
 | 
			
		||||
    
 | 
			
		||||
    int              report_frequency;
 | 
			
		||||
    bool             print_statistics;
 | 
			
		||||
    unsigned         column_norms_update_frequency;
 | 
			
		||||
    bool             scale_with_ratio;
 | 
			
		||||
    double           density_threshold;
 | 
			
		||||
    bool             use_breakpoints_in_feasibility_search;
 | 
			
		||||
    unsigned         max_row_length_for_bound_propagation;
 | 
			
		||||
    bool             backup_costs;
 | 
			
		||||
    unsigned         column_number_threshold_for_using_lu_in_lar_solver;
 | 
			
		||||
    unsigned         m_int_gomory_cut_period;
 | 
			
		||||
    unsigned         m_int_find_cube_period;
 | 
			
		||||
    unsigned         m_hnf_cut_period;
 | 
			
		||||
    bool             m_int_run_gcd_test;
 | 
			
		||||
    bool             m_int_pivot_fixed_vars_from_basis;
 | 
			
		||||
    bool             m_int_patch_only_integer_values;
 | 
			
		||||
    unsigned         limit_on_rows_for_hnf_cutter;
 | 
			
		||||
    unsigned         limit_on_columns_for_hnf_cutter;
 | 
			
		||||
 | 
			
		||||
    unsigned random_next() { return m_rand(); }
 | 
			
		||||
    void set_random_seed(unsigned s) { m_rand.set_seed(s); }
 | 
			
		||||
 | 
			
		||||
    bool bound_progation() const {
 | 
			
		||||
        return m_bound_propagation;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -172,15 +209,15 @@ public:
 | 
			
		|||
    
 | 
			
		||||
    lp_settings() : m_default_resource_limit(*this),
 | 
			
		||||
                    m_resource_limit(&m_default_resource_limit),
 | 
			
		||||
                    m_debug_out( &std::cout),
 | 
			
		||||
                    m_debug_out(&std::cout),
 | 
			
		||||
                    m_message_out(&std::cout),
 | 
			
		||||
                    reps_in_scaler(20),
 | 
			
		||||
                    pivot_epsilon(0.00000001),
 | 
			
		||||
                    positive_price_epsilon(1e-7),
 | 
			
		||||
                    entering_diag_epsilon ( 1e-8),
 | 
			
		||||
                    c_partial_pivoting ( 10), // this is the constant c from page 410
 | 
			
		||||
                    depth_of_rook_search ( 4),
 | 
			
		||||
                    using_partial_pivoting ( true),
 | 
			
		||||
                    entering_diag_epsilon (1e-8),
 | 
			
		||||
                    c_partial_pivoting (10), // this is the constant c from page 410
 | 
			
		||||
                    depth_of_rook_search (4),
 | 
			
		||||
                    using_partial_pivoting (true),
 | 
			
		||||
                    // dissertation of Achim Koberstein
 | 
			
		||||
                    // if Bx - b is different at any component more that refactor_epsilon then we refactor
 | 
			
		||||
                    refactor_tolerance ( 1e-4),
 | 
			
		||||
| 
						 | 
				
			
			@ -189,7 +226,6 @@ public:
 | 
			
		|||
                    drop_tolerance ( 1e-14),
 | 
			
		||||
                    tolerance_for_artificials ( 1e-4),
 | 
			
		||||
                    can_be_taken_to_basis_tolerance ( 0.00001),
 | 
			
		||||
                  
 | 
			
		||||
                    percent_of_entering_to_check ( 5),// we try to find a profitable column in a percentage of the columns
 | 
			
		||||
                    use_scaling ( true),
 | 
			
		||||
                    scaling_maximum ( 1),
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +250,15 @@ public:
 | 
			
		|||
                    use_breakpoints_in_feasibility_search(false),
 | 
			
		||||
                    max_row_length_for_bound_propagation(300),
 | 
			
		||||
                    backup_costs(true),
 | 
			
		||||
                    column_number_threshold_for_using_lu_in_lar_solver(4000)
 | 
			
		||||
                    column_number_threshold_for_using_lu_in_lar_solver(4000),
 | 
			
		||||
                    m_int_gomory_cut_period(4),
 | 
			
		||||
                    m_int_find_cube_period(4),
 | 
			
		||||
                    m_hnf_cut_period(4),
 | 
			
		||||
                    m_int_run_gcd_test(true),
 | 
			
		||||
                    m_int_pivot_fixed_vars_from_basis(false),
 | 
			
		||||
                    m_int_patch_only_integer_values(true),
 | 
			
		||||
                    limit_on_rows_for_hnf_cutter(75),
 | 
			
		||||
                    limit_on_columns_for_hnf_cutter(150)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    void set_resource_limit(lp_resource_limit& lim) { m_resource_limit = &lim; }
 | 
			
		||||
| 
						 | 
				
			
			@ -284,8 +328,6 @@ public:
 | 
			
		|||
        return is_eps_small_general<T>(t, tolerance_for_artificials);
 | 
			
		||||
    }
 | 
			
		||||
    // the method of lar solver to use
 | 
			
		||||
    bool presolve_with_double_solver_for_lar;
 | 
			
		||||
    simplex_strategy_enum m_simplex_strategy;
 | 
			
		||||
    simplex_strategy_enum simplex_strategy() const {
 | 
			
		||||
        return m_simplex_strategy;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -307,20 +349,9 @@ public:
 | 
			
		|||
        return m_simplex_strategy == simplex_strategy_enum::tableau_rows;
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    int report_frequency;
 | 
			
		||||
    bool print_statistics;
 | 
			
		||||
    unsigned column_norms_update_frequency;
 | 
			
		||||
    bool scale_with_ratio;
 | 
			
		||||
    double density_threshold; // need to tune it up, todo
 | 
			
		||||
#ifdef Z3DEBUG
 | 
			
		||||
    static unsigned ddd; // used for debugging    
 | 
			
		||||
#endif
 | 
			
		||||
    bool use_breakpoints_in_feasibility_search;
 | 
			
		||||
    unsigned random_next() { return m_rand(); }
 | 
			
		||||
    void random_seed(unsigned s) { m_rand.set_seed(s); }
 | 
			
		||||
    unsigned max_row_length_for_bound_propagation;
 | 
			
		||||
    bool backup_costs;
 | 
			
		||||
    unsigned column_number_threshold_for_using_lu_in_lar_solver;
 | 
			
		||||
}; // end of lp_settings class
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -343,7 +374,7 @@ inline std::string T_to_string(const numeric_pair<mpq> & t) {
 | 
			
		|||
 | 
			
		||||
inline std::string T_to_string(const mpq & t) {
 | 
			
		||||
    std::ostringstream strs;
 | 
			
		||||
    strs << t.get_double();
 | 
			
		||||
    strs << t;
 | 
			
		||||
    return strs.str();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -382,7 +413,7 @@ inline void print_blanks(int n, std::ostream & out) {
 | 
			
		|||
// after a push of the last element we ensure that the vector increases
 | 
			
		||||
// we also suppose that before the last push the vector was increasing
 | 
			
		||||
inline void ensure_increasing(vector<unsigned> & v) {
 | 
			
		||||
    SASSERT(v.size() > 0);
 | 
			
		||||
    lp_assert(v.size() > 0);
 | 
			
		||||
    unsigned j = v.size() - 1;
 | 
			
		||||
    for (; j > 0; j-- )
 | 
			
		||||
        if (v[j] <= v[j - 1]) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
Some files were not shown because too many files have changed in this diff Show more
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue