Macaulay2 Engine
Loading...
Searching...
No Matches
polyquotient.cpp
Go to the documentation of this file.
1// Copyright 2004 Michael E. Stillman
2
3#include "polyquotient.hpp"
4
5#include "buffer.hpp"
6#include "comp-gb.hpp"
7#include "error.h"
8#include "interface/factory.h"
9#include "matrix-con.hpp"
10#include "matrix.hpp"
11#include "monoid.hpp"
12#include "polyring.hpp"
13#include "relem.hpp"
14#include "ring.hpp"
15
16// For debugging:
17// #include "text-io.hpp"
18// #include "debug.hpp"
19
20struct RingMap;
21
23#if 0
24// PolyRingQuotient *PolyRingQuotient::create(const PolyRing *R,
25// VECTOR(Nterm *) &elems)
26// // Grabs 'elems'. Each element of 'elems' should be in the ring R.
27// // They should also form a GB.
28// {
29// PolyRingQuotient *result = new PolyRingQuotient;
30// result->initialize_ring(R->charac(),
31// R->get_degree_ring());
32// result->R_ = R;
33//
34// result->overZZ_ = R->getCoefficients()->is_ZZ();
35// if (result->overZZ_)
36// result->setQuotientInfo(new QRingInfo_ZZ(R,elems));
37// else
38// result->setQuotientInfo(new QRingInfo_field_basic(R,elems));
39//
40// for (int i=0; i<result->n_quotients(); i++)
41// {
42// if (!R->is_homogeneous(result->quotient_element(i)))
43// {
44// result->setIsGraded(false);
45// break;
46// }
47// }
48//
49// result->zeroV = result->from_int(0);
50// result->oneV = result->from_int(1);
51// result->minus_oneV = result->from_int(-1);
52//
53// return result;
54// }
55//
56//
57// PolyRingQuotient *PolyRingQuotient::create(const PolynomialRing *R,
58// const Matrix *M)
59// {
60// if (M->get_ring() != R)
61// {
62// ERROR("quotient elements not in the expected polynomial ring");
63// return 0;
64// }
65// VECTOR(Nterm *) elems;
66// for (int i=0; i<R->n_quotients(); i++)
67// elems.push_back(R->quotient_element(i));
68// for (int i=0; i<M->n_cols(); i++)
69// elems.push_back(M->elem(0,i));
70//
71// return create(R->getAmbientRing(),elems);
72// }
73//
74// PolyRingQuotient *PolyRingQuotient::create(const PolyRing *R,
75// const PolynomialRing *B)
76// // R should be an ambient poly ring
77// // B should have: ambient of B is the logical coeff ring of R
78// // i.e. R = A[x], B = A/I
79// // return A[x]/I.
80// {
81// VECTOR(Nterm *) elems;
82//
83// for (int i=0; i<B->n_quotients(); i++)
84// {
85// ring_elem f;
86// R->promote(B->getAmbientRing(), B->quotient_element(i), f);
87// elems.push_back(f);
88// }
89// return create(R,elems);
90// }
91//
92// Matrix * PolyRingQuotient::getPresentation() const
93// {
94// const PolyRing *R = getAmbientRing();
95//
96// MatrixConstructor mat(R->make_FreeModule(1), 0);
97// for (int i=0; i<n_quotients(); i++)
98// mat.append(R->make_vec(0, quotient_element(i)));
99// return mat.to_matrix();
100// }
101#endif
102
104{
105 o << "Quotient ring of ";
106 numerR_->text_out(o);
107 o << newline << "quotient elements" << newline;
108 for (int i = 0; i < n_quotients(); i++)
109 {
110 o << " ";
112 o << newline;
113 }
114}
115
117{
118 ring_elem b = invert(a);
119 return !is_zero(b);
120}
121
123 const ring_elem f,
124 ring_elem &result) const
125// f is an element of 'this'. Rg is the desired ring.
126{
127 const PolynomialRing *Rg1 = Rg->cast_to_PolynomialRing();
128 if (Rg == numerR_ || (Rg1 != nullptr && Rg1->getAmbientRing() == numerR_))
129 {
130 result = f;
131 return true;
132 }
133 return numerR_->PolyRing::lift(Rg, f, result);
134}
135
137 const ring_elem f,
138 ring_elem &result) const
139// f is an element of Rf. result will be an element in 'this'.
140{
141 const PolynomialRing *R1 = Rf->cast_to_PolynomialRing();
142 if (Rf == numerR_ || (R1 != nullptr && numerR_ == R1->getAmbientRing()))
143 {
144 result = copy(f);
146 return true;
147 }
148 return numerR_->PolyRing::promote(Rf, f, result);
149}
150
151ring_elem PolyRingQuotient::power(const ring_elem f, mpz_srcptr n) const
152{
153 return Ring::power(f, n);
154}
155
157{
158 return Ring::power(f, n);
159}
160
162{
163 if (nvars_ == 1 && n_quotients() == 1 && K_->is_field() && ! K_->is_fraction_field())
164 {
166
169 const RingElement *u1;
170 const RingElement *v1;
171 const RingElement *ret = rawExtendedGCDRingElement(f1, g1, &u1, &v1);
172 if (ret == nullptr)
173 {
174 // one reason this might return nullptr is if the coefficient ring is not
175 // ZZ/n, ZZ, or QQ
176 // now what do we do?
177 // we can't return nullptr
178 INTERNAL_ERROR("ring element gcd computation failed");
179 }
180 if (!getAmbientRing()->is_unit(ret->get_value())) return from_long(0);
181 return u1->get_value();
182 }
183 else if (M_->numNonTermOrderVariables() == 0)
184 return ann(from_long(1), f);
185 else
186 {
187 // An error message is generated higher up
188 return from_long(0);
189 }
190}
191
193{
194 ring_elem rem, d;
195 rem = numerR_->remainderAndQuotient(f, g, d);
196 if (is_zero(rem)) return d; // This should be in normal form?
197 return ann(f, g);
198 // ring_elem ginv = invert(g);
199 // ring_elem result = mult(f, ginv);
200 // normal_form(result);
201 // return result;
202}
203
205// return the GB of g
206// keeping the change matrix:
207// that is, how every element of the GB is written in terms of g.
208// e.g. if the gb is generated by 1, the change matrix has an entry c such that 1 = c*g
209{
211 mat.set_entry(0, 0, g);
212 Matrix *mg = mat.to_matrix(); // {g}
213
215 for (int i = 0; i < n_vars(); i++) weights->array[i] = 1;
217 false, // collect syz
218 -1,
219 weights,
220 false,
221 -1,
222 0,
223 0,
224 0 // TBB numThreads
225 /* , max_reduction_count */
226 );
227 G->set_stop_conditions(false,
228 nullptr,
229 -1,
230 -1, // syzygy limit
231 -1,
232 -1,
233 -1,
234 false,
235 nullptr);
236
237 G->start_computation();
238 return G;
239}
240
242 const ring_elem g) const
243{
244 if (K_->get_precision() > 0)
245 {
246 ERROR(
247 "polynomial division not yet implemented for RR or CC coefficients");
248 return from_long(0);
249 }
251 matf.set_entry(0, 0, f);
252 const Matrix *mf = matf.to_matrix();
253
254 GBComputation *G = make_gb(g);
255
256 const Matrix *mrem = G->matrix_remainder(mf);
257 ring_elem result = mrem->elem(0, 0);
258
259 delete mrem;
260 delete mf;
261 delete G;
262 return result;
263}
264
266{
267 if (K_->get_precision() > 0)
268 {
269 ERROR(
270 "polynomial division not yet implemented for RR or CC coefficients");
271 return from_long(0);
272 }
274 matf.set_entry(0, 0, f);
275 Matrix *mf = matf.to_matrix();
276
277 GBComputation *G = make_gb(g);
278
279 const Matrix *mrem, *mquot;
280 G->matrix_lift(mf, &mrem, &mquot);
281 ring_elem result = mquot->elem(0, 0);
282
283 delete mrem;
284 delete mquot;
285 delete mf;
286 delete G;
287 return result;
288}
289
291 const ring_elem g,
292 ring_elem &quot) const
293{
294 if (K_->get_precision() > 0)
295 {
296 ERROR(
297 "polynomial division not yet implemented for RR or CC coefficients");
298 quot = from_long(0);
299 return from_long(0);
300 }
302 matf.set_entry(0, 0, f);
303 Matrix *mf = matf.to_matrix();
304
305 GBComputation *G = make_gb(g);
306
307 const Matrix *mrem, *mquot;
308 G->matrix_lift(mf, &mrem, &mquot);
309 quot = mquot->elem(0, 0);
310 ring_elem result = mrem->elem(0, 0);
311
312 delete mrem;
313 delete mquot;
314 delete mf;
315 delete G;
316 return result;
317}
318
320// returns an element h such that h*b == a, if it exists. If no such element
321// exists, 0 is returned.
322{
324 mata.set_entry(0, 0, a);
325 Matrix *ma = mata.to_matrix(); // {a}
326
327 GBComputation *G = make_gb(b);
328
329 const Matrix *mrem, *mquot;
330 G->matrix_lift(ma, &mrem, &mquot);
331 // if (M2_gbTrace >= 2)
332 // {
333 // emit("ann a=");
334 // dringelem(this, a);
335 // emit(" b=");
336 // dringelem(this, b);
337 // emit_line("----------");
338 // emit_line(" G->get_gb is ");
339 // dmatrix(G->get_gb());
340 // emit_line(" G ->get_change()");
341 // dmatrix(G->get_change());
342 // emit_line("----------");
343 // emit_line(" mrem is ");
344 // dmatrix(mrem);
345 // emit_line(" mquot is ");
346 // dmatrix(mquot);
347 // emit_line("---------------");
348 // emit_line("-- gb(b): -----");
349 // G->show();
350 // emit_line("---------------");
351 // }
352 if (mquot->n_cols() == 0 || !mrem->is_zero())
353 {
354 // We have just determined that a/b does not exist.
355 // So b is not a unit in this ring.
356 set_non_unit(b);
357 return from_long(0);
358 }
359 ring_elem answer = mquot->elem(0,0); // possibly off by a scalar?
360 ring_elem a1 = mult (answer, b);
361 if (not is_equal(a1, a))
362 {
363 // so answer * b == a1,
364 // and a1 * c == a. Check this?
365 // so (answer * c) * b == a
366
367 // emit("a1=");
368 // dringelem(this, a1);
369 // emit_line("");
370 ring_elem c = divide(a, a1);
371 if (not is_equal(mult(a1, c), a))
372 {
373 set_non_unit(b);
374 return from_long(0);
375 }
376 answer = mult(c, answer);
377 }
378 return answer;
379}
380
382 const ring_elem b,
383 ring_elem &x,
384 ring_elem &y) const
385{
387 mat.set_entry(0, 0, a);
388 mat.set_entry(0, 1, b);
389 Matrix *m = mat.to_matrix(); // {a,b}
391 for (int i = 0; i < n_vars(); i++) weights->array[i] = 1;
393 true, // collect syz
394 -1, // keep all rows
395 weights,
396 false,
397 -1,
398 0,
399 0,
400 0 // TBB numThreads
401 /* , max_reduction_count */
402 );
403 G->set_stop_conditions(false,
404 nullptr,
405 -1,
406 1, // syzygy limit
407 -1,
408 -1,
409 -1,
410 false,
411 nullptr);
412 G->start_computation();
413 const Matrix *s = G->get_syzygies();
414
415 // Now extract the two pieces of info
416 x = s->elem(0, 0);
417 y = s->elem(1, 0);
419 ring_elem x1 = mult(c, x);
420 ring_elem y1 = mult(c, y);
421 x = x1;
422 y = y1;
423}
424
426{
427 ring_elem result = numerR_->PolyRing::random();
429 return result;
430}
431
433 const ring_elem f,
434 int first_var) const
435{
436 return numerR_->PolyRing::eval(map, f, first_var);
437}
438
439// Local Variables:
440// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
441// indent-tabs-mode: nil
442// End:
Append-only GC-backed byte buffer used throughout the engine for text output.
static GBComputation * choose_gb(const Matrix *m, M2_bool collect_syz, int n_rows_to_keep, M2_arrayint gb_weights, M2_bool use_max_degree, int max_degree, int algorithm, int strategy, int numThreads, int max_reduction_count=10)
Definition comp-gb.cpp:39
base class for Groebner basis computations.
Definition comp-gb.hpp:69
ring_elem elem(int i, int j) const
Definition matrix.cpp:307
bool is_zero() const
Definition matrix.cpp:325
int n_cols() const
Definition matrix.hpp:147
Matrix * to_matrix()
void set_entry(int r, int c, ring_elem a)
Mutable builder used to assemble an immutable Matrix one column (or one term) at a time.
virtual ring_elem divide(const ring_elem f, const ring_elem g) const
friend class PolynomialRing
virtual void text_out(buffer &o) const
virtual ring_elem from_long(long n) const
ring_elem ann(const ring_elem a, const ring_elem b) const
virtual ~PolyRingQuotient()
virtual ring_elem quotient(const ring_elem f, const ring_elem g) const
GBComputation * make_gb(const ring_elem g) const
virtual ring_elem invert(const ring_elem f) const
virtual ring_elem random() const
virtual ring_elem remainder(const ring_elem f, const ring_elem g) const
virtual ring_elem copy(const ring_elem f) const
virtual ring_elem power(const ring_elem f, mpz_srcptr n) const
Exponentiation. This is the default function, if a class doesn't define this.
virtual bool promote(const Ring *R, const ring_elem f, ring_elem &result) const
virtual ring_elem remainderAndQuotient(const ring_elem f, const ring_elem g, ring_elem &quot) const
virtual ring_elem eval(const RingMap *map, const ring_elem f, int first_var) const
virtual void syzygy(const ring_elem a, const ring_elem b, ring_elem &x, ring_elem &y) const
virtual void elem_text_out(buffer &o, const ring_elem f, bool p_one=true, bool p_plus=false, bool p_parens=false) const
virtual bool lift(const Ring *R, const ring_elem f, ring_elem &result) const
void normal_form(ring_elem &f) const
virtual ring_elem preferred_associate(ring_elem f) const
virtual bool is_zero(const ring_elem f) const
virtual bool is_unit(const ring_elem f) const
virtual ring_elem mult(const ring_elem f, const ring_elem g) const
int n_quotients() const
Definition polyring.hpp:219
virtual const PolynomialRing * getAmbientRing() const
Definition polyring.hpp:260
const Ring * K_
Definition polyring.hpp:123
const Monoid * M_
Definition polyring.hpp:124
const PolyRing * numerR_
Definition polyring.hpp:125
Nterm * quotient_element(int i) const
Definition polyring.hpp:220
int n_vars() const
Definition polyring.hpp:196
void set_non_unit(ring_elem zero_div) const
Definition ring.cpp:88
virtual FreeModule * make_FreeModule() const
Definition ring.cpp:53
virtual ring_elem power(const ring_elem f, mpz_srcptr n) const
Exponentiation. This is the default function, if a class doesn't define this.
Definition ring.cpp:109
Ring()
Definition ring.hpp:136
ring_elem get_value() const
Definition relem.hpp:79
static RingElement * make_raw(const Ring *R, ring_elem f)
Definition relem.cpp:20
Front-end-visible "ring element" value: an engine ring_elem paired with the Ring* that gives it meani...
Definition relem.hpp:67
bool is_equal(const RingMap *phi) const
Definition ringmap.cpp:111
Engine-side ring homomorphism: stores, for each source-ring variable, the target-ring element it maps...
Definition ringmap.hpp:60
GBComputation — abstract base of every Groebner-basis algorithm in the engine.
void INTERNAL_ERROR(const char *s,...)
Definition error.c:36
Engine error-reporting primitives: ERROR, INTERNAL_ERROR, error, error_message.
const RingElement * rawExtendedGCDRingElement(const RingElement *f, const RingElement *g, const RingElement **A, const RingElement **B)
Definition factory.cpp:553
#define Matrix
Definition factory.cpp:14
Engine-boundary C API for polynomial GCD, factorisation, and root finding.
void size_t s
Definition m2-mem.cpp:271
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
M2_arrayint M2_makearrayint(int n)
Definition m2-types.cpp:6
char newline[]
Definition m2-types.cpp:49
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.
volatile int x
PolyRingQuotient — polynomial ring modulo an ideal whose Groebner basis is known.
PolynomialRing — abstract polynomial-ring base, the engine's most-reused class.
RingElement — tagged (Ring*, ring_elem) pair, the engine's universal element type.
tbb::flow::graph G
Ring — the legacy abstract base class for every coefficient and polynomial ring.