All Downloads are FREE. Search and download functionalities are using the official Maven repository.

z3-z3-4.13.0.src.math.simplex.simplex_def.h Maven / Gradle / Ivy

The newest version!
/*++
Copyright (c) 2014 Microsoft Corporation

Module Name:

    simplex_def.h

Author:

    Nikolaj Bjorner (nbjorner) 2014-01-15

Notes:

    Sign of base variables can vary.
    Sign could possibly be normalized to positive.
    Otherwise, sign could be accounted in pivoting.

--*/

#pragma once


namespace simplex {

    template
    const typename simplex::var_t simplex::null_var = UINT_MAX; 

    template
    simplex::~simplex() {
        reset();
    }

    template
    typename simplex::row 
    simplex::add_row(var_t base_var, unsigned num_vars, var_t const* vars, numeral const* coeffs) {
        m_base_vars.reset();
        row r = M.mk_row();
        for (unsigned i = 0; i < num_vars; ++i) {
            if (!m.is_zero(coeffs[i])) {
                var_t v = vars[i];
                if (is_base(v)) {
                    m_base_vars.push_back(i);
                }
                M.add_var(r, coeffs[i], v);
            }
        }
        scoped_numeral mul(m), a(m), b(m), c(m);
        m.set(mul, 1);
        for (unsigned i = 0; i < m_base_vars.size(); ++i) {
            var_t v = vars[m_base_vars[i]];
            m.mul(coeffs[m_base_vars[i]], mul, a);            
            m.set(b, m_vars[v].m_base_coeff);
            m.lcm(a, b, c);
            TRACE("simplex",
                  m.display(tout << " a: ", a);
                  m.display(tout << " b v" << v << " : ", b);
                  m.display(tout << " c: ", c);
                  tout << "\n";
                  M.display_row(tout, r);
                  M.display_row(tout, row(m_vars[v].m_base2row));
                  if (m.is_zero(b)) {
                      display(tout);
                  });
            SASSERT(is_base(v));
            m.abs(c);
            m.div(c, a, b);
            m.div(c, m_vars[v].m_base_coeff, a);
            m.mul(mul, b, mul);
            M.mul(r, b);
            m.neg(a);
            M.add(r, a, row(m_vars[v].m_base2row));
            TRACE("simplex", M.display_row(tout, r););
        }

        scoped_numeral base_coeff(m);
        scoped_eps_numeral value(em), tmp(em);
        row_iterator it = M.row_begin(r), end = M.row_end(r);
        for (; it != end; ++it) {
            var_t v = it->m_var;
            if (v == base_var) {
                m.set(base_coeff, it->m_coeff);
            }
            else {
                SASSERT(!is_base(v));
                em.mul(m_vars[v].m_value, it->m_coeff, tmp);
                em.add(value, tmp, value);
            }
        }
        SASSERT(!m.is_zero(base_coeff));
        TRACE("simplex", 
              for (unsigned i = 0; i < num_vars; ++i) {
                  m.display(tout << "v" << vars[i] << " * ", coeffs[i]); tout << " ";
                  if (i + 1 < num_vars) tout << " + ";
              }
              tout << "\n";
              row_iterator it2 = M.row_begin(r);
              bool first = true;
              for (; it2 != end; ++it2) {
                  if (!first) tout << " + ";
                  tout << "v" << it2->m_var << " * ";
                  m.display(tout, it2->m_coeff); tout << " ";                  
                  first = false;
              }
              tout << "\n";
              );
        SASSERT(!is_base(base_var));
        em.neg(value);
        em.div(value, base_coeff, value);
        while (m_row2base.size() <= r.id()) {
            m_row2base.push_back(null_var);
        }
        m_row2base[r.id()] = base_var;
        m_vars[base_var].m_base2row = r.id();
        m_vars[base_var].m_is_base = true;
        m.set(m_vars[base_var].m_base_coeff, base_coeff); 
        em.set(m_vars[base_var].m_value, value);
        add_patch(base_var);
        SASSERT(well_formed_row(r));
        SASSERT(well_formed());
        return r;
    }

    template
    typename simplex::row 
    simplex::get_infeasible_row() {
        SASSERT(is_base(m_infeasible_var));
        unsigned row_id = m_vars[m_infeasible_var].m_base2row;
        return row(row_id);
    }

    template
    void simplex::add_patch(var_t v) {
        SASSERT(is_base(v));
        if (outside_bounds(v)) {
            TRACE("simplex", tout << "Add patch: v" << v << "\n";);
            m_to_patch.insert(v);
        }
    }

