Macaulay2 Engine
Loading...
Searching...
No Matches
mutablecomplex.cpp
Go to the documentation of this file.
1/* Copyright 2017 Mahrud Sayrafi and Michael E. Stillman
2 Mahrud Sayrafi's code in this file is in the public domain. */
3
4#include "mutablecomplex.hpp"
5#include "engine-includes.hpp"
6#include "debug.hpp"
7#include "ring.hpp"
8#include "polyring.hpp"
9#include <utility>
10#include <iostream>
11#include <algorithm>
12
13// TODO: make enums class
14#define FLAG_TRACE_MORPHISMS 1 // See `help pruningMap` in M2
15#define FLAG_TRIM_COMPLEX 2 // Delete pruned rows and columns
16#define FLAG_PRUNE_PMONE 4 // Only prune -1,+1
17#define FLAG_PRUNE_SCALARS 8 // Only prune constants
18#define FLAG_PRUNE_ORIGIN 16 // Only prune functions with constants
19#define FLAG_PRUNE_MAXIMAL 32 // Pruning for maximal ideal
20#define FLAG_PRUNE_PRIME 64 // Pruning for prime ideal
21#define FLAG_BEST_UNIT 1024 // Prune sparsest unit first
22#define FLAG_BEST_MATRIX 2048 // Prune best matrix first
23#define FLAG_REV_ORDER 65536 // Prune the matrices in reverse order
24
25size_t MutableComplex::complexity(const iterator &i, const size_t flags) const
26// Heuristics
27// TODO: save row/column totals in a separate vector and only update when
28// pruning a unit
29{
30 (void) flags;
31 ring_elem e;
32 const size_t n = i.index();
33 const std::pair<size_t, size_t> u = *i;
34 mDifferential[n]->get_entry(u.first, u.second, e);
35 // Count terms in the column
36 int s = 0;
37 if (mLocalRing == nullptr)
38 s = mPolynomialRing->n_terms(e);
39 else
40 s = mLocalRing->n_terms(e);
41 for (size_t r = 0; r < mBetti[n]; ++r)
42 {
43 if (r == u.first) continue;
44 mDifferential[n]->get_entry(r, u.second, e);
45 if (mRing->is_zero(e)) continue;
46 if (mLocalRing == nullptr)
47 s += mPolynomialRing->n_terms(e);
48 else
49 s += mLocalRing->n_terms(e);
50 }
51 // Count terms in the row
52 for (size_t c = 0; c < mBetti[n + 1]; ++c)
53 {
54 if (c == u.second) continue;
55 mDifferential[n]->get_entry(u.first, c, e);
56 if (mRing->is_zero(e)) continue;
57 if (mLocalRing == nullptr)
58 s += mPolynomialRing->n_terms(e);
59 else
60 s += mLocalRing->n_terms(e);
61 }
62 // std::cout<<s<<std::endl;
63 // Local case: (size numerator elt) * (row/numerator/size//sum) *
64 // (col/numerator/size//sum)
65 return static_cast<size_t>(s);
66}
67
68bool MutableComplex::next_unit(iterator &i, const size_t flags) const
69{
70 (void) flags;
71 ring_elem e;
72 for (; i < i.end(); ++i)
73 {
74 mDifferential[i.index()]->get_entry((*i).first, (*i).second, e);
75 if (mRing->is_unit(e)) return true;
76 }
77 return false;
78}
79
80bool MutableComplex::find_unit(iterator &i, const size_t flags) const
81{
82 if (!(flags & FLAG_BEST_UNIT)) return next_unit(i, flags);
83
84 iterator j(*this, i.index());
85 if (!next_unit(j, flags)) return false;
86 size_t t = -1, s = complexity(j, flags);
87 while (next_unit(j, flags))
88 {
89 s = complexity(j, flags);
90 if (s < t)
91 {
92 t = s;
93 *i = *j;
94 }
95 ++j;
96 }
97 return true;
98}
99
100// bool MutableComplex::unit_cmp(const iterator &a, const iterator &b);
101
102std::vector<MutableComplex::iterator> MutableComplex::list_units(
103 size_t n,
104 const size_t flags) const
105{
106 iterator i(*this, n);
107 std::vector<iterator> units;
108 while (next_unit(i, flags))
109 {
110 units.push_back(i);
111 ++i;
112 }
113 // sort units here?
114 // std::sort(units.begin(), units.end(), unit_cmp());
115 return units;
116}
117
118void MutableComplex::prune_unit(const iterator &i, const size_t flags)
119{
120 const size_t n = i.index();
121 const std::pair<size_t, size_t> u = *i;
122 const bool trace = flags & FLAG_TRACE_MORPHISMS;
123 /* There is some redundancy here, can set some stuff to zero.
124 TODO: Maybe check to see which is more efficient?
125 Compare with using rawReduceByPivot
126 */
127 // Move to last row
128 mDifferential[n]->interchange_rows(u.first, mBetti[n] - 1);
129 if (0 < n) mDifferential[n - 1]->interchange_columns(u.first, mBetti[n] - 1);
130 if (trace) mMorphisms[n]->interchange_columns(u.first, mBetti[n] - 1);
131 // Move to last column
132 mDifferential[n]->interchange_columns(u.second, mBetti[n + 1] - 1);
133 if (n < mDifferential.size() - 1)
134 mDifferential[n + 1]->interchange_rows(u.second, mBetti[n + 1] - 1);
135 if (trace)
136 mMorphisms[n + 1]->interchange_columns(u.second, mBetti[n + 1] - 1);
137 // Get the pivot
138 ring_elem p, q, f;
139 mDifferential[n]->get_entry(mBetti[n] - 1, mBetti[n + 1] - 1, p);
140 p = mRing->invert(p);
141 q = mRing->negate(p);
142 // Clear the column
143 for (size_t r = 0; r < mBetti[n] - 1; ++r)
144 {
145 mDifferential[n]->get_entry(r, mBetti[n + 1] - 1, f);
146 mDifferential[n]->row_op(r, mRing->mult(f, q), mBetti[n] - 1);
147 if (0 < n)
148 mDifferential[n - 1]->column_op(mBetti[n] - 1, mRing->mult(f, p), r);
149 if (trace) mMorphisms[n]->column_op(mBetti[n] - 1, mRing->mult(f, p), r);
150 }
151 // Clear the row
152 for (size_t c = 0; c < mBetti[n + 1] - 1; ++c)
153 {
154 mDifferential[n]->get_entry(mBetti[n] - 1, c, f);
155 mDifferential[n]->column_op(c, mRing->mult(f, q), mBetti[n + 1] - 1);
156 if (n < mDifferential.size() - 1)
157 mDifferential[n + 1]->row_op(mBetti[n + 1] - 1, mRing->mult(f, p), c);
158 if (trace)
159 mMorphisms[n + 1]->column_op(c, mRing->mult(f, q), mBetti[n + 1] - 1);
160 }
161 --mBetti[n];
162 --mBetti[n + 1];
163}
164
165// Prunes a single matrix by reducing the units
167{
168 iterator i(*this, n);
169 while (find_unit(i, flags))
170 {
171 prune_unit(i, flags);
172 *i = *iterator(*this, n);
173 }
174}
175
176void MutableComplex::prune_complex(size_t nsteps, size_t flags)
177{
178 // Initialize pruning maps
179 const bool dense = mDifferential[0]->is_dense();
181 for (size_t n = 0; n < mDifferential.size() + 1; ++n)
182 mMorphisms.push_back(MutableMatrix::identity(mRing, mBetti[n], dense));
183 for (size_t n = 0; n < mDifferential.size() && n < nsteps; n++)
184 {
185 if (flags & FLAG_REV_ORDER)
186 prune_matrix(mDifferential.size() - n - 1, flags);
187 else
189 }
190}
191
192std::vector<size_t> MutableComplex::prune_betti(size_t nsteps, size_t flags)
193{
194 (void) nsteps;
195 (void) flags;
196 /* TODO:
197 * separate all units into a square matrix (efficiently?)
198 * start with the ones in sparcest row/column.
199 */
200 // prune_complex(nsteps, flags);
201 return mBetti;
202}
203
205MutableComplex::prune_morphisms(size_t nsteps, size_t flags)
206{
207 (void) nsteps;
208 for (size_t n = 0; n < mMorphisms.size(); ++n)
210 if (mBetti[n] < mMorphisms[n]->n_cols())
211 mMorphisms[n]->delete_columns(mBetti[n], mMorphisms[n]->n_cols() - 1);
212 return mMorphisms;
213}
214
215/*
216MutableComplex* MutableComplex::trim_complex(size_t nsteps, size_t flags)
217{
218 M2_arrayint rows, cols;
219 VECTOR(MutableMatrix *) D;
220 for(size_t n = 0; n < mDifferential.size(); n++)
221 {
222 rows = M2_makearrayint(mBetti[n]);
223 for(int i = 0; i < mBetti[n]; ++i) rows->array[i] = i;
224 cols = M2_makearrayint(mBetti[n+1]);
225 for(int i = 0; i < mBetti[n+1]; ++i) cols->array[i] = i;
226
227 D.push_back(mDifferential[n]->submatrix(rows, cols));
228 }
229 // FIXME how to access the matrices?
230 return new MutableComplex(D);
231}
232*/
233
235{
236 for (size_t i = 0; i < mDifferential.size(); i++) o << mBetti[i] << " <-- ";
237 o << mBetti[mDifferential.size()];
238
239 // auto C = const_cast <MutableComplex *> (this);
240}
241
242/********************************************************************************/
243/* Global functions */
244/********************************************************************************/
245
246extern "C" { // TODO: remove when this function is in e/interface
247
248engine_RawMutableMatrixArray rawPruningMorphism(MutableComplex *C, int n, int f)
249{
250 size_t nsteps = static_cast<size_t>(n), flags = static_cast<size_t>(f);
251 // std::min(static_cast<int>(C->mMorphisms.size()),
252 // static_cast<int>(nsteps));
253 VECTOR(MutableMatrix *) M = C->prune_morphisms(nsteps, flags);
254 int N = static_cast<int>(M.size());
255 engine_RawMutableMatrixArray A =
256 getmemarraytype(engine_RawMutableMatrixArray, N);
257 A->len = N;
258 for (int i = 0; i < N; ++i) A->array[i] = M[i];
259 return A;
260}
261
263{
264 size_t nsteps = static_cast<size_t>(n), flags = static_cast<size_t>(f);
265 std::vector<size_t> betti = C->prune_betti(nsteps, flags);
266 // std::min(static_cast<int>(betti.size()), static_cast<int>(nsteps));
267 int N = static_cast<int>(betti.size());
269 for (int i = 0; i < N; ++i) B->array[i] = static_cast<int>(betti[i]);
270 return B;
271}
272
274{
275 size_t nsteps = static_cast<size_t>(n), flags = static_cast<size_t>(f);
276 C->prune_complex(nsteps, flags);
277 // if (flags & FLAG_TRIM_COMPLEX)
278 // C = C->trim_complex(nsteps, flags);
279 return C;
280}
281
282MutableComplex *rawMutableComplex(const engine_RawMutableMatrixArray M)
283{
285 for (int i = 0; i < M->len; ++i) D.push_back(M->array[i]);
286 return new MutableComplex(D);
287}
288
290{
291 buffer o;
292 M->text_out(o);
293 return o.to_string();
294}
295
297{
298 return M->hash();
299}
300
301} // TODO: remove when this function is in e/interface
302
303// Local Variables:
304// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
305// indent-tabs-mode: nil
306// End:
Cursor pointing at one entry of one differential matrix in the complex: a (matrix index,...
std::vector< size_t > mBetti
bool next_unit(iterator &i, const size_t flags) const
void prune_unit(const iterator &i, const size_t flags)
void prune_complex(const size_t nsteps, const size_t flags)
std::vector< size_t > prune_betti(const size_t nsteps, const size_t flags)
size_t complexity(const iterator &i, const size_t flags) const
const size_t flags
void text_out(buffer &o) const
const Ring * mRing
const LocalRing * mLocalRing
bool find_unit(iterator &i, const size_t flags) const
std::vector< iterator > list_units(size_t n, const size_t flags) const
const PolynomialRing * mPolynomialRing
void prune_matrix(size_t n, const size_t flags)
Sequence of MutableMatrix differentials representing an in-progress chain complex,...
unsigned int hash() const
Definition hash.hpp:106
static MutableMatrix * identity(const Ring *R, size_t nrows, bool dense)
Definition mat.cpp:69
Abstract base class for mutable matrices over an arbitrary engine Ring, the in-place counterpart of t...
Definition mat.hpp:79
M2_string to_string()
Definition buffer.cpp:20
Debugger-callable d* helpers that pretty-print engine values to stderr.
Engine-wide include prelude — a single point of truth for portability shims.
int p
void size_t s
Definition m2-mem.cpp:271
#define getmemarraytype(S, len)
Definition m2-mem.h:142
M2_arrayint M2_makearrayint(int n)
Definition m2-types.cpp:6
#define FLAG_TRACE_MORPHISMS
unsigned int rawMutableComplexHash(const MutableComplex *M)
MutableComplex * rawPruneComplex(MutableComplex *C, int n, int f)
#define FLAG_BEST_UNIT
engine_RawMutableMatrixArray rawPruningMorphism(MutableComplex *C, int n, int f)
M2_arrayint rawPruneBetti(MutableComplex *C, int n, int f)
#define FLAG_REV_ORDER
MutableComplex * rawMutableComplex(const engine_RawMutableMatrixArray M)
M2_string rawMutableComplexToString(const MutableComplex *M)
MutableComplex — in-place chain complex of MutableMatrix differentials.
#define VECTOR(T)
Definition newdelete.hpp:78
PolynomialRing — abstract polynomial-ring base, the engine's most-reused class.
Ring — the legacy abstract base class for every coefficient and polynomial ring.