source: git/Singular/LIB/dmodloc.lib

spielwiese
Last change on this file was 3f7e01a, checked in by Hans Schoenemann <hannes@…>, 9 months ago
remnemae: sat -> sat, sat_with_exp
  • Property mode set to 100644
File size: 65.6 KB
Line 
1/////////////////////////////////////////////////////////////////////
2version="version dmodloc.lib 4.1.2.0 Feb_2019 "; // $Id$
3category="Noncommutative";
4info="
5LIBRARY: dmodloc.lib     Localization of algebraic D-modules and applications
6AUTHOR:  Daniel Andres,  daniel.andres@math.rwth-aachen.de
7
8Support: DFG Graduiertenkolleg 1632 `Experimentelle und konstruktive Algebra'
9
10
11OVERVIEW:
12Let I be a left ideal in the n-th polynomial Weyl algebra D=K[x]<d> and
13let f be a polynomial in K[x].
14
15If D/I is a holonomic module over D, it is known that the localization of D/I
16at f is also holonomic. The procedure @code{Dlocalization} computes an ideal
17J in D such that this localization is isomorphic to D/J as D-modules.
18
19If one regards I as an ideal in the rational Weyl algebra as above, K(x)<d>*I,
20and intersects with K[x]<d>, the result is called the Weyl closure of I.
21The procedures @code{WeylClosure} (if I has finite holonomic rank) and
22@code{WeylClosure1} (if I is in the first Weyl algebra) can be used for
23computations.
24
25As an application of the Weyl closure, the procedure @code{annRatSyz} computes
26a holonomic part of the annihilator of a rational function by computing certain
27syzygies. The full annihilator can be obtained by taking the Weyl closure of
28the result.
29
30If one regards the left ideal I as system of linear PDEs, one can find its
31polynomial solutions with @code{polSol} (if I is holonomic) or
32@code{polSolFiniteRank} (if I is of finite holonomic rank). Rational solutions
33can be obtained with @code{ratSol}.
34
35The procedure @code{bfctBound} computes a possible multiple of the b-function
36for f^s*u at a generic root of f. Here, u stands for [1] in D/I.
37
38This library also offers the procedures @code{holonomicRank} and
39@code{DsingularLocus} to compute the holonomic rank and the singular locus
40of the D-module D/I.
41
42
43REFERENCES:
44   (OT)  T. Oaku, N. Takayama: `Algorithms for D-modules',
45         Journal of Pure and Applied Algebra, 1998.
46@* (OTT) T. Oaku, N. Takayama, H. Tsai: `Polynomial and rational solutions
47         of holonomic systems', Journal of Pure and Applied Algebra, 2001.
48@* (OTW) T. Oaku, N. Takayama, U. Walther: `A Localization Algorithm for
49         D-modules', Journal of Symbolic Computation, 2000.
50@* (Tsa) H. Tsai: `Algorithms for algebraic analysis', PhD thesis, 2000.
51
52
53PROCEDURES:
54Dlocalization(I,f[,k,e]);  computes the localization of a D-module
55WeylClosure(I);    computes the Weyl closure of an ideal in the Weyl algebra
56WeylClosure1(L);   computes the Weyl closure of operator in first Weyl algebra
57holonomicRank(I);  computes the holonomic rank of I
58DsingularLocus(I); computes the singular locus of a D-module
59polSol(I[,w,m]);   computes basis of polynomial solutions to the given system
60polSolFiniteRank(I[,w]); computes basis of polynomial solutions to given system
61ratSol(I);         computes basis of rational solutions to the given system
62bfctBound(I,f[,primdec]); computes multiple of b-function for f^s*u
63annRatSyz(f,g[,db,eng]);  computes part of annihilator of rational function g/f
64
65dmodGeneralAssumptionCheck();   check general assumptions
66extendWeyl(S);     extends basering (Weyl algebra) by given vars
67polyVars(f,v);     checks whether f contains only variables indexed by v
68monomialInIdeal(I);    computes all monomials appearing in generators of ideal
69vars2pars(v);      converts variables specified by v into parameters
70minIntRoot2(L);    finds minimal integer root in a list of roots
71maxIntRoot(L);     finds maximal integer root in a list of roots
72dmodAction(id,f[,v]);  computes the natural action of a D-module on K[x]
73dmodActionRat(id,w);   computes the natural action of a D-module on K(x)
74simplifyRat(v);    simplifies rational function
75addRat(v,w);       adds rational functions
76multRat(v,w);      multiplies rational functions
77diffRat(v,j);      derives rational function
78commRing();        deletes non-commutative relations from ring
79rightNFWeyl(id,k); computes right NF wrt right ideal (var(k)) in Weyl algebra
80
81
82KEYWORDS: D-module; holonomic rank; singular locus of D-module;
83D-localization; localization of D-module; characteristic variety;
84Weyl closure; polynomial solutions; rational solutions;
85annihilator of rational function
86
87
88SEE ALSO: bfun_lib, dmod_lib, dmodapp_lib, dmodvar_lib, gmssing_lib
89";
90
91
92/*
93CHANGELOG:
9412.11.12: bugfixes, updated docu
9517.12.12: updated docu, removed redundant procedure killTerms
96*/
97
98LIB "bfun.lib";    // for pIntersect etc
99LIB "dmodapp.lib"; // for GBWeight, charVariety etc
100LIB "nctools.lib"; // for Weyl, isWeyl etc
101
102// testing for consistency of the library /////////////////////////////////////
103
104static proc testdmodloc()
105{
106  example dmodGeneralAssumptionCheck;
107  example safeVarName;
108  example extendWeyl;
109  example polyVars;
110  example monomialInIdeal;
111  example vars2pars;
112  example minIntRoot2;
113  example maxIntRoot;
114  example dmodAction;
115  example dmodActionRat;
116  example simplifyRat;
117  example addRat;
118  example multRat;
119  example diffRat;
120  example commRing;
121  example holonomicRank;
122  example DsingularLocus;
123  example rightNFWeyl;
124  example Dlocalization;
125  example WeylClosure1;
126  example WeylClosure;
127  example polSol;
128  example polSolFiniteRank;
129  example ratSol;
130  example bfctBound;
131  example annRatSyz;
132}
133
134
135// tools //////////////////////////////////////////////////////////////////////
136
137proc dmodGeneralAssumptionCheck ()
138"
139USAGE:    dmodGeneralAssumptionCheck();
140RETURN:   nothing, but checks general assumptions on the basering
141NOTE:     This procedure checks the following conditions on the basering R
142          and prints an error message if any of them is violated:
143@*         - R is the n-th Weyl algebra over a field of characteristic 0,
144@*         - R is not a qring,
145@*         - for all 1<=i<=n the identity var(i+n)*var(i)=var(i)*var(i+1)+1
146             holds, i.e. the sequence of variables is given by
147             x(1),...,x(n),D(1),...,D(n), where D(i) is the differential
148             operator belonging to x(i).
149EXAMPLE:  example dmodGeneralAssumptionCheck; shows examples
150"
151{
152  // char K <> 0, qring
153  if (  (size(ideal(basering)) >0) || (char(basering) >0) )
154  {
155    ERROR("Basering is inappropriate: characteristic>0 or qring present");
156  }
157  // no Weyl algebra
158  if (isWeyl() == 0)
159  {
160    ERROR("Basering is not a Weyl algebra");
161  }
162  // wrong sequence of vars
163  int i,n;
164  n = nvars(basering) div 2;
165  for (i=1; i<=n; i++)
166  {
167    if (bracket(var(i+n),var(i))<>1)
168    {
169      ERROR(string(var(i+n))+" is not a differential operator for " +string(var(i)));
170    }
171  }
172  return();
173}
174example
175{
176  "EXAMPLE"; echo=2;
177  ring r = 0,(x,D),dp;
178  dmodGeneralAssumptionCheck(); // prints error message
179  def W = Weyl();
180  setring W;
181  dmodGeneralAssumptionCheck(); // returns nothing
182}
183
184
185static proc safeVarName (string s)
186"
187USAGE:    safeVarName(s);  s string
188RETURN:   string, returns s if s is not the name of a par/var of basering
189          and `@' + s otherwise
190EXAMPLE:  example safeVarName; shows examples
191"
192{
193  string S = "," + charstr(basering) + "," + varstr(basering) + ",";
194  s = "," + s + ",";
195  while (find(S,s) <> 0)
196  {
197    s[1] = "@";
198    s = "," + s;
199  }
200  s = s[2..size(s)-1];
201  return(s);
202}
203example
204{
205  "EXAMPLE:"; echo = 2;
206  ring r = (0,a),(w,@w,x,y),dp;
207  safeVarName("a");
208  safeVarName("x");
209  safeVarName("z");
210  safeVarName("w");
211}
212
213
214proc extendWeyl (def newVars)
215"
216USAGE:    extendWeyl(S);  S string or list of strings
217ASSUME:   The basering is the n-th Weyl algebra over a field of
218          characteristic 0 and for all 1<=i<=n the identity
219          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
220          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i)
221          is the differential operator belonging to x(i).
222RETURN:   ring, Weyl algebra extended by vars given by S
223EXAMPLE:  example extendWeyl; shows examples
224"
225{
226  dmodGeneralAssumptionCheck();
227  int i,s;
228  string inpt = typeof(newVars);
229  list L;
230  if (inpt=="string")
231  {
232    s = 1;
233    L = newVars;
234  }
235  else
236  {
237    if (inpt=="list")
238    {
239      s = size(newVars);
240      if (s<1)
241      {
242        ERROR("No new variables specified.");
243      }
244      for (i=1; i<=s; i++)
245      {
246        if (typeof(newVars[i]) <> "string")
247        {
248          ERROR("Entries of input list must be of type string.");
249        }
250      }
251      L = newVars;
252    }
253    else
254    {
255      ERROR("Expected string or list of strings as input.");
256    }
257  }
258  def save = basering;
259  int n = nvars(save) div 2;
260  list RL = ringlist(save);
261  RL = RL[1..4];
262  list Ltemp = L;
263  for (i=s; i>0; i--)
264  {
265    Ltemp[n+s+i] = "D" + newVars[i];
266  }
267  for (i=n; i>0; i--)
268  {
269    Ltemp[s+i]     = RL[2][i];
270    Ltemp[n+2*s+i] = RL[2][n+i];
271  }
272  RL[2] = Ltemp;
273  Ltemp = list();
274  Ltemp[1] = list("dp",intvec(1:(2*n+2*s)));
275  Ltemp[2] = list("C",intvec(0));
276  RL[3] = Ltemp;
277  kill Ltemp;
278  def @Dv = ring(RL);
279  setring @Dv;
280  def Dv = Weyl();
281  setring save;
282  return(Dv);
283}
284example
285{
286  "EXAMPLE:"; echo = 2;
287  ring @D2 = 0,(x,y,Dx,Dy),dp;
288  def D2 = Weyl();
289  setring D2;
290  def D3 = extendWeyl("t");
291  setring D3; D3;
292  list L = "u","v";
293  def D5 = extendWeyl(L);
294  setring D5;
295  D5;
296}
297
298
299proc polyVars (poly f, intvec v)
300"
301USAGE:    polyVars(f,v);  f poly, v intvec
302RETURN:   int, 1 if f contains only variables indexed by v, 0 otherwise
303EXAMPLE:  example polyVars; shows examples
304"
305{
306  ideal varsf = variables(f); // vars contained in f
307  ideal V;
308  int i;
309  int n = nvars(basering);
310  for (i=1; i<=size(v); i++)
311  {
312    if ( (v[i]<0) || (v[i]>n) )
313    {
314      ERROR("var(" + string(v[i]) + ") out of range");
315    }
316    V[i] = var(v[i]);
317  }
318  attrib(V,"isSB",1);
319  ideal N = NF(varsf,V);
320  N = simplify(N,2);
321  if (N[1]==0)
322  {
323    return(1);
324  }
325  else
326  {
327    return(0);
328  }
329}
330example
331{
332  "EXAMPLE:"; echo = 2;
333  ring r = 0,(x,y,z),dp;
334  poly f = y^2+zy;
335  intvec v = 1,2;
336  polyVars(f,v); // does f depend only on x,y?
337  v = 2,3;
338  polyVars(f,v); // does f depend only on y,z?
339}
340
341
342proc monomialInIdeal (ideal I)
343"
344USAGE:    monomialInIdeal(I);  I ideal
345RETURN:   ideal consisting of all monomials appearing in generators of ideal
346EXAMLPE:  example monomialInIdeal; shows examples
347"
348{
349  // returns ideal consisting of all monomials appearing in generators of ideal
350  I = simplify(I,2+8);
351  int i;
352  poly p;
353  ideal M;
354  for (i=1; i<=size(I); i++)
355  {
356    p = I[i];
357    while (p<>0)
358    {
359      M[size(M)+1] = leadmonom(p);
360      p = p - lead(p);
361    }
362  }
363  M = simplify(M,4+2);
364  return(M);
365}
366example
367{
368  "EXAMPLE"; echo=2;
369  ring r = 0,(x,y),dp;
370  ideal I = x2+5x3y7, x-x2-6xy;
371  monomialInIdeal(I);
372}
373
374
375proc vars2pars (intvec v)
376"
377USAGE:    vars2pars(v);  v intvec
378ASSUME:   The basering is commutative.
379RETURN:   ring with variables specified by v converted into parameters
380EXAMPLE:  example vars2pars; shows examples
381"
382{
383  if (isCommutative() == 0)
384  {
385    ERROR("The basering must be commutative.");
386  }
387  v = sortIntvec(v)[1];
388  int sv = size(v);
389  if ( (v[1]<1) || (v[sv]<1) )
390  {
391    ERROR("Expected entries of intvec in the range 1.."+string(n));
392  }
393  def save = basering;
394  int i,j,n;
395  n = nvars(save);
396  list RL = ringlist(save);
397  list Lp,Lv,L1;
398  if (typeof(RL[1]) == "list")
399  {
400    L1 = RL[1];
401    Lp = L1[2];
402  }
403  else
404  {
405    L1[1] = RL[1];
406    L1[4] = ideal(0);
407  }
408  j = sv;
409  for (i=1; i<=n; i++)
410  {
411    if (j>0)
412    {
413      if (v[j]==i)
414      {
415        Lp[size(Lp)+1] = string(var(i));
416        j--;
417      }
418      else
419      {
420        Lv[size(Lv)+1] = string(var(i));
421      }
422    }
423    else
424    {
425      Lv[size(Lv)+1] = string(var(i));
426    }
427  }
428  RL[2] = Lv;
429  L1[2] = Lp;
430  L1[3] = list(list("lp",intvec(1:size(Lp))));
431  RL[1] = L1;
432  L1 = list();
433  L1[1] = list("dp",intvec(1:sv));
434  L1[2] = list("C",intvec(0));
435  RL[3] = L1;
436//   RL;
437  def R = ring(RL);
438  return(R);
439}
440example
441{
442  "EXAMPLE:"; echo = 2;
443  ring r = 0,(x,y,z,a,b,c),dp;
444  intvec v = 4,5,6;
445  def R = vars2pars(v);
446  setring R;
447  R;
448  v = 1,2;
449  def RR = vars2pars(v);
450  setring RR;
451  RR;
452}
453
454
455static proc minMaxIntRoot (list L, string minmax)
456{
457  int win;
458  if (size(L)>1)
459  {
460    if ( (typeof(L[1])<>"ideal") || (typeof(L[2])<>"intvec") )
461    {
462      win = 1;
463    }
464  }
465  else
466  {
467    win = 1;
468  }
469  if (win)
470  {
471    ERROR("Expected list in the format of bFactor");
472  }
473  if (size(L)>2)
474  {
475    if ( (L[3]=="1") || (L[3]=="0") )
476    {
477      print("// Warning: Constant poly. Returning 0.");
478      return(int(0));
479    }
480  }
481  ideal I = L[1];
482  int i,k,b;
483  if (minmax=="min")
484  {
485    i = ncols(I);
486    k = -1;
487    b = 0;
488  }
489  else // minmax=="max"
490  {
491    i = 1;
492    k = 1;
493    b = ncols(I);
494  }
495  for (; k*i<k*b; i=i+k)
496  {
497    if (isInt(leadcoef(I[i])))
498    {
499      return(int(leadcoef(I[i])));
500    }
501  }
502  print("// Warning: No integer root found. Returning 0.");
503  return(int(0));
504}
505
506
507//TODO rename? minIntRoot is name of proc in dmod.lib
508proc minIntRoot2 (list L)
509"
510USAGE:    minIntRoot2(L);  L list
511ASSUME:   L is the output of bFactor.
512RETURN:   int, the minimal integer root in a list of roots
513SEE ALSO: minIntRoot, maxIntRoot, bFactor
514EXAMPLE:  example minIntRoot2; shows examples
515"
516{
517  return(minMaxIntRoot(L,"min"));
518}
519example
520{
521  "EXAMPLE"; echo=2;
522  ring r = 0,x,dp;
523  poly f = x*(x+1)*(x-2)*(x-5/2)*(x+5/2);
524  list L = bFactor(f);
525  minIntRoot2(L);
526}
527
528
529proc maxIntRoot (list L)
530"
531USAGE:    maxIntRoot(L);  L list
532ASSUME:   L is the output of bFactor.
533RETURN:   int, the maximal integer root in a list of roots
534SEE ALSO: minIntRoot2, bFactor
535EXAMPLE:  example maxIntRoot; shows examples
536"
537{
538  return(minMaxIntRoot(L,"max"));
539}
540example
541{
542  "EXAMPLE"; echo=2;
543  ring r = 0,x,dp;
544  poly f = x*(x+1)*(x-2)*(x-5/2)*(x+5/2);
545  list L = bFactor(f);
546  maxIntRoot(L);
547}
548
549
550proc dmodAction (def id, poly f, list #)
551"
552USAGE:    dmodAction(id,f[,v]);  id ideal or poly, f poly, v optional intvec
553ASSUME:   If v is not given, the basering is the n-th Weyl algebra W over a
554          field of characteristic 0 and for all 1<=i<=n the identity
555          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
556          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
557          differential operator belonging to x(i).
558          Otherwise, v is assumed to specify positions of variables, which form
559          a Weyl algebra as a subalgebra of the basering:
560          If size(v) equals 2*n, then bracket(var(v[i]),var(v[j])) must equal
561          1 if and only if j equals i+n, and 0 otherwise,  for all 1<=i,j<=n.
562@*        Further, assume that f does not contain any D(i).
563RETURN:   same type as id, the result of the natural D-module action of id on f
564NOTE:     The assumptions made are not checked.
565EXAMPLE:  example dmodAction; shows examples
566"
567{
568  string inp1 = typeof(id);
569  if ((inp1<>"poly") && (inp1<>"ideal"))
570  {
571    ERROR("Expected first argument to be poly or ideal but received "+inp1);
572  }
573  intvec posXD = 1..nvars(basering);
574  if (size(#)>0)
575  {
576    if (typeof(#[1])=="intvec")
577    {
578      posXD = #[1];
579    }
580  }
581  if ((size(posXD) mod 2)<>0)
582  {
583    ERROR("Even number of variables expected.")
584  }
585  int n = (size(posXD)) div 2;
586  int i,j,k,l;
587  ideal resI = id;
588  int sid = ncols(resI);
589  intvec v;
590  poly P,h;
591  for (l=1; l<=sid; l++)
592  {
593    P = resI[l];
594    resI[l] = 0;
595    for (i=1; i<=size(P); i++)
596    {
597      v = leadexp(P[i]);
598      h = f;
599      for (j=1; j<=n; j++)
600      {
601        for (k=1; k<=v[posXD[j+n]]; k++) // action of Dx
602        {
603          h = diff(h,var(posXD[j]));
604        }
605        h = h*var(posXD[j])^v[posXD[j]]; // action of x
606      }
607      h = leadcoef(P[i])*h;
608      resI[l] = resI[l] + h;
609    }
610  }
611  if (inp1 == "ideal")
612  {
613    return(resI);
614  }
615  else
616  {
617    return(resI[1]);
618  }
619}
620example
621{
622  ring r = 0,(x,y,z),dp;
623  poly f = x^2*z - y^3;
624  def A = annPoly(f);
625  setring A;
626  poly f = imap(r,f);
627  dmodAction(LD,f);
628  poly P = y*Dy+3*z*Dz-3;
629  dmodAction(P,f);
630  dmodAction(P[1],f);
631}
632
633
634static proc checkRatInput (vector I)
635{
636  // check for valid input
637  int wrginpt;
638  if (nrows(I)<>2)
639  {
640    wrginpt = 1;
641  }
642  else
643  {
644    if (I[2] == 0)
645    {
646      wrginpt = 1;
647    }
648  }
649  if (wrginpt)
650  {
651    ERROR("Vector must consist of exactly two components, second one not 0");
652  }
653  return();
654}
655
656
657proc dmodActionRat(def id, vector w)
658"
659USAGE:    dmodActionRat(id,w);  id ideal or poly, f vector
660ASSUME:   The basering is the n-th Weyl algebra W over a field of
661          characteristic 0 and for all 1<=i<=n the identity
662          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
663          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
664          differential operator belonging to x(i).
665@*        Further, assume that w has exactly two components, second one not 0,
666          and that w does not contain any D(i).
667RETURN:   same type as id, the result of the natural D-module action of id on
668          the rational function w[1]/w[2]
669EXAMPLE:  example dmodActionRat; shows examples
670"
671{
672  string inp1 = typeof(id);
673  if ( (inp1<>"poly") && (inp1<>"ideal") )
674  {
675    ERROR("Expected first argument to be poly or ideal but received " + inp1);
676  }
677  checkRatInput(w);
678  poly f = w[1];
679  finKx(f);
680  f = w[2];
681  finKx(f);
682  def save = basering;
683  def r = commRing();
684  setring r;
685  ideal I = imap(save,id);
686  vector w = imap(save,w);
687  int i,j,k,l;
688  int n = nvars(basering) div 2;
689  int sid = ncols(I);
690  intvec v;
691  poly P;
692  vector h,resT;
693  module resL;
694  for (l=1; l<=sid; l++)
695  {
696    P = I[l];
697    resT = [0,1];
698    for (i=1; i<=size(P); i++)
699    {
700      v = leadexp(P[i]);
701      h = w;
702      for (j=1; j<=n; j++)
703      {
704        for (k=1; k<=v[j+n]; k++) // action of Dx
705        {
706          h = diffRat(h,j);
707        }
708        h = h + h[1]*(var(j)^v[j]-1)*gen(1);  // action of x
709      }
710      h = h + (leadcoef(P[i])-1)*h[1]*gen(1);
711      resT = addRat(resT,h);
712    }
713    resL[l] = resT;
714  }
715  setring save;
716  module resL = imap(r,resL);
717  return(resL);
718}
719example
720{
721  "EXAMPLE:"; echo = 2;
722  ring r = 0,(x,y),dp;
723  poly f = 2*x;  poly g = y;
724  def A = annRat(f,g); setring A;
725  poly f = imap(r,f); poly g = imap(r,g);
726  vector v = [f,g]; // represents f/g
727  // x and y act by multiplication
728  dmodActionRat(x,v);
729  dmodActionRat(y,v);
730  // Dx and Dy act by partial derivation
731  dmodActionRat(Dx,v);
732  dmodActionRat(Dy,v);
733  dmodActionRat(x*Dx+y*Dy,v);
734  setring r;
735  f = 2*x*y; g = x^2 - y^3;
736  def B = annRat(f,g); setring B;
737  poly f = imap(r,f); poly g = imap(r,g);
738  vector v = [f,g];
739  dmodActionRat(LD,v); // hence LD is indeed the annihilator of f/g
740}
741
742
743static proc arithmeticRat (vector I, vector J, string op, list #)
744{
745  // op = "+": return I+J
746  // op = "*": return I*J
747  // op = "s": return simplified I
748  // op = "d": return diff(I,var(#[1]))
749  int isComm = isCommutative();
750  if (!isComm)
751  {
752    def save = basering;
753    def r = commRing();
754    setring r;
755    ideal m = maxideal(1);
756    map f = save,m;
757    vector I = f(I);
758    vector J = f(J);
759  }
760  vector K;
761  poly p;
762  if (op == "s")
763  {
764    p = gcd(I[1],I[2]);
765    K = (I[1]/p)*gen(1) + (I[2]/p)*gen(2);
766  }
767  else
768  {
769    if (op == "+")
770    {
771      I = arithmeticRat(I,vector(0),"s");
772      J = arithmeticRat(J,vector(0),"s");
773      p = lcm(I[2],J[2]);
774      K = (I[1]*p/I[2] + J[1]*p/J[2])*gen(1) + p*gen(2);
775    }
776    else
777    {
778      if (op == "*")
779      {
780        K = (I[1]*J[1])*gen(1) + (I[2]*J[2])*gen(2);
781      }
782      else
783      {
784        if (op == "d")
785        {
786          int j = #[1];
787          K = (diff(I[1],var(j))*I[2] - I[1]*diff(I[2],var(j)))*gen(1)+ (I[2]^2)*gen(2);
788        }
789      }
790    }
791    K = arithmeticRat(K,vector(0),"s");
792  }
793  if (!isComm)
794  {
795    setring save;
796    vector K = imap(r,K);
797  }
798  return(K);
799}
800
801
802proc simplifyRat (vector J)
803"
804USAGE:    simplifyRat(v);  v vector
805ASSUME:   Assume that v has exactly two components, second one not 0.
806RETURN:   vector, representing simplified rational function v[1]/v[2]
807NOTE:     Possibly present non-commutative relations of the basering are
808          ignored.
809EXAMPLE:  example simplifyRat; shows examples
810"
811{
812  checkRatInput(J);
813  return(arithmeticRat(J,vector(0),"s"));
814}
815example
816{
817  "EXAMPLE:"; echo = 2;
818   ring r = 0,(x,y),dp;
819  vector v = [x2-1,x+1];
820  simplifyRat(v);
821  simplifyRat(v) - [x-1,1];
822}
823
824
825proc addRat (vector I, vector J)
826"
827USAGE:    addRat(v,w);  v,w vectors
828ASSUME:   Assume that v,w have exactly two components, second ones not 0.
829RETURN:   vector, representing rational function (v[1]/v[2])+(w[1]/w[2])
830NOTE:     Possibly present non-commutative relations of the basering are
831          ignored.
832EXAMPLE:  example addRat; shows examples
833"
834{
835  checkRatInput(I);
836  checkRatInput(J);
837  return(arithmeticRat(I,J,"+"));
838}
839example
840{
841  "EXAMPLE:"; echo = 2;
842  ring r = 0,(x,y),dp;
843  vector v = [x,y];
844  vector w = [y,x];
845  addRat(v,w);
846  addRat(v,w) - [x2+y2,xy];
847}
848
849
850proc multRat (vector I, vector J)
851"
852USAGE:    multRat(v,w);  v,w vectors
853ASSUME:   Assume that v,w have exactly two components, second ones not 0.
854RETURN:   vector, representing rational function (v[1]/v[2])*(w[1]/w[2])
855NOTE:     Possibly present non-commutative relations of the basering are
856          ignored.
857EXAMPLE:  example multRat; shows examples
858"
859{
860  checkRatInput(I);
861  checkRatInput(J);
862  return(arithmeticRat(I,J,"*"));
863}
864example
865{
866  "EXAMPLE:"; echo = 2;
867  ring r = 0,(x,y),dp;
868  vector v = [x,y];
869  vector w = [y,x];
870  multRat(v,w);
871  multRat(v,w) - [1,1];
872}
873
874
875proc diffRat (vector I, int j)
876"
877USAGE:    diffRat(v,j);  v vector, j int
878ASSUME:   Assume that v has exactly two components, second one not 0.
879RETURN:   vector, representing rational function derivative of rational
880          function (v[1]/v[2]) w.r.t. var(j)
881NOTE:     Possibly present non-commutative relations of the basering are
882          ignored.
883EXAMPLE:  example diffRat; shows examples
884"
885{
886  checkRatInput(I);
887  if ( (j<1) || (j>nvars(basering)) )
888  {
889    ERROR("Second argument must be in the range 1.."+string(nvars(basering)));
890  }
891  return(arithmeticRat(I,vector(0),"d",j));
892}
893example
894{
895  "EXAMPLE:"; echo = 2;
896  ring r = 0,(x,y),dp;
897  vector v = [x,y];
898  diffRat(v,1);
899  diffRat(v,1) - [1,y];
900  diffRat(v,2);
901  diffRat(v,2) - [-x,y2];
902}
903
904
905proc commRing ()
906"
907USAGE:    commRing();
908RETURN:   ring, basering without non-commutative relations
909EXAMPLE:  example commRing; shows examples
910"
911{
912  list RL = ringlist(basering);
913  if (size(RL)<=4)
914  {
915    return(basering);
916  }
917  RL = RL[1..4];
918  def r = ring(RL);
919  return(r);
920}
921example
922{
923  "EXAMPLE:"; echo = 2;
924  def W = makeWeyl(3);
925  setring W; W;
926  def W2 = commRing();
927  setring W2; W2;
928  ring r = 0,(x,y),dp;
929  def r2 = commRing(); // same as r
930  setring r2; r2;
931}
932
933
934// TODO remove this proc once chern.lib is ready
935static proc orderedPartition(int n, list #)
936"
937USAGE:   orderedPartition(n,a); n,a positive ints
938         orderedPartition(n,w); n positive int, w positive intvec
939RETURN:  list of intvecs
940PURPOSE: Computes all partitions of n of length a, if the second
941         argument is an int, or computes all weighted partitions
942         w.r.t. w of n of length size(w) if the second argument
943         is an intvec.
944         In both cases, zero parts are included.
945EXAMPLE: example orderedPartition; shows an example
946"
947{
948  int a,wrongInpt,intInpt;
949  intvec w = 1;
950  if (size(#)>0)
951  {
952    if (typeof(#[1]) == "int")
953    {
954      a = #[1];
955      intInpt = 1;
956    }
957    else
958    {
959      if (typeof(#[1]) == "intvec")
960      {
961        w = #[1];
962        a = size(w);
963      }
964      else
965      {
966        wrongInpt = 1;
967      }
968    }
969  }
970  else
971  {
972    wrongInpt = 1;
973  }
974  if (wrongInpt)
975  {
976    ERROR("Expected second argument of type int or intvec.");
977  }
978  kill wrongInpt;
979  if (n==0 && a>0)
980  {
981    return(list(0:a));
982  }
983  if (n<=0 || a<=0 || allPositive(w)==0)
984  {
985    ERROR("Positive arguments expected.");
986  }
987  int baseringdef;
988  if (defined(basering)) // if a basering is defined, it should be saved for later use
989  {
990    def save = basering;
991    baseringdef = 1;
992  }
993  ring r = 0,(x(1..a)),dp; // all variables for partition of length a
994  ideal M;
995  if (intInpt)
996  {
997    M = maxideal(n);   // all monomials of total degree n
998  }
999  else
1000  {
1001    M = weightKB(ideal(0),n,w); // all monomials of total weighted degree n
1002  }
1003  list L;
1004  int i;
1005  for (i = 1; i <= ncols(M); i++) {L = insert(L,leadexp(M[i]));}
1006  // the leadexp corresponds to a partition
1007  if (baseringdef) // sets the old ring as basering again
1008  {
1009    setring save;
1010  }
1011  return(L); //returns the list of partitions
1012}
1013example
1014{
1015 "EXAMPLE"; echo = 2;
1016 orderedPartition(4,2);
1017 orderedPartition(5,3);
1018 orderedPartition(2,4);
1019 orderedPartition(8,intvec(2,3));
1020 orderedPartition(7,intvec(2,2)); // no such partition
1021}
1022
1023
1024// applications of characteristic variety /////////////////////////////////////
1025
1026proc holonomicRank (ideal I, list #)
1027"
1028USAGE:    holonomicRank(I[,e]);   I ideal, e optional int
1029ASSUME:   The basering is the n-th Weyl algebra over a field of
1030          characteristic 0 and for all 1<=i<=n the identity
1031          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1032          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i)
1033          is the differential operator belonging to x(i).
1034RETURN:   int, the holonomic rank of I
1035REMARKS:  The holonomic rank of I is defined to be the K(x(1..n))-dimension of
1036          the module W/WI, where W is the rational Weyl algebra
1037          K(x(1..n))<D(1..n)>.
1038          If this dimension is infinite, -1 is returned.
1039NOTE:     If e<>0, @code{std} is used for Groebner basis computations,
1040          otherwise (and by default) @code{slimgb} is used.
1041@*        If printlevel=1, progress debug messages will be printed,
1042          if printlevel>=2, all the debug messages will be printed.
1043EXAMPLE:  example holonomicRank; shows examples
1044"
1045{
1046  // assumption check is done by charVariety
1047  int ppl = printlevel - voice + 2;
1048  int eng;
1049  if (size(#)>0)
1050  {
1051    if(typeof(#[1])=="int")
1052    {
1053      eng = #[1];
1054    }
1055  }
1056  def save = basering;
1057  dbprint(ppl  ,"// Computing characteristic variety...");
1058  def grD = charVariety(I);
1059  setring grD; // commutative ring
1060  dbprint(ppl  ,"// ...done.");
1061  dbprint(ppl-1,"// " + string(charVar));
1062  int n = nvars(save) div 2;
1063  intvec v = 1..n;
1064  def R = vars2pars(v);
1065  setring R;
1066  ideal J = imap(grD,charVar);
1067  dbprint(ppl  ,"// Starting GB computation...");
1068  J = engine(J,0); // use slimgb
1069  dbprint(ppl  ,"// ...done.");
1070  dbprint(ppl-1,"// " + string(J));
1071  int d = vdim(J);
1072  setring save;
1073  return(d);
1074}
1075example
1076{
1077  "EXAMPLE:"; echo = 2;
1078  // (OTW), Example 8
1079  ring r3 = 0,(x,y,z,Dx,Dy,Dz),dp;
1080  def D3 = Weyl();
1081  setring D3;
1082  poly f = x^3-y^2*z^2;
1083  ideal I = f^2*Dx+3*x^2, f^2*Dy-2*y*z^2, f^2*Dz-2*y^2*z;
1084  // I annihilates exp(1/f)
1085  holonomicRank(I);
1086}
1087
1088
1089proc DsingularLocus (ideal I)
1090"
1091USAGE:    DsingularLocus(I);  I ideal
1092ASSUME:   The basering is the n-th Weyl algebra over a field of
1093          characteristic 0 and for all 1<=i<=n the identity
1094          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1095          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i)
1096          is the differential operator belonging to x(i).
1097RETURN:   ideal, describing the singular locus of the D-module D/I
1098NOTE:     If printlevel>=1, progress debug messages will be printed,
1099          if printlevel>=2, all the debug messages will be printed
1100EXAMPLE:  example DsingularLocus; shows examples
1101"
1102{
1103  // assumption check is done by charVariety
1104  int ppl = printlevel - voice + 2;
1105  def save = basering;
1106  dbprint(ppl  ,"// Computing characteristic variety...");
1107  def grD = charVariety(I);
1108  setring grD;
1109  dbprint(ppl  ,"// ...done");
1110  dbprint(ppl-1,"// " + string(charVar));
1111  poly pDD = 1;
1112  ideal IDD;
1113  int i;
1114  int n = nvars(basering) div 2;
1115  for (i=1; i<=n; i++)
1116  {
1117    pDD = pDD*var(i+n);
1118    IDD[i] = var(i+n);
1119  }
1120  dbprint(ppl  ,"// Computing saturation...");
1121  ideal S = sat(charVar,IDD);
1122  dbprint(ppl  ,"// ...done");
1123  dbprint(ppl-1,"// " + string(S));
1124  dbprint(ppl  ,"// Computing elimination...");
1125  S = eliminate(S,pDD);
1126  dbprint(ppl  ,"// ...done");
1127  dbprint(ppl-1,"// " + string(S));
1128  dbprint(ppl  ,"// Computing radical...");
1129  S = radical(S);
1130  dbprint(ppl  ,"// ...done");
1131  dbprint(ppl-1,"// " + string(S));
1132  setring save;
1133  ideal S = imap(grD,S);
1134  return(S);
1135}
1136example
1137{
1138  "EXAMPLE:"; echo = 2;
1139  // (OTW), Example 8
1140  ring @D3 = 0,(x,y,z,Dx,Dy,Dz),dp;
1141  def D3 = Weyl();
1142  setring D3;
1143  poly f = x^3-y^2*z^2;
1144  ideal I = f^2*Dx + 3*x^2, f^2*Dy-2*y*z^2, f^2*Dz-2*y^2*z;
1145  // I annihilates exp(1/f)
1146  DsingularLocus(I);
1147}
1148
1149
1150// localization ///////////////////////////////////////////////////////////////
1151
1152static proc finKx(poly f)
1153{
1154  int n = nvars(basering) div 2;
1155  intvec iv = 1..n;
1156  if (polyVars(f,iv) == 0)
1157  {
1158    ERROR("Given poly may not contain differential operators.");
1159  }
1160  return();
1161}
1162
1163
1164proc rightNFWeyl (def id, int k)
1165"
1166USAGE:    rightNFWeyl(id,k);  id ideal or poly, k int
1167ASSUME:   The basering is the n-th Weyl algebra over a field of
1168          characteristic 0 and for all 1<=i<=n the identity
1169          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1170          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i)
1171          is the differential operator belonging to x(i).
1172RETURN:   same type as id, the right normal form of id with respect to the
1173          principal right ideal generated by the k-th variable
1174NOTE:     No Groebner basis computation is used.
1175EXAMPLE:  example rightNFWeyl; shows examples.
1176"
1177{
1178  dmodGeneralAssumptionCheck();
1179  string inpt = typeof(id);
1180  if (inpt=="ideal" || inpt=="poly")
1181  {
1182    ideal I = id;
1183  }
1184  else
1185  {
1186    ERROR("Expected first input to be of type ideal or poly.");
1187  }
1188  def save = basering;
1189  int n = nvars(save) div 2;
1190  if (0>k || k>2*n)
1191  {
1192    ERROR("Expected second input to be in the range 1.."+string(2*n)+".");
1193  }
1194  int i,j;
1195  if (k>n) // var(k) = Dx(k-n)
1196  {
1197    // switch var(k),var(k-n)
1198    list RL = ringlist(save);
1199    matrix rel = RL[6];
1200    rel[k-n,k] = -1;
1201    RL = RL[1..4];
1202    list L = RL[2];
1203    string str = L[k-n];
1204    L[k-n] = L[k];
1205    L[k] = str;
1206    RL[2] = L;
1207    def @W = ring(RL);
1208    kill L,RL,str;
1209    ideal @mm = maxideal(1);
1210    setring @W;
1211    matrix rel = imap(save,rel);
1212    def W = nc_algebra(1,rel);
1213    setring W;
1214    ideal @mm = imap(save,@mm);
1215    map mm = save,@mm;
1216    ideal I = mm(I);
1217    i = k-n;
1218  }
1219  else  // var(k) = x(k)
1220  {
1221    def W = save;
1222    i = k;
1223  }
1224  for (j=1; j<=ncols(I); j++)
1225  {
1226    I[j] = subst(I[j],var(i),0);
1227  }
1228  setring save;
1229  I = imap(W,I);
1230  if (inpt=="poly")
1231  {
1232    return(I[1]);
1233  }
1234  else
1235  {
1236    return(I);
1237  }
1238}
1239example
1240{
1241  "EXAMPLE:"; echo = 2;
1242  ring r = 0,(x,y,Dx,Dy),dp;
1243  def W = Weyl();
1244  setring W;
1245  ideal I = x^3*Dx^3, y^2*Dy^2, x*Dy, y*Dx;
1246  rightNFWeyl(I,1); // right NF wrt principal right ideal x*W
1247  rightNFWeyl(I,3); // right NF wrt principal right ideal Dx*W
1248  rightNFWeyl(I,2); // right NF wrt principal right ideal y*W
1249  rightNFWeyl(I,4); // right NF wrt principal right ideal Dy*W
1250  poly p = x*Dx+1;
1251  rightNFWeyl(p,1); // right NF wrt principal right ideal x*W
1252}
1253
1254
1255// TODO check OTW for assumptions on holonomicity
1256proc Dlocalization (ideal J, poly f, list #)
1257"
1258USAGE:    Dlocalization(I,f[,k,e]);  I ideal, f poly, k,e optional ints
1259ASSUME:   The basering is the n-th Weyl algebra over a field of
1260          characteristic 0 and for all 1<=i<=n the identity
1261          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1262          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i)
1263          is the differential operator belonging to x(i).
1264@*        Further, assume that f does not contain any D(i) and that I is
1265          holonomic on K^n\V(f).
1266RETURN:   ideal or list, computes an ideal J such that D/J is isomorphic
1267          to D/I localized at f as D-modules.
1268          If k<>0, a list consisting of J and an integer m is returned,
1269          such that f^m represents the natural map from D/I to D/J.
1270          Otherwise (and by default), only the ideal J is returned.
1271REMARKS:  It is known that a localization at f of a holonomic D-module is
1272          again a holonomic D-module.
1273@*        Reference: (OTW)
1274NOTE:     If e<>0, @code{std} is used for Groebner basis computations,
1275          otherwise (and by default) @code{slimgb} is used.
1276@*        If printlevel=1, progress debug messages will be printed,
1277          if printlevel>=2, all the debug messages will be printed.
1278SEE ALSO: DLoc, SDLoc, DLoc0
1279EXAMPLE: example Dlocalization; shows examples
1280"
1281{
1282  dmodGeneralAssumptionCheck();
1283  finKx(f);
1284  int ppl = printlevel - voice + 2;
1285  int outList,eng;
1286  if (size(#)>0)
1287  {
1288    if (typeof(#[1])=="int" || typeof(#[1])=="number")
1289    {
1290      outList = int(#[1]);
1291    }
1292    if (size(#)>1)
1293    {
1294      if (typeof(#[2])=="int" || typeof(#[2])=="number")
1295      {
1296        eng = int(#[2]);
1297      }
1298    }
1299  }
1300  int i,j;
1301  def save = basering;
1302  int n = nvars(save) div 2;
1303  def Dv = extendWeyl(safeVarName("v"));
1304  setring Dv;
1305  poly f = imap(save,f);
1306  ideal phiI;
1307  for (i=n; i>0; i--)
1308  {
1309    phiI[i+n] = var(i+n+2)-var(1)^2*bracket(var(i+n+2),f)*var(n+2);
1310    phiI[i]   = var(i+1);
1311  }
1312  map phi = save,phiI;
1313  ideal J = phi(J);
1314  J = J, 1-f*var(1);
1315  // TODO original J has to be holonomic only on K^n\V(f), not on all of K^n
1316  // does is suffice to show that new J is holonomic on Dv??
1317  if (isHolonomic(J) == 0)
1318  {
1319    ERROR("Module is not holonomic.");
1320  }
1321  intvec w = 1; w[n+1]=0;
1322  ideal G = GBWeight(J,w,-w,eng);
1323  dbprint(ppl  ,"// found GB wrt weight " +string(-w));
1324  dbprint(ppl-1,"// " + string(G));
1325  intvec ww = w,-w;
1326  ideal inG = inForm(G,ww);
1327  inG = engine(inG,eng);
1328  poly s = var(1)*var(n+2); // s=v*Dv
1329  vector intersecvec = pIntersect(s,inG);
1330  s = vec2poly(intersecvec);
1331  s = subst(s,var(1),-var(1)-1);
1332  list L = bFactor(s);
1333  dbprint(ppl  ,"// found b-function");
1334  dbprint(ppl-1,"// roots: "+string(L[1]));
1335  dbprint(ppl-1,"// multiplicities: "+string(L[2]));
1336  kill inG,intersecvec,s;
1337  // TODO: use maxIntRoot
1338  L = intRoots(L);           // integral roots of b-function
1339  if (L[2]==0:size(L[2]))    // no integral roots
1340  {
1341    setring save;
1342    return(ideal(1));
1343  }
1344  intvec iv;
1345  for (i=1; i<=ncols(L[1]); i++)
1346  {
1347    iv[i] = int(L[1][i]);
1348  }
1349  int l0 = Max(iv);
1350  dbprint(ppl,"// maximal integral root is " +string(l0));
1351  kill L,iv;
1352  intvec degG;
1353  ideal Gk;
1354  for (j=1; j<=ncols(G); j++)
1355  {
1356    degG[j] = deg(G[j],ww);
1357    for (i=0; i<=l0-degG[j]; i++)
1358    {
1359      Gk[ncols(Gk)+1] = var(1)^i*G[j];
1360    }
1361  }
1362  Gk = rightNFWeyl(Gk,n+2);
1363  dbprint(ppl,"// found right normalforms");
1364  module M = coeffs(Gk,var(1));
1365  setring save;
1366  def mer = makeModElimRing(save);
1367  setring mer;
1368  module M = imap(Dv,M);
1369  kill Dv;
1370  M = engine(M,eng);
1371  dbprint(ppl  ,"// found GB of free module of rank " + string(l0+1));
1372  dbprint(ppl-1,"// " + string(M));
1373  M = prune(M);
1374  setring save;
1375  matrix M = imap(mer,M);
1376  kill mer;
1377  int ro = nrows(M);
1378  int co = ncols(M);
1379  ideal I;
1380  if (ro == 1) // nothing to do
1381  {
1382    I = M;
1383  }
1384  else
1385  {
1386    matrix zm[ro-1][1]; // zero matrix
1387    matrix v[ro-1][1];
1388    for (i=1; i<=co; i++)
1389    {
1390      v = M[1..ro-1,i];
1391      if (v == zm)
1392      {
1393        I[size(I)+1] = M[ro,i];
1394      }
1395    }
1396  }
1397  if (outList<>0)
1398  {
1399    return(list(I,l0+2));
1400  }
1401  else
1402  {
1403    return(I);
1404  }
1405}
1406example
1407{
1408  "EXAMPLE:"; echo = 2;
1409  // (OTW), Example 8
1410  ring r = 0,(x,y,z,Dx,Dy,Dz),dp;
1411  def W = Weyl();
1412  setring W;
1413  poly f = x^3-y^2*z^2;
1414  ideal I = f^2*Dx+3*x^2, f^2*Dy-2*y*z^2, f^2*Dz-2*y^2*z;
1415  // I annihilates exp(1/f)
1416  ideal J = Dlocalization(I,f);
1417  J;
1418  Dlocalization(I,f,1); // The natural map D/I -> D/J is given by 1/f^2
1419}
1420
1421
1422
1423// Weyl closure ///////////////////////////////////////////////////////////////
1424
1425static proc orderFiltrationD1 (poly f)
1426{
1427  // returns list of ideal and intvec
1428  // ideal contains x-parts, intvec corresponding degree in Dx
1429  poly g,h;
1430  g = f;
1431  ideal I;
1432  intvec v,w,u;
1433  w = 0,1;
1434  int i,j;
1435  i = 1;
1436  while (g<>0)
1437  {
1438    h = inForm(g,w);
1439    I[i] = 0;
1440    for (j=1; j<=size(h); j++)
1441    {
1442      v = leadexp(h[j]);
1443      u[i] = v[2];
1444      v[2] = 0;
1445      I[i] = I[i] + leadcoef(h[j])*monomial(v);
1446    }
1447    g = g-h;
1448    i++;
1449  }
1450  return(list(I,u));
1451}
1452
1453
1454static proc kerLinMapD1 (ideal W, poly L, poly p)
1455{
1456  // computes kernel of right multiplication with L viewed
1457  // as homomorphism of K-vector spaces span(W) -> D1/p*D1
1458  // assume p in K[x], basering is K<x,Dx>
1459  ideal G,K;
1460  G = std(p);
1461  list l;
1462  int i,j;
1463  // first, compute the image of span(W)
1464  if (simplify(W,2)[1] == 0)
1465  {
1466    return(K); // = 0
1467  }
1468  for (i=1; i<=size(W); i++)
1469  {
1470    l = orderFiltrationD1(W[i]*L);
1471    K[i] = 0;
1472    for (j=1; j<=size(l[1]); j++)
1473    {
1474      K[i] = K[i] + NF(l[1][j],G)*var(2)^(l[2][j]);
1475    }
1476  }
1477  // now, we get the kernel by linear algebra
1478  l = linReduceIdeal(K,1);
1479  i = ncols(l[1]) - size(l[1]);
1480  if (i<>0)
1481  {
1482    K = matrix(W)*matrix(l[2]);
1483    K = K[1..i];
1484  }
1485  else
1486  {
1487    K = 0;
1488  }
1489  return(K);
1490}
1491
1492
1493static proc leftDivisionKxD1 (poly p, poly L)
1494{
1495  // basering is D1 = K<x,Dx>
1496  // p in K[x]
1497  // compute p^(-1)*L if p is a left divisor of L
1498//   if (rightNF(L,ideal(p))<>0)
1499//   {
1500//     ERROR("First poly is not a right factor of second poly");
1501//   }
1502  def save = basering;
1503  list l = orderFiltrationD1(L);
1504  ideal l1 = l[1];
1505  ring r = 0,x,dp;
1506  ideal l1 = fetch(save,l1);
1507  poly p = fetch(save,p);
1508  int i;
1509  for (i=1; i<=ncols(l1); i++)
1510  {
1511    l1[i] =  division(l1[i],p)[1][1,1];
1512  }
1513  setring save;
1514  ideal I = fetch(r,l1);
1515  poly f;
1516  for (i=1; i<=ncols(I); i++)
1517  {
1518    f = f + I[i]*var(2)^(l[2][i]);
1519  }
1520  return(f);
1521}
1522
1523
1524proc WeylClosure1 (poly L)
1525"
1526USAGE:    WeylClosure1(L);  L a poly
1527ASSUME:   The basering is the first Weyl algebra D=K<x,d|dx=xd+1> over a field
1528          K of characteristic 0.
1529RETURN:   ideal, the Weyl closure of the principal left ideal generated by L
1530REMARKS:  The Weyl closure of a left ideal I in the Weyl algebra D is defined
1531          to be the intersection of I regarded as left ideal in the rational
1532          Weyl algebra K(x)<d> with the polynomial Weyl algebra D.
1533@*        Reference: (Tsa), Algorithm 1.2.4
1534NOTE:     If printlevel=1, progress debug messages will be printed,
1535          if printlevel>=2, all the debug messages will be printed.
1536SEE ALSO: WeylClosure
1537EXAMPLE:  example WeylClosure1; shows examples
1538"
1539{
1540  dmodGeneralAssumptionCheck(); // assumption check
1541  int ppl = printlevel - voice + 2;
1542  def save = basering;
1543  intvec w = 0,1; // for order filtration
1544  poly p = inForm(L,w);
1545  ring @R = 0,var(1),dp;
1546  ideal mm = var(1),1;
1547  map m = save,mm;
1548  ideal @p = m(p);
1549  poly p = @p[1];
1550  poly g = gcd(p,diff(p,var(1)));
1551  if (g == 1)
1552  {
1553    g = p;
1554  }
1555  ideal facp = factorize(g,1); // g is squarefree, constants aren't interesting
1556  dbprint(ppl-1,
1557          "// squarefree part of highest coefficient w.r.t. order filtration:");
1558  dbprint(ppl-1, "// " + string(facp));
1559  setring save;
1560  p = imap(@R,p);
1561  // 1-1 extend basering by parameter and introduce new var t=x*d
1562  list RL = ringlist(save);
1563  RL = RL[1..4];
1564  list l;
1565  l[1] = int(0);
1566  l[2] = list(safeVarName("a"));
1567  l[3] = list(list("lp",intvec(1)));
1568  l[4] = ideal(0);
1569  RL[1] = l;
1570  l = RL[2] + list(safeVarName("t"));
1571  RL[2] = l;
1572  l = list();
1573  l[1] = list("dp",intvec(1,1));
1574  l[2] = list("dp",intvec(1));
1575  l[3] = list("C",intvec(0));
1576  RL[3] = l;
1577  def @Wat = ring(RL);
1578  kill RL,l;
1579  setring @Wat;
1580  matrix relD[3][3];
1581  relD[1,2] = 1;
1582  relD[1,3] = var(1);
1583  relD[2,3] = -var(2);
1584  def Wat = nc_algebra(1,relD);
1585  setring Wat;
1586  kill @Wat;
1587  // 1-2 rewrite L using Euler operators
1588  ideal mm = var(1)+par(1),var(2);
1589  map m = save,mm;
1590  poly L = m(L);
1591  w = -1,1,0; // for Bernstein filtration
1592  int i = 1;
1593  ideal Q;
1594  poly p = L;
1595  intvec d;
1596  while (p<>0)
1597  {
1598    Q[i] = inForm(p,w);
1599    p = p - Q[i];
1600    d[i] = -deg(Q[i],w);
1601    i++;
1602  }
1603  ideal S = std(var(1)*var(2)-var(3));
1604  Q = NF(Q,S);
1605  dbprint(ppl,  "// found Euler representation of operator");
1606  dbprint(ppl-1,"// " + string(Q));
1607  Q = subst(Q,var(1),1);
1608  Q = subst(Q,var(2),1);
1609  // 1-3 prepare for algebraic extensions with minpoly = facp[i]
1610  list RL = ringlist(Wat);
1611  RL = RL[1..4];
1612  list l;
1613  l = string(var(3));
1614  RL[2] = l;
1615  l = list();
1616  l[1] = list("dp",intvec(1));
1617  l[2] = list("C",intvec(0));
1618  RL[3] = l;
1619  mm = par(1);
1620  m = @R,par(1);
1621  ideal facp = m(facp);
1622  kill @R,m,mm,l,S;
1623  intvec maxroots,testroots;
1624  int sq = size(Q);
1625  string strQ = "ideal Q = " + string(Q) + ";";
1626  // TODO do it without string workaround when issue with maps from
1627  //   transcendental to algebraic extension fields is fixed
1628  int j,maxr;
1629  // 2-1 get max int root of lowest nonzero entry of Q in algebraic extension
1630  for (i=1; i<=size(facp); i++)
1631  {
1632    testroots = 0;
1633    def Ra = ring(RL);
1634    setring Ra;
1635    ideal mm = 1,1,var(1);
1636    map m = Wat,mm;
1637    ideal facp = m(facp);
1638    minpoly = leadcoef(facp[i]);
1639    execute(strQ);
1640    if (simplify(Q,2)[1] == poly(0))
1641    {
1642      break;
1643    }
1644    j = 1;
1645    while (j<sq)
1646    {
1647      if (Q[j]==0)
1648      {
1649        j++;
1650      }
1651      else
1652      {
1653        break;
1654      }
1655    }
1656    maxroots[i] = d[j]; // d[j] = r_k
1657    list LR = bFactor(Q[j]);
1658    LR = intRoots(LR);
1659    if (LR[2]<>0:size(LR[2])) // there are integral roots
1660    {
1661      for (j=1; j<=ncols(LR[1]); j++)
1662      {
1663        testroots[j] = int(LR[1][j]);
1664      }
1665      maxr = Max(testroots);
1666      if(maxr<0)
1667      {
1668        maxr = 0;
1669      }
1670      maxroots[i] = maxroots[i] + maxr;
1671    }
1672    kill LR;
1673    setring Wat;
1674    kill Ra;
1675  }
1676  maxr = Max(maxroots);
1677  // 3-1 build basis of vectorspace
1678  setring save;
1679  ideal KB;
1680  for (i=0; i<deg(p); i++)  // it's really <, not <=
1681  {
1682    for (j=0; j<=maxr; j++) // it's really <=, not <
1683    {
1684      KB[size(KB)+1] = monomial(intvec(i,j));
1685    }
1686  }
1687  dbprint(ppl,"// got vector space basis");
1688  dbprint(ppl-1, "// " + string(KB));
1689  // 3-2 get kernel of *L: span(KB)->D/pD
1690  KB = kerLinMapD1(KB,L,p);
1691  dbprint(ppl,"// got kernel");
1692  dbprint(ppl-1, "// " + string(KB));
1693  // 4-1 get (1/p)*f*L where f in KB
1694  for (i=1; i<=ncols(KB); i++)
1695  {
1696    KB[i] = leftDivisionKxD1(p,KB[i]*L);
1697  }
1698  KB = L,KB;
1699  // 4-2 done
1700  return(KB);
1701}
1702example
1703{
1704  "EXAMPLE:"; echo = 2;
1705  ring r = 0,(x,Dx),dp;
1706  def W = Weyl();
1707  setring W;
1708  poly L = (x^3+2)*Dx-3*x^2;
1709  WeylClosure1(L);
1710  L = (x^4-4*x^3+3*x^2)*Dx^2+(-6*x^3+20*x^2-12*x)*Dx+(12*x^2-32*x+12);
1711  WeylClosure1(L);
1712}
1713
1714
1715proc WeylClosure (ideal I)
1716"
1717USAGE:    WeylClosure(I);  I an ideal
1718ASSUME:   The basering is the n-th Weyl algebra W over a field of
1719          characteristic 0 and for all 1<=i<=n the identity
1720          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1721          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
1722          differential operator belonging to x(i).
1723@*        Moreover, assume that the holonomic rank of W/I is finite.
1724RETURN:   ideal, the Weyl closure of I
1725REMARKS:  The Weyl closure of a left ideal I in the Weyl algebra W is defined to
1726          be the intersection of I regarded as left ideal in the rational Weyl
1727          algebra K(x(1..n))<D(1..n)> with the polynomial Weyl algebra W.
1728@*        Reference: (Tsa), Algorithm 2.2.4
1729NOTE:     If printlevel=1, progress debug messages will be printed,
1730          if printlevel>=2, all the debug messages will be printed.
1731SEE ALSO: WeylClosure1
1732EXAMPLE:  example WeylClosure; shows examples
1733"
1734{
1735  // assumption check
1736  dmodGeneralAssumptionCheck();
1737  if (holonomicRank(I)==-1)
1738  {
1739    ERROR("Input is not of finite holonomic rank.");
1740  }
1741  int ppl = printlevel - voice + 2;
1742  int eng = 0; // engine
1743  def save = basering;
1744  dbprint(ppl  ,"// Starting to compute singular locus...");
1745  ideal sl = DsingularLocus(I);
1746  sl = simplify(sl,2);
1747  dbprint(ppl  ,"// ...done.");
1748  dbprint(ppl-1,"// " + string(sl));
1749  if (sl[1] == 0) // can never get here
1750  {
1751    ERROR("Can't find polynomial in K[x] vanishing on singular locus.");
1752  }
1753  poly f = sl[1];
1754  dbprint(ppl  ,"// Found poly vanishing on singular locus: " + string(f));
1755  dbprint(ppl  ,"// Starting to compute localization...");
1756  list L = Dlocalization(I,f,1);
1757  ideal G = L[1];
1758  dbprint(ppl  ,"// ...done.");
1759  dbprint(ppl-1,"// " + string(G));
1760  dbprint(ppl  ,"// Starting to compute kernel of localization map...");
1761  if (eng == 0)
1762  {
1763    G = moduloSlim(f^L[2],G);
1764  }
1765  else
1766  {
1767    G = modulo(f^L[2],G);
1768  }
1769  dbprint(ppl  ,"// ...done.");
1770  return(G);
1771}
1772example
1773{
1774  "EXAMPLE:"; echo = 2;
1775  // (OTW), Example 8
1776  ring r = 0,(x,y,z,Dx,Dy,Dz),dp;
1777  def D3 = Weyl();
1778  setring D3;
1779  poly f = x^3-y^2*z^2;
1780  ideal I = f^2*Dx + 3*x^2, f^2*Dy-2*y*z^2, f^2*Dz-2*y^2*z;
1781  // I annihilates exp(1/f)
1782  WeylClosure(I);
1783}
1784
1785
1786
1787// solutions to systems of PDEs ///////////////////////////////////////////////
1788
1789proc polSol (ideal I, list #)
1790"
1791USAGE:    polSol(I[,w,m]);  I ideal, w optional intvec, m optional int
1792ASSUME:   The basering is the n-th Weyl algebra W over a field of
1793          characteristic 0 and for all 1<=i<=n the identity
1794          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1795          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
1796          differential operator belonging to x(i).
1797@*        Moreover, assume that I is holonomic.
1798RETURN:   ideal, a basis of the polynomial solutions to the given system of
1799          linear PDEs with polynomial coefficients, encoded via I
1800REMARKS:  If w is given, w should consist of n strictly negative entries.
1801          Otherwise and by default, w is set to -1:n.
1802          In this case, w is used as weight vector for the computation of a
1803          b-function.
1804@*        If m is given, m is assumed to be the minimal integer root of the
1805          b-function of I w.r.t. w. Note that this assumption is not checked.
1806@*        Reference: (OTT), Algorithm 2.4
1807NOTE:     If printlevel=1, progress debug messages will be printed,
1808          if printlevel>=2, all the debug messages will be printed.
1809SEE ALSO: polSolFiniteRank, ratSol
1810EXAMPLE:  example polSol; shows examples
1811"
1812{
1813  dmodGeneralAssumptionCheck();
1814  int ppl = printlevel - voice + 2;
1815  int mr,mrgiven;
1816  def save = basering;
1817  int n = nvars(save);
1818  intvec w = -1:(n div 2);
1819  if (size(#)>0)
1820  {
1821    if (typeof(#[1])=="intvec")
1822    {
1823      if (allPositive(-#[1]))
1824      {
1825        w = #[1];
1826      }
1827    }
1828    if (size(#)>1)
1829    {
1830      if (typeof(#[2])=="int")
1831      {
1832        mr = #[2];
1833        mrgiven = 1;
1834      }
1835    }
1836  }
1837  // Step 1: the b-function
1838  list L;
1839  if (!mrgiven)
1840  {
1841    if (!isHolonomic(I))
1842    {
1843      ERROR("Ideal is not holonomic. Try polSolFiniteRank.");
1844    }
1845    dbprint(ppl,"// Computing b-function...");
1846    L = bfctIdeal(I,w);
1847    dbprint(ppl,"// ...done.");
1848    dbprint(ppl-1,"//   Roots: " + string(L[1]));
1849    dbprint(ppl-1,"//   Multiplicities: " + string(L[2]));
1850    mr = minIntRoot2(L);
1851    dbprint(ppl,"// Minimal integer root is " + string(mr) + ".");
1852  }
1853  if (mr>0)
1854  {
1855    return(ideal(0));
1856  }
1857  // Step 2: get the form of a solution f
1858  int i;
1859  L = list();
1860  for (i=0; i<=-mr; i++)
1861  {
1862    L = L + orderedPartition(i,-w);
1863  }
1864  ideal mons;
1865  for (i=1; i<=size(L); i++)
1866  {
1867    mons[i] = monomial(L[i]);
1868  }
1869  kill L;
1870  mons = simplify(mons,2+4); // L might contain lots of 0s by construction
1871  ring @C = (0,@c(1..size(mons))),dummyvar,dp;
1872  def WC = save + @C;
1873  setring WC;
1874  ideal mons = imap(save,mons);
1875  poly f;
1876  for (i=1; i<=size(mons); i++)
1877  {
1878    f = f + par(i)*mons[i];
1879  }
1880  // Step 3: determine values of @c(i) by equating coefficients
1881  ideal I = imap(save,I);
1882  I = dmodAction(I,f,1..n);
1883  ideal M = monomialInIdeal(I);
1884  matrix CC = coeffs(I,M);
1885  int j;
1886  ideal C;
1887  for (i=1; i<=nrows(CC); i++)
1888  {
1889    f = 0;
1890    for (j=1; j<=ncols(CC); j++)
1891    {
1892      f = f + CC[i,j];
1893    }
1894    C[size(C)+1] = f;
1895  }
1896  // Step 3.1: solve a linear system
1897  ring rC = 0,(@c(1..size(mons))),dp;
1898  ideal C = imap(WC,C);
1899  matrix M = coeffs(C,maxideal(1));
1900  module MM = leftKernel(M);
1901  setring WC;
1902  module MM = imap(rC,MM);
1903  // Step 3.2: return the solution
1904  ideal F = ideal(MM*transpose(mons));
1905  setring save;
1906  ideal F = imap(WC,F);
1907  return(F);
1908}
1909example
1910{
1911  "EXAMPLE:"; echo=2;
1912  ring r = 0,(x,y,Dx,Dy),dp;
1913  def W = Weyl();
1914  setring W;
1915  poly tx,ty = x*Dx, y*Dy;
1916  ideal I =      // Appel F1 with parameters (2,-3,-2,5)
1917    tx*(tx+ty+4)-x*(tx+ty+2)*(tx-3),
1918    ty*(tx+ty+4)-y*(tx+ty+2)*(ty-2),
1919    (x-y)*Dx*Dy+2*Dx-3*Dy;
1920  intvec w = -1,-1;
1921  polSol(I,w);
1922}
1923
1924
1925static proc ex_polSol()
1926{  ring r = 0,(x,y,Dx,Dy),dp;
1927  def W = Weyl();
1928  setring W;
1929  poly tx,ty = x*Dx, y*Dy;
1930  ideal I =      // Appel F1 with parameters (2,-3,-2,5)
1931    tx*(tx+ty+4)-x*(tx+ty+2)*(tx-3),
1932    ty*(tx+ty+4)-y*(tx+ty+2)*(ty-2),
1933    (x-y)*Dx*Dy+2*Dx-3*Dy;
1934  intvec w = -5,-7;
1935  // the following gives a bug
1936  polSol(I,w);
1937  // this is due to a bug in weightKB, see ticket #339
1938  // http://www.singular.uni-kl.de:8002/trac/ticket/339
1939}
1940
1941
1942proc polSolFiniteRank (ideal I, list #)
1943"
1944USAGE:    polSolFiniteRank(I[,w]);  I ideal, w optional intvec
1945ASSUME:   The basering is the n-th Weyl algebra W over a field of
1946          characteristic 0 and for all 1<=i<=n the identity
1947          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
1948          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
1949          differential operator belonging to x(i).
1950@*        Moreover, assume that I is of finite holonomic rank.
1951RETURN:   ideal, a basis of the polynomial solutions to the given system of
1952          linear PDEs with polynomial coefficients, encoded via I
1953REMARKS:  If w is given, w should consist of n strictly negative entries.
1954          Otherwise and by default, w is set to -1:n.
1955          In this case, w is used as weight vector for the computation of a
1956          b-function.
1957@*        Reference: (OTT), Algorithm 2.6
1958NOTE:     If printlevel=1, progress debug messages will be printed,
1959          if printlevel>=2, all the debug messages will be printed.
1960SEE ALSO: polSol, ratSol
1961EXAMPLE:  example polSolFiniteRank; shows examples
1962"
1963{
1964  dmodGeneralAssumptionCheck();
1965  if (holonomicRank(I)==-1)
1966  {
1967    ERROR("Ideal is not of finite holonomic rank.");
1968  }
1969  int ppl = printlevel - voice + 2;
1970  int n = nvars(basering) div 2;
1971  int eng;
1972  intvec w = -1:(n div 2);
1973  if (size(#)>0)
1974  {
1975    if (typeof(#[1])=="intvec")
1976    {
1977      if (allPositive(-#[1]))
1978      {
1979        w = #[1];
1980      }
1981    }
1982  }
1983  dbprint(ppl,"// Computing initial ideal...");
1984  ideal J = initialIdealW(I,-w,w);
1985  dbprint(ppl,"// ...done.");
1986  dbprint(ppl,"// Computing Weyl closure...");
1987  J = WeylClosure(J);
1988  J = engine(J,eng);
1989  dbprint(ppl,"// ...done.");
1990  poly s;
1991  int i;
1992  for (i=1; i<=n; i++)
1993  {
1994    s = s + w[i]*var(i)*var(i+n);
1995  }
1996  dbprint(ppl,"// Computing intersection...");
1997  vector v = pIntersect(s,J);
1998  list L = bFactor(vec2poly(v));
1999  dbprint(ppl-1,"//   roots: " + string(L[1]));
2000  dbprint(ppl-1,"//   multiplicities: " + string(L[2]));
2001  dbprint(ppl,"// ...done.");
2002  int mr =  minIntRoot2(L);
2003  int pl = printlevel;
2004  printlevel = printlevel + 1;
2005  ideal K = polSol(I,w,mr);
2006  printlevel = printlevel - 1;
2007  return(K);
2008}
2009example
2010{
2011  "EXAMPLE:"; echo=2;
2012  ring r = 0,(x,y,Dx,Dy),dp;
2013  def W = Weyl();
2014  setring W;
2015  poly tx,ty = x*Dx, y*Dy;
2016  ideal I =      // Appel F1 with parameters (2,-3,-2,5)
2017    tx*(tx+ty+4)-x*(tx+ty+2)*(tx-3),
2018    ty*(tx+ty+4)-y*(tx+ty+2)*(ty-2),
2019    (x-y)*Dx*Dy+2*Dx-3*Dy;
2020  intvec w = -1,-1;
2021  polSolFiniteRank(I,w);
2022}
2023
2024
2025static proc twistedIdeal(ideal I, poly f, intvec k, ideal F)
2026{
2027  // I subset D_n, f in K[x], F = factorize(f,1), size(k) = size(F), k[i]>0
2028  def save = basering;
2029  int n = nvars(save) div 2;
2030  int i,j;
2031  intvec a,v,w;
2032  w = (0:n),(1:n);
2033  for (i=1; i<=size(I); i++)
2034  {
2035    a[i] = deg(I[i],w);
2036  }
2037  ring FD = 0,(fd(1..n)),dp;
2038  def @@WFD = save + FD;
2039  setring @@WFD;
2040  poly f = imap(save,f);
2041  list RL = ringlist(basering);
2042  RL = RL[1..4];
2043  list L = RL[3];
2044  v = (1:(2*n)),((deg(f)+1):n);
2045  L = insert(L,list("a",v));
2046  RL[3] = L;
2047  def @WFD = ring(RL);
2048  setring @WFD;
2049  poly f = imap(save,f);
2050  matrix Drel[3*n][3*n];
2051  for (i=1; i<=n; i++)
2052  {
2053    Drel[i,i+n] = 1;     // [D,x]
2054    Drel[i,i+2*n] = f;   // [fD,x]
2055    for (j=1; j<=n; j++)
2056    {
2057      Drel[i+n,j+2*n] = -diff(f,var(i))*var(j+n);  // [fD,D]
2058      Drel[j+2*n,i+2*n] = diff(f,var(i))*var(j+2*n) - diff(f,var(j))*var(i+2*n);
2059      // [fD,fD]
2060    }
2061  }
2062  def WFD = nc_algebra(1,Drel);
2063  setring WFD;
2064  kill @WFD,@@WFD;
2065  ideal I = imap(save,I);
2066  poly f = imap(save,f);
2067  for (i=1; i<=size(I); i++)
2068  {
2069    I[i] = f^(a[i])*I[i];
2070  }
2071  ideal S;
2072  for (i=1; i<=n; i++)
2073  {
2074    S[size(S)+1] = var(i+2*n) - f*var(i+n);
2075  }
2076  S = slimgb(S);
2077  I = NF(I,S);
2078  if (select1(I,intvec((n+1)..2*n))[1] <> 0)
2079  {
2080    // should never get here
2081    ERROR("Something's wrong. Please inform the author.");
2082  }
2083  setring save;
2084  ideal mm = maxideal(1);
2085  poly s;
2086  for (i=1; i<=n; i++)
2087  {
2088    s = f*var(i+n);
2089    for (j=1; j<=size(F); j++)
2090    {
2091      s = s + k[j]*(f/F[j])*bracket(var(i+n),F[j]);
2092    }
2093    mm[i+2*n] = s;
2094  }
2095  map m = WFD,mm;
2096  ideal J = m(I);
2097  return(J);
2098}
2099example
2100{
2101  "EXAMPLE"; echo=2;
2102  ring r = 0,(x,y,Dx,Dy),dp;
2103  def W = Weyl();
2104  setring W;
2105  poly tx,ty = x*Dx, y*Dy;
2106  ideal I =      // Appel F1 with parameters (3,-1,1,1) is a solution
2107    tx*(tx+ty)-x*(tx+ty+3)*(tx-1),
2108    ty*(tx+ty)-y*(tx+ty+3)*(ty+1);
2109  kill tx,ty;
2110  poly f = x^3*y^2-x^2*y^3-x^3*y+x*y^3+x^2*y-x*y^2;
2111  ideal F = x-1,x,-x+y,y-1,y;
2112  intvec k = -1,-1,-1,-3,-1;
2113  ideal T = twistedIdeal(I,f,k,F);
2114  // TODO change the ordering of WFD
2115  // introduce new var f??
2116  //paper:
2117  poly fx = diff(f,x);
2118  poly fy = diff(f,y);
2119  poly fDx = f*Dx;
2120  poly fDy = f*Dy;
2121  poly fd(1) = fDx;
2122  poly fd(2) = fDy;
2123  ideal K=
2124    (x^2-x^3)*(fDx)^2+x*((1-3*x)*f-(1-x)*y*fy-(1-x)*x*fx)*(fDx)
2125    +x*(1-x)*y*(fDy)*(fDx)+x*y*f*(fDy)+3*x*f^2,
2126    (y^2-y^3)*(fDy)^2+y*((1-5*y)*f-(1-y)*x*fx-(1-y)*y*fy)*(fDy)
2127    +y*(1-y)*x*(fDx)*(fDy)-y*x*f*(fDx)-3*y*f^2;
2128}
2129
2130
2131proc ratSol (ideal I)
2132"
2133USAGE:    ratSol(I);  I ideal
2134ASSUME:   The basering is the n-th Weyl algebra W over a field of
2135          characteristic 0 and for all 1<=i<=n the identity
2136          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
2137          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
2138          differential operator belonging to x(i).
2139@*        Moreover, assume that I is holonomic.
2140RETURN:   module, a basis of the rational solutions to the given system of
2141          linear PDEs with polynomial coefficients, encoded via I
2142          Note that each entry has two components, the first one standing for
2143          the enumerator, the second one for the denominator.
2144REMARKS:  Reference: (OTT), Algorithm 3.10
2145NOTE:     If printlevel=1, progress debug messages will be printed,
2146          if printlevel>=2, all the debug messages will be printed.
2147SEE ALSO: polSol, polSolFiniteRank
2148EXAMPLE:  example ratSol; shows examples
2149"
2150{
2151  dmodGeneralAssumptionCheck();
2152  if (!isHolonomic(I))
2153  {
2154    ERROR("Ideal is not holonomic.");
2155  }
2156  int ppl = printlevel - voice + 2;
2157  def save = basering;
2158  dbprint(ppl,"// computing singular locus...");
2159  ideal S = DsingularLocus(I);
2160  dbprint(ppl,"// ...done.");
2161  poly f = S[1];
2162  dbprint(ppl,"// considering poly " + string(f));
2163  int n = nvars(save) div 2;
2164  list RL = ringlist(save);
2165  RL = RL[1..4];
2166  list L = RL[2];
2167  L = list(L[1..n]);
2168  RL[2] = L;
2169  L = list();
2170  L[1] = list("dp",intvec(1:n));
2171  L[2] = list("C",intvec(0));
2172  RL[3] = L;
2173  def rr = ring(RL);
2174  setring rr;
2175  poly f = imap(save,f);
2176  ideal F = factorize(f,1); // not interested in multiplicities
2177  dbprint(ppl,"// with irreducible factors " + string(F));
2178  setring save;
2179  ideal F = imap(rr,F);
2180  kill rr,RL;
2181  int i;
2182  intvec k;
2183  ideal FF = 1,1;
2184  dbprint(ppl,"// computing b-functions of irreducible factors...");
2185  for (i=1; i<=size(F); i++)
2186  {
2187    dbprint(ppl,"//   considering " + string(F[i]) + "...");
2188    L = bfctBound(I,F[i]);
2189    if (size(L) == 3) // bfct is constant
2190    {
2191      dbprint(ppl,"//   ...got " + string(L[3]));
2192      if (L[3] == "1")
2193      {
2194        return(0); // TODO type // no rational solutions
2195      }
2196      else // should never get here
2197      {
2198        ERROR("Oops, something went wrong. Please inform the author.");
2199      }
2200    }
2201    else
2202    {
2203      dbprint(ppl,"//   ...got roots " + string(L[1]));
2204      dbprint(ppl,"//      with multiplicities " + string(L[2]));
2205      k[i] = -maxIntRoot(L)-1;
2206      if (k[i] < 0)
2207      {
2208        FF[2] = FF[2]*F[i]^(-k[i]);
2209      }
2210      else
2211      {
2212        FF[1] = FF[1]*F[i]^(k[i]);
2213      }
2214    }
2215  }
2216  vector v = FF[1]*gen(1) + FF[2]*gen(2);
2217  kill FF;
2218  dbprint(ppl,"// ...done");
2219  ideal twI = twistedIdeal(I,f,k,F);
2220  intvec w = -1:n;
2221  dbprint(ppl,"// computing polynomial solutions of twisted system...");
2222  if (isHolonomic(twI))
2223  {
2224    ideal P = polSol(twI,w);
2225  }
2226  else
2227  {
2228    ideal P = polSolFiniteRank(twI,w);
2229  }
2230  module M;
2231  vector vv;
2232  for (i=1; i<=ncols(P); i++)
2233  {
2234    vv = P[i]*gen(1) + 1*gen(2);
2235    M[i] = multRat(v,vv);
2236  }
2237  dbprint(ppl,"// ...done");
2238  return (M);
2239}
2240example
2241{
2242  "EXAMPLE"; echo=2;
2243  ring r = 0,(x,y,Dx,Dy),dp;
2244  def W = Weyl();
2245  setring W;
2246  poly tx,ty = x*Dx, y*Dy;
2247  ideal I =      // Appel F1 with parameters (3,-1,1,1) is a solution
2248    tx*(tx+ty)-x*(tx+ty+3)*(tx-1),
2249    ty*(tx+ty)-y*(tx+ty+3)*(ty+1);
2250  module M = ratSol(I);
2251  // We obtain a basis of the rational solutions to I represented by a
2252  // module / matrix with two rows.
2253  // Each column of the matrix represents a rational function, where
2254  // the first row correspond to the enumerator and the second row to
2255  // the denominator.
2256  print(M);
2257}
2258
2259
2260proc bfctBound (ideal I, poly f, list #)
2261"
2262USAGE:    bfctBound (I,f[,primdec]);  I ideal, f poly, primdec optional string
2263ASSUME:   The basering is the n-th Weyl algebra W over a field of
2264          characteristic 0 and for all 1<=i<=n the identity
2265          var(i+n)*var(i)=var(i)*var(i+1)+1 holds, i.e. the sequence of
2266          variables is given by x(1),...,x(n),D(1),...,D(n), where D(i) is the
2267          differential operator belonging to x(i).
2268@*        Moreover, assume that I is holonomic.
2269RETURN:   list of roots (of type ideal) and multiplicities (of type intvec) of
2270          a multiple of the b-function for f^s*u at a generic root of f.
2271          Here, u stands for [1] in D/I.
2272REMARKS:  Reference: (OTT), Algorithm 3.4
2273NOTE:     This procedure requires to compute a primary decomposition in a
2274          commutative ring. The optional string primdec can be used to specify
2275          the algorithm to do so. It may either be `GTZ' (Gianni, Trager,
2276          Zacharias) or `SY' (Shimoyama, Yokoyama). By default, `GTZ' is used.
2277@*        If printlevel=1, progress debug messages will be printed,
2278          if printlevel>=2, all the debug messages will be printed.
2279SEE ALSO: bernstein, bfct, bfctAnn
2280EXAMPLE:  example bfctBound; shows examples
2281"
2282{
2283  dmodGeneralAssumptionCheck();
2284  finKx(f);
2285  if (!isHolonomic(I))
2286  {
2287    ERROR("Ideal is not holonomic.");
2288  }
2289  int ppl = printlevel - voice + 2;
2290  string primdec = "GTZ";
2291  if (size(#)>1)
2292  {
2293    if (typeof(#[1])=="string")
2294    {
2295      if ( (#[1]=="SY") || (#[1]=="sy") || (#[1]=="Sy") )
2296      {
2297        primdec = "SY";
2298      }
2299      else
2300      {
2301        if ( (#[1]<>"GTZ") && (#[1]<>"gtz") && (#[1]<>"Gtz") )
2302        {
2303          print("// Warning: optional string may either be `GTZ' or `SY',");
2304          print("//          proceeding with `GTZ'.");
2305          primdec = "GTZ";
2306        }
2307      }
2308    }
2309  }
2310  def save = basering;
2311  int n = nvars(save) div 2;
2312  // step 1
2313  ideal mm = maxideal(1);
2314  def Wt = extendWeyl(safeVarName("t"));
2315  setring Wt;
2316  poly f = imap(save,f);
2317  ideal mm = imap(save,mm);
2318  int i;
2319  for (i=1; i<=n; i++)
2320  {
2321    mm[i+n] = var(i+n+2) + bracket(var(i+n+2),f)*var(n+2);
2322  }
2323  map m = save,mm;
2324  ideal I = m(I);
2325  I = I, var(1)-f;
2326  // step 2
2327  intvec w = 1,(0:n);
2328  dbprint(ppl  ,"// Computing initial ideal...");
2329  I = initialIdealW(I,-w,w);
2330  dbprint(ppl  ,"// ...done.");
2331  dbprint(ppl-1,"// " + string(I));
2332  // step 3: rewrite I using Euler operator t*Dt
2333  list RL = ringlist(Wt);
2334  RL = RL[1..4];
2335  list L = RL[2] + list(safeVarName("s")); // s=t*Dt
2336  RL[2] = L;
2337  L = list();
2338  L[1] = list("dp",intvec(1:(2*n+2)));
2339  L[2] = list("dp",intvec(1));
2340  L[3] = list("C",intvec(0));
2341  RL[3] = L;
2342  def @Wts = ring(RL);
2343  kill L,RL;
2344  setring @Wts;
2345  matrix relD[2*n+3][2*n+3];
2346  relD[1,2*n+3] = var(1);
2347  relD[n+2,2*n+3] = -var(n+2);
2348  for (i=1; i<=n+1; i++)
2349  {
2350    relD[i,n+i+1] = 1;
2351  }
2352  def Wts = nc_algebra(1,relD);
2353  setring Wts;
2354  ideal I = imap(Wt,I);
2355  kill Wt,@Wts;
2356  ideal S = var(1)*var(n+2)-var(2*n+3);
2357  attrib(S,"isSB",1);
2358  dbprint(ppl  ,"// Computing Euler representation...");
2359  // I = NF(I,S);
2360  int d;
2361  intvec ww = 0:(2*2+2); ww[1] = -1; ww[n+2] = 1;
2362  for (i=1; i<=size(I); i++)
2363  {
2364    d = deg(I[i],ww);
2365    if (d>0)
2366    {
2367      I[i] = var(1)^d*I[i];
2368    }
2369    if (d<0)
2370    {
2371      d = -d;
2372      I[i] = var(n+2)^d*I[i];
2373    }
2374  }
2375  I = NF(I,S); // now there are no t,Dt in I, only s
2376  dbprint(ppl  ,"// ...done.");
2377  I = subst(I,var(2*n+3),-var(2*n+3)-1);
2378  ring Ks = 0,s,dp;
2379  def Ws = save + Ks;
2380  setring Ws;
2381  ideal I = imap(Wts,I);
2382  kill Wts;
2383  poly DD = 1;
2384  for (i=1; i<=n; i++)
2385  {
2386    DD = DD * var(n+i);
2387  }
2388  dbprint(ppl  ,"// Eliminating differential operators...");
2389  ideal J = eliminate(I,DD); // J subset K[x,s]
2390  dbprint(ppl  ,"// ...done.");
2391  dbprint(ppl-1,"// " + string(J));
2392  list RL = ringlist(Ws);
2393  RL = RL[1..4];
2394  list L = RL[2];
2395  L = list(L[1..n]) + list(L[2*n+1]);
2396  RL[2] = L;
2397  L = list();
2398  L[1] = list("dp",intvec(1:(n+1)));
2399  L[2] = list("C",intvec(0));
2400  RL[3] = L;
2401  def Kxs = ring(RL);
2402  setring Kxs;
2403  ideal J = imap(Ws,J);
2404  dbprint(ppl  ,"// Computing primary decomposition with engine "
2405          + primdec + "...");
2406  if (primdec == "GTZ")
2407  {
2408    list P = primdecGTZ(J);
2409  }
2410  else
2411  {
2412    list P = primdecSY(J);
2413  }
2414  dbprint(ppl  ,"// ...done.");
2415  dbprint(ppl-1,"// " + string(P));
2416  ideal GP,Qix,rad,B;
2417  poly f = imap(save,f);
2418  vector v;
2419  for (i=1; i<=size(P); i++)
2420  {
2421    dbprint(ppl  ,"// Considering primary component " + string(i)
2422            + " of " + string(size(P)) + "...");
2423    dbprint(ppl  ,"//   Intersecting with K[x] and computing radical...");
2424    GP = std(P[i][1]);
2425    Qix = eliminate(GP,var(n+1)); // subset K[x]
2426    rad = radical(Qix);
2427    rad = std(rad);
2428    dbprint(ppl  ,"//   ...done.");
2429    dbprint(ppl-1,"// " + string(rad));
2430    if (rad[1]==0 || NF(f,rad)==0)
2431    {
2432      dbprint(ppl  ,"//   Intersecting with K[s]...");
2433      v = pIntersect(var(n+1),GP);
2434      B[size(B)+1] = vec2poly(v,n+1);
2435      dbprint(ppl  ,"//   ...done.");
2436      dbprint(ppl-1,"// " + string(B[size(B)]));
2437    }
2438    dbprint(ppl  ,"// ...done.");
2439  }
2440  f = lcm(B); // =lcm(B[1],...,B[size(B)])
2441  list bb = bFactor(f);
2442  setring save;
2443  list bb = imap(Kxs,bb);
2444  return(bb);
2445}
2446example
2447{
2448  "EXAMPLE"; echo=2;
2449  ring r = 0,(x,y,Dx,Dy),dp;
2450  def W = Weyl();
2451  setring W;
2452  poly tx,ty = x*Dx, y*Dy;
2453  ideal I =      // Appel F1 with parameters (2,-3,-2,5)
2454    tx*(tx+ty+4)-x*(tx+ty+2)*(tx-3),
2455    ty*(tx+ty+4)-y*(tx+ty+2)*(ty-2),
2456    (x-y)*Dx*Dy+2*Dx-3*Dy;
2457  kill tx,ty;
2458  poly f = x-1;
2459  bfctBound(I,f);
2460}
2461
2462
2463//TODO check f/g or g/f, check Weyl closure of result
2464proc annRatSyz (poly f, poly g, list #)
2465"
2466USAGE:    annRatSyz(f,g[,db,eng]);  f, g polynomials, db,eng optional integers
2467ASSUME:   The basering is commutative and over a field of characteristic 0.
2468RETURN:   ring (a Weyl algebra) containing an ideal `LD', which is (part of)
2469          the annihilator of the rational function g/f in the corresponding
2470          Weyl algebra
2471REMARKS:  This procedure uses the computation of certain syzygies.
2472          One can obtain the full annihilator by computing the Weyl closure of
2473          the ideal LD.
2474NOTE:     Activate the output ring with the @code{setring} command.
2475          In the output ring, the ideal `LD' (in Groebner basis) is (part of)
2476          the annihilator of g/f.
2477@*        If db>0 is given, operators of order up to db are considered,
2478          otherwise, and by default, a minimal holonomic solution is computed.
2479@*        If eng<>0, @code{std} is used for Groebner basis computations,
2480          otherwise, and by default, @code{slimgb} is used.
2481@*        If printlevel =1, progress debug messages will be printed,
2482          if printlevel>=2, all the debug messages will be printed.
2483SEE ALSO: annRat, annPoly
2484EXAMPLE:  example annRatSyz; shows examples
2485"
2486{
2487  // check assumptions
2488  if (!isCommutative())
2489  {
2490    ERROR("Basering must be commutative.");
2491  }
2492  if (  (size(ideal(basering)) >0) || (char(basering) >0) )
2493  {
2494    ERROR("Basering is inappropriate: characteristic>0 or qring present.");
2495  }
2496  if (g == 0)
2497  {
2498    ERROR("Second polynomial must not be zero.");
2499  }
2500  int db,eng;
2501  if (size(#)>0)
2502  {
2503    if (typeof(#[1]) == "int")
2504    {
2505      db = int(#[1]);
2506    }
2507    if (size(#)>1)
2508    {
2509      if (typeof(#[2]) == "int")
2510      {
2511        eng = int(#[1]);
2512      }
2513    }
2514  }
2515  int ppl = printlevel - voice + 2;
2516  vector I = f*gen(1)+g*gen(2);
2517  checkRatInput(I);
2518  int i,j;
2519  def R = basering;
2520  int n = nvars(R);
2521  list RL = ringlist(R);
2522  RL = RL[1..4];
2523  list Ltmp = RL[2];
2524  for (i=1; i<=n; i++)
2525  {
2526    Ltmp[i+n] = safeVarName("D" + Ltmp[i]);
2527  }
2528  RL[2] = Ltmp;
2529  Ltmp = list();
2530  Ltmp[1] = list("dp",intvec(1:2*n));
2531  Ltmp[2] = list("C",intvec(0));
2532  RL[3] = Ltmp;
2533  kill Ltmp;
2534  def @D = ring(RL);
2535  setring @D;
2536  def D = Weyl();
2537  setring D;
2538  ideal DD = 1;
2539  ideal Dcd,Dnd,LD,tmp;
2540  Dnd = 1;
2541  module DS;
2542  poly DJ;
2543  kill @D;
2544  setring R;
2545  module Rnd,Rcd;
2546  Rnd[1] = I;
2547  vector RJ;
2548  ideal L = I[1];
2549  module RS;
2550  poly p,pnew;
2551  pnew = I[2];
2552  int k,c;
2553  while(1)
2554  {
2555    k++;
2556    setring R;
2557    dbprint(ppl,"// Testing order: " + string(k));
2558    Rcd = Rnd;
2559    Rnd = 0;
2560    setring D;
2561    Dcd = Dnd;
2562    Dnd = 0;
2563    dbprint(ppl-1,"// Current members of the annihilator: " + string(LD));
2564    setring R;
2565    c = size(Rcd);
2566    p = pnew;
2567    for (i=1; i<=c; i++)
2568    {
2569      for (j=1; j<=n; j++)
2570      {
2571        RJ = diffRat(Rcd[i],j);
2572        setring D;
2573        DJ = Dcd[i]*var(n+j);
2574        tmp = Dnd,DJ;
2575        if (size(Dnd) <> size(simplify(tmp,4))) // new element
2576        {
2577          Dnd[size(Dnd)+1] = DJ;
2578          setring R;
2579          Rnd[size(Rnd)+1] = RJ;
2580          pnew = lcm(pnew,RJ[2]);
2581        }
2582        else // already have DJ in Dnd
2583        {
2584          setring R;
2585        }
2586      }
2587    }
2588    p = pnew/p;
2589    for (i=1; i<=size(L); i++)
2590    {
2591      L[i] = p*L[i];
2592    }
2593    for (i=1; i<=size(Rnd); i++)
2594    {
2595      L[size(L)+1] = pnew/Rnd[i][2]*Rnd[i][1];
2596    }
2597    RS = syz(L);
2598    setring D;
2599    DD = DD,Dnd;
2600    setring R;
2601    if (RS <> 0)
2602    {
2603      setring D;
2604      DS = imap(R,RS);
2605      LD = ideal(transpose(DS)*transpose(DD));
2606    }
2607    else
2608    {
2609      setring D;
2610    }
2611    LD = engine(LD,eng);
2612    // test if we're done
2613    if (db<=0)
2614    {
2615      if (isHolonomic(LD)) { break; }
2616    }
2617    else
2618    {
2619      if (k==db) { break; }
2620    }
2621  }
2622  export(LD);
2623  setring R;
2624  return(D);
2625}
2626example
2627{
2628  "EXAMPLE:"; echo = 2;
2629  // printlevel = 3;
2630  ring r = 0,(x,y),dp;
2631  poly f = 2*x*y; poly g = x^2 - y^3;
2632  def A = annRatSyz(f,g);   // compute a holonomic solution
2633  setring A; A;
2634  LD;
2635  setring r;
2636  def B = annRatSyz(f,g,5); // compute a solution up to degree 5
2637  setring B;
2638  LD; // this is the full annihilator as we will check below
2639  setring r;
2640  def C = annRat(f,g); setring C;
2641  LD; // the full annihilator
2642  ideal BLD = imap(B,LD);
2643  NF(LD,std(BLD));
2644}
2645
Note: See TracBrowser for help on using the repository browser.