    template
    void simplex::del_row(row const& r) {
        var_t var = m_row2base[r.id()];
        m_vars[var].m_is_base = false;
        m_vars[var].m_lower_valid = false;
        m_vars[var].m_upper_valid = false;
        m_row2base[r.id()] = null_var;
        M.del(r);
        SASSERT(M.col_begin(var) == M.col_end(var));
        SASSERT(well_formed());
    }

    template
    void simplex::del_row(var_t var) {
        TRACE("simplex", tout << var << "\n";);
        row r;
        if (is_base(var)) {
            r = row(m_vars[var].m_base2row);                                    
        }
        else {
            col_iterator it = M.col_begin(var), end = M.col_end(var);
            if (it == end) {
                return;
            }
            typename matrix::row_entry const& re = it.get_row_entry();
            r = it.get_row();
            var_t old_base = m_row2base[r.id()];
            scoped_eps_numeral new_value(em);
            var_info& vi = m_vars[old_base];
            if (below_lower(old_base)) {
                new_value = vi.m_lower;
            }
            else if (above_upper(old_base)) {
                new_value = vi.m_upper;
            }
            else {
                new_value = vi.m_value;
            }
            // need to move var such that old_base comes in bound.
            update_and_pivot(old_base, var, re.m_coeff, new_value);   
            SASSERT(is_base(var));
            SASSERT(m_vars[var].m_base2row == r.id());            
            SASSERT(!below_lower(old_base) && !above_upper(old_base));
        }
        del_row(r);
        TRACE("simplex", display(tout););
        SASSERT(well_formed());
    }

    template
    bool simplex::above_lower(var_t var, eps_numeral const& b) const {
        var_info const& vi = m_vars[var];        
        return !vi.m_lower_valid || em.gt(b, vi.m_lower);
    }

    template
    bool simplex::below_upper(var_t var, eps_numeral const& b) const {
        var_info const& vi = m_vars[var];        
        return !vi.m_upper_valid || em.lt(b, vi.m_upper);
    }

    template
    void simplex::set_lower(var_t var, eps_numeral const& b) {
        var_info& vi = m_vars[var];
        em.set(vi.m_lower, b);
        vi.m_lower_valid = true;
        TRACE("simplex", em.display(tout << "v" << var << " lower: ", b);
              em.display(tout << " value: ", vi.m_value););
        SASSERT(!vi.m_upper_valid || em.le(b, vi.m_upper));
        if (!vi.m_is_base && em.lt(vi.m_value, b)) {
            scoped_eps_numeral delta(em);
            em.sub(b, vi.m_value, delta);
            update_value(var, delta);
        }
        else if (vi.m_is_base && em.lt(vi.m_value, b)) {
            SASSERT(outside_bounds(var));
            add_patch(var);
        }
        SASSERT(well_formed());
    }

    template
    void simplex::set_upper(var_t var, eps_numeral const& b) {
        var_info& vi = m_vars[var];
        em.set(vi.m_upper, b);
        vi.m_upper_valid = true;
        SASSERT(!vi.m_lower_valid || em.le(vi.m_lower, b));
        if (!vi.m_is_base && em.gt(vi.m_value, b)) {
            scoped_eps_numeral delta(em);
            em.sub(b, vi.m_value, delta);
            update_value(var, delta);
        }
        else if (vi.m_is_base && em.lt(b, vi.m_value)) {
            SASSERT(outside_bounds(var));
            add_patch(var);
        }
        SASSERT(well_formed());
    }

    template
    void simplex::unset_lower(var_t var) {
        m_vars[var].m_lower_valid = false;
    }

    template
    void simplex::unset_upper(var_t var) {
        m_vars[var].m_upper_valid = false;
    }

    template
    void simplex::set_value(var_t var, eps_numeral const& b) {
        scoped_eps_numeral delta(em);
        em.sub(b, m_vars[var].m_value, delta);
        update_value(var, delta);
        SASSERT(well_formed());
    }

    template
    typename simplex::eps_numeral const& 
    simplex::get_value(var_t v) {
        return m_vars[v].m_value;
    }

