Macaulay2 Engine
Loading...
Searching...
No Matches
weylalg.cpp
Go to the documentation of this file.
1// Copyright 1997 Michael E. Stillman
2
3#include "weylalg.hpp"
4#include "gbring.hpp"
5
6#include "ExponentVector.hpp"
7#include "geopoly.hpp"
8#include "text-io.hpp"
9
11 M2_arrayint comms,
12 int homog_var)
13{
14 if (homog_var >= nvars_)
15 {
16 ERROR("Weyl algebra homogenizing variable out of range");
17 return false;
18 }
19 if (homog_var < 0) _homog_var = -1;
20 if (derivs->len != comms->len)
21 {
22 ERROR("Weyl algebra: expected arrays of the same length");
23 return false;
24 }
25 for (unsigned int i = 0; i < derivs->len; i++)
26 {
27 if (derivs->array[i] < 0 || derivs->array[i] >= nvars_)
28 {
29 ERROR("Weyl algebra: variable out of range");
30 return false;
31 }
32 if (comms->array[i] < 0 || comms->array[i] >= nvars_)
33 {
34 ERROR("Weyl algebra: variable out of range");
35 return false;
36 }
37 }
38
39 this->_nderivatives = derivs->len;
40 this->_homogeneous_weyl_algebra = (homog_var >= 0);
41 this->_homog_var = homog_var;
42
45 for (int i = 0; i < _nderivatives; i++)
46 {
47 this->_derivative[i] = derivs->array[i];
48 this->_commutative[i] = comms->array[i];
49 }
50
51 // Now set whether this ring is graded. This will be the case iff
52 // deg(x_i) + deg(D_i) = 2 deg(h), for every i.
53
54 if (_homog_var < 0)
55 {
56 bool isgraded = true;
57 auto D = degree_monoid();
58 monomial degxD = D->make_one();
59 for (int j = 0; j < _nderivatives; j++)
60 {
61 const_monomial degx = M_->degree_of_var(_commutative[j]);
62 const_monomial degD = M_->degree_of_var(_derivative[j]);
63 D->mult(degx, degD, degxD);
64 if (not D->is_one(degxD))
65 {
66 isgraded = false;
67 break;
68 }
69 }
70 this->setIsGraded(isgraded);
71 }
72 else
73 {
74 this->setIsGraded(true);
75 auto D = degree_monoid();
76 const_monomial degh = M_->degree_of_var(_homog_var);
77 monomial deg2h = D->make_one();
78 monomial degxD = D->make_one();
79 D->mult(degh, degh, deg2h);
80
81 for (int j = 0; j < _nderivatives; j++)
82 {
83 const_monomial degx = M_->degree_of_var(_commutative[j]);
84 const_monomial degD = M_->degree_of_var(_derivative[j]);
85 D->mult(degx, degD, degxD);
86 if (D->compare(deg2h, degxD) != EQ)
87 {
88 ERROR("Weyl algebra: failed to create homogeneous Weyl algebra");
89 return false;
90 }
91 }
92 }
93
94 // Now initialize the tables
96 return true;
97}
98
100 const Monoid *M,
101 M2_arrayint derivs,
102 M2_arrayint comms,
103 int homog_var)
104{
106
107 result->initialize_poly_ring(K, M);
108 if (!result->initialize_weyl(derivs, comms, homog_var)) return nullptr;
109#ifdef DEVELOPMENT
110#warning "hack for ZZ and QQ coeffs in Weyl algebra: clean it up?"
111#endif
112 WeylAlgebra *weyl = result;
113 if (K->is_QQ())
114 {
115 weyl = WeylAlgebra::create(globalZZ, M, derivs, comms, homog_var);
116 }
117 result->gb_ring_ = GBRing::create_WeylAlgebra(K, M, weyl);
118 return result;
119}
120
121#if 0
122// const WeylAlgebra *WeylAlgebra::createPolyRing(const Monoid *M) const
123// // creates this[M], which is commutative in M variables, but skew commutative in
124// // (some of) the variables of this
125// {
126// const Monoid *newM = Monoid::tensor_product(M, getMonoid());
127// if (newM == 0) return 0;
128//
129// int nvars = M->n_vars();
130// M2_arrayint new_derivs = M2_makearrayint(_nderivatives);
131// M2_arrayint new_comms = M2_makearrayint(_nderivatives);
132//
133// int new_homog_var;
134// if (_homog_var >= 0)
135// new_homog_var = _homog_var + nvars;
136// else
137// new_homog_var = -1;
138//
139// for (int i=0; i<_nderivatives; i++)
140// {
141// new_derivs->array[i] = (_derivative[i] >= 0 ?
142// nvars + _derivative[i]
143// :
144// -1);
145// new_comms->array[i] = (_commutative[i] >= 0 ?
146// nvars + _commutative[i]
147// :
148// -1);
149// }
150//
151// return create(getCoefficients(),
152// newM,
153// this,
154// M,
155// new_derivs,
156// new_comms,
157// new_homog_var);
158// }
159#endif
160
162{
163 o << "WeylAlgebra(";
164 K_->text_out(o);
165 M_->text_out(o);
166 o << ")";
167}
168
170int WeylAlgebra::binomtop = 15;
172int **WeylAlgebra::binomtable = nullptr;
173int **WeylAlgebra::diffcoeffstable = nullptr;
174
176{
177 if (binomtable == nullptr)
178 {
179 int i, j;
180
181 binomtable = newarray(int *, binomtop + 1);
182 for (i = 0; i <= binomtop; i++)
183 binomtable[i] = newarray_atomic(int, i + 1);
184 binomtable[0][0] = 1;
185 binomtable[1][0] = 1;
186 binomtable[1][1] = 1;
187 for (i = 2; i <= binomtop; i++)
188 {
189 binomtable[i][0] = 1;
190 binomtable[i][i] = 1;
191 for (j = 1; j < i; j++)
192 binomtable[i][j] = binomtable[i - 1][j - 1] + binomtable[i - 1][j];
193 }
194
196 for (i = 0; i <= diffcoeffstop; i++)
197 diffcoeffstable[i] = newarray_atomic(int, i + 1);
198 diffcoeffstable[0][0] = 1;
199 diffcoeffstable[1][0] = 1;
200 diffcoeffstable[1][1] = 1;
201 for (i = 2; i <= diffcoeffstop; i++)
202 {
203 diffcoeffstable[i][0] = 1;
204 for (j = 1; j <= i; j++)
205 diffcoeffstable[i][j] = i * diffcoeffstable[i - 1][j - 1];
206 }
207#if 0
208// // Display the binomial tables:
209// cout << "---binom table---" << endl;
210// for (i=0; i<=binomtop; i++)
211// {
212// for (j=0; j<=i; j++)
213// cout << " " << binomtable[i][j];
214// cout << endl;
215// }
216// cout << "---diff table---" << endl;
217// for (i=0; i<=diffcoeffstop; i++)
218// {
219// for (j=0; j<=i; j++)
220// cout << " " << diffcoeffstable[i][j];
221// cout << endl;
222// }
223#endif
224 }
225}
226
227ring_elem WeylAlgebra::binomial(int top, int bottom) const
228{
229 // This should be located elsewhere
230 // Assumption: bottom <= top, top >= 0, bottom >= 0.
231 if (bottom == 0) return K_->from_long(1);
232 if (bottom == 1) return K_->from_long(top);
233 if (top <= binomtop) return K_->from_long(binomtable[top][bottom]);
234 ring_elem result = K_->from_long(1);
235 for (int a = 0; a < bottom; a++)
236 {
237 ring_elem b = K_->from_long(top - a);
238 ring_elem result1 = K_->mult(result, b);
239 K_->remove(result);
240 K_->remove(b);
241 ring_elem c = K_->from_long(a + 1);
242 result = K_->divide(result1, c); // exact
243 K_->remove(c);
244 }
245 return result;
246}
247
249 const int *top,
250 const int *bottom) const
251{
252 // Assumed: top[i] >= bottom[i] for all i.
253 ring_elem result = K_->copy(c);
254 for (int i = 0; i < _nderivatives; i++)
255 if (bottom[i] > 0)
256 {
257 ring_elem a = binomial(top[i], bottom[i]);
258 ring_elem b = K_->mult(a, result);
259 K_->remove(a);
260 K_->remove(result);
261 result = b;
262 }
263 return result;
264}
265
267{
268 for (int i = 0; i < _nderivatives; i++)
269 if (expbottom[i] > exptop[i]) return false;
270 return true;
271}
272
273bool WeylAlgebra::increment(int *current_derivative,
274 const int *top_derivative) const
275{
276 int i = 0;
277 while (current_derivative[i] == top_derivative[i])
278 {
279 i++;
280 if (i >= _nderivatives)
281 {
282 return false;
283 }
284 }
285 for (int j = 0; j < i; j++) current_derivative[j] = 0;
286 current_derivative[i]++;
287 return true;
288}
289
291 int *result_derivatives) const
292{
293 // exp: 0..nvars-1
294 // result_derivatives: 0.._nderivatives-1 is the result
295 for (int i = 0; i < _nderivatives; i++)
296 result_derivatives[i] = exp[_derivative[i]];
297}
299 int *result_exp) const
300{
301 // exp: 0..nvars-1
302 // result_exp: 0.._nderivatives-1 is the result
303 for (int i = 0; i < _nderivatives; i++)
304 result_exp[i] = exp[_commutative[i]];
305}
306
308 const int *derivatives,
309 const_exponents exp) const
310{
311 ring_elem result = K_->copy(c);
312 for (int i = 0; i < _nderivatives; i++)
313 {
314 if (derivatives[i] == 0) continue;
315 if (exp[i] <= diffcoeffstop)
316 {
317 ring_elem g =
318 K_->from_long(diffcoeffstable[exp[i]][derivatives[i]]);
319 ring_elem h = K_->mult(result, g);
320 K_->remove(g);
321 K_->remove(result);
322 result = h;
323 if (K_->is_zero(result)) return result;
324 }
325 else
326 for (int j = derivatives[i] - 1; j >= 0; j--)
327 {
328 ring_elem g = K_->from_long(exp[i] - j);
329 ring_elem h = K_->mult(result, g);
330 K_->remove(g);
331 K_->remove(result);
332 result = h;
333 if (K_->is_zero(result)) return result;
334 }
335 }
336 return result;
337}
338
340 const_exponents expf, // The exponent vector of f
341 const int *derivatives,
342 const Nterm *g) const // An entire polynomial
343{
344 // This isn't really differentiation, but it is close.
345 // It is the inner loop of the multiplication routine for the Weyl algebra.
346 // Returns: sum of d*[n,derivative]*c*n*m/(derivative,derivatives) e_i, for
347 // each
348 // term d*n*e_i of v which satisfies: x part of n is >= derivatives,
349 // and where the multiplication and division of monomials is in the
350 // commutative
351 // monoid.
352
353 Nterm head;
354 head.next = nullptr;
355 Nterm *result = &head;
356
357 int i;
359 exponents_t deriv_exp = newarray_atomic(int, nvars_);
360 exponents_t result_exp = newarray_atomic(int, nvars_);
361 for (i = 0; i < nvars_; i++) deriv_exp[i] = 0;
363 {
364 int sum = 0;
365 for (i = 0; i < _nderivatives; i++)
366 {
367 sum += 2 * derivatives[i];
368 deriv_exp[_derivative[i]] = derivatives[i];
369 deriv_exp[_commutative[i]] = derivatives[i];
370 }
371 deriv_exp[_homog_var] = -sum;
372 }
373 else
374 for (i = 0; i < _nderivatives; i++)
375 {
376 deriv_exp[_derivative[i]] = derivatives[i];
377 deriv_exp[_commutative[i]] = derivatives[i];
378 }
379
380 for (Nterm& t : ring_elem(g))
381 {
382 // This first part checks whether the x-part of t->monom is divisible by
383 // 'derivatives'. If so, true is returned, and the resulting monomial is
384 // set.
385 M_->to_expvector(t.monom, result_exp);
386 extractCommutativePart(result_exp, exp);
387 if (divides(derivatives, exp))
388 {
389 ring_elem a = diff_coefficients(c, derivatives, exp);
390 if (K_->is_zero(a))
391 {
392 K_->remove(a);
393 continue;
394 }
395 ring_elem b = K_->mult(a, t.coeff);
396 K_->remove(a);
397 if (K_->is_zero(b))
398 {
399 K_->remove(b);
400 continue;
401 }
402 // Now compute the new monomial:
403 Nterm *tm = new_term();
404 tm->coeff = b;
405 for (int i2 = 0; i2 < nvars_; i2++)
406 result_exp[i2] += expf[i2] - deriv_exp[i2];
407 M_->from_expvector(result_exp, tm->monom);
408
409 // Append to the result
410 result->next = tm;
411 result = tm;
412 }
413 }
414 freemem(exp);
415 freemem(result_exp);
416 result->next = nullptr;
417 return head.next;
418}
419
421 const ring_elem c,
422 const_monomial m) const
423// Computes c*m*f
424{
425 int *top_derivative = newarray_atomic(int, _nderivatives);
426 int *current_derivative = newarray_atomic_clear(int, _nderivatives);
428 polyheap result(this);
429
430 M_->to_expvector(m, expf);
431 extractDerivativePart(expf, top_derivative);
432 // Loop over each current_derivative <= top_derivative.
433 do
434 {
435 ring_elem d = multinomial(c, top_derivative, current_derivative);
436 Nterm *h = weyl_diff(d, expf, current_derivative, f);
437 K_->remove(d);
438 result.add(h);
439 }
440 while (increment(current_derivative, top_derivative));
441
442 freemem(expf);
443 freemem(top_derivative);
444 freemem(current_derivative);
445 return result.value();
446}
447
449// gbvector multiplication ///////
451// These are essentially identical to the two
452// routines above. Perhaps they should be
453// formed from a template?
454// It seems difficult, since the interfaces are somewhat different.
455
457 GBRing *GR,
458 const ring_elem c, // in K_
459 int comp, // adds this component to each component of g.
460 const_exponents expf, // The exponent vector of f
461 const int *derivatives,
462 const FreeModule
463 *F, // freemodule of g, only needed because of possible Schreyer order
464 const gbvector *g) const // An entire polynomial
465{
466 // This isn't really differentiation, but it is close.
467 // It is the inner loop of the multiplication routine for the Weyl algebra.
468 // Returns: sum of d*[n,derivative]*c*n*m/(derivative,derivatives) e_i, for
469 // each
470 // term d*n*e_i of v which satisfies: x part of n is >= derivatives,
471 // and where the multiplication and division of monomials is in the
472 // commutative
473 // monoid.
474
475 gbvector head;
476 head.next = nullptr;
477 gbvector *result = &head;
478
479 int i;
481 exponents_t deriv_exp = newarray_atomic_clear(int, nvars_);
482 exponents_t result_exp = newarray_atomic(int, nvars_);
484 {
485 int sum = 0;
486 for (i = 0; i < _nderivatives; i++)
487 {
488 sum += 2 * derivatives[i];
489 deriv_exp[_derivative[i]] = derivatives[i];
490 deriv_exp[_commutative[i]] = derivatives[i];
491 }
492 deriv_exp[_homog_var] = -sum;
493 }
494 else
495 for (i = 0; i < _nderivatives; i++)
496 {
497 deriv_exp[_derivative[i]] = derivatives[i];
498 deriv_exp[_commutative[i]] = derivatives[i];
499 }
500
501 for (const gbvector *t = g; t != nullptr; t = t->next)
502 {
503 // This first part checks whether the x-part of t->monom is divisible by
504 // 'derivatives'. If so, true is returned, and the resulting monomial is
505 // set.
506 GR->gbvector_get_lead_exponents(F, t, result_exp);
507 extractCommutativePart(result_exp, exp);
508 if (divides(derivatives, exp))
509 {
510 ring_elem a = diff_coefficients(c, derivatives, exp);
511 if (K_->is_zero(a))
512 {
513 K_->remove(a);
514 continue;
515 }
516 ring_elem b = K_->mult(a, t->coeff);
517 K_->remove(a);
518 if (K_->is_zero(b))
519 {
520 K_->remove(b);
521 continue;
522 }
523 // Now compute the new monomial:
524 for (int i2 = 0; i2 < nvars_; i2++)
525 result_exp[i2] += expf[i2] - deriv_exp[i2];
526
527 gbvector *tm =
528 GR->gbvector_term_exponents(F, b, result_exp, comp + t->comp);
529
530 // Append to the result
531 result->next = tm;
532 result = tm;
533 }
534 }
535 freemem(exp);
536 freemem(result_exp);
537 result->next = nullptr;
538 return head.next;
539}
540
543 const gbvector *f,
544 const ring_elem c, // in the base K_
545 const_monomial m, // monomial, in M_
546 int comp) const // comp is either 0 or a real component.
547// Computes c*m*f*e_comp (where components of f and e_comp add).
548{
549 int *top_derivative = newarray_atomic(int, _nderivatives);
550 int *current_derivative = newarray_atomic_clear(int, _nderivatives);
552
553 GBRing *GR = result.get_gb_ring();
554 const FreeModule *F = result.get_freemodule();
555 M_->to_expvector(m, expf);
556 extractDerivativePart(expf, top_derivative);
557 // Loop over each current_derivative <= top_derivative.
558 do
559 {
560 ring_elem d =
561 multinomial(c, top_derivative, current_derivative); // in K_
562 gbvector *h =
563 gbvector_weyl_diff(GR, d, comp, expf, current_derivative, F, f);
564 K_->remove(d);
565 result.add(h);
566 }
567 while (increment(current_derivative, top_derivative));
568
569 freemem(expf);
570 freemem(top_derivative);
571 freemem(current_derivative);
572 return result.value();
573}
574
577{
578 ring_elem result = K_->from_long(1);
579 for (int i = 0; i < nvars_; i++)
580 if (exptop[i] > 0)
581 {
582 for (int j = exptop[i]; j > exp[i]; j--)
583 {
584 ring_elem c = K_->from_long(j);
585 ring_elem d = K_->from_long(exptop[i] - j + 1);
586 K_->mult_to(result, c);
587 ring_elem e = K_->divide(result, d); // exact
588 K_->remove(c);
589 K_->remove(d);
590 K_->remove(result);
591 result = e;
592 }
593 }
594 return result;
595}
596
597ring_elem WeylAlgebra::power(const ring_elem f, mpz_srcptr n) const
598{
599 std::pair<bool, int> n1 = RingZZ::get_si(n);
600 if (n1.first)
601 return power(f, n1.second);
602 else
603 throw exc::engine_error("exponent too large");
604}
605
607{
608 return Ring::power(f, n);
609}
610
611// Local Variables:
612// compile-command: "make -C $M2BUILDDIR/Macaulay2/e "
613// indent-tabs-mode: nil
614// End:
exponents::ConstExponents const_exponents
exponents::Exponents exponents_t
Dense exponent-vector template [e_0, ..., e_{nvars-1}] for monomial operations.
static GBRing * create_WeylAlgebra(const Ring *K0, const Monoid *M0, const WeylAlgebra *W0)
Definition gbring.cpp:208
Polynomial-ring view tuned for the inner loop of classical Buchberger Groebner-basis computations.
Definition gbring.hpp:120
Engine-side commutative monomial monoid: variable names, ordering, multidegree machinery,...
Definition monoid.hpp:89
friend class FreeModule
Definition poly.hpp:66
Nterm * new_term() const
Definition poly.cpp:146
void setIsGraded(bool new_val)
Definition polyring.hpp:142
const Ring * K_
Definition polyring.hpp:123
const Monoid * M_
Definition polyring.hpp:124
virtual void remove(ring_elem &f) const =0
virtual ring_elem copy(const ring_elem f) const =0
virtual bool is_QQ() const
Definition ring.hpp:172
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
virtual ring_elem mult(const ring_elem f, const ring_elem g) const =0
const Monoid * degree_monoid() const
Definition ring.cpp:13
xxx xxx xxx
Definition ring.hpp:102
static std::pair< bool, int > get_si(mpz_srcptr n)
Definition ZZ.cpp:46
bool initialize_weyl(M2_arrayint derivs, M2_arrayint comms, int homog_var)
Definition weylalg.cpp:10
static int diffcoeffstop
Definition weylalg.hpp:70
ring_elem diff_coefficients(const ring_elem c, const int *derivatives, const_exponents exp) const
Definition weylalg.cpp:307
void extractCommutativePart(const_exponents exp, int *result) const
Definition weylalg.cpp:298
static int binomtop
Definition weylalg.hpp:69
int * _derivative
Definition weylalg.hpp:65
gbvector * gbvector_weyl_diff(GBRing *GR, const ring_elem c, int comp, const_exponents expf, const int *derivatives, const FreeModule *Fg, const gbvector *g) const
Definition weylalg.cpp:456
ring_elem multinomial(const ring_elem a, const_exponents exptop, const_exponents expbottom) const
int _homog_var
Definition weylalg.hpp:64
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 weylalg.cpp:597
gbvector * gbvector_mult_by_term(gbvectorHeap &result, const gbvector *f, const ring_elem c, const_monomial m, int comp) const
Definition weylalg.cpp:541
void extractDerivativePart(const_exponents exp, int *result) const
Definition weylalg.cpp:290
int _nderivatives
Definition weylalg.hpp:62
virtual void text_out(buffer &o) const
Definition weylalg.cpp:161
bool _homogeneous_weyl_algebra
Definition weylalg.hpp:63
virtual ring_elem mult_by_term(const ring_elem f, const ring_elem c, const_monomial m) const
Definition weylalg.cpp:420
int * _commutative
Definition weylalg.hpp:67
static int ** binomtable
Definition weylalg.hpp:71
void initialize1()
Definition weylalg.cpp:175
ring_elem binomial(int top, int bottom) const
Definition weylalg.cpp:227
Nterm * weyl_diff(const ring_elem c, const_exponents expf, const int *derivatives, const Nterm *g) const
Definition weylalg.cpp:339
bool divides(const_exponents expbottom, const_exponents exptop) const
Definition weylalg.cpp:266
bool increment(int *current_derivative, const int *top_derivative) const
Definition weylalg.cpp:273
static WeylAlgebra * create(const Ring *K, const Monoid *M, M2_arrayint derivs, M2_arrayint comms, int homog_var)
Definition weylalg.cpp:99
static int ** diffcoeffstable
Definition weylalg.hpp:72
RingZZ * globalZZ
Definition relem.cpp:13
#define monomial
Definition gb-toric.cpp:11
GBRing and gbvector — the GB-tuned polynomial-ring view used by classical Buchberger code.
polyheap — polynomial-specialised geometric heap for reduction accumulators.
const int * const_monomial
Definition imonorder.hpp:45
void freemem(void *s)
Definition m2-mem.cpp:103
const int ERROR
Definition m2-mem.cpp:55
VALGRIND_MAKE_MEM_DEFINED & result(result)
#define newarray_atomic_clear(T, len)
Definition newdelete.hpp:93
#define newarray(T, len)
Definition newdelete.hpp:82
#define newarray_atomic(T, len)
Definition newdelete.hpp:91
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
gbvector * next
Definition gbring.hpp:80
const int EQ
Definition style.hpp:40
Text-formatting helpers layered on buffer: bignum print, line wrapping, M2_gbTrace-gated emit.
WeylAlgebra — ring of polynomial differential operators with [d_i, x_i] = 1.