inline void copy(const Dense& other)
 {
   nrows = other.nrows;
   ncols = other.ncols;
   std::vector<Float> new_m(other.m);
   std::swap(m, new_m);
 }
    inline void resize(const Int new_nrows, const Int new_ncols)
    {
      std::vector<Float> new_m(new_nrows * new_ncols);
      Int row_m = std::min(new_nrows, nrows);
      Int col_m = std::min(new_ncols, ncols);
      ITER_2(row_m, col_m)
	new_m[i*new_ncols + j] = at(i,j);
      std::swap(m, new_m);
      nrows = new_nrows;
      ncols = new_ncols;
    }
    inline void addRow(InIter begin)
    {
      Int nrows_new = nrows + 1;
      std::vector<Float> new_m(nrows_new * ncols);
      for (Int i = 0; i < nrows; ++i) 
	for (Int j = 0; j < ncols; ++j) 
	  new_m[i*ncols+j] = at(i,j);
      Int k = nrows*ncols;
      for (Int j = 0; j < ncols; ++j, ++begin)
	new_m[k+j] = *begin;
      std::swap(m, new_m);
      nrows = nrows_new;
    }
 inline void deleteCols(InIter del, InIter del_end)
 {
   Int ncols_new = ncols - (del_end - del);
   std::set<Int> del_set(del, del_end);
   std::vector<Float> new_m(nrows * ncols_new);
   Int j1 = 0;
   for (Int j = 0; j < ncols; ++j) {
     if (del_set.find(j) == del_set.end()) {
       for (Int i = 0; i < nrows; ++i) 
         new_m[i*ncols_new + j1] = at(i,j);
       ++j1;
     }
   }
   std::swap(m, new_m);
   ncols = ncols_new;
 }
 inline void deleteRows(InIter del, InIter del_end)
 {
   Int nrows_new = nrows - (del_end - del);
   std::set<Int> del_set(del, del_end);
   std::vector<Float> new_m(nrows_new * ncols);
   Int i1 = 0;
   for (Int i = 0; i < nrows; ++i) {
     if (del_set.find(i) == del_set.end()) {
       for (Int j = 0; j < ncols; ++j) 
         new_m[i1*ncols + j] = at(i,j);
       ++i1;
     }
   }
   std::swap(m, new_m);
   nrows = nrows_new;
 }
bool arith_solver_plugin::solve(expr * lhs, expr * rhs, expr_mark const & forbidden, app_ref & var, expr_ref & subst) {
    rational k;
    if (!m_simplifier.is_numeral(rhs, k))
        return false;
    bool _is_int = m_simplifier.is_int(lhs);
    ptr_buffer<expr> monomials;
    ptr_buffer<expr> todo;
    bool already_found = false;
    rational c;
    todo.push_back(lhs);
    while (!todo.empty()) {
        expr * curr = todo.back();
        todo.pop_back();
        rational coeff;
        if (m_simplifier.is_add(curr)) {
            SASSERT(to_app(curr)->get_num_args() == 2);
            todo.push_back(to_app(curr)->get_arg(1));
            todo.push_back(to_app(curr)->get_arg(0));
        }
        else {
            if (!already_found) {
                if (m_simplifier.is_mul(curr) && 
                    m_simplifier.is_numeral(to_app(curr)->get_arg(0), coeff) && !coeff.is_zero() && (!_is_int || coeff.is_minus_one()) && 
                    is_uninterp_const(to_app(curr)->get_arg(1)) &&
                    !forbidden.is_marked(to_app(curr)->get_arg(1))) {
                    c             = coeff;
                    var           = to_app(to_app(curr)->get_arg(1));
                    already_found = true;
                }
                else if (is_uninterp_const(curr) && !forbidden.is_marked(curr)) {
                    c             = rational::one();
                    var           = to_app(curr);
                    already_found = true;
                }
                else {
                    monomials.push_back(curr);
                }
            }
            else {
                monomials.push_back(curr);
            }
        }
    }
    if (!already_found)
        return false;
    SASSERT(!c.is_zero());
    k /= c;
    expr_ref_vector new_monomials(m_manager);
    if (!k.is_zero())
        new_monomials.push_back(m_simplifier.mk_numeral(k, _is_int));
    c.neg();
    expr_ref inv_c(m_manager);
    if (!c.is_one()) {
        rational inv(1);
        inv /= c;
        inv_c = m_simplifier.mk_numeral(inv, _is_int);
    }
    // divide monomials by c
    unsigned sz = monomials.size();
    for (unsigned i = 0; i < sz; i++) {
        expr * m       = monomials[i];
        expr_ref new_m(m_manager); 
        if (!c.is_one())
            m_simplifier.mk_mul(inv_c, m, new_m);
        else
            new_m = m;
        new_monomials.push_back(new_m);
    }
    if (new_monomials.empty()) 
        subst = m_simplifier.mk_numeral(rational(0), _is_int);
    else
        m_simplifier.mk_add(new_monomials.size(), new_monomials.c_ptr(), subst);
    TRACE("arith_solver", tout << "solving:\n" << mk_pp(lhs, m_manager) << "\n" << mk_pp(rhs, m_manager) 
          << "\nresult:\n" << mk_pp(var, m_manager) << "\n" << mk_pp(subst, m_manager) << "\n";);