    template
    void simplex::display(std::ostream& out) const {
        M.display(out);
        for (unsigned i = 0; i < m_vars.size(); ++i) {
            var_info const& vi = m_vars[i];
            out << "v" << i << " ";
            out << em.to_string(vi.m_value);
            out << " [";
            if (vi.m_lower_valid) out << em.to_string(vi.m_lower); else out << "-oo";
            out << ":";
            if (vi.m_upper_valid) out << em.to_string(vi.m_upper); else out << "oo";
            out << "] ";
            if (vi.m_is_base) out << "b:" << vi.m_base2row << " ";
            //col_iterator it = M.col_begin(i), end = M.col_end(i);
            //for (; it != end; ++it) {
            //    out << "r" << it.get_row().id() << " ";
            //}
            out << "\n";
        }
    }

    template
    void simplex::display_row(std::ostream& out, row const& r, bool values) {
        row_iterator it = M.row_begin(r), end = M.row_end(r);        
        for (; it != end; ++it) {
            m.display(out, it->m_coeff);
            out << "*v" << it->m_var << " ";
            if (values) {
                var_info const& vi = m_vars[it->m_var];
                out << em.to_string(vi.m_value);
                out << " [";
                if (vi.m_lower_valid) out << em.to_string(vi.m_lower); else out << "-oo";
                out << ":";
                if (vi.m_upper_valid) out << em.to_string(vi.m_upper); else out << "oo";
                out << "] ";
            }
        }
        out << "\n";
    }


    template
    void simplex::ensure_var(var_t v) {
        while (v >= m_vars.size()) {
            M.ensure_var(m_vars.size());
            m_vars.push_back(var_info());            
        }
        if (m_to_patch.get_bounds() <= v) {
            m_to_patch.set_bounds(2*v+1);
        }
    }

    template
    void simplex::reset() {
        M.reset();
        m_to_patch.reset();
        for (var_info& v : m_vars) {
            em.del(v.m_value);
            em.del(v.m_lower);
            em.del(v.m_upper);
            m.del(v.m_base_coeff);
        }
        m_vars.reset();
        m_row2base.reset();
        m_left_basis.reset();
        m_base_vars.reset();
    }

    template
    lbool simplex::make_feasible() {
        ++m_stats.m_num_checks;
        m_left_basis.reset();
        m_infeasible_var = null_var;
        unsigned num_iterations = 0;
        unsigned num_repeated = 0;
        var_t v = null_var;
        m_bland = false;
        SASSERT(well_formed());
        while ((v = select_var_to_fix()) != null_var) {
            TRACE("simplex", display(tout << "v" << v << "\n"););
            if (!m_limit.inc() || num_iterations > m_max_iterations) {
                return l_undef;
            }
            check_blands_rule(v, num_repeated);
            if (!make_var_feasible(v)) {
                m_to_patch.insert(v);
                m_infeasible_var = v;
                ++m_stats.m_num_infeasible;
                return l_false;
            }
            ++num_iterations;
        }
        SASSERT(well_formed());
        return l_true;
    }

    /**
       \brief Make x_j the new base variable for row of x_i.
       x_i is assumed base variable of row r_i.
       x_j is assumed to have coefficient a_ij in r_i.                      

       a_ii*x_i + a_ij*x_j + r_i = 0
       
       current value of x_i is v_i
       new value of x_i is     new_value
       a_ii*(x_i + new_value - x_i) + a_ij*((x_i - new_value)*a_ii/a_ij + x_j) + r_i = 0

       Let r_k be a row where x_j has coefficient x_kj != 0.
       r_k <- r_k * a_ij - r_i * a_kj
    */
    template
    void simplex::update_and_pivot(var_t x_i, var_t x_j, numeral const& a_ij, eps_numeral const& new_value) {
        SASSERT(is_base(x_i));
        SASSERT(!is_base(x_j));
        var_info& x_iI = m_vars[x_i];
        scoped_eps_numeral theta(em);
        theta = x_iI.m_value;
        theta -= new_value;
        numeral const& a_ii = x_iI.m_base_coeff;
        em.mul(theta, a_ii, theta);
        em.div(theta, a_ij, theta);
        update_value(x_j, theta);
        SASSERT(em.eq(x_iI.m_value, new_value));
        pivot(x_i, x_j, a_ij);
    }
    
