source: git/Singular/LIB/dmodloc.lib @ 1739dc9

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