Macaulay2 Engine
Loading...
Searching...
No Matches
det.cpp
Go to the documentation of this file.
1// Copyright 1996 Michael E. Stillman.
2
3#include "det.hpp"
4#include "text-io.hpp"
5#include "interrupted.hpp"
6#include "comb.hpp"
7
9 int p0,
10 bool do_exterior0,
11 int strategy0)
12 : R(M0->get_ring()),
13 M(M0),
14 done(false),
15 p(p0),
16 do_exterior(do_exterior0),
17 strategy(strategy0),
18 row_set(nullptr),
19 col_set(nullptr),
20 this_row(0),
21 this_col(0),
22 D(nullptr),
24{
25 if (do_exterior)
26 {
27 F = M->rows()->exterior(p);
28 FreeModule *G = M->cols()->exterior(p);
29 int *deg = R->degree_monoid()->make_new(M->degree_shift());
30 R->degree_monoid()->power(deg, p, deg);
31 result = MatrixConstructor(F, G, deg);
32 R->degree_monoid()->remove(deg);
33 }
34 else
35 {
36 F = R->make_FreeModule(1);
38 }
39
40 // Handle trivial cases
41 if (p < 0)
42 {
43 // In either case, want a zero matrix
44 done = true;
45 return;
46 }
47 if (p == 0)
48 {
49 // We want a single element which is '1'
50 if (do_exterior)
51 result.set_entry(0, 0, R->one());
52 else
53 result.append(R->make_vec(0, R->one()));
54 done = true;
55 return;
56 }
57 if (p > M->n_rows() || p > M->n_cols())
58 {
59 // Zero matrix in either case
60 done = true;
61 return;
62 }
63 done = false;
64
65 row_set = newarray_atomic(size_t, p);
66 col_set = newarray_atomic(size_t, p);
67
68 for (size_t i = 0; i < p; i++)
69 {
70 row_set[i] = i;
71 col_set[i] = i;
72 }
73
74 D = newarray(ring_elem *, p);
75 for (size_t i = 0; i < p; i++)
76 {
77 D[i] = newarray(ring_elem, p);
78 for (size_t j = 0; j < p; j++) D[i][j] = ZERO_RINGELEM;
79 }
80}
81
83{
86
87 if (D)
88 {
89 for (size_t i = 0; i < p; i++) freemem(D[i]);
90 freemem(D);
91 }
92}
93
95{
96 // Traverse through matrix entries, find nonzero entries
97 int nonzero = -1;
98 for (int i = 0; i < M->n_rows(); ++i)
99 {
100 bool flag = false;
101 for (int j = 0; j < M->n_cols(); ++j)
102 {
103 if (!R->is_zero(M->elem(i, j)))
104 {
105 if (!flag)
106 {
107 flag = true;
108 dynamic_cache[0][++nonzero] = {};
109 row_lookup[i] = nonzero;
110 }
111 dynamic_cache[0][nonzero][{{i}, {j}}] = M->elem(i, j);
112 }
113 }
114 }
115 int n_nonzero_rows = dynamic_cache[0].size();
116 for (int minor_size = 1; minor_size < p; ++minor_size)
117 {
118 for (int top_row = p - (minor_size + 1);
119 top_row <= n_nonzero_rows - minor_size;
120 ++top_row)
121 {
122 dynamic_cache[minor_size].insert({top_row, {}});
123 for (const auto &[pp, map] : dynamic_cache[minor_size - 1])
124 {
125 if (system_interrupted())
126 return COMP_INTERRUPTED; // Allow interruption
127 if (pp <= top_row)
128 {
129 continue;
130 } // top_row wouldn't be the top row, so skip
131 for (auto x : dynamic_cache[0][top_row])
132 {
133 for (const auto &[Didx, Dval] : map)
134 {
135 // Check if x and D live on distinct columns
136 const std::vector<int> &Dcols = Didx.second;
137 int xcol = x.first.second[0];
138 auto col_find =
139 std::find(Dcols.begin(), Dcols.end(), xcol);
140 if (col_find != Dcols.end())
141 {
142 continue;
143 } // xcol found in Dcols, so skip
144 // if no skip, compute a term in the cofactor
145 ColRowIndices newKey = Didx;
146 newKey.first.insert(newKey.first.begin(),
147 x.first.first[0]);
148 // Get iterator to future location of xcol
149 auto xcol_position = std::upper_bound(
150 newKey.second.begin(), newKey.second.end(), xcol);
151 newKey.second.insert(xcol_position, xcol);
152 bool negate =
153 ((xcol_position - newKey.second.begin()) % 2 != 0);
154 // Insert, add or negate cofactor term
155 auto search =
156 dynamic_cache[minor_size][top_row].find(newKey);
157 if (search == dynamic_cache[minor_size][top_row].end())
158 { // not found
159 dynamic_cache[minor_size][top_row].insert(
160 {newKey, R->mult(x.second, Dval)});
161 if (negate)
162 {
163 R->negate_to(
164 dynamic_cache[minor_size][top_row][newKey]);
165 }
166 }
167 else
168 { // found
169 if (!negate)
170 {
171 R->add_to(
172 dynamic_cache[minor_size][top_row][newKey],
173 R->mult(x.second, Dval));
174 }
175 else
176 {
177 R->subtract_to(
178 dynamic_cache[minor_size][top_row][newKey],
179 R->mult(x.second, Dval));
180 }
181 }
182 }
183 }
184 }
185 }
186 }
187 return COMP_DONE;
188}
189
191// Compute one more determinant of size p.
192// increments I and/or J and updates 'dets', 'table'.
193{
194 if (done) return COMP_DONE;
195
196 ring_elem r;
197
198 if (strategy == DET_BAREISS)
199 {
201 r = bareiss_det();
202 }
203 else if (strategy == DET_DYNAMIC)
204 {
205 if (dynamic_cache.empty())
206 { // Cache minors if needed
207 dynamic_cache.resize(p);
209 }
210 std::vector<int> row_vec(p), col_vec(p);
211 for (int i = 0; i < p; ++i)
212 {
213 row_vec[i] = static_cast<int>(row_set[i]);
214 col_vec[i] = static_cast<int>(col_set[i]);
215 }
216 // Find row number
217 const Subdeterminant &map = dynamic_cache[p - 1][row_lookup[row_vec[0]]];
218 auto it = map.find({row_vec, col_vec});
219 if (it != map.end()) { r = it->second; }
220 else { r = ZERO_RINGELEM; }
221 }
222 else
223 r = calc_det(row_set, col_set, p);
224
225 if (!R->is_zero(r))
226 {
227 if (do_exterior)
228 result.set_entry(this_row, this_col, r);
229 else
230 result.append(R->make_vec(0, r));
231 }
232 else
233 R->remove(r);
234
235 this_row++;
236 if (!Subsets::increment(M->n_rows(), p, row_set))
237 {
238 // Now we increment column
239 if (!Subsets::increment(M->n_cols(), p, col_set))
240 {
241 done = true;
242 return COMP_DONE;
243 }
244 // Now set the row set back to initial value
245 this_col++;
246 this_row = 0;
247 for (size_t i = 0; i < p; i++) row_set[i] = i;
248 }
249 return COMP_COMPUTING;
250}
251
253{
254 if (do_exterior) return;
256}
257
258void DetComputation::set_next_minor(const int *rows, const int *cols)
259{
260 if (do_exterior) return;
261 if (rows != nullptr && Subsets::isValid(M->n_rows(), p, rows))
262 for (size_t i = 0; i < p; i++) row_set[i] = rows[i];
263 else
264 for (size_t i = 0; i < p; i++) row_set[i] = i;
265
266 if (cols != nullptr && Subsets::isValid(M->n_cols(), p, cols))
267 for (size_t i = 0; i < p; i++) col_set[i] = cols[i];
268 else
269 for (size_t i = 0; i < p; i++) col_set[i] = i;
270}
271
272int DetComputation::calc(int nsteps)
273{
274 for (;;)
275 {
276 int r = step();
277 if (M2_gbTrace >= 3) emit_wrapped(".");
278 if (r == COMP_DONE) return COMP_DONE;
279 if (--nsteps == 0) return COMP_DONE_STEPS;
281 }
282}
283
284void DetComputation::get_minor(size_t *r, size_t *c, int p0, ring_elem **D0)
285{
286 for (size_t i = 0; i < p0; i++)
287 for (size_t j = 0; j < p0; j++)
288 D0[i][j] = M->elem(static_cast<int>(r[i]), static_cast<int>(c[j]));
289}
290
292 size_t r,
293 ring_elem &pivot,
294 size_t &pivot_col)
295// Get a non-zero column 0..r in the r th row.
296{
297 // MES: it would be worthwhile to find a good pivot.
298 for (size_t c = 0; c <= r; c++)
299 if (!R->is_zero(D0[r][c]))
300 {
301 pivot_col = c;
302 pivot = D0[r][c];
303 return true;
304 }
305 return false;
306}
307
309 ring_elem g1,
310 ring_elem f2,
311 ring_elem g2,
312 ring_elem d)
313{
314 ring_elem a = R->mult(f1, g1);
315 ring_elem b = R->mult(f2, g2);
316 R->subtract_to(a, b);
317 if (!R->is_zero(d))
318 {
319 ring_elem tmp = R->divide(a, d); // exact division
320 R->remove(a);
321 a = tmp;
322 }
323 R->remove(g1);
324 return a;
325}
326
328 size_t i,
329 size_t r,
330 size_t pivot_col,
331 ring_elem lastpivot)
332{
333 ring_elem f = D0[i][pivot_col];
334 ring_elem pivot = D0[r][pivot_col];
335
336 for (size_t c = 0; c < pivot_col; c++)
337 D0[i][c] = detmult(pivot, D0[i][c], f, D0[r][c], lastpivot);
338
339 for (size_t c = pivot_col + 1; c <= r; c++)
340 D0[i][c - 1] = detmult(pivot, D0[i][c], f, D0[r][c], lastpivot);
341
342 R->remove(f);
343}
344
346{
347 // Computes the determinant of the p by p matrix D. (dense form).
348 int sign = 1;
349 size_t pivot_col;
350
351 ring_elem pivot = R->from_long(0);
352 ring_elem lastpivot = R->from_long(0);
353
354 for (size_t r = p - 1; r >= 1; --r)
355 {
356 R->remove(lastpivot);
357 lastpivot = pivot;
358 if (!get_pivot(D, r, pivot, pivot_col)) // sets pivot_col and pivot
359 {
360 // Remove the rest of D.
361 for (size_t i = 0; i <= r; i++)
362 for (size_t j = 0; j <= r; j++) R->remove(D[i][j]);
363 R->remove(lastpivot);
364 return R->from_long(0);
365 }
366 for (size_t i = 0; i < r; i++) gauss(D, i, r, pivot_col, lastpivot);
367
368 if (((r + pivot_col) % 2) == 1)
369 sign = -sign; // MES: do I need to rethink this logic?
370
371 for (size_t c = 0; c <= r; c++)
372 if (c != pivot_col)
373 R->remove(D[r][c]);
374 else
375 D[r][c] = ZERO_RINGELEM;
376 }
377
378 R->remove(pivot);
379 R->remove(lastpivot);
380 ring_elem r = D[0][0];
381 D[0][0] = ZERO_RINGELEM;
382
383 if (sign < 0) R->negate_to(r);
384
385 return r;
386}
387ring_elem DetComputation::calc_det(size_t *r, size_t *c, int p0)
388// Compute the determinant of the minor with rows r[0]..r[p0-1]
389// and columns c[0]..c[p0-1].
390{
391 if (p0 == 1) return M->elem(static_cast<int>(r[0]), static_cast<int>(c[0]));
392 ring_elem answer = R->from_long(0);
393
394 int negate = 1;
395 for (int i = p0 - 1; i >= 0; i--)
396 {
397 std::swap(c[i], c[p0 - 1]);
398 negate = !negate;
399 ring_elem g =
400 M->elem(static_cast<int>(r[p0 - 1]), static_cast<int>(c[p0 - 1]));
401 if (R->is_zero(g))
402 {
403 R->remove(g);
404 continue;
405 }
406 ring_elem h = calc_det(r, c, p0 - 1);
407 ring_elem gh = R->mult(g, h);
408 R->remove(g);
409 R->remove(h);
410 if (negate)
411 R->subtract_to(answer, gh);
412 else
413 R->add_to(answer, gh);
414 }
415
416 // pulling out the columns has disordered c. Fix it.
417
418 size_t temp = c[p0 - 1];
419 for (size_t i = p0 - 1; i > 0; i--) c[i] = c[i - 1];
420 c[0] = temp;
421
422 return answer;
423}
424
425Matrix /* or null */ *Matrix::exterior(int p, int strategy) const
426{
427 if (strategy == DET_BAREISS && get_ring()->get_precision() > 0)
428 {
429 ERROR(
430 "determinant computations over RR or CC requires Strategy=>Cofactor");
431 return nullptr;
432 }
433 DetComputation *d = new DetComputation(this, p, 1, strategy);
434 d->calc(-1);
435 Matrix *result = d->determinants();
436 freemem(d);
437 return result;
438}
439
440Matrix /* or null */ *Matrix::minors(int p, int strategy) const
441{
442 if (strategy == DET_BAREISS && get_ring()->get_precision() > 0)
443 {
444 ERROR(
445 "determinant computations over RR or CC requires Strategy=>Cofactor");
446 return nullptr;
447 }
448 DetComputation *d = new DetComputation(this, p, 0, strategy);
449 d->calc(-1);
450 Matrix *result = d->determinants();
451 freemem(d);
452 return result;
453}
454
455Matrix /* or null */ *Matrix::minors(
456 int p,
457 int strategy,
458 int n_to_compute, // -1 means all
459 M2_arrayintOrNull first_row, // possibly NULL
460 M2_arrayintOrNull first_col // possibly NULL
461) const
462{
463 if (strategy == DET_BAREISS && get_ring()->get_precision() > 0)
464 {
465 ERROR(
466 "determinant computations over RR or CC requires Strategy=>Cofactor");
467 return nullptr;
468 }
469 if (first_row != nullptr || first_col != nullptr)
470 {
471 // Make sure these are the correct size, and both are given
472 if (first_row == nullptr || first_row->len != p)
473 {
474 ERROR("row index set inappropriate");
475 return nullptr;
476 }
477 if (first_col == nullptr || first_col->len != p)
478 {
479 ERROR("column index set inappropriate");
480 return nullptr;
481 }
482 }
483 DetComputation *d = new DetComputation(this, p, 0, strategy);
484 if (first_row != nullptr && first_col != nullptr)
485 d->set_next_minor(first_row->array, first_col->array);
486 d->calc(n_to_compute);
487 Matrix *result = d->determinants();
488 freemem(d);
489 return result;
490}
491
492// Local Variables:
493// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
494// indent-tabs-mode: nil
495// End:
std::pair< std::vector< int >, std::vector< int > > ColRowIndices
Definition det.hpp:83
MinorsCache dynamic_cache
Definition det.hpp:99
void set_next_minor(const int *rows, const int *cols)
Definition det.cpp:258
const Ring * R
Definition det.hpp:56
void gauss(ring_elem **D, size_t i, size_t r, size_t pivot_col, ring_elem lastpivot)
Definition det.cpp:327
size_t * row_set
Definition det.hpp:75
int make_dynamic_cache()
Definition det.cpp:94
std::map< ColRowIndices, ring_elem, std::less< ColRowIndices >, gc_allocator< std::pair< const ColRowIndices, ring_elem > > > Subdeterminant
Definition det.hpp:84
size_t * col_set
Definition det.hpp:76
ring_elem ** D
Definition det.hpp:80
ring_elem detmult(ring_elem f1, ring_elem g1, ring_elem f2, ring_elem g2, ring_elem d)
Definition det.cpp:308
int calc(int nsteps)
Definition det.cpp:272
MatrixConstructor result
Definition det.hpp:62
const FreeModule * F
Definition det.hpp:58
int step()
Definition det.cpp:190
ring_elem bareiss_det()
Definition det.cpp:345
int strategy
Definition det.hpp:72
int this_col
Definition det.hpp:78
bool done
Definition det.hpp:66
~DetComputation()
Definition det.cpp:82
bool get_pivot(ring_elem **D, size_t p, ring_elem &pivot, size_t &pivot_col)
Definition det.cpp:291
bool do_exterior
Definition det.hpp:69
ring_elem calc_det(size_t *r, size_t *c, int p)
Definition det.cpp:387
DetComputation(const Matrix *M, int p, bool do_exterior, int strategy)
Definition det.cpp:8
void get_minor(size_t *r, size_t *c, int p, ring_elem **D)
Definition det.cpp:284
std::map< int, int > row_lookup
Definition det.hpp:100
int this_row
Definition det.hpp:77
void clear()
Definition det.cpp:252
const Matrix * M
Definition det.hpp:57
Matrix * determinants()
Definition det.hpp:143
Computation of minors of a matrix.
Definition det.hpp:55
Engine-side free module R^n over a Ring.
Definition freemod.hpp:66
const Ring * get_ring() const
Definition matrix.hpp:134
Matrix * minors(int p, int strategy) const
Definition det.cpp:440
Matrix(const FreeModule *rows, const FreeModule *cols, const_monomial degree_shift, VECTOR(vec) &entries)
Definition matrix.cpp:32
Matrix * exterior(int p, int strategy) const
Definition det.cpp:425
Mutable builder used to assemble an immutable Matrix one column (or one term) at a time.
static bool increment(size_t n, Subset &s)
Definition comb.cpp:124
bool isValid(const Subset &a)
Definition comb.cpp:41
Subsets — combinatorial-number-system encoding of p-subsets of {0,...,n-1}.
@ COMP_DONE_STEPS
Definition computation.h:69
@ COMP_DONE
Definition computation.h:60
@ COMP_COMPUTING
Definition computation.h:71
@ COMP_INTERRUPTED
Definition computation.h:57
const int DET_BAREISS
Definition det.hpp:45
const int DET_DYNAMIC
Definition det.hpp:47
Determinants and minors of Matrix values via Bareiss, cofactor, or dynamic-programming strategies.
#define Matrix
Definition factory.cpp:14
int p
bool system_interrupted()
system_interrupted() — thread-safe polling predicate for Ctrl+C handling.
void freemem(void *s)
Definition m2-mem.cpp:103
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
int M2_gbTrace
Definition m2-types.cpp:52
M2_arrayint M2_arrayintOrNull
Definition m2-types.h:99
void swap(mpfr::mpreal &x, mpfr::mpreal &y)
Definition mpreal.h:3244
#define newarray(T, len)
Definition newdelete.hpp:82
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
volatile int x
tbb::flow::graph G
#define ZERO_RINGELEM
Definition ring.hpp:677
TermIterator< Nterm > end(Nterm *)
Definition ringelem.cpp:5
void emit_wrapped(const char *s)
Definition text-io.cpp:27
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.