Macaulay2 Engine
Loading...
Searching...
No Matches
relem.cpp
Go to the documentation of this file.
1// Copyright 1995 Michael E. Stillman
2
3#include "relem.hpp"
4#include "monoid.hpp"
5#include "monomial.hpp"
6#include "frac.hpp"
7#include "localring.hpp"
8#include "polyring.hpp"
9#include "M2FreeAlgebra.hpp"
10
11#include "aring-glue.hpp"
12
14
16{
18}
19
21{
22 return new RingElement(R, f);
23}
24
25int RingElement::n_terms(int nvars) const
26{
27 const PolynomialRing *P = R->cast_to_PolynomialRing();
28 if (is_zero()) return 0;
29 if (P != nullptr)
30 {
31 return P->n_logical_terms(nvars, val);
32 }
33 auto Q = dynamic_cast<const M2FreeAlgebra *>(R);
34 if (Q != nullptr)
35 {
36 return Q->n_terms(val);
37 }
38
39 return 1;
40}
41
43{
44 return new RingElement(R, R->negate(val));
45}
46
48{
49 if (is_zero())
50 {
51 ERROR("ring division: attempt to divide by zero");
52 return nullptr;
53 }
54 return new RingElement(R, R->invert(val));
55}
56
57RingElement /* or null */ *RingElement::operator+(const RingElement &b) const
58{
59 if (R != b.get_ring())
60 {
61 ERROR("ring addition requires both elements to have the same base ring");
62 return nullptr;
63 }
64 ring_elem result = R->add(get_value(), b.get_value());
65 if (error()) return nullptr;
66 return new RingElement(R, result);
67}
68
69RingElement /* or null */ *RingElement::operator-(const RingElement &b) const
70{
71 if (R != b.get_ring())
72 {
73 ERROR(
74 "ring subtraction requires both elements to have the same base ring");
75 return nullptr;
76 }
77 ring_elem result = R->subtract(get_value(), b.get_value());
78 if (error()) return nullptr;
79 return new RingElement(R, result);
80}
81
82RingElement /* or null */ *RingElement::operator*(const RingElement &b) const
83{
84 if (R != b.get_ring())
85 {
86 ERROR(
87 "ring multiplication requires both elements to have the same base "
88 "ring");
89 return nullptr;
90 }
91 ring_elem result = R->mult(get_value(), b.get_value());
92 if (error()) return nullptr;
93 return new RingElement(R, result);
94}
95
97{
98 ring_elem nR = R->from_long(n);
99 if (is_zero() || (n == 0))
100 return new RingElement(R, ZERO_RINGELEM);
101 else
102 return new RingElement(R, R->mult(nR, get_value()));
103}
104
105RingElement /* or null */ *RingElement::operator/(const RingElement &b) const
106{
107 if (R != b.get_ring())
108 {
109 ERROR("ring division requires both elements to have the same base ring");
110 return nullptr;
111 }
112 if (b.is_zero())
113 {
114 ERROR("ring division: attempt to divide by zero");
115 return nullptr;
116 }
117 ring_elem result = R->divide(get_value(), b.get_value());
118 if (error()) return nullptr;
119 return new RingElement(R, result);
120}
121
122RingElement /* or null */ *RingElement::power(int n) const
123{
124 // n negative is handled.
125 ring_elem f = R->power(val, n);
126 if (error()) return nullptr;
127 return new RingElement(R, f);
128}
129
130RingElement /* or null */ *RingElement::power(mpz_srcptr n) const
131{
132 ring_elem f = R->power(val, n);
133 if (error()) return nullptr;
134 return new RingElement(R, f);
135}
136
138{
139 return new RingElement(R, R->random());
140}
141
143{
144 R->elem_text_out(o, val);
145}
146
147RingElement /* or null */ *RingElement::get_terms(int nvars,
148 int lo,
149 int hi) const
150{
151 const PolynomialRing *P = R->cast_to_PolynomialRing();
152 if (P != nullptr)
153 {
154 return new RingElement(P, P->get_terms(nvars, val, lo, hi));
155 }
156 const M2FreeAlgebra* A = dynamic_cast<const M2FreeAlgebra*>(R);
157 if (A != nullptr)
158 {
159 return new RingElement(A, A->get_terms(val, lo, hi));
160 }
161 ERROR("expected polynomial ring");
162 return nullptr;
163}
164
165RingElement /* or null */ *RingElement::lead_coeff(const Ring *coeffR) const
166{
167 if (is_zero())
168 {
169 return new RingElement(coeffR, coeffR->zero());
170 }
171 const PolynomialRing *P = R->cast_to_PolynomialRing();
172 if (P != nullptr)
173 {
174 return new RingElement(coeffR, P->lead_logical_coeff(coeffR, val));
175 }
176 const M2FreeAlgebra* A = dynamic_cast<const M2FreeAlgebra*>(R);
177 if (A != nullptr)
178 {
179 return new RingElement(coeffR, A->lead_coefficient(coeffR, val));
180 }
181 ERROR("expected polynomial ring");
182 return nullptr;
183}
184
185RingElement /* or null */ *RingElement::get_coeff(const Ring *coeffR,
186 const EngineMonomial *m) const
187{
188 const PolynomialRing *P = R->cast_to_PolynomialRing();
189 if (P == nullptr)
190 {
191 ERROR("expected polynomial ring");
192 return nullptr;
193 }
194 return new RingElement(coeffR, P->get_coeff(coeffR, get_value(), m->ints()));
195}
196
198{
199 if (is_zero())
200 {
201 ERROR("the zero element has no lead monomial");
202 return nullptr;
203 }
204 const PolynomialRing *P = R->cast_to_PolynomialRing();
205 if (P != nullptr)
206 {
207 gc_vector<int> resultvp;
208 Nterm *t = get_value();
209
210 exponents_t exp = newarray_atomic(int, nvars);
211 P->lead_logical_exponents(nvars, t, exp);
212 varpower::from_expvector(nvars, exp, resultvp);
213 return EngineMonomial::make(resultvp.data());
214 }
215 const M2FreeAlgebraOrQuotient* Q = dynamic_cast<const M2FreeAlgebraOrQuotient*>(R);
216 if (Q != nullptr)
217 {
218 ERROR("not implemented yet");
219 return nullptr;
220 }
221 ERROR("expected polynomial ring");
222 return nullptr;
223}
224
225bool RingElement::is_homogeneous() const { return R->is_homogeneous(val); }
226
227void RingElement::degree_weights(const std::vector<int> &wts,
228 int &lo,
229 int &hi) const
230{
231 const PolynomialRing *P = R->cast_to_PolynomialRing();
232 if (is_zero())
233 {
234 ERROR("zero element has no degree");
235 return;
236 }
237 if (P == nullptr)
238 {
239 ERROR("expected polynomial ring");
240 return;
241 }
242 P->degree_weights(val, wts, lo, hi);
243}
244
245RingElement *RingElement::homogenize(int v, const std::vector<int> &wts) const
246{
247 const PolynomialRing *P = R->cast_to_PolynomialRing();
248 if (P == nullptr)
249 {
250 ERROR("expected polynomial ring");
251 return nullptr;
252 }
253 if (v < 0 || v >= P->n_vars())
254 {
255 ERROR("homogenization: improper ring variable");
256 return nullptr;
257 }
258 if (wts.size() == 0 || wts.size() != static_cast<unsigned int>(P->n_vars()))
259 {
260 ERROR("homogenization: improper weight function");
261 return nullptr;
262 }
263 if (wts[v] == 0)
264 {
265 ERROR("homogenization: variable weight is zero");
266 return nullptr;
267 }
268
269 RingElement *result = new RingElement(P, P->homogenize(val, v, wts));
270 if (error()) return nullptr;
271 return result;
272}
273
275 int deg,
276 const std::vector<int> &wts) const
277{
278 const PolynomialRing *P = R->cast_to_PolynomialRing();
279 if (P == nullptr)
280 {
281 ERROR("expected polynomial ring");
282 return nullptr;
283 }
284 if (v < 0 || v >= P->n_vars())
285 {
286 ERROR("homogenization: improper ring variable");
287 return nullptr;
288 }
289 if (wts.size() == 0 || wts.size() != static_cast<unsigned int>(P->n_vars()))
290 {
291 ERROR("homogenization: improper weight function");
292 return nullptr;
293 }
294 if (wts[v] == 0)
295 {
296 ERROR("homogenization: variable weight is zero");
297 return nullptr;
298 }
299
300 RingElement *result = new RingElement(R, P->homogenize(val, v, deg, wts));
301 if (error()) return nullptr;
302 return result;
303}
304
305bool RingElement::promote(const Ring *S, const RingElement *&result) const
306{
307 if (S == R)
308 {
309 result = this;
310 return true;
311 }
312 ring_elem g;
313 if (S->promote(R, val, g))
314 {
315 result = new RingElement(S, g);
316 return true;
317 }
318 return false;
319}
320
321bool RingElement::lift(const Ring *S, const RingElement *&result) const
322{
323 if (S == R)
324 {
325 result = this;
326 return true;
327 }
328 ring_elem g;
329 if (R->lift(S, val, g))
330 {
331 result = new RingElement(S, g);
332 return true;
333 }
334 return false;
335}
336
337const RingElement /* or null */ *RingElement::content() const
338{
339 const PolynomialRing *P = R->cast_to_PolynomialRing();
340 const Ring *targetR = (P == nullptr ? R : P->getCoefficients());
341
342 return new RingElement(targetR, R->content(val));
343}
344
345const RingElement /* or null */ *RingElement::remove_content() const
346{
347 ring_elem g = R->divide_by_content(val);
348 return new RingElement(R, g);
349}
350
352 const RingElement /* or null */ *&result) const
353{
354 const RingElement *c = content();
355 ring_elem g = R->divide_by_given_content(val, c->val);
356 result = new RingElement(R, g);
357 return c;
358}
359
361{
362 if (R == globalQQ) return new RingElement(globalZZ, globalQQ->numerator(val));
363 const FractionField *K = R->cast_to_FractionField();
364 if (K != nullptr)
365 return new RingElement(K->get_ring(), K->numerator(val));
366
367 const LocalRing *L = R->cast_to_LocalRing();
368 if (L != nullptr)
369 return new RingElement(L->get_ring(), L->numerator(val));
370 ERROR("fraction field or local ring required");
371 return nullptr;
372}
373
375{
376 if (R == globalQQ)
377 return new RingElement(globalZZ, globalQQ->denominator(val));
378 const FractionField *K = R->cast_to_FractionField();
379 if (K != nullptr)
380 return new RingElement(K->get_ring(), K->denominator(val));
381 const LocalRing *L = R->cast_to_LocalRing();
382 if (L != nullptr)
383 return new RingElement(L->get_ring(), L->denominator(val));
384 ERROR("fraction field or local rings required");
385 return nullptr;
386}
387
389 const RingElement *bottom) const
390{
391 if (bottom->is_zero())
393
394 if (K == globalQQ)
395 return new RingElement(globalQQ,
396 globalQQ->fraction(val, bottom->get_value()));
397 const FractionField *K1 = K->cast_to_FractionField();
398 if (K1 != nullptr)
399 {
400 if (K1->get_ring() != R)
401 {
402 ERROR("fraction field required");
403 return nullptr;
404 }
405 return new RingElement(K1, K1->fraction(val, bottom->get_value()));
406 }
407 const LocalRing *L1 = K->cast_to_LocalRing();
408 if (L1 != nullptr)
409 {
410 if (L1->get_ring() != R)
411 {
412 ERROR("local ring required");
413 return nullptr;
414 }
415 return new RingElement(L1, L1->fraction(val, bottom->get_value()));
416 }
417 ERROR("fraction field or local ring required");
418 return nullptr;
419}
420
422 std::vector<long> &result_coeffs) const
423{
425 const Ring *K = R->getCoefficientRing();
426 if (R == nullptr || R->n_vars() != 1)
427 {
428 throw exc::engine_error(
429 "Expected a polynomial in a univariate polynomial ring");
430 return false; // Should not be needed
431 }
432
433 if (is_zero())
434 {
435 result_coeffs.resize(0);
436 return true;
437 }
438 int lo, deg; // ignore lo, and deg == degree of the univariate polynomial f.
439 R->degree_of_var(0, get_value(), lo, deg);
440 result_coeffs.resize(deg + 1);
441 for (int i = 0; i <= deg; i++) result_coeffs[i] = 0;
442 int exp[1];
443 for (Nterm& t : get_value())
444 {
445 std::pair<bool, long> res = K->coerceToLongInteger(t.coeff);
446 if (not res.first)
447 {
448 // At this point, the answer is meaningless
449 result_coeffs.resize(0);
450 return false;
451 }
452 long coeff = res.second;
453
454 R->getMonoid()->to_expvector(t.monom, exp);
455 assert(exp[0] >= 0);
456 assert(exp[0] <= deg);
457 result_coeffs[exp[0]] = coeff;
458 }
459 return true;
460}
461
463{
464 std::vector<long> coeffs;
465 if (!getSmallIntegerCoefficients(coeffs)) return nullptr;
466 return stdvector_to_M2_arrayint(coeffs);
467}
468
469// Local Variables:
470// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
471// indent-tabs-mode: nil
472// End:
exponents::Exponents exponents_t
Ring-shaped wrapper that exposes a non-commutative FreeAlgebra to the rest of the engine.
const RingQQ * globalQQ
Definition aring.cpp:24
ConcreteRing<RingType> — the templated bridge between aring and the legacy Ring API.
static EngineMonomial * make(int v, int e)
Definition monomial.cpp:26
Engine-side immutable monomial value type wrapping a varpower- encoded exponent vector.
Definition monomial.hpp:61
static void from_expvector(int n, exponents::ConstExponents a, Vector &result)
const Ring * get_ring() const
Definition frac.hpp:84
ring_elem numerator(ring_elem f) const
Definition frac.cpp:69
ring_elem denominator(ring_elem f) const
Definition frac.cpp:75
ring_elem fraction(const ring_elem top, const ring_elem bottom) const
Definition frac.cpp:102
Engine-side fraction field of a polynomial domain R_.
Definition frac.hpp:62
ring_elem numerator(ring_elem f) const
ring_elem fraction(const ring_elem top, const ring_elem bottom) const
ring_elem denominator(ring_elem f) const
const PolyRing * get_ring() const
Definition localring.hpp:90
Engine-side localisation of a polynomial ring at a prime ideal.
Definition localring.hpp:67
ring_elem lead_coefficient(const Ring *coeffRing, const Poly *f) const
Poly * get_terms(const Poly *f, int lo, int hi) const
Concrete Ring wrapper around an owned FreeAlgebra (no quotient).
Abstract Ring subclass that lifts either a FreeAlgebra or a FreeAlgebraQuotient into the engine's Rin...
virtual ring_elem get_coeff(const Ring *coeffR, const ring_elem f, const_varpower vp) const =0
virtual int n_logical_terms(int nvars0, const ring_elem f) const =0
virtual ring_elem homogenize(const ring_elem f, int v, int deg, const std::vector< int > &wts) const =0
virtual void lead_logical_exponents(int nvars0, const ring_elem f, exponents_t result_exp) const =0
virtual void degree_weights(const ring_elem f, const std::vector< int > &wts, int &lo, int &hi) const =0
virtual const Ring * getCoefficients() const
Definition polyring.hpp:277
virtual ring_elem get_terms(int nvars0, const ring_elem f, int lo, int hi) const =0
virtual ring_elem lead_logical_coeff(const Ring *coeffR, const ring_elem f) const =0
int n_vars() const
Definition polyring.hpp:196
Abstract base for the engine's polynomial-ring hierarchy.
Definition polyring.hpp:96
virtual bool promote(const Ring *R, const ring_elem f, ring_elem &result) const =0
virtual unsigned int computeHashValue(const ring_elem a) const =0
virtual std::pair< bool, long > coerceToLongInteger(ring_elem a) const
Definition ring.cpp:236
ring_elem zero() const
Definition ring.hpp:359
virtual const PolynomialRing * cast_to_PolynomialRing() const
Definition ring.hpp:243
virtual const LocalRing * cast_to_LocalRing() const
Definition ring.hpp:253
virtual const FractionField * cast_to_FractionField() const
Definition ring.hpp:251
RingElement(const Ring *R, ring_elem f)
Definition relem.hpp:166
RingElement * power(mpz_srcptr n) const
Definition relem.cpp:130
RingElement * operator+(const RingElement &b) const
Definition relem.cpp:57
void text_out(buffer &o) const
Definition relem.cpp:142
RingElement * fraction(const Ring *R, const RingElement *bottom) const
Definition relem.cpp:388
static RingElement * random(const Ring *R)
Definition relem.cpp:137
bool is_homogeneous() const
Definition relem.cpp:225
EngineMonomial * lead_monom(int nvars) const
Definition relem.cpp:197
RingElement * denominator() const
Definition relem.cpp:374
RingElement * operator/(const RingElement &b) const
Definition relem.cpp:105
ring_elem val
Definition relem.hpp:69
M2_arrayintOrNull getSmallIntegerCoefficients() const
Definition relem.cpp:462
ring_elem get_value() const
Definition relem.hpp:79
bool promote(const Ring *S, const RingElement *&result) const
Definition relem.cpp:305
const RingElement * split_off_content(const RingElement *&result) const
Definition relem.cpp:351
bool is_zero() const
Definition relem.hpp:167
int n_terms(int nvars) const
Definition relem.cpp:25
RingElement * lead_coeff(const Ring *coeffR) const
Definition relem.cpp:165
RingElement * get_terms(int nvars, int lo, int hi) const
Definition relem.cpp:147
const Ring * R
Definition relem.hpp:68
RingElement * numerator() const
Definition relem.cpp:360
RingElement * operator-() const
Definition relem.cpp:42
RingElement * invert() const
Definition relem.cpp:47
static RingElement * make_raw(const Ring *R, ring_elem f)
Definition relem.cpp:20
void degree_weights(const std::vector< int > &wts, int &lo, int &hi) const
Definition relem.cpp:227
const RingElement * remove_content() const
Definition relem.cpp:345
RingElement * get_coeff(const Ring *coeffR, const EngineMonomial *m) const
Definition relem.cpp:185
bool lift(const Ring *S, const RingElement *&result) const
Definition relem.cpp:321
const RingElement * content() const
Definition relem.cpp:337
const Ring * get_ring() const
Definition relem.hpp:81
virtual unsigned int computeHashValue() const
Definition relem.cpp:15
RingElement * homogenize(int v, const std::vector< int > &wts) const
Definition relem.cpp:245
RingElement * operator*(const RingElement &b) const
Definition relem.cpp:82
xxx xxx xxx
Definition ring.hpp:102
Engine-side ring of integers, backed by GMP mpz_ptr elements.
Definition ZZ.hpp:77
int error()
Definition error.c:48
FractionField — field of fractions of an integral domain, with on-the-fly normalisation.
RingZZ * globalZZ
Definition relem.cpp:13
LocalRing — localisation of a polynomial ring at a prime ideal P.
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
M2_arrayint M2_arrayintOrNull
Definition m2-types.h:99
Monoid — variable count, naming, grading, and monomial order of a polynomial ring.
EngineMonomial — opaque single-monomial value type used at the engine boundary.
typename std::vector< T, gc_allocator< T > > gc_vector
a version of the STL vector, which allocates its backing memory with gc.
Definition newdelete.hpp:76
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
PolynomialRing — abstract polynomial-ring base, the engine's most-reused class.
RingElement — tagged (Ring*, ring_elem) pair, the engine's universal element type.
#define ZERO_RINGELEM
Definition ring.hpp:677
Singly linked-list node carrying one term of a polynomial-ring element.
Definition ringelem.hpp:156
M2_arrayint stdvector_to_M2_arrayint(const std::vector< T > &v)
Definition util.hpp:79