    template
    void simplex::pivot(var_t x_i, var_t x_j, numeral const& a_ij) {
        ++m_stats.m_num_pivots;
        var_info& x_iI = m_vars[x_i];
        var_info& x_jI = m_vars[x_j];
        unsigned r_i = x_iI.m_base2row;
        m_row2base[r_i] = x_j;
        x_jI.m_base2row = r_i;
        m.set(x_jI.m_base_coeff, a_ij);
        x_jI.m_is_base = true;
        x_iI.m_is_base = false;
        add_patch(x_j);
        SASSERT(well_formed_row(row(r_i)));

        col_iterator it = M.col_begin(x_j), end = M.col_end(x_j);
        scoped_numeral a_kj(m), g(m);
        for (; it != end; ++it) {
            row r_k = it.get_row();
            if (r_k.id() != r_i) {
                a_kj = it.get_row_entry().m_coeff;
                a_kj.neg();
                M.mul(r_k, a_ij);
                M.add(r_k, a_kj, row(r_i));
                var_t s = m_row2base[r_k.id()];
                numeral& coeff = m_vars[s].m_base_coeff;
                m.mul(coeff, a_ij, coeff);
                M.gcd_normalize(r_k, g);
                if (!m.is_one(g)) {
                    m.div(coeff, g, coeff);
                }
                SASSERT(well_formed_row(row(r_k)));
            }
        }
        SASSERT(well_formed());
    }

    template
    void simplex::update_value(var_t v, eps_numeral const& delta) {
        if (em.is_zero(delta)) {
            return;
        }
        update_value_core(v, delta);
        col_iterator it = M.col_begin(v), end = M.col_end(v);

        // v <- v + delta
        // s*s_coeff + v*v_coeff + R = 0
        // -> 
        // (v + delta)*v_coeff + (s - delta*v_coeff/s_coeff)*v + R = 0
        for (; it != end; ++it) {
            row r = it.get_row();
            var_t s = m_row2base[r.id()];
            var_info& si = m_vars[s];
            scoped_eps_numeral delta2(em);
            numeral const& coeff = it.get_row_entry().m_coeff;
            em.mul(delta,  coeff, delta2);
            em.div(delta2, si.m_base_coeff, delta2);
            delta2.neg();
            update_value_core(s, delta2);
        }            
    }    

    template
    void simplex::update_value_core(var_t v, eps_numeral const& delta) {
        eps_numeral& val = m_vars[v].m_value;
        em.add(val, delta, val);
        if (is_base(v)) {
            add_patch(v);
        }
    }

    template
    bool simplex::below_lower(var_t v) const {
        var_info const& vi = m_vars[v];
        return vi.m_lower_valid && em.lt(vi.m_value, vi.m_lower);
    }



    template
    bool simplex::above_upper(var_t v) const {
        var_info const& vi = m_vars[v];
        return vi.m_upper_valid && em.gt(vi.m_value, vi.m_upper);
    }

    template
    bool simplex::above_lower(var_t v) const {
        var_info const& vi = m_vars[v];
        return !vi.m_lower_valid || em.gt(vi.m_value, vi.m_lower);
    }

    template
    bool simplex::below_upper(var_t v) const {
        var_info const& vi = m_vars[v];
        return !vi.m_upper_valid || em.lt(vi.m_value, vi.m_upper);
    }

    template
    bool simplex::at_lower(var_t v) const {
        var_info const& vi = m_vars[v];
        return vi.m_lower_valid && em.eq(vi.m_value, vi.m_lower);
    }

    template
    bool simplex::at_upper(var_t v) const {
        var_info const& vi = m_vars[v];
        return vi.m_upper_valid && em.eq(vi.m_value, vi.m_upper);
    }

    template
    bool simplex::make_var_feasible(var_t x_i) {
        scoped_numeral a_ij(m);        
        scoped_eps_numeral value(em);
        bool is_below;
        if (below_lower(x_i)) {
            SASSERT(is_base(x_i));
            is_below = m.is_pos(m_vars[x_i].m_base_coeff);
            value = m_vars[x_i].m_lower;
        }
        else if (above_upper(x_i)) {
            SASSERT(is_base(x_i));
            is_below = m.is_neg(m_vars[x_i].m_base_coeff);
            value = m_vars[x_i].m_upper;
        }
        else {
            // x_i is already feasible
            return true;
        }
        var_t x_j = select_pivot(x_i, is_below, a_ij);
        if (x_j != null_var) {
            update_and_pivot(x_i, x_j, a_ij, value);
        }
        return x_j != null_var;
    }

    /**
       \brief Wrapper for select_pivot_blands and select_pivot_core
    */
    template
    typename simplex::var_t
    simplex::select_pivot(var_t x_i, bool is_below, scoped_numeral& out_a_ij) {
        if (m_bland) {
            return select_pivot_blands(x_i, is_below, out_a_ij);
        }
        return select_pivot_core(x_i, is_below, out_a_ij);
    }

