mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 12:28:44 +00:00
Add matrix operations needed for implementing non-naive sign determination
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
ff809db16d
commit
9c8b428ffb
409
src/math/realclosure/mpz_matrix.cpp
Normal file
409
src/math/realclosure/mpz_matrix.cpp
Normal file
|
@ -0,0 +1,409 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpz_matrix.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Matrix with integer coefficients. This is not a general purpose
|
||||
module for handling matrices with integer coefficients. Instead,
|
||||
it is a custom package that only contains operations needed to
|
||||
implement Sign Determination (Algorithm 10.11) in the Book:
|
||||
"Algorithms in real algebraic geometry", Basu, Pollack, Roy
|
||||
|
||||
Design choices:
|
||||
- Dense representation. The matrices in Alg 10.11 are small and dense.
|
||||
- Integer coefficients instead of rational coefficients (it only complicates the solver a little bit).
|
||||
Remark: in Algorithm 10.11, the coefficients of the input matrices are always in {-1, 0, 1}.
|
||||
During solving, bigger coefficients are produced, but they are usually very small. It may be
|
||||
an overkill to use mpz instead of int. We use mpz just to be safe.
|
||||
Remark: We do not use rational arithmetic. The solver is slightly more complicated with integers, but is saves space.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2013-01-07
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#include"mpz_matrix.h"
|
||||
#include"buffer.h"
|
||||
|
||||
mpz_matrix_manager::mpz_matrix_manager(unsynch_mpz_manager & nm, small_object_allocator & a):
|
||||
m_nm(nm),
|
||||
m_allocator(a) {
|
||||
}
|
||||
|
||||
mpz_matrix_manager::~mpz_matrix_manager() {
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::mk(unsigned m, unsigned n, mpz_matrix & A) {
|
||||
SASSERT(m > 0 && n > 0);
|
||||
del(A);
|
||||
A.m = m;
|
||||
A.n = n;
|
||||
A.a_ij = new (m_allocator) mpz[m*n];
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::del(mpz_matrix & A) {
|
||||
if (A.a_ij != 0) {
|
||||
for (unsigned i = 0; i < A.m; i++)
|
||||
for (unsigned j = 0; j < A.n; j++)
|
||||
nm().del(A(i,j));
|
||||
unsigned sz = sizeof(mpz) * A.m * A.n;
|
||||
m_allocator.deallocate(sz, A.a_ij);
|
||||
A.m = 0;
|
||||
A.n = 0;
|
||||
A.a_ij = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::set(mpz_matrix & A, mpz_matrix const & B) {
|
||||
if (&A == &B)
|
||||
return;
|
||||
if (A.m != B.m || A.n != B.n) {
|
||||
del(A);
|
||||
mk(B.m, B.n, A);
|
||||
}
|
||||
SASSERT(A.m == B.m && A.n == B.n);
|
||||
for (unsigned i = 0; i < B.m; i++)
|
||||
for (unsigned j = 0; j < B.n; j++)
|
||||
nm().set(A(i, j), B(i, j));
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::tensor_product(mpz_matrix const & A, mpz_matrix const & B, mpz_matrix & C) {
|
||||
scoped_mpz_matrix _C(*this);
|
||||
mk(A.m * B.m, A.n * B.n, _C);
|
||||
for (unsigned i = 0; i < _C.m(); i++)
|
||||
for (unsigned j = 0; j < _C.n(); j++)
|
||||
nm().mul(A(i / B.m, j / B.n),
|
||||
B(i % B.m, j % B.n),
|
||||
_C(i, j));
|
||||
C.swap(_C);
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::swap_rows(mpz_matrix & A, unsigned i, unsigned j) {
|
||||
if (i != j) {
|
||||
for (unsigned k = 0; k < A.n; k++)
|
||||
::swap(A(i, k), A(j, k));
|
||||
}
|
||||
}
|
||||
|
||||
// If b_i == 0, then method just divides the given row by its GCD
|
||||
// If b_i != 0
|
||||
// If the GCD of the row divides *b_i
|
||||
// divide the row and *b_i by the GCD
|
||||
// Else
|
||||
// If int_solver == true ==> return false (the system is unsolvable)
|
||||
bool mpz_matrix_manager::normalize_row(mpz * A_i, unsigned n, mpz * b_i, bool int_solver) {
|
||||
scoped_mpz g(nm());
|
||||
bool first = true;
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
if (nm().is_zero(A_i[j]))
|
||||
continue;
|
||||
if (first) {
|
||||
nm().set(g, A_i[j]);
|
||||
nm().abs(g);
|
||||
first = false;
|
||||
}
|
||||
else {
|
||||
nm().gcd(g, A_i[j], g);
|
||||
}
|
||||
if (nm().is_one(g))
|
||||
return true;
|
||||
}
|
||||
if (first)
|
||||
return true; // zero row
|
||||
if (!nm().is_one(g)) {
|
||||
if (b_i) {
|
||||
if (nm().divides(g, *b_i)) {
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
nm().div(A_i[j], g, A_i[j]);
|
||||
}
|
||||
nm().div(*b_i, g, *b_i);
|
||||
}
|
||||
else {
|
||||
if (int_solver)
|
||||
return false; // system does not have an integer solution
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (unsigned j = 0; j < n; j++) {
|
||||
nm().div(A_i[j], g, A_i[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Given a matrix of the form
|
||||
|
||||
k2
|
||||
|
|
||||
V
|
||||
X X ... X X ... X
|
||||
0 X ... X X ... X
|
||||
... ... X X ... X
|
||||
k1=> 0 0 ... 0 X ... X
|
||||
0 0 ... 0 X ... X
|
||||
... ... 0 X ... X
|
||||
0 0 ... 0 X ... X
|
||||
|
||||
It will "zero" the elements a_{k1+1, k2} ... a_{m, k2} by addining multiples of the row k1 to multiples of the
|
||||
rows k1+1, ..., m
|
||||
|
||||
The resultant matrix will look like
|
||||
|
||||
k2
|
||||
|
|
||||
V
|
||||
X X ... X X ... X
|
||||
0 X ... X X ... X
|
||||
... ... X X ... X
|
||||
k1=> 0 0 ... 0 X ... X
|
||||
0 0 ... 0 0 ... X
|
||||
... ... 0 0 ... X
|
||||
0 0 ... 0 0 ... X
|
||||
|
||||
|
||||
If b != 0, then the transformations are also applied to b.
|
||||
If int_solver == true and b != 0, then the method returns false if when
|
||||
performing the transformations it detected that it is impossible to
|
||||
solve the integer system of equations A x = b.
|
||||
*/
|
||||
bool mpz_matrix_manager::eliminate(mpz_matrix & A, mpz * b, unsigned k1, unsigned k2, bool int_solver) {
|
||||
// check if first k2-1 positions of row k1 are 0
|
||||
DEBUG_CODE(for (unsigned j = 0; j < k2; j++) { SASSERT(nm().is_zero(A(k1, j))); });
|
||||
mpz & a_kk = A(k1, k2);
|
||||
SASSERT(!nm().is_zero(a_kk));
|
||||
scoped_mpz t1(nm()), t2(nm());
|
||||
scoped_mpz a_ik_prime(nm()), a_kk_prime(nm()), lcm_a_kk_a_ik(nm());
|
||||
// for all rows below pivot
|
||||
for (unsigned i = k1+1; i < A.m; i++) {
|
||||
// check if first k-1 positions of row k are 0
|
||||
DEBUG_CODE(for (unsigned j = 0; j < k2; j++) { SASSERT(nm().is_zero(A(i, j))); });
|
||||
mpz & a_ik = A(i, k2);
|
||||
if (!nm().is_zero(a_ik)) {
|
||||
// a_ik' = lcm(a_kk, a_ik)/a_kk
|
||||
// a_kk' = lcm(a_kk, a_ik)/a_ik
|
||||
nm().lcm(a_kk, a_ik, lcm_a_kk_a_ik);
|
||||
nm().div(lcm_a_kk_a_ik, a_kk, a_ik_prime);
|
||||
nm().div(lcm_a_kk_a_ik, a_ik, a_kk_prime);
|
||||
for (unsigned j = k2+1; j < A.n; j++) {
|
||||
// a_ij <- a_kk' * a_ij - a_ik' * a_kj
|
||||
nm().mul(a_ik_prime, A(k1, j), t1);
|
||||
nm().mul(a_kk_prime, A(i, j), t2);
|
||||
nm().sub(t2, t1, A(i, j));
|
||||
}
|
||||
if (b) {
|
||||
// b_i <- a_kk' * b_i - a_ik' * b_k
|
||||
nm().mul(a_ik_prime, b[k1], t1);
|
||||
nm().mul(a_kk_prime, b[i], t2);
|
||||
nm().sub(t2, t1, b[i]);
|
||||
}
|
||||
// a_ik <- 0
|
||||
nm().set(A(i, k2), 0);
|
||||
// normalize row i
|
||||
if (!normalize_row(A.row(i), A.n, b ? &(b[i]) : 0, int_solver))
|
||||
return false;
|
||||
}
|
||||
SASSERT(nm().is_zero(A(i, k2)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpz_matrix_manager::solve_core(mpz_matrix const & _A, mpz * b, bool int_solver) {
|
||||
SASSERT(_A.n == _A.m);
|
||||
scoped_mpz_matrix A(*this);
|
||||
set(A, _A);
|
||||
for (unsigned k = 0; k < A.m(); k++) {
|
||||
TRACE("mpz_matrix",
|
||||
tout << "k: " << k << "\n" << A;
|
||||
tout << "b:";
|
||||
for (unsigned i = 0; i < A.m(); i++) {
|
||||
tout << " ";
|
||||
nm().display(tout, b[i]);
|
||||
}
|
||||
tout << "\n";);
|
||||
// find pivot
|
||||
unsigned i = k;
|
||||
for (; i < A.m(); i++) {
|
||||
if (!nm().is_zero(A(i, k)))
|
||||
break;
|
||||
}
|
||||
if (i == A.m())
|
||||
return false; // matrix is singular
|
||||
// swap rows k and i
|
||||
swap_rows(A, k, i);
|
||||
swap(b[k], b[i]);
|
||||
//
|
||||
if (!eliminate(A, b, k, k, int_solver))
|
||||
return false;
|
||||
}
|
||||
// Back substitution
|
||||
unsigned k = A.m();
|
||||
while (k > 0) {
|
||||
--k;
|
||||
DEBUG_CODE(for (unsigned j = 0; j < A.n(); j++) { SASSERT(j == k || nm().is_zero(A(k, j))); });
|
||||
SASSERT(!nm().is_zero(A(k, k)));
|
||||
if (nm().divides(A(k, k), b[k])) {
|
||||
nm().div(b[k], A(k, k), b[k]);
|
||||
nm().set(A(k, k), 1);
|
||||
}
|
||||
else {
|
||||
if (int_solver)
|
||||
return false; // no integer solution
|
||||
if (nm().is_neg(A(k, k))) {
|
||||
nm().neg(A(k, k));
|
||||
nm().neg(b[k]);
|
||||
}
|
||||
}
|
||||
if (!int_solver) {
|
||||
// REMARK:
|
||||
// For the sign determination algorithm, we only use int_solver == true.
|
||||
//
|
||||
// TODO: implement backward substitution when int_solver == false
|
||||
// In this case, A(k, k) may not be 1.
|
||||
NOT_IMPLEMENTED_YET();
|
||||
}
|
||||
SASSERT(!int_solver || nm().is_one(A(k, k)));
|
||||
// back substitute
|
||||
unsigned i = k;
|
||||
while (i > 0) {
|
||||
--i;
|
||||
// Assuming int_solver == true
|
||||
SASSERT(int_solver); // See comment above
|
||||
// b_i <- b_i - a_ik * b_k
|
||||
nm().submul(b[i], A(i, k), b[k], b[i]);
|
||||
nm().set(A(i, k), 0);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool mpz_matrix_manager::solve(mpz_matrix const & A, mpz * b, mpz const * c) {
|
||||
for (unsigned i = 0; i < A.n; i++)
|
||||
nm().set(b[i], c[i]);
|
||||
return solve_core(A, b, true);
|
||||
}
|
||||
|
||||
bool mpz_matrix_manager::solve(mpz_matrix const & A, int * b, int const * c) {
|
||||
scoped_mpz_matrix _b(*this);
|
||||
mk(A.n, 1, _b);
|
||||
for (unsigned i = 0; i < A.n; i++)
|
||||
nm().set(_b(i,0), c[i]);
|
||||
bool r = solve_core(A, _b.A.a_ij, true);
|
||||
if (r) {
|
||||
for (unsigned i = 0; i < A.n; i++)
|
||||
b[i] = _b.get_int(i, 0);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::filter_cols(mpz_matrix const & A, unsigned num_cols, unsigned const * cols, mpz_matrix & B) {
|
||||
SASSERT(num_cols <= A.n);
|
||||
// Check pre-condition:
|
||||
// - All elements in cols are smaller than A.n
|
||||
// - cols is sorted
|
||||
// - cols does not contain repeated elements
|
||||
DEBUG_CODE({
|
||||
for (unsigned i = 0; i < num_cols; i ++) {
|
||||
SASSERT(cols[i] < A.n);
|
||||
SASSERT(i == 0 || cols[i-1] < cols[i]);
|
||||
}
|
||||
});
|
||||
if (num_cols == A.n) {
|
||||
// keep everything
|
||||
set(B, A);
|
||||
}
|
||||
else {
|
||||
SASSERT(num_cols < A.n);
|
||||
scoped_mpz_matrix C(*this);
|
||||
mk(A.m, num_cols, C);
|
||||
for (unsigned i = 0; i < A.m; i++)
|
||||
for (unsigned j = 0; j < num_cols; j++)
|
||||
nm().set(C(i, j), A(i, cols[j]));
|
||||
B.swap(C);
|
||||
}
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::permute_rows(mpz_matrix const & A, unsigned const * p, mpz_matrix & B) {
|
||||
// Check if p is really a permutation
|
||||
DEBUG_CODE({
|
||||
buffer<bool> seen;
|
||||
seen.resize(A.m, false);
|
||||
for (unsigned i = 0; i < A.m; i++) {
|
||||
SASSERT(p[i] < A.m);
|
||||
SASSERT(!seen[p[i]]);
|
||||
seen[p[i]] = true;
|
||||
}
|
||||
});
|
||||
scoped_mpz_matrix C(*this);
|
||||
mk(A.m, A.n, C);
|
||||
for (unsigned i = 0; i < A.m; i++)
|
||||
for (unsigned j = 0; j < A.n; j++)
|
||||
nm().set(C(i, j), A(p[i], j));
|
||||
B.swap(C);
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::linear_independent_rows(mpz_matrix const & _A, unsigned_vector & r) {
|
||||
r.reset();
|
||||
scoped_mpz_matrix A(*this);
|
||||
scoped_mpz g(nm());
|
||||
scoped_mpz t1(nm()), t2(nm());
|
||||
scoped_mpz a_ik_prime(nm()), a_kk_prime(nm()), lcm_a_kk_a_ik(nm());
|
||||
set(A, _A);
|
||||
sbuffer<unsigned, 128> rows;
|
||||
rows.resize(A.m(), 0);
|
||||
for (unsigned i = 0; i < A.m(); i++)
|
||||
rows[i] = i;
|
||||
for (unsigned k1 = 0, k2 = 0; k1 < A.m(); k1++) {
|
||||
TRACE("mpz_matrix", tout << "k1: " << k1 << ", k2: " << k2 << "\n" << A;);
|
||||
// find pivot
|
||||
unsigned pivot = UINT_MAX;
|
||||
for (unsigned i = k1; i < A.m(); i++) {
|
||||
if (!nm().is_zero(A(i, k2))) {
|
||||
if (pivot == UINT_MAX) {
|
||||
pivot = i;
|
||||
}
|
||||
else {
|
||||
if (rows[i] < rows[pivot])
|
||||
pivot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pivot == UINT_MAX)
|
||||
continue;
|
||||
// swap rows k and pivot
|
||||
swap_rows(A, k1, pivot);
|
||||
std::swap(rows[k1], rows[pivot]);
|
||||
//
|
||||
r.push_back(rows[k1]);
|
||||
if (r.size() >= A.n())
|
||||
break;
|
||||
eliminate(A, 0, k1, k2, false);
|
||||
k2++;
|
||||
}
|
||||
std::sort(r.begin(), r.end());
|
||||
}
|
||||
|
||||
void mpz_matrix_manager::display(std::ostream & out, mpz_matrix const & A, unsigned cell_width) const {
|
||||
out << A.m << " x " << A.n << " Matrix\n";
|
||||
for (unsigned i = 0; i < A.m; i++) {
|
||||
for (unsigned j = 0; j < A.n; j++) {
|
||||
if (j > 0)
|
||||
out << " ";
|
||||
std::string s = nm().to_string(A(i, j));
|
||||
if (s.size() < cell_width) {
|
||||
unsigned space = cell_width - s.size();
|
||||
for (unsigned k = 0; k < space; k++)
|
||||
out << " ";
|
||||
}
|
||||
out << s;
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
151
src/math/realclosure/mpz_matrix.h
Normal file
151
src/math/realclosure/mpz_matrix.h
Normal file
|
@ -0,0 +1,151 @@
|
|||
/*++
|
||||
Copyright (c) 2013 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
mpz_matrix.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Matrix with integer coefficients. This is not a general purpose
|
||||
module for handling matrices with integer coefficients. Instead,
|
||||
it is a custom package that only contains operations needed to
|
||||
implement Sign Determination (Algorithm 10.11) in the Book:
|
||||
"Algorithms in real algebraic geometry", Basu, Pollack, Roy
|
||||
|
||||
Design choices:
|
||||
- Dense representation. The matrices in Alg 10.11 are small and dense.
|
||||
- Integer coefficients instead of rational coefficients (it only complicates the solver a little bit).
|
||||
Remark: in Algorithm 10.11, the coefficients of the input matrices are always in {-1, 0, 1}.
|
||||
During solving, bigger coefficients are produced, but they are usually very small. It may be
|
||||
an overkill to use mpz instead of int. We use mpz just to be safe.
|
||||
Remark: We do not use rational arithmetic. The solver is slightly more complicated with integers, but is saves space.
|
||||
|
||||
Author:
|
||||
|
||||
Leonardo (leonardo) 2013-01-07
|
||||
|
||||
Notes:
|
||||
|
||||
--*/
|
||||
#ifndef _MPZ_MATRIX_H_
|
||||
#define _MPZ_MATRIX_H_
|
||||
|
||||
#include"mpz.h"
|
||||
|
||||
/**
|
||||
\brief A mxn matrix.
|
||||
Remark: Algorithm 10.11 only uses square matrices, but supporting
|
||||
arbitrary matrices does not increase the complexity of this module.
|
||||
*/
|
||||
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(0) {}
|
||||
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) { 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);
|
||||
~mpz_matrix_manager();
|
||||
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);
|
||||
/**
|
||||
\brief Solve A*b = c
|
||||
|
||||
Return false if the system does not have an integer solution.
|
||||
|
||||
\pre A is a square matrix
|
||||
\pre b and c are vectors of size A.n (== A.m)
|
||||
*/
|
||||
bool solve(mpz_matrix const & A, mpz * b, mpz const * c);
|
||||
/**
|
||||
\brief Solve A*b = c
|
||||
|
||||
Return false if the system does not have an integer solution.
|
||||
|
||||
\pre A is a square matrix
|
||||
\pre b and c are vectors of size A.n (== A.m)
|
||||
*/
|
||||
bool solve(mpz_matrix const & A, int * b, int const * c);
|
||||
/**
|
||||
\brief Store in B that contains the subset cols of columns of A.
|
||||
|
||||
\pre num_cols <= A.n
|
||||
\pre Forall i < num_cols, cols[i] < A.n
|
||||
\pre Forall 0 < i < num_cols, cols[i-1] < cols[i]
|
||||
*/
|
||||
void filter_cols(mpz_matrix const & A, unsigned num_cols, unsigned const * cols, mpz_matrix & B);
|
||||
/**
|
||||
\brief Store in B the matrix obtained after applying the given permutation to the rows of A.
|
||||
*/
|
||||
void permute_rows(mpz_matrix const & A, unsigned const * p, mpz_matrix & B);
|
||||
/**
|
||||
\brief Store in r the row (ids) of A that are linear independent.
|
||||
|
||||
\remark If there is an option between rows i and j,
|
||||
this method will give preference to the row that occurs first.
|
||||
*/
|
||||
void linear_independent_rows(mpz_matrix const & A, unsigned_vector & r);
|
||||
|
||||
// method for debugging purposes
|
||||
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) { 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;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -17,6 +17,7 @@ Notes:
|
|||
|
||||
--*/
|
||||
#include"realclosure.h"
|
||||
#include"mpz_matrix.h"
|
||||
|
||||
static void tst1() {
|
||||
unsynch_mpq_manager qm;
|
||||
|
@ -66,6 +67,87 @@ static void tst1() {
|
|||
std::cout << interval_pp((a + eps)/(a - eps)) << std::endl;
|
||||
}
|
||||
|
||||
void tst_rcf() {
|
||||
tst1();
|
||||
static void tst2() {
|
||||
enable_trace("mpz_matrix");
|
||||
unsynch_mpq_manager nm;
|
||||
small_object_allocator allocator;
|
||||
mpz_matrix_manager mm(nm, allocator);
|
||||
scoped_mpz_matrix A(mm);
|
||||
mm.mk(3, 3, A);
|
||||
// Matrix
|
||||
// 1 1 1
|
||||
// 0 1 -1
|
||||
// 0 1 1
|
||||
A.set(0, 0, 1); A.set(0, 1, 1); A.set(0, 2, 1);
|
||||
A.set(1, 0, 0); A.set(1, 1, 1); A.set(1, 2, -1);
|
||||
A.set(2, 0, 0); A.set(2, 1, 1); A.set(2, 2, 1);
|
||||
std::cout << A;
|
||||
{
|
||||
int b[3];
|
||||
int c[3] = { 10, -2, 8 };
|
||||
std::cout << "solve: " << mm.solve(A, b, c) << "\n";
|
||||
for (unsigned i = 0; i < 3; i++) std::cout << b[i] << " ";
|
||||
std::cout << "\n";
|
||||
}
|
||||
scoped_mpz_matrix A2(mm);
|
||||
mm.tensor_product(A, A, A2);
|
||||
std::cout << A2;
|
||||
scoped_mpz_matrix B(mm);
|
||||
unsigned cols[] = { 1, 3, 7, 8 };
|
||||
mm.filter_cols(A2, 4, cols, B);
|
||||
std::cout << B;
|
||||
scoped_mpz_matrix C(mm);
|
||||
unsigned perm[] = { 8, 7, 6, 5, 4, 3, 2, 1, 0 };
|
||||
mm.permute_rows(B, perm, C);
|
||||
std::cout << C;
|
||||
}
|
||||
|
||||
static void tst_solve(unsigned n, int _A[], int _b[], int _c[], bool solved) {
|
||||
unsynch_mpq_manager nm;
|
||||
small_object_allocator allocator;
|
||||
mpz_matrix_manager mm(nm, allocator);
|
||||
scoped_mpz_matrix A(mm);
|
||||
mm.mk(n, n, A);
|
||||
for (unsigned i = 0; i < n; i++)
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
A.set(i, j, _A[i*n + j]);
|
||||
svector<int> b;
|
||||
b.resize(n, 0);
|
||||
if (mm.solve(A, b.c_ptr(), _c)) {
|
||||
SASSERT(solved);
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
SASSERT(b[i] == _b[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
SASSERT(!solved);
|
||||
}
|
||||
}
|
||||
|
||||
static void tst_lin_indep(unsigned m, unsigned n, int _A[], unsigned ex_sz, unsigned ex_r[]) {
|
||||
unsynch_mpq_manager nm;
|
||||
small_object_allocator allocator;
|
||||
mpz_matrix_manager mm(nm, allocator);
|
||||
scoped_mpz_matrix A(mm);
|
||||
mm.mk(m, n, A);
|
||||
for (unsigned i = 0; i < m; i++)
|
||||
for (unsigned j = 0; j < n; j++)
|
||||
A.set(i, j, _A[i*n + j]);
|
||||
unsigned_vector r;
|
||||
mm.linear_independent_rows(A, r);
|
||||
SASSERT(r.size() == ex_sz);
|
||||
for (unsigned i = 0; i < ex_sz; i++) {
|
||||
SASSERT(r[i] == ex_r[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void tst_rcf() {
|
||||
// tst1();
|
||||
tst2();
|
||||
{ int A[] = {0, 1, 1, 1, 0, 1, 1, 1, -1}; int c[] = {10, 4, -4}; int b[] = {-2, 4, 6}; tst_solve(3, A, b, c, true); }
|
||||
{ int A[] = {1, 1, 1, 0, 1, 1, 0, 1, 1}; int c[] = {3, 2, 2}; int b[] = {1, 1, 1}; tst_solve(3, A, b, c, false); }
|
||||
{ int A[] = {1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, -1}; unsigned r[] = {0, 1, 4}; tst_lin_indep(5, 3, A, 3, r); }
|
||||
{ int A[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, -1}; unsigned r[] = {0, 4}; tst_lin_indep(5, 3, A, 2, r); }
|
||||
{ int A[] = {1, 1, 1, 1, 1, 1, 1, 0, 1, 2, 1, 2, 3, 1, 3}; unsigned r[] = {0, 2}; tst_lin_indep(5, 3, A, 2, r); }
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue