Macaulay2 Engine
Loading...
Searching...
No Matches
cra.cpp
Go to the documentation of this file.
1#include "cra.hpp"
2
3#include <assert.h>
4#include <stddef.h>
5
6#include "error.h"
7#include "freemod.hpp"
8#include "matrix-con.hpp"
9#include "matrix.hpp"
10#include "monoid.hpp"
11#include "poly.hpp"
12#include "ring.hpp"
13#include "style.hpp"
14
15void ChineseRemainder::CRA0(mpz_srcptr a,
16 mpz_srcptr b,
17 mpz_srcptr um,
18 mpz_srcptr vn,
19 mpz_srcptr mn,
20 mpz_t result)
21{
22 mpz_t mn_half;
23 mpz_init(mn_half);
24 mpz_mul(result, um, b);
25 mpz_addmul(result, vn, a);
26 mpz_mod(result, result, mn);
27 mpz_tdiv_q_2exp(mn_half, mn, 1);
28 // get canonical representative
29 if (mpz_cmp(result, mn_half) > 0)
30 {
31 mpz_sub(result, result, mn);
32 }
33 mpz_clear(mn_half);
34}
35
37 mpz_srcptr n,
38 mpz_t result_um,
39 mpz_t result_vn,
40 mpz_t result_mn)
41{
42 mpz_t g;
43 mpz_init(g);
44 mpz_gcdext(g, result_um, result_vn, m, n);
45 if (0 != mpz_cmp_si(g, 1)) return false;
46 mpz_mul(result_mn, m, n);
47 mpz_mul(result_um, result_um, m);
48 mpz_mul(result_vn, result_vn, n);
49 mpz_clear(g);
50 return true;
51}
52
54 ring_elem ff,
55 ring_elem gg,
56 mpz_srcptr um,
57 mpz_srcptr vn,
58 mpz_srcptr mn)
59{
60 mpz_t result_coeff;
61 mpz_t mn_half;
62 mpz_init(result_coeff);
63 mpz_init(mn_half);
64 Nterm *f = ff;
65 Nterm *g = gg;
66 Nterm head;
67 Nterm *result = &head;
68
69 mpz_tdiv_q_2exp(mn_half, mn, 1);
70
71 const Monoid *M = R->getMonoid();
72 const Ring *K = R->getCoefficientRing();
73
74 while (1)
75 {
76 if (g == nullptr)
77 {
78 // mult each term of f by n:
79 for (; f != nullptr; f = f->next)
80 {
81 result->next = R->new_term();
82 result = result->next;
83 result->next = nullptr;
84 M->copy(f->monom, result->monom);
85 mpz_mul(result_coeff, f->coeff.get_mpz(), vn);
86 mpz_mod(result_coeff, result_coeff, mn);
87 if (mpz_cmp(result_coeff, mn_half) > 0)
88 {
89 mpz_sub(result_coeff, result_coeff, mn);
90 }
91 result->coeff = K->from_int(result_coeff);
92 }
93 break;
94 }
95 if (f == nullptr)
96 {
97 // mult each term of g by n:
98 for (; g != nullptr; g = g->next)
99 {
100 result->next = R->new_term();
101 result = result->next;
102 result->next = nullptr;
103 M->copy(g->monom, result->monom);
104 mpz_mul(result_coeff, g->coeff.get_mpz(), um);
105 mpz_mod(result_coeff, result_coeff, mn);
106 if (mpz_cmp(result_coeff, mn_half) > 0)
107 {
108 mpz_sub(result_coeff, result_coeff, mn);
109 }
110 result->coeff = K->from_int(result_coeff);
111 }
112 break;
113 }
114 switch (M->compare(f->monom, g->monom))
115 {
116 case -1:
117 result->next = R->new_term();
118 result = result->next;
119 result->next = nullptr;
120 M->copy(g->monom, result->monom);
121 mpz_mul(result_coeff, g->coeff.get_mpz(), um);
122 result->coeff = K->from_int(result_coeff);
123 g = g->next;
124 break;
125 case 1:
126 result->next = R->new_term();
127 result = result->next;
128 result->next = nullptr;
129 M->copy(f->monom, result->monom);
130 mpz_mul(result_coeff, f->coeff.get_mpz(), vn);
131 result->coeff = K->from_int(result_coeff);
132 f = f->next;
133 break;
134 case 0:
135 Nterm *tmf = f;
136 Nterm *tmg = g;
137 f = f->next;
138 g = g->next;
139 CRA0(tmf->coeff.get_mpz(),
140 tmg->coeff.get_mpz(),
141 um,
142 vn,
143 mn,
144 result_coeff);
145 Nterm *t = R->new_term();
146 M->copy(tmf->monom, t->monom);
147 t->coeff = K->from_int(result_coeff);
148 t->next = nullptr;
149 result->next = t;
150 result = t;
151 break;
152 }
153 }
154
155 mpz_clear(result_coeff);
156 mpz_clear(mn_half);
157 result->next = nullptr;
158 return head.next;
159}
160
162 ring_elem ff,
163 ring_elem gg,
164 mpz_srcptr m,
165 mpz_srcptr n)
166{
167 // compute the multipliers
168 mpz_t um, vn, mn;
169 mpz_init(um);
170 mpz_init(vn);
171 mpz_init(mn);
172 computeMultipliers(m, n, um, vn, mn);
173 // compute the chinese remainder with precomputed multipliers
174 ring_elem result = CRA(R, ff, gg, um, vn, mn);
175 mpz_clear(um);
176 mpz_clear(vn);
177 mpz_clear(mn);
178 return result;
179}
180
182 vec f,
183 vec g,
184 mpz_srcptr um,
185 mpz_srcptr vn,
186 mpz_srcptr mn)
187{
188 vecterm head;
189 vec result = &head;
190
191 while (1)
192 {
193 if (g == nullptr)
194 {
195 // mult each term of f by n:
196 for (; f != nullptr; f = f->next)
197 {
198 result->next = R->new_vec();
199 result = result->next;
200 result->next = nullptr;
201 result->coeff = CRA(R, f->coeff, nullptr, um, vn, mn);
202 result->comp = f->comp;
203 }
204 break;
205 }
206 if (f == nullptr)
207 {
208 // mult each term of g by n:
209 for (; g != nullptr; g = g->next)
210 {
211 result->next = R->new_vec();
212 result = result->next;
213 result->next = nullptr;
214 result->coeff = CRA(R, nullptr, g->coeff, um, vn, mn);
215 result->comp = g->comp;
216 }
217 break;
218 }
219 if (f->comp < g->comp)
220 {
221 result->next = R->new_vec();
222 result = result->next;
223 result->next = nullptr;
224 result->coeff = CRA(R, nullptr, g->coeff, um, vn, mn);
225 result->comp = g->comp;
226 g = g->next;
227 }
228 else if (f->comp > g->comp)
229 {
230 result->next = R->new_vec();
231 result = result->next;
232 result->next = nullptr;
233 result->coeff = CRA(R, f->coeff, nullptr, um, vn, mn);
234 result->comp = f->comp;
235 f = f->next;
236 }
237 else
238 {
239 result->next = R->new_vec();
240 result = result->next;
241 result->next = nullptr;
242 result->coeff = CRA(R, f->coeff, g->coeff, um, vn, mn);
243 result->comp = f->comp;
244 f = f->next;
245 g = g->next;
246 }
247 }
248 result->next = nullptr;
249 return head.next;
250}
251
253 const Matrix *g,
254 mpz_srcptr um,
255 mpz_srcptr vn,
256 mpz_srcptr mn)
257{
258 auto R = f->get_ring();
259 if (R != g->get_ring())
260 {
261 ERROR("matrices have different base rings");
262 return nullptr;
263 }
264 if (f->rows()->rank() != g->rows()->rank() ||
265 f->cols()->rank() != g->cols()->rank())
266 {
267 ERROR("matrices have different shapes");
268 return nullptr;
269 }
270
271 const PolyRing *S = R->cast_to_PolyRing();
272 if (S == nullptr)
273 {
274 ERROR("expected polynomial ring over ZZ");
275 return nullptr;
276 }
277
278 const FreeModule *F = f->rows();
279 const FreeModule *G = f->cols();
280 const int *deg;
281
282 if (!f->rows()->is_equal(g->rows())) F = S->make_FreeModule(f->n_rows());
283
284 if (!f->cols()->is_equal(g->cols())) G = S->make_FreeModule(f->n_cols());
285
286 if (EQ == R->degree_monoid()->compare(f->degree_shift(), g->degree_shift()))
287 deg = f->degree_shift();
288 else
289 deg = R->degree_monoid()->make_one();
290
291 MatrixConstructor mat(F, G, deg);
292 for (int i = 0; i < f->n_cols(); i++)
293 {
294 vec u = CRA(S, f->elem(i), g->elem(i), um, vn, mn);
295 mat.set_column(i, u);
296 }
297 return mat.to_matrix();
298}
299
300bool ChineseRemainder::ratConversion(mpz_srcptr c, mpz_srcptr m, mpq_t result)
301{
302 mpz_t a1, a2, u1, u2, q, h, mhalf, u2sqr, a2sqr;
303 bool retVal = true;
304 mpz_init_set(a1, m);
305 mpz_init_set(a2, c);
306 mpz_init_set_si(u1, 0);
307 mpz_init_set_si(u2, 1);
308 mpz_init_set_si(q, 0);
309 mpz_init_set_si(h, 0);
310 mpz_init(u2sqr);
311 mpz_init(a2sqr);
312 mpz_init(mhalf);
313
314 mpz_tdiv_q_2exp(mhalf, m, 1);
315
316 for (;;)
317 {
318 mpz_mul(u2sqr, u2, u2);
319
320 if (mpz_cmp(u2sqr, mhalf) >= 0) // u2sqr >= mhalf
321 {
322 retVal = false;
323 mpq_set_z(result, c);
324 break;
325 }
326
327 mpz_mul(a2sqr, a2, a2);
328
329 if (mpz_cmp(a2sqr, mhalf) < 0) // a2sqr < half
330 {
331 retVal = true;
332 mpq_set_num(result, a2);
333 mpq_set_den(result, u2);
334 mpq_canonicalize(result);
335 break;
336 }
337
338 mpz_fdiv_q(q, a1, a2);
339 mpz_submul(a1, q, a2);
340 mpz_submul(u1, q, u2);
341 mpz_swap(a1, a2);
342 mpz_swap(u1, u2);
343 }
344 // clean up
345 // mpz_clears(a1,a2,u1,u2,q,h,mhalf,u2sqr,a2sqr,(void *)0);
346 mpz_clear(a1);
347 mpz_clear(a2);
348 mpz_clear(u1);
349 mpz_clear(u2);
350 mpz_clear(q);
351 mpz_clear(h);
352 mpz_clear(mhalf);
353 mpz_clear(u2sqr);
354 mpz_clear(a2sqr);
355
356 return retVal;
357}
358
360 mpz_srcptr m,
361 const PolyRing *RQ)
362{
363 mpq_t result_coeff;
364 mpq_init(result_coeff);
365 Nterm *f = ff;
366 Nterm head;
367 Nterm *result = &head;
368
369 const Monoid *M = RQ->getMonoid();
370 const Ring *K = RQ->getCoefficientRing();
371
372 for (; f != nullptr; f = f->next)
373 {
374 result->next = RQ->new_term();
375 result = result->next;
376 result->next = nullptr;
377 M->copy(f->monom, result->monom);
378 ratConversion(f->coeff.get_mpz(), m, result_coeff);
379 bool ok1 = K->from_rational(result_coeff, result->coeff);
380 (void)ok1;
381 assert(ok1); // K is supposed to contain (or be) the rationals, so this
382 // should not fail.
383 }
384
385 mpq_clear(result_coeff);
386 result->next = nullptr;
387 return head.next;
388}
389
390vec ChineseRemainder::ratConversion(vec f, mpz_srcptr m, const PolyRing *RQ)
391{
392 vecterm head;
393 vec result = &head;
394 for (; f != nullptr; f = f->next)
395 {
396 result->next = RQ->new_vec();
397 result = result->next;
398 result->next = nullptr;
399 result->comp = f->comp;
400 result->coeff = ratConversion(f->coeff, m, RQ);
401 }
402
403 result->next = nullptr;
404 return head.next;
405}
406
407// Local Variables:
408// indent-tabs-mode: nil
409// End:
410
411
412
static bool computeMultipliers(mpz_srcptr m, mpz_srcptr n, mpz_t result_um, mpz_t result_vn, mpz_t result_mn)
Definition cra.cpp:36
static bool ratConversion(mpz_srcptr a, mpz_srcptr m, mpq_t result)
Definition cra.cpp:300
static ring_elem CRA(const PolyRing *R, const ring_elem f, const ring_elem g, mpz_srcptr um, mpz_srcptr vn, mpz_srcptr mn)
Definition cra.cpp:53
static void CRA0(mpz_srcptr a, mpz_srcptr b, mpz_srcptr um, mpz_srcptr vn, mpz_srcptr mn, mpz_t result)
Definition cra.cpp:15
bool is_equal(const FreeModule *F) const
Definition freemod.cpp:154
int rank() const
Definition freemod.hpp:105
Engine-side free module R^n over a Ring.
Definition freemod.hpp:66
const_monomial degree_shift() const
Definition matrix.hpp:149
const Ring * get_ring() const
Definition matrix.hpp:134
ring_elem elem(int i, int j) const
Definition matrix.cpp:307
int n_cols() const
Definition matrix.hpp:147
int n_rows() const
Definition matrix.hpp:146
const FreeModule * rows() const
Definition matrix.hpp:144
const FreeModule * cols() const
Definition matrix.hpp:145
Matrix * to_matrix()
void set_column(int c, vec v)
Mutable builder used to assemble an immutable Matrix one column (or one term) at a time.
int compare(int nslots, const_monomial m, const_monomial n) const
Definition monoid.hpp:226
void copy(const_monomial m, monomial result) const
Definition monoid.cpp:475
Engine-side commutative monomial monoid: variable names, ordering, multidegree machinery,...
Definition monoid.hpp:89
virtual const PolyRing * cast_to_PolyRing() const
Definition poly.hpp:94
Nterm * new_term() const
Definition poly.cpp:146
Concrete PolyRingFlat subclass implementing ordinary commutative polynomial rings K[x_1,...
Definition poly.hpp:64
const Ring * getCoefficientRing() const
Definition polyring.hpp:200
virtual const Monoid * getMonoid() const
Definition polyring.hpp:282
virtual FreeModule * make_FreeModule() const
Definition ring.cpp:53
virtual ring_elem from_int(mpz_srcptr n) const =0
virtual bool from_rational(const mpq_srcptr q, ring_elem &result) const =0
vec new_vec() const
vector operations ////////////////////
Definition ring-vecs.cpp:54
xxx xxx xxx
Definition ring.hpp:102
ChineseRemainder — CRT lifting and rational reconstruction primitives.
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
#define Matrix
Definition factory.cpp:14
FreeModule — finite-rank free module R^n, the type-level anchor for every Matrix.
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
MatrixConstructor — the mutable builder that produces an immutable Matrix.
Matrix — the engine's immutable homomorphism F -> G between free modules.
Monoid — variable count, naming, grading, and monomial order of a polynomial ring.
Concrete commutative PolyRing — standard polynomial ring inheriting from PolyRingFlat.
tbb::flow::graph G
Ring — the legacy abstract base class for every coefficient and polynomial ring.
Nterm * next
Definition ringelem.hpp:157
ring_elem coeff
Definition ringelem.hpp:158
int monom[1]
Definition ringelem.hpp:160
Singly linked-list node carrying one term of a polynomial-ring element.
Definition ringelem.hpp:156
const int EQ
Definition style.hpp:40
Engine-wide stylistic constants: LT / EQ / GT codes, INTSIZE, GEOHEAP_SIZE.
mpz_srcptr get_mpz() const
Definition ringelem.hpp:127