    /**
       \brief Select a variable x_j in the row r defining the base var x_i, 
       s.t. x_j can be used to patch the error in x_i.  Return null_theory_var
       if there is no x_j. Otherwise, return x_j and store its coefficient
       in out_a_ij.

       The argument is_below is true (false) if x_i is below its lower
       bound (above its upper bound).
    */
    template
    typename simplex::var_t 
    simplex::select_pivot_core(var_t x_i, bool is_below, scoped_numeral & out_a_ij) {
        SASSERT(is_base(x_i));
        var_t max    = get_num_vars();
        var_t result = max;
        row r = row(m_vars[x_i].m_base2row);
        int n = 0;
        unsigned best_col_sz = UINT_MAX;
        int best_so_far    = INT_MAX;
        
        row_iterator it = M.row_begin(r), end = M.row_end(r);
    
        for (; it != end; ++it) {
            var_t x_j       = it->m_var;          
            if (x_i == x_j) continue;
            numeral const & a_ij = it->m_coeff;  
                                                               
            bool is_neg = is_below ? m.is_neg(a_ij) : m.is_pos(a_ij);
            bool is_pos = !is_neg;                                   
            bool can_pivot = ((is_pos && above_lower(x_j)) || (is_neg && below_upper(x_j)));
            if (can_pivot) {
                int num  = get_num_non_free_dep_vars(x_j, best_so_far);
                unsigned col_sz    = M.column_size(x_j);
                if (num < best_so_far || (num == best_so_far && col_sz < best_col_sz)) {
                    result        = x_j;
                    out_a_ij      = a_ij;
                    best_so_far   = num;
                    best_col_sz   = col_sz;
                    n             = 1;
                } 
                else if (num == best_so_far && col_sz == best_col_sz) {
                    n++;
                    if (m_random()%n == 0) {
                        result      = x_j;
                        out_a_ij    = a_ij;
                    }
                }                              
            }
        }
        return result < max ? result : null_var;
    }

    /**
       \brief Return the number of base variables that are non free and are v dependent.
       The function adds 1 to the result if v is non free.
       The function returns with a partial result r if r > best_so_far.
       This function is used to select the pivot variable.
    */
    template
    int simplex::get_num_non_free_dep_vars(var_t x_j, int best_so_far) {
        int result = is_non_free(x_j);
        col_iterator it = M.col_begin(x_j), end = M.col_end(x_j);
        for (; it != end; ++it) {
            var_t s = m_row2base[it.get_row().id()];
            result += is_non_free(s);
            if (result > best_so_far)
                return result;
        }
        return result;
    }
        
    /**
       \brief Using Bland's rule, select a variable x_j in the row r defining the base var x_i, 
       s.t. x_j can be used to patch the error in x_i.  Return null_var
       if there is no x_j. Otherwise, return x_j and store its coefficient
       in out_a_ij.
    */
    template
    typename simplex::var_t 
    simplex::select_pivot_blands(var_t x_i, bool is_below, scoped_numeral & out_a_ij) {
        SASSERT(is_base(x_i));
        unsigned max = get_num_vars();
        var_t result = max;
        row r(m_vars[x_i].m_base2row);
        row_iterator it = M.row_begin(r), end = M.row_end(r);
        for (; it != end; ++it) {
            var_t x_j = it->m_var;    
            numeral const & a_ij = it->m_coeff;                
            bool is_neg = is_below ? m.is_neg(a_ij) : m.is_pos(a_ij);
            if (x_i != x_j && ((!is_neg && above_lower(x_j)) || (is_neg && below_upper(x_j)))) {
                SASSERT(!is_base(x_j));
                if (x_j < result) { 
                    result = x_j; 
                    out_a_ij = a_ij; 
                }
            }
        }
        return result < max ? result : null_var;
    }

