Macaulay2 Engine
Loading...
Searching...
No Matches
dmat-lu-qq.hpp
Go to the documentation of this file.
1
34
36// ZZpFlint //////////
38
40
54template <>
55class DMatLinAlg<M2::ARingQQ>
56{
57 public:
61
62 public:
63 DMatLinAlg(const Mat& A) : mInputMatrix(A) {}
64 size_t rank()
65 {
67 fmpz_mat_t m1;
68 fmpz_mat_init(m1, A.numRows(), A.numColumns());
69 fmpq_mat_get_fmpz_mat_rowwise(m1, NULL, A.value());
70 size_t rk = fmpz_mat_rank(m1);
71 fmpz_mat_clear(m1);
72 return rk;
73 }
74
75 void determinant(ElementType& result_det)
76 {
78 fmpq_t det;
79 fmpq_init(det);
80 fmpq_mat_det(det, A.value());
81 fmpq_get_mpq(&result_det, det);
82 fmpq_clear(det);
83 }
84
85 static void findColumnRankProfileFromLU(const fmpq_mat_t B,
86 std::vector<size_t>& profile)
87 {
88 profile.clear();
89 long nrows = fmpq_mat_nrows(B);
90 long ncols = fmpq_mat_ncols(B);
91 long thiscol = 0;
92 long thisrow = 0;
93 while (thisrow < nrows and thiscol < ncols)
94 {
95 if (not fmpq_is_zero(fmpq_mat_entry(B, thisrow, thiscol)))
96 {
97 profile.push_back(thiscol);
98 thisrow++;
99 }
100 thiscol++;
101 }
102 }
103 void columnRankProfile(std::vector<size_t>& profile)
104 {
106 FlintQQMat B(A.numRows(), A.numColumns());
107 fmpq_mat_rref(B.value(), A.value());
108
110 }
111
112 void matrixPLU(std::vector<size_t>& P, Mat& L, Mat& U)
113 {
114 // std::cout << "calling matrixPLU FlintQQ\n";
115
116 // I had wanted to use fmpz_mat_fflu, but it doesn't return a LU decomposition
117 // only something similar, which doesn't actually give a factorization of A.
118 // Instead, we use the generic code for LU (in dmat-lu.hpp)
120
121 // std::cout << "calling matrixPLU generic\n";
123 const Mat& LU = luObject.LUinPlace();
124
126 P = luObject.permutation();
127 //return luObject.signOfPermutation();
128 }
129
130// #if 0
131// // The following code calls the fraction free LU decomp code in flint.
132// // But this is *not* what we want, I think.
133// FlintZZMat LU(A.numRows(), A.numColumns());
134// fmpz_t den, den2;
135// fmpz_init(den);
136// fmpz_init(den2);
137// mp_limb_signed_t* perm = newarray_atomic(mp_limb_signed_t, LU.numRows());
138// for (long i = 0; i < LU.numRows(); i++) perm[i] = i;
139// fmpq_mat_get_fmpz_mat_matwise(LU.value(), den, A.value());
140// int rk = fmpz_mat_fflu(LU.value(),
141// den2,
142// perm,
143// LU.value(),
144// 0); // the 0 means do not abort if rank is not maximal
145// fmpz_mat_print_pretty(LU.value());
146// fmpz_print(den2);
147// // std::cout << "rank = " << rk << std::endl;
148// P.resize(0);
149// for (long i = 0; i < LU.numRows(); i++) P.push_back(perm[i]);
150// freemem(perm);
151
152// fmpz_mul(den, den, den2); // total denominator
153// // Now we need to set L and U.
154// // Sigh, this code is taken and hacked from LUUtil<RingType>::setUpperLower.
155// size_t min = std::min(LU.numRows(), LU.numColumns());
156// L.resize(LU.numRows(), min);
157// U.resize(min, LU.numColumns());
158
159// // At this point, lower and upper should be zero matrices.
160// assert(MatrixOps::isZero(L));
161// assert(MatrixOps::isZero(U));
162
163// fmpq_t b;
164// fmpq_init(b);
165// for (size_t c = 0; c < LU.numColumns(); c++)
166// {
167// if (c < min) L.ring().set_from_long(L.entry(c, c), 1);
168// for (size_t r = 0; r < LU.numRows(); r++)
169// {
170// if (r <= c)
171// {
172// mpq_t a;
173// // Set the value in U by dividing the fmpz by the denom
174// // Note: the elements in LU have type fmpz_t
175// // the elements in L or U: have type mpq_t
176
177// fmpq_set_fmpz_frac(b, fmpz_mat_entry(LU.value(), r, c), den);
178// flint_mpq_init_set_readonly(a, b);
179// assert(U.ring().set_from_mpq(U.entry(r, c), a));
180// U.ring().set_from_mpq(U.entry(r, c), a); // ignore the result
181// // boolean: this
182// // operation should
183// // not fail
184// flint_mpq_clear_readonly(a);
185// }
186// else if (c < L.numRows())
187// {
188// mpz_t a;
189// flint_mpz_init_set_readonly(a,
190// fmpz_mat_entry(LU.value(), r, c));
191// L.ring().set_from_mpz(L.entry(r, c), a);
192// flint_mpz_clear_readonly(a);
193// }
194// }
195// }
196
197// fmpq_clear(b);
198// fmpz_clear(den);
199// fmpz_clear(den2);
200// }
201// #endif
202
203 bool solve(const Mat& B1, Mat& X1)
204 {
205 // This is the version where A = this isn't nec square or full rank...
206 // Plan for now (we will see how efficient this version is): put A|B into a
207 // single matrix.
208 // rref
209 // get column rank profile
210 // from that, either return false (inconsistent), or copy the correct values
211 // into X
212
213 // Too bad flint doesn't do this automatically...
214 // 1. copy A, B to flint objects
215 // 2. concatenate them
216 // 3. rref
217 // 4. pivot columns
218 // 5. if pivot column is in B columns, return false.
219 // 6. otherwise:
220 // resize X
221 // populate X with the solution (only non-zero entries are in pivot
222 // columns
223 // 6. copy
224 // TODO
225
226 long nrows = mInputMatrix.numRows();
227 long ncols = mInputMatrix.numColumns();
228 std::vector<size_t> profile;
229 Mat AB1(mInputMatrix.ring(), nrows, ncols + B1.numColumns());
231 FlintQQMat AB(AB1);
232 fmpq_mat_rref(AB.value(), AB.value());
233 findColumnRankProfileFromLU(AB.value(), profile);
234 if (profile[profile.size() - 1] >= ncols)
235 return false; // system is inconsistent
236 // At this point, we know the solutions. Should we go through FlintQQMat,
237 // or go directly to Mat?
238 FlintQQMat X(ncols, B1.numColumns());
239 for (long c = 0; c < B1.numColumns(); c++)
240 {
241 // Fill in this column
242 for (long r = 0; r < profile.size(); r++)
243 {
244 fmpq_set(fmpq_mat_entry(X.value(), profile[r], c),
245 fmpq_mat_entry(AB.value(), r, ncols + c));
246 }
247 }
248 X.toDMat(X1);
249 return true;
250 }
251
252 bool solveInvertible(const Mat& B1, Mat& X1)
253 {
255 FlintQQMat B(B1);
256 FlintQQMat X(mInputMatrix.numColumns(), B1.numColumns());
257 // int isfullrank = fmpq_mat_solve_fraction_free(X.value(), A.value(),
258 // B.value());
259 int isfullrank = fmpq_mat_solve_dixon(X.value(), A.value(), B.value());
260 if (isfullrank == 0) return false;
261 X.toDMat(X1);
262 return true;
263 }
264
265 bool inverse(Mat& result_inv)
266 {
268 // This seems like a lot of fuzzing around to get the inverse of a matrix
269 // over QQ...
270 // printf("in dmat-lu-qq inverse\n");
271 long nrows = A.numRows();
272 FlintQQMat inv(nrows, nrows);
273 fmpz_t D, den;
274 fmpz_mat_t matZZ, invZZ;
275 fmpz_init(D);
276 fmpz_init(den);
277 fmpz_mat_init(matZZ, nrows, nrows);
278 fmpz_mat_init(invZZ, nrows, nrows);
279
280 fmpq_mat_get_fmpz_mat_matwise(matZZ, D, A.value());
281 int result = fmpz_mat_inv(invZZ, den, matZZ); // sets invZZ, den
282 if (result != 0)
283 {
284 fmpq_mat_set_fmpz_mat_div_fmpz(inv.value(), invZZ, den);
285 fmpq_mat_scalar_mul_fmpz(inv.value(), inv.value(), D);
286 inv.toDMat(result_inv);
287 }
288 fmpz_clear(D);
289 fmpz_clear(den);
290 fmpz_mat_clear(matZZ);
291 fmpz_mat_clear(invZZ);
292 return (result != 0);
293 }
294
295 size_t kernel(Mat& result_nullspace)
296 {
298 // printf("in dmat-lu-qq kernel\n");
299 fmpz_mat_t matZZ;
300 fmpz_mat_t kerZZ;
301 fmpz_mat_init(matZZ, A.numRows(), A.numColumns());
302 fmpz_mat_init(kerZZ, A.numColumns(), A.numColumns());
303
304 fmpq_mat_get_fmpz_mat_rowwise(matZZ, NULL, A.value());
305 long nullity = fmpz_mat_nullspace(kerZZ, matZZ);
306 FlintQQMat kerQQ(A.numColumns(), nullity);
307 for (long r = 0; r < A.numColumns(); r++)
308 for (long c = 0; c < nullity; c++)
309 {
310 // There is no function which sets an fmpq from an fmpz!
311 kerQQ.set_from_fmpz(r, c, fmpz_mat_entry(kerZZ, r, c));
312 }
313 // fmpq_mat_set_fmpz_mat(kerQQ.value(), kerZZ);
314 kerQQ.toDMat(result_nullspace);
315 fmpz_mat_clear(matZZ);
316 fmpz_mat_clear(kerZZ);
317 return nullity;
318 }
319
320 private:
322};
323
324// Local Variables:
325// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
326// indent-tabs-mode: nil
327// End:
size_t numColumns() const
Definition dmat.hpp:145
Definition dmat.hpp:62
const Mat & LUinPlace()
const std::vector< size_t > & permutation()
bool inverse(Mat &result_inv)
void determinant(ElementType &result_det)
void matrixPLU(std::vector< size_t > &P, Mat &L, Mat &U)
void columnRankProfile(std::vector< size_t > &profile)
size_t kernel(Mat &result_nullspace)
static void findColumnRankProfileFromLU(const fmpq_mat_t B, std::vector< size_t > &profile)
bool solve(const Mat &B1, Mat &X1)
bool solveInvertible(const Mat &B1, Mat &X1)
RingType::ElementType ElementType
void set_from_fmpz(long r, long c, fmpz_t val)
fmpq_mat_struct * value()
void toDMat(DMatQQ &result)
RAII wrapper around FLINT's fmpq_mat_t for translating dense QQ-coefficient matrices between the engi...
static void setUpperLower(const Mat &LU, Mat &lower, Mat &upper)
__mpq_struct ElementType
Translation bridge that lets GMP-backed DMat<ARingQQ> borrow FLINT matrix arithmetic.
VALGRIND_MAKE_MEM_DEFINED & result(result)
static void concatenateMatrices(const Mat &A, const Mat &B, Mat &C)
Definition mat-util.hpp:90
ARingQQGMP ARingQQ
Definition aring-qq.hpp:38
Definition aring-CC.cpp:3