#pragma once
#include "util/mpz.h"
class mpz_matrix {
friend class mpz_matrix_manager;
friend class scoped_mpz_matrix;
unsigned m;
unsigned n;
mpz * a_ij;
public:
mpz_matrix():m(0), n(0), a_ij(nullptr) {}
mpz const & operator()(unsigned i, unsigned j) const {
SASSERT(i < m);
SASSERT(j < n);
return a_ij[i*n + j]; }
mpz & operator()(unsigned i, unsigned j) { SASSERT(i < m); SASSERT(j < n); return a_ij[i*n + j]; }
void swap(mpz_matrix & B) noexcept { std::swap(m, B.m); std::swap(n, B.n); std::swap(a_ij, B.a_ij); }
mpz * row(unsigned i) const { SASSERT(i < m); return a_ij + i*n; }
};
class mpz_matrix_manager {
unsynch_mpz_manager & m_nm;
small_object_allocator & m_allocator;
static void swap_rows(mpz_matrix & A, unsigned i, unsigned j);
bool normalize_row(mpz * A_i, unsigned n, mpz * b_i, bool int_solver);
bool eliminate(mpz_matrix & A, mpz * b, unsigned k1, unsigned k2, bool int_solver);
bool solve_core(mpz_matrix const & A, mpz * b, bool int_solver);
public:
mpz_matrix_manager(unsynch_mpz_manager & nm, small_object_allocator & a);
unsynch_mpz_manager & nm() const { return m_nm; }
void mk(unsigned m, unsigned n, mpz_matrix & A);
void del(mpz_matrix & r);
void set(mpz_matrix & A, mpz_matrix const & B);
void tensor_product(mpz_matrix const & A, mpz_matrix const & B, mpz_matrix & C);
bool solve(mpz_matrix const & A, mpz * b, mpz const * c);
bool solve(mpz_matrix const & A, int * b, int const * c);
void filter_cols(mpz_matrix const & A, unsigned num_cols, unsigned const * cols, mpz_matrix & B);
void permute_rows(mpz_matrix const & A, unsigned const * p, mpz_matrix & B);
unsigned linear_independent_rows(mpz_matrix const & A, unsigned * r, mpz_matrix & B);
void display(std::ostream & out, mpz_matrix const & A, unsigned cell_width=4) const;
};
class scoped_mpz_matrix {
friend class mpz_matrix_manager;
mpz_matrix_manager & m_manager;
mpz_matrix A;
public:
scoped_mpz_matrix(mpz_matrix_manager & m):m_manager(m) {}
scoped_mpz_matrix(mpz_matrix const & B, mpz_matrix_manager & m):m_manager(m) { m_manager.set(A, B); }
~scoped_mpz_matrix() { m_manager.del(A); }
mpz_matrix_manager & mm() const { return m_manager; }
unsynch_mpz_manager & nm() const { return mm().nm(); }
unsigned m() const { return A.m; }
unsigned n() const { return A.n; }
mpz * row(unsigned i) const { return A.row(i); }
operator mpz_matrix const &() const { return A; }
operator mpz_matrix &() { return A; }
mpz_matrix const & get() const { return A; }
mpz_matrix & get() { return A; }
void swap(mpz_matrix & B) noexcept { A.swap(B); }
void set(unsigned i, unsigned j, mpz const & v) { nm().set(A(i, j), v); }
void set(unsigned i, unsigned j, int v) { nm().set(A(i, j), v); }
mpz const & operator()(unsigned i, unsigned j) const { return A(i, j); }
mpz & operator()(unsigned i, unsigned j) { return A(i, j); }
int get_int(unsigned i, unsigned j) const { SASSERT(nm().is_int(A(i, j))); return nm().get_int(A(i, j)); }
};
inline std::ostream & operator<<(std::ostream & out, scoped_mpz_matrix const & m) {
m.mm().display(out, m);
return out;
}