    template
    lbool simplex::minimize(var_t v) {
        
        // minimize v, such that tableau is feasible.
        // Assume there are no bounds on v.
        // Let  k*v + c*x = 0 e.g, maximize c*x over 
        // tableau constraints:
        //
        //   max { c*x | A*x = 0 and l <= x <= u }
        //
        // start with feasible assignment
        // A*x0 = 0 and l <= x0 <= u
        //
        // Identify pivot: i, j: such that x_i is base,
        // there is a row k1*x_i + k2*x_j + R = 0
        // and a delta such that:
        //
        // x_i' <- x_i + delta
        // x_j' <- x_j - delta*k1/k2
        // l_i <= x_i' <= u_i
        // l_j <= x_j' <= u_j
        // and c*x' > c*x
        // e.g., c*x := c_i*x_i + c_j*x_j + ...
        // and c_i*delta > c_j*delta*k1/k2 
        // and x_i < u_i (if delta > 0), l_i < x_i (if delta < 0)
        // and l_j < x_j (if delta > 0), x_j < u_j (if delta < 0)
        // 
        // update all rows, including c*x, using the pivot.
        // 
        // If there is c_i*x_i in c*x such that c_i > 0 
        // and upper_i = oo and complementary lower_j = -oo
        // then the objective is unbounded.
        // 
        // There is a singularity if there is a pivot such that
        // c_i*delta == c_j*delta*k1/k2, e.g., nothing is improved,
        // pivot, but use bland's rule to ensure
        // convergence in the limit.
        // 

        SASSERT(is_feasible());
        scoped_eps_numeral delta(em);
        scoped_numeral a_ij(m);
        var_t x_i, x_j;
        bool inc_x_i, inc_x_j;

        while (true) {
            if (!m_limit.inc()) {
                return l_undef;
            }
            select_pivot_primal(v, x_i, x_j, a_ij, inc_x_i, inc_x_j);
            if (x_j == null_var) {
                // optimal
                return l_true;
            }
            TRACE("simplex", tout << "x_i: v" << x_i << " x_j: v" << x_j << "\n";);
            var_info& vj = m_vars[x_j];
            if (x_i == null_var) {
                if (inc_x_j && vj.m_upper_valid) {
                    delta = vj.m_upper;
                    delta -= vj.m_value;
                    update_value(x_j, delta);
                }
                else if (!inc_x_j && vj.m_lower_valid) {
                    delta = vj.m_lower;
                    delta -= vj.m_value;
                    update_value(x_j, delta);
                }
                else {
                    // unbounded
                    return l_false;
                }
                continue;
            }

            // TBD: Change the value of x_j directly without pivoting:
            // 
            // if (!vj.is_fixed() && vj.bounded() && gain >= upper - lower) {
            // 
            // }
            // 

            pivot(x_i, x_j, a_ij);
            TRACE("simplex", display(tout << "after pivot\n"););
            move_to_bound(x_i, !inc_x_i);
            SASSERT(well_formed_row(row(m_vars[x_j].m_base2row)));
            TRACE("simplex", display(tout););
            SASSERT(is_feasible());
        }
        return l_true;
    }

    template
    void simplex::move_to_bound(var_t x, bool to_lower) {
        scoped_eps_numeral delta(em), delta2(em);
        var_info& vi = m_vars[x];
        if (to_lower) {
            em.sub(vi.m_value, vi.m_lower, delta);
        }
        else {
            em.sub(vi.m_upper, vi.m_value, delta);
        }
        TRACE("simplex", tout << "move " << (to_lower?"to_lower":"to_upper") 
              << " v" << x << " delta: " << em.to_string(delta) << "\n";);
        col_iterator it = M.col_begin(x), end = M.col_end(x);
        for (; it != end && is_pos(delta); ++it) {
            //
            // base_coeff*s + coeff*x + R = 0
            // 
            // to_lower    coeff > 0    base_coeff > 0     bound(s)
            // ------------------------------------------------------
            // T           T            T                  !to_lower
            // T           T            F                   to_lower
            // T           F            T                   to_lower
            // T           F            F                  !to_lower
            //
            var_t s = m_row2base[it.get_row().id()];
            var_info& vs = m_vars[s];
            numeral const& coeff = it.get_row_entry().m_coeff;
            numeral const& base_coeff = vs.m_base_coeff;
            SASSERT(!m.is_zero(coeff));
            bool base_to_lower = (m.is_pos(coeff) != m.is_pos(base_coeff)) == to_lower;
            eps_numeral const* bound = nullptr;
            if (!base_to_lower && vs.m_upper_valid) {
                bound = &vs.m_upper;
            }
            else if (base_to_lower && vs.m_lower_valid) {
                bound = &vs.m_lower;
            }
            if (bound) {
                // |delta2*coeff| = |(bound-value)*base_coeff|
                em.sub(*bound, vs.m_value, delta2);
                em.mul(delta2, base_coeff, delta2);
                em.div(delta2, coeff, delta2);
                em.abs(delta2);
                TRACE("simplex", tout << "Delta for v" << s << " " << delta2 << "\n";);
                if (delta2 < delta) {
                    delta = delta2;
                }
            }
        }
        if (to_lower) {
            delta.neg();
        }
        update_value(x, delta);        
    }

    /**
       \brief 
       Arguments:
       v   - base variable of row(v) to optimize
       x_i - base variable of row(x_i) to become non-base
       x_j - variable in row(v) to make a base variable
       a_ij - coefficient to x_j in row(x_i)
       inc  - whether to increment x_i 
     */
    template
    void simplex::select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij, 
                                           bool& inc_x_i, bool& inc_x_j) {
        row r(m_vars[v].m_base2row);
        row_iterator it = M.row_begin(r), end = M.row_end(r);
    
        scoped_eps_numeral gain(em), new_gain(em);
        scoped_numeral new_a_ij(m);
        x_i = null_var;
        x_j = null_var;
        inc_x_i = false;
        bool inc_y = false;

        for (; it != end; ++it) {
            var_t x = it->m_var;          
            if (x == v) continue; 
            bool inc_x = m.is_pos(it->m_coeff) == m.is_pos(m_vars[v].m_base_coeff);
            if ((inc_x && at_upper(x)) || (!inc_x && at_lower(x))) {
                TRACE("simplex", tout << "v" << x << " pos: " << inc_x 
                      << " at upper: " << at_upper(x) 
                      << " at lower: " << at_lower(x) << "\n";);
                continue; // variable cannot be used for improving bounds.
                // TBD check?
            }            
            var_t y = pick_var_to_leave(x, inc_x, new_gain, new_a_ij, inc_y);
            if (y == null_var) {
                // unbounded.
                x_i = y;
                x_j = x;
                inc_x_i = inc_y;
                inc_x_j = inc_x;
                a_ij = new_a_ij;
                break;
            }
            bool better = 
                (new_gain > gain) ||
                ((is_zero(new_gain) && is_zero(gain) && (x_i == null_var || y < x_i)));

            if (better) {
                TRACE("simplex", 
                      em.display(tout << "gain:", gain); 
                      em.display(tout << " new gain:", new_gain);
                      tout << " base x_i: " << y << ", new base x_j: " << x << ", inc x_j: " << inc_x << "\n";);

                x_i = y;
                x_j = x;
                inc_x_i = inc_y;
                inc_x_j = inc_x;
                gain = new_gain;
                a_ij = new_a_ij;
            }            
        }
    }

    //
    // y is a base variable.
    // v is a base variable.
    // v*a_v + x*a_x + E = 0
    // y*b_y + x*b_x + F = 0
    // inc(x)  := sign(a_v) == sign(a_x)
    // sign_eq := sign(b_y) == sign(b_x)
    // sign_eq => (inc(x) != inc(y))
    // !sign_eq => (inc(x) = inc(y))
    // -> 
    // inc(y) := sign_eq != inc(x)
    //

    template
    typename simplex::var_t 
    simplex::pick_var_to_leave(
        var_t x_j, bool inc_x_j, 
        scoped_eps_numeral& gain, scoped_numeral& new_a_ij, bool& inc_x_i) {
        var_t x_i = null_var;
        gain.reset();
        scoped_eps_numeral curr_gain(em);
        col_iterator it = M.col_begin(x_j), end = M.col_end(x_j);
        for (; it != end; ++it) {
            row r = it.get_row();
            var_t s = m_row2base[r.id()];
            var_info& vi = m_vars[s];
            numeral const& a_ij = it.get_row_entry().m_coeff;
            numeral const& a_ii = vi.m_base_coeff;
            bool sign_eq = (m.is_pos(a_ii) == m.is_pos(a_ij));
            bool inc_s =  sign_eq != inc_x_j;
            TRACE("simplex", tout << "x_j: v" << x_j << ", base x_i: v" << s 
                  << ", inc_x_i: " << inc_s 
                  << ", inc_x_j: " << inc_x_j 
                  << ", upper valid:" << vi.m_upper_valid 
                  << ", lower valid:" << vi.m_lower_valid << "\n";
                  display_row(tout, r););
            if ((inc_s && !vi.m_upper_valid) || (!inc_s && !vi.m_lower_valid)) {
                continue;
            }            
            // 
            // current gain: (value(x_i)-bound)*a_ii/a_ij
            // 
            curr_gain = vi.m_value;
            curr_gain -= inc_s?vi.m_upper:vi.m_lower;
            em.mul(curr_gain, a_ii, curr_gain);
            em.div(curr_gain, a_ij, curr_gain);
            if (is_neg(curr_gain)) {
                curr_gain.neg();
            }
            if (x_i == null_var || (curr_gain < gain) || 
                (is_zero(gain) && is_zero(curr_gain) && s < x_i)) {
                x_i = s;
                gain = curr_gain;
                new_a_ij = a_ij;
                inc_x_i = inc_s;
                TRACE("simplex", tout << "x_j v" << x_j << " x_i v" << x_i << " gain: ";
                      tout << curr_gain << "\n";);
            }
        }
        return x_i;
    }

    template
    void simplex::check_blands_rule(var_t v, unsigned& num_repeated) {
        if (m_bland) 
            return;
        if (m_left_basis.contains(v)) {
            num_repeated++;        
            if (num_repeated > m_blands_rule_threshold) {
                TRACE("simplex", tout << "using blands rule, " << num_repeated << "\n";);
                // std::cerr << "BLANDS RULE...\n";
                m_bland = true;
            }
        }
        else {
            m_left_basis.insert(v);
        }
    }


    template
    typename simplex::pivot_strategy_t 
    simplex::pivot_strategy() {
        if (m_bland) {
            return S_BLAND;
        }
        return S_DEFAULT;
    }

    template
    typename simplex::var_t 
    simplex::select_var_to_fix() {
        switch (pivot_strategy()) {
        case S_BLAND:
            return select_smallest_var();
        case S_GREATEST_ERROR:
            return select_error_var(false);
        case S_LEAST_ERROR:
            return select_error_var(true);
        default:
            return select_smallest_var();
        }
    }

    template
    typename simplex::var_t 
    simplex::select_error_var(bool least) {
        var_t best = null_var;
        scoped_eps_numeral best_error(em);
        scoped_eps_numeral curr_error(em);
        typename var_heap::iterator it  = m_to_patch.begin();
        typename var_heap::iterator end = m_to_patch.end();
        for (; it != end; ++it) {
            var_t v = *it;
            var_info const& vi = m_vars[v];
            if (below_lower(v)) 
                em.sub(vi.m_lower, vi.m_value, curr_error);
            else if (above_upper(v)) 
                em.sub(vi.m_value, vi.m_lower, curr_error);
            else
                continue;
            SASSERT(is_pos(curr_error));
            if ((best == null_var) ||
                (!least && curr_error > best_error) ||
                (least && curr_error < best_error)) {
                best = v;
                best_error = curr_error;
            }
        }
        if (best == null_var)
            m_to_patch.clear(); // all variables are satisfied
        else
            m_to_patch.erase(best);
        return best;
    }

    template
    bool simplex::well_formed() const {
        SASSERT(M.well_formed());
        for (unsigned i = 0; i < m_row2base.size(); ++i) {
            var_t s = m_row2base[i];
            if (s == null_var) continue;
            SASSERT(i == m_vars[s].m_base2row); 
            VERIFY(well_formed_row(row(i)));            
        }
        for (unsigned i = 0; i < m_vars.size(); ++i) {
            if (!is_base(i)) {
                SASSERT(!above_upper(i));
                SASSERT(!below_lower(i));
            }
        }
        return true;
    }

    template
    bool simplex::is_feasible() const {
        for (unsigned i = 0; i < m_vars.size(); ++i) {
            if (below_lower(i) || above_upper(i)) return false;            
        }
        return true;
    }

    template
    bool simplex::well_formed_row(row const& r) const {
        var_t s = m_row2base[r.id()];
        (void)s;
        SASSERT(m_vars[s].m_base2row == r.id());
        SASSERT(m_vars[s].m_is_base);
        // SASSERT(m.is_neg(m_vars[s].m_base_coeff));
        row_iterator it = M.row_begin(r), end = M.row_end(r);
        scoped_eps_numeral sum(em), tmp(em);
        for (; it != end; ++it) {
            em.mul(m_vars[it->m_var].m_value, it->m_coeff, tmp);
            sum += tmp;
            SASSERT(s != it->m_var || m.eq(m_vars[s].m_base_coeff, it->m_coeff));
        }
        if (!em.is_zero(sum)) {
            IF_VERBOSE(0, M.display_row(verbose_stream(), r););
            TRACE("pb", display(tout << "non-well formed row\n"); M.display_row(tout << "row: ", r););
            throw default_exception("non-well formed row");
        }

        return true;
    }

    template
    void simplex::collect_statistics(::statistics & st) const {
        M.collect_statistics(st);
        st.update("simplex num pivots", m_stats.m_num_pivots);
        st.update("simplex num infeasible", m_stats.m_num_infeasible);
        st.update("simplex num checks", m_stats.m_num_checks);
    }
        

};






© 2015 - 2024 Weber Informatics LLC | Privacy Policy