source: git/Singular/LIB/normal.lib @ 7e49b5

spielwiese
Last change on this file since 7e49b5 was 7e49b5, checked in by Hans Schönemann <hannes@…>, 14 years ago
*hannes: typo in doc. git-svn-id: file:///usr/local/Singular/svn/trunk@12078 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 203.7 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2version="$Id: normal.lib,v 1.56 2009-08-19 13:17:25 Singular Exp $";
3category="Commutative Algebra";
4info="
5LIBRARY:  normal.lib     Normalization of Affine Rings
6AUTHORS:  G.-M. Greuel,  greuel@mathematik.uni-kl.de,
7@*        S. Laplagne,   slaplagn@dm.uba.ar,
8@*        G. Pfister,    pfister@mathematik.uni-kl.de
9
10
11MAIN PROCEDURES:
12 normal(I[...]);     normalization of an affine ring
13 normalP(I,[...]);   normalization of an affine ring in positive characteristic
14 normalC(I,[...]);   normalization of an affine ring through a chain of rings
15 HomJJ(L);           presentation of End_R(J) as affine ring, J an ideal
16 genus(I);           computes the geometric genus of a projective curve
17 primeClosure(L);    integral closure of R/p, p a prime ideal
18 closureFrac(L);     write a polynomial in integral closure as element of Quot(R/p)
19 iMult(L);           intersection multiplicity of the ideals of the list L
20
21AUXILIARY PROCEDURES:
22 deltaLoc(f,S);      sum of delta invariants at conjugated singular points
23 locAtZero(I);       checks whether the zero set of I is located at 0
24 norTest(I,nor);     checks the output of normal, normalP, normalC
25";
26
27LIB "general.lib";
28LIB "poly.lib";
29LIB "sing.lib";
30LIB "primdec.lib";
31LIB "elim.lib";
32LIB "presolve.lib";
33LIB "inout.lib";
34LIB "ring.lib";
35LIB "hnoether.lib";
36LIB "reesclos.lib";
37LIB "algebra.lib";
38
39
40///////////////////////////////////////////////////////////////////////////////
41
42proc normal(ideal id, list #)
43"USAGE:  normal(id [,choose]); id = radical ideal, choose = optional string. @*
44         Optional parameters in list choose (can be entered in any order):@*
45         Decomposition:@*
46         - \"equidim\" -> computes first an equidimensional decomposition,
47         and then the normalization of each component. (default)@*
48         - \"prim\" -> computes first the minimal associated primes, and then
49         the normalization of each prime. @*
50         - \"noDeco\" -> no preliminary decomposition is done. If the ideal is
51         not equidimensional radical, output might be wrong.@*
52         - \"isPrim\" -> assumes that the ideal is prime. If assumption does
53         not hold, output might be wrong.@*
54         - \"noFac\" -> factorization is avoided in the computation of the
55         minimal associated primes;
56         Other:@*
57         - \"useRing\" -> uses the original ring ordering.@*
58         If the ring ordering is not global, it will change to a global
59         ordering only for computing radicals and prime or equidimensional
60         decompositions.@*
61         If this option is not set, it changes to dp ordering and perform all
62         computation with respect to this ordering.@*
63         - \"withDelta\" (or \"wd\") -> returns also the delta invariants.
64         If choose is not given or empty, the default options are used.@*
65ASSUME:  The ideal must be radical, for non-radical ideals the output may
66         be wrong (id=radical(id); makes id radical). However, when using
67         \"prim\" option the minimal associated primes of id are computed first
68         and hence normal computes the normalization of the radical of id.@*
69         \"isPrim\" should only be used if id is known to be prime.
70RETURN:  a list, say nor, of size 2 (resp. 3 with option \"withDelta\").
71@format
72         * nor[1], the first element, is a list of r rings, where r is the
73         number of associated primes P_i with option \"prim\" (resp. >= no
74         of equidimenensional components P_i with option \"equidim\").@*
75         Each ring Ri:=nor[1][i], i=1..r, contains two ideals with given
76         names @code{norid} and @code{normap} such that @*
77         - Ri/norid is the normalization of the i-th component, i.e. the
78          integral closure in its field of fractions (as affine ring);
79         - @code{normap} gives the normalization map from basering/id to
80           Ri/norid for each i.@*
81         - the direct sum of the rings Ri/norid, i=1,..r, is the normalization
82           of basering/id; @*
83         * nor[2] is a list of size r with information on the normalization of
84         the i-th component as module over the basering:@*
85         nor[2][i] is an ideal, say U, in the basering such that the integral
86         closure of basering/P_i is generated as module over the basering by
87         1/c * U, with c the last element U[size(U)] of U.@*
88         * nor[3] (if option \"withDelta\" is set) is a list of an intvec
89         of size r, the delta invariants of the r components, and an integer,
90         the total delta invariant of basering/id (-1 means infinite, and 0
91         that basering/P_i resp. basering/input is normal).
92@end format
93THEORY:  We use a general algorithm described in [G.-M. Greuel, S. Laplagne,
94         F. Seelisch: Normalization of Rings (2009)].@*
95         The delta invariant of a reduced ring K[x1,...,xn]/id is
96             dim_K(normalization(K[x1,...,xn]/id) / K[x1,...,xn]/id)
97         We call this number also the delta invariant of id.
98NOTE:    To use the i-th ring type: @code{def R=nor[1][i]; setring R;}.
99@*       Increasing/decreasing printlevel displays more/less comments
100         (default: printlevel=0).
101@*       Implementation works also for local rings.
102@*       Not implemented for quotient rings.
103@*       If the input ideal id is weighted homogeneous a weighted ordering may
104         be used (qhweight(id); computes weights).
105KEYWORDS: normalization; integral closure; delta invariant.
106EXAMPLE: example normal; shows an example
107"
108{
109   intvec opt = option(get);     // Save current options
110
111  int i,j;
112  int decomp;   // Preliminar decomposition:
113                // 0 -> no decomposition (id is assumed to be prime)
114                // 1 -> no decomposition
115                //      (id is assumed to be equidimensional radical)
116                // 2 -> equidimensional decomposition
117                // 3 -> minimal associated primes
118  int noFac, useRing, withDelta;
119  int dbg = printlevel - voice + 2;
120  int nvar = nvars(basering);
121  int chara  = char(basering);
122  list result;
123  list keepresult;
124  list ringStruc;
125  ideal U;
126  poly c;
127  int sp;            // Number of components.
128
129  // Default methods:
130  noFac = 0;         // Use facSTD when computing minimal associated primes
131  decomp = 2;        // Equidimensional decomposition
132  useRing = 0;       // Change first to dp ordering, and perform all
133                     // computations there.
134  withDelta = 0;     // Do not compute the delta invariant.
135
136//--------------------------- define the method ---------------------------
137  string method;                //make all options one string in order to use
138                               //all combinations of options simultaneously
139  for ( i=1; i <= size(#); i++ )
140  {
141    if ( typeof(#[i]) == "string" )
142    {
143      method = method + #[i];
144    }
145  }
146
147//--------------------------- choosen methods -----------------------
148  if ( find(method,"isprim") or find(method,"isPrim") )
149  {decomp = 0;}
150
151  if ( find(method,"nodeco") or find(method,"noDeco") )
152  {decomp = 1;}
153
154  if ( find(method,"prim") )
155  {decomp = 3;}
156
157  if ( find(method,"equidim") )
158  {decomp = 2;}
159
160  if ( find(method,"nofac") or find(method,"noFac") )
161  {noFac=1;}
162
163  if ( (find(method,"useRing") or find(method,"usering")) and (ordstr(basering) != "dp("+string(nvars(basering))+"),C"))
164  {useRing = 1;}
165
166  if ( find(method,"withDelta") or find(method,"wd") or find(method,"withdelta"))
167  {
168    if((decomp == 0) or (decomp == 3))
169    {
170      withDelta = 1;
171    }
172    else
173    {
174      "WARNING: the delta invariants cannot be computed with an equidimensional";
175      "         decomposition.";
176      "         Use option \"prim\" to compute first the minimal associated primes.";
177      "";
178    }
179  }
180
181  kill #;
182  list #;
183
184//------------------------ change ring if required ------------------------
185// If the ordering is not global, we change to dp ordering for computing the
186// min ass primes.
187// If the ordering is global, but not dp, and useRing = 0, we also change to
188// dp ordering.
189
190  int isGlobal = ord_test(basering);      // Checks if the original ring has
191                                          // global ordering.
192
193  def origR = basering;   // origR is the original ring
194                          // R is the ring where computations will be done
195
196  if((useRing  == 1) and (isGlobal == 1))
197  {
198    def globR = basering;
199  }
200  else
201  {
202    // We change to dp ordering.
203    list rl = ringlist(origR);
204    list origOrd = rl[3];
205    list newOrd = list("dp", intvec(1:nvars(origR))), list("C", 0);
206    rl[3] = newOrd;
207    def globR = ring(rl);
208    setring globR;
209    ideal id = fetch(origR, id);
210  }
211
212//------------------------ trivial checkings ------------------------
213  id = groebner(id);
214  if((size(id) == 0) or (id[1] == 1))
215  {
216    // The original ring R/I was normal. Nothing to do.
217    // We define anyway a new ring, equal to R, to be able to return it.
218    setring origR;
219    list lR = ringlist(origR);
220    def ROut = ring(lR);
221    setring ROut;
222    ideal norid = 0;
223    ideal normap = maxideal(1);
224    export norid;
225    export normap;
226    setring origR;
227    if(withDelta)
228    {
229      result = list(list(ideal(1), poly(1), ROut), 0);
230    }
231    else
232    {
233      result = list(list(ideal(1), poly(1), ROut));
234    }
235    return(result);
236  }
237
238//------------------------ preliminary decomposition-----------------------
239  list prim;
240  if(decomp == 2)
241  {
242    dbprint(dbg, "// Computing the equidimensional decomposition...");
243    prim = equidim(id);
244  }
245  if((decomp == 0) or (decomp == 1))
246  {
247    prim = id;
248  }
249  if(decomp == 3)
250  {
251    dbprint(dbg, "// Computing the minimal associated primes...");
252    if( noFac )
253    { prim = minAssGTZ(id,1); }
254    else
255    { prim = minAssGTZ(id); }
256  }
257  sp = size(prim);
258  if(dbg>=1)
259  {
260    prim; "";
261    "// number of components is", sp;
262    "";
263  }
264
265
266//----------------- back to the original ring if required ------------------
267// if ring was not global and useRing is on, we go back to the original ring
268  if((useRing == 1) and (isGlobal != 1))
269  {
270    setring origR;
271    def R = basering;
272    list prim = fetch(globR, prim);
273  }
274  else
275  {
276    def R = basering;
277    if(useRing == 0)
278    {
279      ideal U;
280      poly c;
281    }
282  }
283
284// ---------------- normalization of the components-------------------------
285// calls normalM to compute the normalization of each component.
286
287  list norComp;       // The normalization of each component.
288  int delt;
289  int deltI = 0;
290  int totalComps = 0;
291
292  setring origR;
293  def newROrigOrd;
294  list newRListO;
295  setring R;
296  def newR;
297  list newRList;
298
299  for(i=1; i<=size(prim); i++)
300  {
301    if(dbg>=2){pause();}
302    if(dbg>=1)
303    {
304      "// start computation of component",i;
305      "   --------------------------------";
306    }
307    if(groebner(prim[i])[1] != 1)
308    {
309      if(dbg>=2)
310      {
311        "We compute the normalization in the ring"; basering;
312      }
313      printlevel = printlevel + 1;
314      norComp = normalM(prim[i], decomp, withDelta);
315      printlevel = printlevel - 1;
316      for(j = 1; j <= size(norComp); j++)
317      {
318        newR = norComp[j][3];
319        newRList = ringlist(newR);
320        U = norComp[j][1];
321        c = norComp[j][2];
322        if(withDelta)
323        {
324          delt = norComp[j][4];
325          if((delt >= 0) and (deltI >= 0))
326          {
327            deltI = deltI + delt;
328          }
329          else
330          {
331            deltI = -1;
332          }
333        }
334        // -- incorporate result for this component to the list of results ---
335        if(useRing == 0)
336        {
337          // We go back to the original ring.
338          setring origR;
339          U = fetch(R, U);
340          c = fetch(R, c);
341          newRListO = imap(R, newRList);
342          // We change the ordering in the new ring.
343          if(nvars(newR) > nvars(origR))
344          {
345            newRListO[3]=insert(origOrd, newRListO[3][1]);
346          }
347          else
348          {
349            newRListO[3] = origOrd;
350          }
351          newROrigOrd = ring(newRListO);
352          setring newROrigOrd;
353          ideal norid = imap(newR, norid);
354          ideal normap = imap(newR, normap);
355          export norid;
356          export normap;
357          setring origR;
358          totalComps++;
359          result[totalComps] = list(U, c, newROrigOrd);
360          if(withDelta)
361          {
362            result[totalComps] = insert(result[totalComps], delt, 3);
363          }
364          setring R;
365        }
366        else
367        {
368          setring R;
369          totalComps++;
370          result[totalComps] = norComp[j];
371        }
372      }
373    }
374  }
375
376// -------------------------- delta computation ----------------------------
377  if(withDelta == 1)
378  {
379    // Intersection multiplicities of list prim, sp=size(prim).
380    if ( dbg >= 1 )
381    {
382      "// Sum of delta for all components: ", deltI;
383    }
384    if(size(prim) > 1)
385    {
386      dbprint(dbg, "// Computing the sum of the intersection multiplicities of the components...");
387      int mul = iMult(prim);
388      if ( mul < 0 )
389      {
390        deltI = -1;
391      }
392      else
393      {
394        deltI = deltI + mul;
395      }
396      if ( dbg >= 1 )
397      {
398        "// Intersection multiplicity is : ", mul;
399      }
400    }
401  }
402
403// -------------------------- prepare output ------------------------------
404  setring origR;
405
406  list RL;      // List of rings
407  list MG;      // Module generators
408  intvec DV;    // Vector of delta's of each component
409  for(i = 1; i <= size(result); i++)
410  {
411    RL[i] = result[i][3];
412    MG[i] = lineUpLast(result[i][1], result[i][2]);
413    if(withDelta)
414    {
415      DV[i] = result[i][4];
416    }
417  }
418  list resultNew;
419
420  if(withDelta)
421  {
422    resultNew = list(RL, MG, list(DV, deltI));
423  }
424  else
425  {
426    resultNew = list(RL, MG);
427  }
428
429  option(set, opt);
430
431  if ( dbg >= 0 )
432  {
433    "";
434    if(!withDelta)
435    {
436      "// 'normal' created a list, say nor, of two elements.";
437    }
438    else
439    {
440      "// 'normal' created a list, say nor, of three elements.";
441    }
442    "// * nor[1] is a list of", sp, "ring(s). To access the i-th ring nor[1][i], ";
443    "// give it a name, say Ri, and type e.g. ";
444    "     def R1 = nor[1][1]; setring R1; norid; normap;";
445    "// For the other rings type first ";
446    "     setring r;";
447    "// (if r is the name of your original basering) and then continue as";
448    "// for the first ring.";
449    "// Ri/norid is the affine algebra of the normalization of the i-th ";
450    "// component r/P_i (where P_i is the i-th component of a decomposition of";
451    "// the input ideal) and normap the normalization map from r to Ri/norid.";
452    "// * nor[2] is a list of", sp, "ideal(s) such that the integral";
453    "// closure of basering/P_i is generated as module over the basering by";
454    "// 1/ci * Ui, with Ui the i-th ideal of nor[2] and ci the last element";
455    "// Ui[size(Ui)] of Ui.";
456    if(withDelta)
457    {
458      "// * nor[3] is a list of an intvec of size r, the delta invariants ";
459      "// of the r components, and an integer, the total delta invariant ";
460      "// of basering/id (-1 means infinite, and 0 that basering/P_i resp. ";
461      "// basering/input is normal).";
462    }
463  }
464  return(resultNew);
465}
466
467example
468{ "EXAMPLE:";
469  printlevel = printlevel+1;
470  echo = 2;
471  ring s = 0,(x,y),dp;
472  ideal i = (x2-y3)*(x2+y2)*x;
473  list nor = normal(i, "withDelta", "prim");
474  nor;
475
476  // 2 branches have delta = 1, and 1 branch has delta = 0
477  // the total delta invariant is 13
478
479  def R2 = nor[1][2];  setring R2;
480  norid; normap;
481
482  echo = 0;
483  printlevel = printlevel-1;
484  pause("   hit return to continue"); echo=2;
485
486  ring r = 2,(x,y,z),dp;
487  ideal i = z3-xy4;
488  list nor = normal(i, "withDelta", "prim");  nor;
489  // the delta invariant is infinite
490  // xy2z/z2 and xy3/z2 generate the integral closure of r/i as r/i-module
491  // in its quotient field Quot(r/i)
492
493  // the normalization as affine algebra over the ground field:
494  def R = nor[1][1]; setring R;
495  norid; normap;
496}
497
498///////////////////////////////////////////////////////////////////////////////
499
500proc HomJJ (list Li)
501"USAGE:   HomJJ (Li);  Li = list: ideal SBid, ideal id, ideal J, poly p
502ASSUME:  R    = P/id,  P = basering, a polynomial ring, id an ideal of P,
503@*       SBid = standard basis of id,
504@*       J    = ideal of P containing the polynomial p,
505@*       p    = nonzero divisor of R
506COMPUTE: Endomorphism ring End_R(J)=Hom_R(J,J) with its ring structure as
507         affine ring, together with the map R --> Hom_R(J,J) of affine rings,
508         where R is the quotient ring of P modulo the standard basis SBid.
509RETURN:  a list l of three objects
510@format
511         l[1] : a polynomial ring, containing two ideals, 'endid' and 'endphi'
512               such that l[1]/endid = Hom_R(J,J) and
513               endphi describes the canonical map R -> Hom_R(J,J)
514         l[2] : an integer which is 1 if phi is an isomorphism, 0 if not
515         l[3] : an integer, = dim_K(Hom_R(J,J)/R) (the contribution to delta)
516                if the dimension is finite, -1 otherwise
517@end format
518NOTE:    printlevel >=1: display comments (default: printlevel=0)
519EXAMPLE: example HomJJ;  shows an example
520"
521{
522//---------- initialisation ---------------------------------------------------
523   int isIso,isPr,isHy,isCo,isRe,isEq,oSAZ,ii,jj,q,y;
524   intvec rw,rw1;
525   list L;
526   y = printlevel-voice+2;  // y=printlevel (default: y=0)
527   def P = basering;
528   ideal SBid, id, J = Li[1], Li[2], Li[3];
529   poly p = Li[4];
530   int noRed = 0;
531   if(size(Li) > 4)
532   {
533     if(Li[5] == 1) { noRed = 1; }
534   }
535
536   attrib(SBid,"isSB",1);
537   int homo = homog(Li[2]);               //is 1 if id is homogeneous, 0 if not
538
539//---- set attributes for special cases where algorithm can be simplified -----
540   if( homo==1 )
541   {
542      rw = ringweights(P);
543   }
544   if( typeof(attrib(id,"isPrim"))=="int" )
545   {
546      if(attrib(id,"isPrim")==1)  { isPr=1; }
547   }
548   if( typeof(attrib(id,"onlySingularAtZero"))=="int" )
549   {
550      if(attrib(id,"onlySingularAtZero")==1){oSAZ=1; }
551   }
552   if( typeof(attrib(id,"isIsolatedSingularity"))=="int" )
553   {
554      if(attrib(id,"isIsolatedSingularity")==1) { isIso=1; }
555   }
556   if( typeof(attrib(id,"isCohenMacaulay"))=="int" )
557   {
558      if(attrib(id,"isCohenMacaulay")==1) { isCo=1; }
559   }
560   if( typeof(attrib(id,"isRegInCodim2"))=="int" )
561   {
562      if(attrib(id,"isRegInCodim2")==1) { isRe=1; }
563   }
564   if( typeof(attrib(id,"isEquidimensional"))=="int" )
565   {
566      if(attrib(id,"isEquidimensional")==1) { isEq=1; }
567   }
568//-------------------------- go to quotient ring ------------------------------
569   qring R  = SBid;
570   ideal id = fetch(P,id);
571   ideal J  = fetch(P,J);
572   poly p   = fetch(P,p);
573   ideal f,rf,f2;
574   module syzf;
575//---------- computation of p*Hom(J,J) as R-ideal -----------------------------
576   if ( y>=1 )
577   {
578     "// compute p*Hom(J,J) = p*J:J";
579     "//   the ideal J:";J;
580   }
581   f  = quotient(p*J,J);
582
583   //### (neu GMG 4.10.08) divide by the greatest common divisor:
584   poly gg = gcd( f[1],p );
585   for(ii=2; ii <=ncols(f); ii++)
586   {
587      gg=gcd(gg,f[ii]);
588   }
589   for(ii=1; ii<=ncols(f); ii++)
590   {
591      f[ii]=f[ii]/gg;
592   }
593   p = p/gg;
594
595   if ( y>=1 )
596   {
597      "//   the non-zerodivisor p:"; p;
598      "//   the module p*Hom(J,J) = p*J:J :"; f;
599      "";
600   }
601   f2 = std(p);
602
603//---------- Test: Hom(J,J) == R ?, if yes, go home ---------------------------
604
605   //rf = interred(reduce(f,f2));
606   //### interred hier weggelassen, unten zugefŸgt
607   rf = reduce(f,f2);       //represents p*Hom(J,J)/p*R = Hom(J,J)/R
608   if ( size(rf) == 0 )
609   {
610      if ( homog(f) && find(ordstr(basering),"s")==0 )
611      {
612         ring newR1 = char(P),(X(1..nvars(P))),(a(rw),dp);
613      }
614      else
615      {
616         ring newR1 = char(P),(X(1..nvars(P))),dp;
617      }
618      ideal endphi = maxideal(1);
619      ideal endid = fetch(P,id);
620      endid = simplify(endid,2);
621      L = substpart(endid,endphi,homo,rw);   //## hier substpart
622      def lastRing = L[1];
623      setring lastRing;
624
625      attrib(endid,"onlySingularAtZero",oSAZ);
626      attrib(endid,"isCohenMacaulay",isCo);
627      attrib(endid,"isPrim",isPr);
628      attrib(endid,"isIsolatedSingularity",isIso);
629      attrib(endid,"isRegInCodim2",isRe);
630      attrib(endid,"isEqudimensional",isEq);
631      attrib(endid,"isHypersurface",0);
632      attrib(endid,"isCompleteIntersection",0);
633      attrib(endid,"isRadical",0);
634      L=lastRing;
635      L = insert(L,1,1);
636      dbprint(y,"// case R = Hom(J,J)");
637      if(y>=1)
638      {
639         "//   R=Hom(J,J)";
640         lastRing;
641         "//   the new ideal";
642         endid;
643         "   ";
644         "//   the old ring";
645         P;
646         "//   the old ideal";
647         setring P;
648         id;
649         "   ";
650         setring lastRing;
651         "//   the map to the new ring";
652         endphi;
653         "   ";
654         pause();
655         "";
656      }
657      setring P;
658      L[3]=0;
659      return(L);
660   }
661   if(y>=1)
662   {
663      "// R is not equal to Hom(J,J), we have to try again";
664      pause();
665      "";
666   }
667//---------- Hom(J,J) != R: create new ring and map from old ring -------------
668// the ring newR1/SBid+syzf will be isomorphic to Hom(J,J) as R-module
669// f2=p (i.e. ideal generated by p)
670
671   //f = mstd(f)[2];              //### geŠndert GMG 04.10.08
672   //ideal ann = quotient(f2,f);  //### f durch rf ersetzt
673   rf = mstd(rf)[2];              //rf = NF(f,p), hence <p,rf> = <p,f>
674   ideal ann = quotient(f2,rf);   //p:f = p:rf
675
676   //------------- compute the contribution to delta ----------
677   //delt=dim_K(Hom(JJ)/R (or -1 if infinite)
678
679   int delt=vdim(std(modulo(f,ideal(p))));
680
681   f = p,rf;          // generates pJ:J mod(p), i.e. p*Hom(J,J)/p*R as R-module
682   q = size(f);
683   syzf = syz(f);
684
685   if ( homo==1 )
686   {
687      rw1 = rw,0;
688      for ( ii=2; ii<=q; ii++ )
689      {
690         rw  = rw, deg(f[ii])-deg(f[1]);
691         rw1 = rw1, deg(f[ii])-deg(f[1]);
692      }
693      ring newR1 = char(R),(X(1..nvars(R)),T(1..q)),(a(rw1),dp);
694   }
695   else
696   {
697      ring newR1 = char(R),(X(1..nvars(R)),T(1..q)),dp;
698   }
699
700   //map psi1 = P,maxideal(1);          //### psi1 durch fetch ersetzt
701   //ideal SBid = psi1(SBid);
702   ideal SBid = fetch(P,SBid);
703   attrib(SBid,"isSB",1);
704
705   qring newR = std(SBid);
706
707   //map psi = R,ideal(X(1..nvars(R)));  //### psi durch fetch ersetzt
708   //ideal id = psi(id);
709   //ideal f = psi(f);
710   //module syzf = psi(syzf);
711   ideal id = fetch(R,id);
712   ideal f = fetch(R,f);
713   module syzf = fetch(R,syzf);
714   ideal pf,Lin,Quad,Q;
715   matrix T,A;
716   list L1;
717
718//---------- computation of Hom(J,J) as affine ring ---------------------------
719// determine kernel of: R[T1,...,Tq] -> J:J >-> R[1/p]=R[t]/(t*p-1),
720// Ti -> fi/p -> t*fi (p=f1=f[1]), to get ring structure. This is of course
721// the same as the kernel of R[T1,...,Tq] -> pJ:J >-> R, Ti -> fi.
722// It is a fact, that the kernel is generated by the linear and the quadratic
723// relations
724// f=p,rf, rf=reduce(f,p), generates pJ:J mod(p),
725// i.e. p*Hom(J,J)/p*R as R-module
726
727   pf = f[1]*f;
728   T = matrix(ideal(T(1..q)),1,q);
729   Lin = ideal(T*syzf);
730   if(y>=1)
731   {
732      "// the ring structure of Hom(J,J) as R-algebra";
733      "//   the linear relations:";
734      Lin;
735   }
736
737   poly ff;
738   for (ii=2; ii<=q; ii++ )
739   {
740      for ( jj=2; jj<=ii; jj++ )
741      {
742         ff = NF(f[ii]*f[jj],std(0));       //this makes lift much faster
743         A = lift(pf,ff);                   //ff lin. comb. of elts of pf mod I
744         Quad = Quad, ideal(T(jj)*T(ii) - T*A);  //quadratic relations
745      }
746   }
747
748   if(y>=1)
749   {
750      "//   the quadratic relations";
751      Quad;
752      pause();
753      newline;
754   }
755   Q = Lin,Quad;
756   Q = subst(Q,T(1),1);
757   //Q = mstd(Q)[2];            //### sehr aufwendig, daher weggelassen (GMG)
758   //### ev das neue interred
759   //mstd dient nur zum verkleinern, die SB-Eigenschaft geht spaeter verloren
760   //da in neuen Ring abgebildet und mit id vereinigt
761
762//---------- reduce number of variables by substitution, if possible ----------
763   if (homo==1)
764   {
765      ring newRing = char(R),(X(1..nvars(R)),T(2..q)),(a(rw),dp);
766   }
767   else
768   {
769      ring newRing = char(R),(X(1..nvars(R)),T(2..q)),dp;
770   }
771
772   ideal endid  = imap(newR,id),imap(newR,Q);
773   //hier wird Q weiterverwendet, die SB-Eigenschaft wird nicht verwendet.
774   endid = simplify(endid,2);
775   ideal endphi = ideal(X(1..nvars(R)));
776
777
778  if(noRed == 0)
779  {
780    L = substpart(endid,endphi,homo,rw);
781    def lastRing=L[1];
782    setring lastRing;
783    //return(lastRing);
784  }
785  else
786  {
787    list RL = ringlist(newRing);
788    def lastRing = ring(RL);
789    setring lastRing;
790    ideal endid = fetch(newRing, endid);
791    ideal endphi = fetch(newRing, endphi);
792    export(endid);
793    export(endphi);
794    //def lastRing = newRing;
795    //setring R;
796    //return(newR);
797  }
798
799
800
801//   L = substpart(endid,endphi,homo,rw);
802
803//   def lastRing=L[1];
804//   setring lastRing;
805
806   attrib(endid,"onlySingularAtZero",0);
807   map sigma=R,endphi;
808   ideal an=sigma(ann);
809   export(an);  //noetig?
810   //ideal te=an,endid;
811   //if(isIso && (size(reduce(te,std(maxideal(1))))==0))   //#### ok???
812   // {
813   //    attrib(endid,"onlySingularAtZero",oSAZ);
814   // }
815   //kill te;
816   attrib(endid,"isCohenMacaulay",isCo);                //#### ok???
817   attrib(endid,"isPrim",isPr);
818   attrib(endid,"isIsolatedSingularity",isIso);
819   attrib(endid,"isRegInCodim2",isRe);
820   attrib(endid,"isEquidimensional",isEq);
821   attrib(endid,"isHypersurface",0);
822   attrib(endid,"isCompleteIntersection",0);
823   attrib(endid,"isRadical",0);
824   if(y>=1)
825   {
826      "// the new ring after reduction of the number of variables";
827      lastRing;
828      "//   the new ideal";
829      endid;  "";
830      "// the old ring";
831      P;
832      "//   the old ideal";
833      setring P;
834      id;
835      "   ";
836      setring lastRing;
837      "//   the map to the new ring";
838      endphi;
839      "   ";
840      pause();
841      "";
842   }
843   L = lastRing;
844   L = insert(L,0,1);
845   L[3] = delt;
846   return(L);
847}
848example
849{"EXAMPLE:";  echo = 2;
850  ring r   = 0,(x,y),wp(2,3);
851  ideal id = y^2-x^3;
852  ideal J  = x,y;
853  poly p   = x;
854  list Li  = std(id),id,J,p;
855  list L   = HomJJ(Li);
856  def end = L[1];    // defines ring L[1], containing ideals endid, endphi
857  setring end;       // makes end the basering
858  end;
859  endid;             // end/endid is isomorphic to End(r/id) as ring
860  map psi = r,endphi;// defines the canonical map r/id -> End(r/id)
861  psi;
862  L[3];              // contribution to delta
863}
864
865
866///////////////////////////////////////////////////////////////////////////////
867//compute intersection multiplicities as needed for delta(I) in
868//normalizationPrimes and normalP:
869
870proc iMult (list prim)
871"USAGE:   iMult(L);  L a list of ideals
872RETURN:  int, the intersection multiplicity of the ideals of L;
873         if iMult(L) is infinite, -1 is returned.
874THEORY:  If r=size(L)=2 then iMult(L) = vdim(std(L[1]+L[2])) and in general
875         iMult(L) = sum{ iMult(L[j],Lj) | j=1..r-1 } with Lj the intersection
876         of L[j+1],...,L[r]. If I is the intersection of all ideals in L then
877         we have delta(I) = delta(L[1])+...+delta(L[r]) + iMult(L) where
878         delta(I) = vdim (normalisation(R/I)/(R/I)), R the basering.
879EXAMPLE: example iMult; shows an example
880"
881{    int i,mul,mu;
882     int sp = size(prim);
883     int y = printlevel-voice+2;
884     if ( sp > 1 )
885     {
886        ideal I(sp-1) = prim[sp];
887        mu = vdim(std(I(sp-1)+prim[sp-1]));
888        mul = mu;
889        if ( y>=1 )
890        {
891          "// intersection multiplicity of component",sp,"with",sp-1,":"; mu;
892        }
893        if ( mu >= 0 )
894        {
895           for (i=sp-2; i>=1 ; i--)
896           {
897              ideal I(i) = intersect(I(i+1),prim[i+1]);
898              mu = vdim(std(I(i)+prim[i]));
899              if ( mu < 0 )
900              {
901                break;
902              }
903              mul = mul + mu;
904              if ( y>=1 )
905              {
906                "// intersection multiplicity of components",sp,"...",i+1,"with",i; mu;
907              }
908           }
909        }
910     }
911     return(mul);
912}
913example
914{ "EXAMPLE:"; echo = 2;
915   ring s  = 23,(x,y),dp;
916   list L = (x-y),(x3+y2);
917   iMult(L);
918   L = (x-y),(x3+y2),(x3-y4);
919   iMult(L);
920}
921///////////////////////////////////////////////////////////////////////////////
922//check if I has a singularity only at zero, as needed in normalizationPrimes
923
924proc locAtZero (ideal I)
925"USAGE:   locAtZero(I);  I = ideal
926RETURN:  int, 1 if I has only one point which is located at zero, 0 otherwise
927ASSUME:  I is given as a standard bases in the basering
928NOTE:    only useful in affine rings, in local rings vdim does the check
929EXAMPLE: example locAtZero; shows an example
930"
931{
932   int ii,jj, caz;                   //caz: conzentrated at zero
933   int dbp = printlevel-voice+2;
934   int nva = nvars(basering);
935   int vdi = vdim(I);
936   if ( vdi < 0 )
937   {
938      if (dbp >=1)
939      { "// non-isolated singularitiy";""; }
940      return(caz);
941   }
942
943   //Now the ideal is 0-dim
944   //First an easy test
945   //If I is homogenous and not constant it is concentrated at 0
946   if( homog(I)==1 && size(jet(I,0))==0)
947   {
948      caz=1;
949      if (dbp >=1)
950      { "// isolated singularity and homogeneous";""; }
951      return(caz);
952   }
953
954   //Now the general case with I 0-dim. Choose an appropriate power pot,
955   //and check each variable x whether x^pot is in I.
956   int mi1 = mindeg1(lead(I));
957   int pot = vdi;
958   if ( (mi1+(mi1==1))^2 < vdi )
959   {
960      pot = (mi1+(mi1==1))^2;      //### alternativ: pot = vdi lassen
961   }
962
963   while ( 1 )
964   {
965      caz = 1;
966      for ( ii=1; ii<= nva; ii++ )
967      {
968        if ( NF(var(ii)^pot,I) != 0 )
969        {
970           caz = 0; break;
971        }
972      }
973      if ( caz == 1 || pot >= vdi )
974      {
975        if (dbp >=1)
976        {
977          "// mindeg, exponent, vdim used in 'locAtZero':", mi1,pot,vdi; "";
978        }
979        return(caz);
980      }
981      else
982      {
983        if ( pot^2 < vdi )
984        { pot = pot^2; }
985        else
986        { pot = vdi; }
987      }
988   }
989}
990example
991{ "EXAMPLE:"; echo = 2;
992   ring r = 0,(x,y,z),dp;
993   poly f = z5+y4+x3+xyz;
994   ideal i = jacob(f),f;
995   i=std(i);
996   locAtZero(i);
997   i= std(i*ideal(x-1,y,z));
998   locAtZero(i);
999}
1000
1001///////////////////////////////////////////////////////////////////////////////
1002
1003//The next procedure normalizationPrimes computes the normalization of an
1004//irreducible or an equidimensional ideal i.
1005//- If i is irreducuble, then the returned list, say nor, has size 2
1006//with nor[1] the normalization ring and nor[2] the delta invariant.
1007//- If i is equidimensional, than the "splitting tools" can create a
1008//decomposition of i and nor can have more than 1 ring.
1009
1010static proc normalizationPrimes(ideal i,ideal ihp,int delt,intvec delti,list #)
1011"USAGE:   normalizationPrimes(i,ihp,delt[,si]);  i = equidimensional ideal,
1012         ihp = map (partial normalization), delt = partial delta-invariant,
1013         si = ideal s.t. V(si) contains singular locus (optional)
1014RETURN:   a list of rings, say nor, and an integer, the delta-invariant
1015          at the end of the list.
1016          each ring nor[j], j = 1..size(nor)-1, contains two ideals
1017          with given names norid and normap such that
1018           - the direct sum of the rings nor[j]/norid is
1019             the normalization of basering/i;
1020           - normap gives the normalization map from basering/id
1021             to nor[j]/norid (for each j)
1022          nor[size(nor)] = dim_K(normalisation(P/i) / (P/i)) is the
1023          delta-invariant, where P is the basering.
1024EXAMPLE: example normalizationPrimes; shows an example
1025"
1026{
1027   //Note: this procedure calls itself as long as the test for
1028   //normality, i.e if R==Hom(J,J), is negative.
1029
1030   int printlev = printlevel;   //store printlevel in order to reset it later
1031   int y = printlevel-voice+2;  // y=printlevel (default: y=0)
1032   if(y>=1)
1033   {
1034     "";
1035     "// START a normalization loop with the ideal";
1036     i;  "";
1037     "// in the ring:";
1038     basering;  "";
1039     pause();
1040     "";
1041   }
1042
1043   def BAS=basering;
1044   list result,keepresult1,keepresult2,JM,gnirlist;
1045   ideal J,SB,MB;
1046   int depth,lauf,prdim,osaz;
1047   int ti=timer;
1048
1049   gnirlist = ringlist(BAS);
1050
1051//----------- the trivial case of a zero ideal as input, RETURN ------------
1052   if(size(i)==0)
1053   {
1054      if(y>=1)
1055      {
1056          "// the ideal was the zero-ideal";
1057      }
1058     // execute("ring newR7="+charstr(basering)+",("+varstr(basering)+"),("
1059     //                 +ordstr(basering)+");");
1060         def newR7 = ring(gnirlist);
1061         setring newR7;
1062         ideal norid=ideal(0);
1063         ideal normap=fetch(BAS,ihp);
1064         export norid;
1065         export normap;
1066         result=newR7;
1067         result[size(result)+1]=list(delt,delti);
1068         setring BAS;
1069         return(result);
1070   }
1071
1072//--------------- General NOTATION, compute SB of input -----------------
1073// SM is a list, the result of mstd(i)
1074// SM[1] = SB of input ideal i,
1075// SM[2] = (minimal) generators for i.
1076// We work with SM and will copy the attributes from i to SM[2]
1077// JM will be a list, either JM[1]=maxideal(1),JM[2]=maxideal(1)
1078// in case i has onlySingularAtZero, or JM = mstd(si) where si = #[1],
1079// or JM = mstd(J) where J is the ideal of the singular locus
1080// JM[2] must be (made) radical
1081
1082   if(y>=1)
1083   {
1084     "// SB-computation of the ideal";
1085   }
1086
1087   list SM = mstd(i);              //Now the work starts
1088   int dimSM =  dim(SM[1]);        //dimension of variety to normalize
1089   if(y>=1)
1090   {
1091      "// the dimension is:";  dimSM;
1092   }
1093//----------------- the general case, set attributes ----------------
1094   //Note: onlySingularAtZero is NOT preserved under the ring extension
1095   //basering --> Hom(J,J) (in contrast to isIsolatedSingularity),
1096   //therefore we reset it:
1097
1098   attrib(i,"onlySingularAtZero",0);
1099
1100   if(attrib(i,"isPrim")==1)
1101   {
1102      attrib(SM[2],"isPrim",1);
1103   }
1104   else
1105   {
1106      attrib(SM[2],"isPrim",0);
1107   }
1108   if(attrib(i,"isIsolatedSingularity")==1)
1109   {
1110      attrib(SM[2],"isIsolatedSingularity",1);
1111   }
1112   else
1113   {
1114      attrib(SM[2],"isIsolatedSingularity",0);
1115   }
1116   if(attrib(i,"isCohenMacaulay")==1)
1117   {
1118      attrib(SM[2],"isCohenMacaulay",1);
1119   }
1120   else
1121   {
1122      attrib(SM[2],"isCohenMacaulay",0);
1123   }
1124   if(attrib(i,"isRegInCodim2")==1)
1125   {
1126      attrib(SM[2],"isRegInCodim2",1);
1127   }
1128   else
1129   {
1130      attrib(SM[2],"isRegInCodim2",0);
1131   }
1132   if(attrib(i,"isEquidimensional")==1)
1133   {
1134      attrib(SM[2],"isEquidimensional",1);
1135   }
1136   else
1137   {
1138      attrib(SM[2],"isEquidimensional",0);
1139   }
1140   if(attrib(i,"isCompleteIntersection")==1)
1141   {
1142     attrib(SM[2],"isCompleteIntersection",1);
1143   }
1144   else
1145   {
1146      attrib(SM[2],"isCompleteIntersection",0);
1147   }
1148   if(attrib(i,"isHypersurface")==1)
1149   {
1150     attrib(SM[2],"isHypersurface",1);
1151   }
1152   else
1153   {
1154      attrib(SM[2],"isHypersurface",0);
1155   }
1156
1157   if(attrib(i,"onlySingularAtZero")==1)
1158   {
1159      attrib(SM[2],"onlySingularAtZero",1);
1160   }
1161   else
1162   {
1163      attrib(SM[2],"onlySingularAtZero",0);
1164   }
1165
1166   //------- an easy and cheap test for onlySingularAtZero ---------
1167   if( (attrib(SM[2],"isIsolatedSingularity")==1) && (homog(SM[2])==1) )
1168   {
1169      attrib(SM[2],"onlySingularAtZero",1);
1170   }
1171
1172//-------------------- Trivial cases, in each case RETURN ------------------
1173// input ideal is the ideal of a partial normalization
1174
1175   // ------------ Trivial case: input ideal contains a unit ---------------
1176   if( dimSM == -1)
1177   {  "";
1178      "      // A unit ideal was found.";
1179      "      // Stop with partial result computed so far";"";
1180
1181         MB=SM[2];
1182         intvec rw;
1183         list LL=substpart(MB,ihp,0,rw);
1184         def newR6=LL[1];
1185         setring newR6;
1186         ideal norid=endid;
1187         ideal normap=endphi;
1188         kill endid,endphi;
1189         export norid;
1190         export normap;
1191         result=newR6;
1192         result[size(result)+1]=list(delt,delti);
1193         setring BAS;
1194         return(result);
1195   }
1196
1197   // --- Trivial case: input ideal is zero-dimensional and homog ---
1198   if( (dim(SM[1])==0) && (homog(SM[2])==1) )
1199   {
1200      if(y>=1)
1201      {
1202         "// the ideal was zero-dimensional and homogeneous";
1203      }
1204      MB=maxideal(1);
1205      intvec rw;
1206      list LL=substpart(MB,ihp,0,rw);
1207      def newR5=LL[1];
1208      setring newR5;
1209      ideal norid=endid;
1210      ideal normap=endphi;
1211      kill endid,endphi;
1212      export norid;
1213      export normap;
1214      result=newR5;
1215      result[size(result)+1]=list(delt,delti);
1216      setring BAS;
1217      return(result);
1218   }
1219
1220   // --- Trivial case: input ideal defines a line ---
1221   //the one-dimensional, homogeneous case and degree 1 case
1222   if( (dim(SM[1])==1) && (maxdeg1(SM[2])==1) && (homog(SM[2])==1) )
1223   {
1224      if(y>=1)
1225      {
1226         "// the ideal defines a line";
1227      }
1228      MB=SM[2];
1229      intvec rw;
1230      list LL=substpart(MB,ihp,0,rw);
1231      def newR4=LL[1];
1232      setring newR4;
1233      ideal norid=endid;
1234      ideal normap=endphi;
1235      kill endid,endphi;
1236      export norid;
1237      export normap;
1238      result=newR4;
1239      result[size(result)+1]=list(delt,delti);
1240      setring BAS;
1241      return(result);
1242   }
1243
1244//---------------------- The non-trivial cases start -------------------
1245   //the higher dimensional case
1246   //we test first hypersurface, CohenMacaulay and complete intersection
1247
1248   if( ((size(SM[2])+dim(SM[1])) == nvars(basering)) )
1249   {
1250      //the test for complete intersection
1251      attrib(SM[2],"isCohenMacaulay",1);
1252      attrib(SM[2],"isCompleteIntersection",1);
1253      attrib(SM[2],"isEquidimensional",1);
1254      if(y>=1)
1255      {
1256         "// the ideal is a complete intersection";
1257      }
1258   }
1259   if( size(SM[2]) == 1 )
1260   {
1261      attrib(SM[2],"isHypersurface",1);
1262      if(y>=1)
1263      {
1264         "// the ideal is a hypersurface";
1265      }
1266   }
1267
1268   //------------------- compute the singular locus -------------------
1269   // Computation if singular locus is critical
1270   // Notation: J ideal of singular locus or (if given) containing it
1271   // JM = mstd(J) or maxideal(1),maxideal(1)
1272   // JM[1] SB of singular locus, JM[2] minbasis, dimJ = dim(JM[1])
1273   // SM[1] SB of the input ideal i, SM[2] minbasis
1274   // Computation if singular locus is critical, because it determines the
1275   // size of the ring Hom_R(J,J). We only need a test ideal contained in J.
1276
1277   //----------------------- onlySingularAtZero -------------------------
1278   if( attrib(SM[2],"onlySingularAtZero") )
1279   {
1280       JM = maxideal(1),maxideal(1);
1281       attrib(JM[1],"isSB",1);
1282       attrib(JM[2],"isRadical",1);
1283       if( dim(SM[1]) >=2 )
1284       {
1285         attrib(SM[2],"isRegInCodim2",1);
1286       }
1287   }
1288
1289   //-------------------- not onlySingularAtZero -------------------------
1290   if( attrib(SM[2],"onlySingularAtZero") == 0 )
1291   {
1292      //--- the case where an ideal #[1] is given:
1293      if( size(#)>0 )
1294      {
1295         J = #[1],SM[2];
1296         JM = mstd(J);
1297         if( typeof(attrib(#[1],"isRadical"))!="int" )
1298         {
1299            attrib(JM[2],"isRadical",0);
1300         }
1301      }
1302
1303      //--- the case where an ideal #[1] is not given:
1304      if( (size(#)==0) )
1305      {
1306         if(y >=1 )
1307         {
1308            "// singular locus will be computed";
1309         }
1310
1311         J = SM[1],minor(jacob(SM[2]),nvars(basering)-dim(SM[1]),SM[1]);
1312         if( y >=1 )
1313         {
1314            "// SB of singular locus will be computed";
1315         }
1316         JM = mstd(J);
1317      }
1318
1319      int dimJ = dim(JM[1]);
1320      attrib(JM[1],"isSB",1);
1321      if( y>=1 )
1322      {
1323         "// the dimension of the singular locus is";  dimJ ; "";
1324      }
1325
1326      if(dim(JM[1]) <= dim(SM[1])-2)
1327      {
1328         attrib(SM[2],"isRegInCodim2",1);
1329      }
1330
1331      //------------------ the smooth case, RETURN -------------------
1332      if( dimJ == -1 )
1333      {
1334         if(y>=1)
1335         {
1336            "// the ideal is smooth";
1337         }
1338         MB=SM[2];
1339         intvec rw;
1340         list LL=substpart(MB,ihp,0,rw);
1341         def newR3=LL[1];
1342         setring newR3;
1343         ideal norid=endid;
1344         ideal normap=endphi;
1345         kill endid,endphi;
1346         export norid;
1347         export normap;
1348         result=newR3;
1349         result[size(result)+1]=list(delt,delti);
1350         setring BAS;
1351         return(result);
1352      }
1353
1354      //------- extra check for onlySingularAtZero, relatively cheap ----------
1355      //it uses the procedure 'locAtZero' from for testing
1356      //if an ideal is concentrated at 0
1357       if(y>=1)
1358       {
1359         "// extra test for onlySingularAtZero:";
1360       }
1361       if ( locAtZero(JM[1]) )
1362       {
1363           attrib(SM[2],"onlySingularAtZero",1);
1364           JM = maxideal(1),maxideal(1);
1365           attrib(JM[1],"isSB",1);
1366           attrib(JM[2],"isRadical",1);
1367       }
1368       else
1369       {
1370              attrib(SM[2],"onlySingularAtZero",0);
1371       }
1372   }
1373
1374  //displaying the attributes:
1375   if(y>=2)
1376   {
1377      "// the attributes of the ideal are:";
1378      "// isCohenMacaulay:", attrib(SM[2],"isCohenMacaulay");
1379      "// isCompleteIntersection:", attrib(SM[2],"isCompleteIntersection");
1380      "// isHypersurface:", attrib(SM[2],"isHypersurface");
1381      "// isEquidimensional:", attrib(SM[2],"isEquidimensional");
1382      "// isPrim:", attrib(SM[2],"isPrim");
1383      "// isRegInCodim2:", attrib(SM[2],"isRegInCodim2");
1384      "// isIsolatedSingularity:", attrib(SM[2],"isIsolatedSingularity");
1385      "// onlySingularAtZero:", attrib(SM[2],"onlySingularAtZero");
1386      "// isRad:", attrib(SM[2],"isRad");"";
1387   }
1388
1389   //------------- case: CohenMacaulay in codim 2, RETURN ---------------
1390   if( (attrib(SM[2],"isRegInCodim2")==1) &&
1391       (attrib(SM[2],"isCohenMacaulay")==1) )
1392   {
1393      if(y>=1)
1394      {
1395         "// the ideal was CohenMacaulay and regular in codim 2, hence normal";
1396      }
1397      MB=SM[2];
1398      intvec rw;
1399      list LL=substpart(MB,ihp,0,rw);
1400      def newR6=LL[1];
1401      setring newR6;
1402      ideal norid=endid;
1403      ideal normap=endphi;
1404      kill endid,endphi;
1405      export norid;
1406      export normap;
1407      result=newR6;
1408      result[size(result)+1]=list(delt,delti);
1409      setring BAS;
1410      return(result);
1411   }
1412
1413//---------- case: isolated singularity only at 0, RETURN ------------
1414   // In this case things are easier, we can use the maximal ideal as radical
1415   // of the singular locus;
1416   // JM mstd of ideal of singular locus, SM mstd of input ideal
1417
1418   if( attrib(SM[2],"onlySingularAtZero") )
1419   {
1420   //------ check variables for being a non zero-divizor ------
1421   // SL = ideal of vars not contained in ideal SM[1]:
1422
1423      attrib(SM[2],"isIsolatedSingularity",1);
1424      ideal SL = simplify(reduce(maxideal(1),SM[1]),2);
1425      ideal Ann = quotient(SM[2],SL[1]);
1426      ideal qAnn = simplify(reduce(Ann,SM[1]),2);
1427      //NOTE: qAnn=0 if and only if first var (=SL[1]) not in SM is a nzd of R/SM
1428
1429   //------------- We found a non-zerodivisor of R/SM -----------------------
1430   // here the enlarging of the ring via Hom_R(J,J) starts
1431
1432      if( size(qAnn)==0 )
1433      {
1434         if(y>=1)
1435         {
1436            "";
1437            "// the ideal rad(J):"; maxideal(1);
1438            "";
1439         }
1440
1441      // ------------- test for normality, compute Hom_R(J,J) -------------
1442      // Note:
1443      // HomJJ (ideal SBid, ideal id, ideal J, poly p) with
1444      //        SBid = SB of id, J = radical ideal of basering  P with:
1445      //        nonNormal(R) is in V(J), J contains the nonzero divisor p
1446      //        of R = P/id (J = test ideal)
1447      // returns a list l of three objects
1448      // l[1] : a polynomial ring, containing two ideals, 'endid' and 'endphi'
1449      //        s.t. l[1]/endid = Hom_R(J,J) and endphi= map R -> Hom_R(J,J)
1450      // l[2] : an integer which is 1 if phi is an isomorphism, 0 if not
1451      // l[3] : an integer, = dim_K(Hom_R(J,J)/R) if finite, -1 otherwise
1452
1453         list RR;
1454         RR = SM[1],SM[2],maxideal(1),SL[1];
1455         RR = HomJJ(RR,y);
1456         // --------------------- non-normal case ------------------
1457         //RR[2]==0 means that the test for normality is negative
1458         if( RR[2]==0 )
1459         {
1460            def newR=RR[1];
1461            setring newR;
1462            map psi=BAS,endphi;
1463            list JM = psi(JM); //###
1464            ideal J = JM[2];
1465            if ( delt>=0 && RR[3]>=0 )
1466            {
1467               delt = delt+RR[3];
1468            }
1469            else
1470            { delt = -1; }
1471            delti[size(delti)]=delt;
1472
1473            // ---------- recursive call of normalizationPrimes -----------
1474        //normalizationPrimes(ideal i,ideal ihp,int delt,intvec delti,list #)
1475        //ihp = (partial) normalisation map from basering
1476        //#[1] ideal s.t. V(#[1]) contains singular locus of i (test ideal)
1477
1478            if ( y>=1 )
1479            {
1480            "// case: onlySingularAtZero, non-zerodivisor found";
1481            "// contribution of delta in ringextension R -> Hom_R(J,J):"; delt;
1482            }
1483
1484            //intvec atr=getAttrib(endid);
1485            //"//### case: isolated singularity only at 0, recursive";
1486            //"size endid:", size(endid), size(string(endid));
1487            //"interred:";
1488            //endid = interred(endid);
1489            //endid = setAttrib(endid,atr);
1490            //"size endid:", size(endid), size(string(endid));
1491
1492           printlevel=printlevel+1;
1493           list tluser =
1494                normalizationPrimes(endid,psi(ihp),delt,delti);
1495           //list tluser =
1496           //     normalizationPrimes(endid,psi(ihp),delt,delti,J);
1497           //#### ??? improvement: give also the old ideal of sing locus???
1498
1499           printlevel = printlev;             //reset printlevel
1500           setring BAS;
1501           return(tluser);
1502         }
1503
1504         // ------------------ the normal case, RETURN -----------------
1505         // Now RR[2] must be 1, hence the test for normality was positive
1506         MB=SM[2];
1507         //execute("ring newR7="+charstr(basering)+",("+varstr(basering)+"),("
1508         //             +ordstr(basering)+");");
1509         def newR7 = ring(gnirlist);
1510         setring newR7;
1511         ideal norid=fetch(BAS,MB);
1512         ideal normap=fetch(BAS,ihp);
1513         if ( delt>=0 && RR[3]>=0 )
1514         {
1515               delt = delt+RR[3];
1516         }
1517         else
1518         { delt = -1; }
1519         delti[size(delti)]=delt;
1520
1521         intvec atr = getAttrib(norid);
1522
1523         //"//### case: isolated singularity only at 0, final";
1524         //"size norid:", size(norid), size(string(norid));
1525         //"interred:";
1526         //norid = interred(norid);
1527         //norid = setAttrib(norid,atr);
1528         //"size norid:", size(norid), size(string(norid));
1529
1530         export norid;
1531         export normap;
1532         result=newR7;
1533         result[size(result)+1]=list(delt,delti);
1534         setring BAS;
1535         return(result);
1536      }
1537
1538   //------ zerodivisor of R/SM was found, gives a splitting ------------
1539   //Now the case where qAnn!=0, i.e. SL[1] is a zero divisor of R/SM
1540   //and we have found a splitting: id and id1
1541   //id = Ann defines components of R/SM in the complement of V(SL[1])
1542   //id1 defines components of R/SM in the complement of V(id)
1543
1544      else
1545       {
1546          ideal id = Ann;
1547          attrib(id,"isCohenMacaulay",0);
1548          attrib(id,"isPrim",0);
1549          attrib(id,"isIsolatedSingularity",1);
1550          attrib(id,"isRegInCodim2",0);
1551          attrib(id,"isHypersurface",0);
1552          attrib(id,"isCompleteIntersection",0);
1553          attrib(id,"isEquidimensional",0);
1554          attrib(id,"onlySingularAtZero",1);
1555
1556          ideal id1 = quotient(SM[2],Ann);
1557          attrib(id1,"isCohenMacaulay",0);
1558          attrib(id1,"isPrim",0);
1559          attrib(id1,"isIsolatedSingularity",1);
1560          attrib(id1,"isRegInCodim2",0);
1561          attrib(id1,"isHypersurface",0);
1562          attrib(id1,"isCompleteIntersection",0);
1563          attrib(id1,"isEquidimensional",0);
1564          attrib(id1,"onlySingularAtZero",1);
1565
1566          // ---------- recursive call of normalizationPrimes -----------
1567          if ( y>=1 )
1568          {
1569            "// case: onlySingularAtZero, zerodivisor found, splitting:";
1570            "// total delta before splitting:", delt;
1571            "// splitting in two components:";
1572          }
1573
1574          printlevel = printlevel+1;  //to see comments in normalizationPrimes
1575          keepresult1 = normalizationPrimes(id,ihp,0,0);   //1st split factor
1576          keepresult2 = normalizationPrimes(id1,ihp,0,0);  //2nd split factor
1577          printlevel = printlev;                           //reset printlevel
1578
1579          int delt1 = keepresult1[size(keepresult1)][1];
1580          int delt2 = keepresult2[size(keepresult2)][1];
1581          intvec delti1 = keepresult1[size(keepresult1)][2];
1582          intvec delti2 = keepresult2[size(keepresult2)][2];
1583
1584          if( delt>=0 && delt1>=0 && delt2>=0 )
1585          {  ideal idid1=id,id1;
1586             int mul = vdim(std(idid1));
1587             if ( mul>=0 )
1588             {
1589               delt = delt+mul+delt1+delt2;
1590             }
1591             else
1592             {
1593               delt = -1;
1594             }
1595          }
1596         if ( y>=1 )
1597         {
1598           "// delta of first component:", delt1;
1599           "// delta of second componenet:", delt2;
1600           "// intersection multiplicity of both components:", mul;
1601           "// total delta after splitting:", delt;
1602         }
1603
1604          else
1605          {
1606            delt = -1;
1607          }
1608          for(lauf=1;lauf<=size(keepresult2)-1;lauf++)
1609          {
1610             keepresult1=insert(keepresult1,keepresult2[lauf]);
1611          }
1612          keepresult1[size(keepresult1)]=list(delt,delti);
1613
1614          return(keepresult1);
1615       }
1616   }
1617   // Case "onlySingularAtZero" has finished and returned result
1618
1619//-------------- General case, not onlySingularAtZero, RETURN ---------------
1620   //test for non-normality, i.e. if Hom(I,I)<>R
1621   //we can use Hom(I,I) to continue
1622
1623   //------ check variables for being a non zero-divizor ------
1624   // SL = ideal of vars not contained in ideal SM[1]:
1625
1626   ideal SL = simplify(reduce(JM[2],SM[1]),2);
1627   ideal Ann = quotient(SM[2],SL[1]);
1628   ideal qAnn = simplify(reduce(Ann,SM[1]),2);
1629   //NOTE: qAnn=0 <==> first var (=SL[1]) not contained in SM is a nzd of R/SM
1630
1631   //------------- We found a non-zerodivisor of R/SM -----------------------
1632   //SM = mstd of ideal of variety, JM = mstd of ideal of singular locus
1633
1634   if( size(qAnn)==0 )
1635   {
1636      list RR;
1637      list RS;
1638      // ----------------- Computation of the radical -----------------
1639      if(y>=1)
1640      {
1641         "// radical computation of singular locus";
1642      }
1643      J = radical(JM[2]);   //the radical of singular locus
1644      JM = mstd(J);
1645
1646      if(y>=1)
1647      {
1648        "// radical is equal to:";"";  JM[2];
1649        "";
1650      }
1651      // ------------ choose non-zerodivisor of smaller degree ----------
1652      //### evtl. fuer SL[1] anderen Nichtnullteiler aus J waehlen ?
1653      if( deg(SL[1]) > deg(J[1]) )
1654      {
1655         Ann=quotient(SM[2],J[1]);
1656         qAnn=simplify(reduce(Ann,SM[1]),2);
1657         if(size(qAnn)==0)
1658         {
1659           SL[1]=J[1];
1660         }
1661      }
1662
1663      // --------------- computation of Hom(rad(J),rad(J)) --------------
1664      RR=SM[1],SM[2],JM[2],SL[1];
1665
1666     if(y>=1)
1667     {
1668        "// compute Hom(rad(J),rad(J))";
1669     }
1670
1671     RS=HomJJ(RR,y);               //most important subprocedure
1672
1673     // ------------------ the normal case, RETURN -----------------
1674     // RS[2]==1 means that the test for normality was positive
1675     if(RS[2]==1)
1676     {
1677         def lastR=RS[1];
1678         setring lastR;
1679         map psi1=BAS,endphi;
1680         ideal norid=endid;
1681         ideal normap=psi1(ihp);
1682         kill endid,endphi;
1683
1684        intvec atr=getAttrib(norid);
1685
1686        //"//### general case: not isolated singularity only at 0, final";
1687        //"size norid:", size(norid), size(string(norid));
1688        //"interred:";
1689        //norid = interred(norid);
1690        //norid = setAttrib(norid,atr);
1691        //"size norid:", size(norid), size(string(norid));
1692
1693         export norid;
1694         export normap;
1695         result=lastR;
1696         if ( y>=1 )
1697         {
1698            "// case: not onlySingularAtZero, last ring Hom_R(J,J) computed";
1699            "// delta before last ring:", delt;
1700         }
1701
1702         if ( delt>=0 && RS[3]>=0 )
1703         {
1704            delt = delt+RS[3];
1705         }
1706         else
1707         { delt = -1; }
1708
1709        // delti = delti,delt;
1710         delti[size(delti)]=delt;
1711
1712         if ( y>=1 )
1713         {
1714           "// delta of last ring:", delt;
1715         }
1716
1717         result[size(result)+1]=list(delt,delti);
1718         setring BAS;
1719         return(result);
1720     }
1721
1722    // ----- the non-normal case, recursive call of normalizationPrimes -------
1723    // RS=HomJJ(RR,y) was computed above, RS[1] contains endid and endphi
1724    // RS[1] = new ring Hom_R(J,J), RS[2]= 0 or 1, RS[2]=contribution to delta
1725    // now RS[2]must be 0, i.e. the test for normality was negative
1726
1727      int n = nvars(basering);
1728      ideal MJ = JM[2];
1729
1730      def newR=RS[1];
1731      setring newR;
1732      map psi=BAS,endphi;
1733      if ( y>=1 )
1734      {
1735        "// case: not onlySingularAtZero, compute new ring = Hom_R(J,J)";
1736        "// delta of old ring:", delt;
1737      }
1738      if ( delt>=0 && RS[3]>=0 )
1739      {
1740         delt = delt+RS[3];
1741      }
1742      else
1743      { delt = -1; }
1744      if ( y>=1 )
1745      {
1746        "// delta of new ring:", delt;
1747      }
1748
1749      delti[size(delti)]=delt;
1750      intvec atr=getAttrib(endid);
1751
1752      //"//### general case: not isolated singularity only at 0, recursive";
1753      //"size endid:", size(endid), size(string(endid));
1754      //"interred:";
1755      //endid = interred(endid);
1756      //endid = setAttrib(endid,atr);
1757      //"size endid:", size(endid), size(string(endid));
1758
1759      printlevel = printlevel+1;
1760      list tluser=
1761          normalizationPrimes(endid,psi(ihp),delt,delti,psi(MJ));
1762      printlevel = printlev;                //reset printlevel
1763      setring BAS;
1764      return(tluser);
1765   }
1766
1767   //---- A whole singular component was found, RETURN -----
1768   if( Ann == 1)
1769   {
1770      "// Input appeared not to be a radical ideal!";
1771      "// A (everywhere singular) component with ideal";
1772      "// equal to its Jacobian ideal was found";
1773      "// Procedure will stop with partial result computed so far";"";
1774
1775         MB=SM[2];
1776         intvec rw;
1777         list LL=substpart(MB,ihp,0,rw);
1778         def newR6=LL[1];
1779         setring newR6;
1780         ideal norid=endid;
1781         ideal normap=endphi;
1782         kill endid,endphi;
1783         export norid;
1784         export normap;
1785         result=newR6;
1786         result[size(result)+1]=lst(delt,delti);
1787         setring BAS;
1788         return(result);
1789   }
1790
1791   //------ zerodivisor of R/SM was found, gives a splitting ------------
1792   //Now the case where qAnn!=0, i.e. SL[1] is a zero divisor of R/SM
1793   //and we have found a splitting: new1 and new2
1794   //id = Ann defines components of R/SM in the complement of V(SL[1])
1795   //id1 defines components of R/SM in the complement of V(id)
1796
1797   else
1798   {
1799      if(y>=1)
1800      {
1801         "// zero-divisor found";
1802      }
1803      int equi = attrib(SM[2],"isEquidimensional");
1804      int oSAZ = attrib(SM[2],"onlySingularAtZero");
1805      int isIs = attrib(SM[2],"isIsolatedSingularity");
1806
1807      ideal new1 = Ann;
1808      ideal new2 = quotient(SM[2],Ann);
1809      //ideal new2=SL[1],SM[2];
1810
1811      //execute("ring newR1="+charstr(basering)+",("+varstr(basering)+"),("
1812      //                +ordstr(basering)+");");
1813      def newR1 = ring(gnirlist);
1814      setring newR1;
1815
1816      ideal vid = fetch(BAS,new1);
1817      ideal ihp = fetch(BAS,ihp);
1818      attrib(vid,"isCohenMacaulay",0);
1819      attrib(vid,"isPrim",0);
1820      attrib(vid,"isIsolatedSingularity",isIs);
1821      attrib(vid,"isRegInCodim2",0);
1822      attrib(vid,"onlySingularAtZero",oSAZ);
1823      attrib(vid,"isEquidimensional",equi);
1824      attrib(vid,"isHypersurface",0);
1825      attrib(vid,"isCompleteIntersection",0);
1826
1827      // ---------- recursive call of normalizationPrimes -----------
1828      if ( y>=1 )
1829      {
1830        "// total delta before splitting:", delt;
1831        "// splitting in two components:";
1832      }
1833      printlevel = printlevel+1;
1834      keepresult1 =
1835                  normalizationPrimes(vid,ihp,0,0);  //1st split factor
1836
1837      list delta1 = keepresult1[size(keepresult1)];
1838
1839      setring BAS;
1840      //execute("ring newR2="+charstr(basering)+",("+varstr(basering)+"),("
1841      //                +ordstr(basering)+");");
1842      def newR2 = ring(gnirlist);
1843      setring newR2;
1844
1845      ideal vid = fetch(BAS,new2);
1846      ideal ihp = fetch(BAS,ihp);
1847      attrib(vid,"isCohenMacaulay",0);
1848      attrib(vid,"isPrim",0);
1849      attrib(vid,"isIsolatedSingularity",isIs);
1850      attrib(vid,"isRegInCodim2",0);
1851      attrib(vid,"isEquidimensional",equi);
1852      attrib(vid,"isHypersurface",0);
1853      attrib(vid,"isCompleteIntersection",0);
1854      attrib(vid,"onlySingularAtZero",oSAZ);
1855
1856      keepresult2 =
1857                    normalizationPrimes(vid,ihp,0,0);
1858      list delta2 = keepresult2[size(keepresult2)];   //2nd split factor
1859      printlevel = printlev;                          //reset printlevel
1860
1861      setring BAS;
1862
1863      //compute intersection multiplicity of both components:
1864      new1 = new1,new2;
1865      int mul=vdim(std(new1));
1866
1867     // ----- normalizationPrimes finished, add up results, RETURN --------
1868      for(lauf=1;lauf<=size(keepresult2)-1;lauf++)
1869      {
1870         keepresult1 = insert(keepresult1,keepresult2[lauf]);
1871      }
1872      if ( delt >=0 && delta1[1] >=0 && delta2[1] >=0 && mul >=0 )
1873      {
1874         delt = delt+mul+delta1[1]+delta2[1];
1875      }
1876      else
1877      {  delt = -1; }
1878      delti = -2;
1879
1880      if ( y>=1 )
1881      {
1882        "// zero divisor produced a splitting into two components";
1883        "// delta of first component:", delta1;
1884        "// delta of second componenet:", delta2;
1885        "// intersection multiplicity of both components:", mul;
1886        "// total delta after splitting:", delt;
1887      }
1888      keepresult1[size(keepresult1)] = list(delt,delti);
1889      return(keepresult1);
1890   }
1891}
1892example
1893{ "EXAMPLE:";echo = 2;
1894   // Huneke
1895   ring qr=31991,(a,b,c,d,e),dp;
1896   ideal i=
1897   5abcde-a5-b5-c5-d5-e5,
1898   ab3c+bc3d+a3be+cd3e+ade3,
1899   a2bc2+b2cd2+a2d2e+ab2e2+c2de2,
1900   abc5-b4c2d-2a2b2cde+ac3d2e-a4de2+bcd2e3+abe5,
1901   ab2c4-b5cd-a2b3de+2abc2d2e+ad4e2-a2bce3-cde5,
1902   a3b2cd-bc2d4+ab2c3e-b5de-d6e+3abcd2e2-a2be4-de6,
1903   a4b2c-abc2d3-ab5e-b3c2de-ad5e+2a2bcde2+cd2e4,
1904   b6c+bc6+a2b4e-3ab2c2de+c4d2e-a3cde2-abd3e2+bce5;
1905
1906   list pr=normalizationPrimes(i);
1907   def r1 = pr[1];
1908   setring r1;
1909   norid;
1910   normap;
1911}
1912
1913///////////////////////////////////////////////////////////////////////////////
1914static proc substpart(ideal endid, ideal endphi, int homo, intvec rw)
1915
1916"//Repeated application of elimpart to endid, until no variables can be
1917//directy substituded. homo=1 if input is homogeneous, rw contains
1918//original weights, endphi (partial) normalization map";
1919
1920//NOTE concerning iteration of maps: Let phi: x->f(y,z), y->g(x,z) then
1921//phi: x+y+z->f(y,z)+g(x,z)+z, phi(phi):x+y+z->f(g(x,z),z)+g(f(y,z),z)+z
1922//and so on: none of the x or y will be eliminated
1923//Now subst: first x and then y: x+y+z->f(g(x,z),z)+g(x,z)+z eliminates y
1924//further subst replaces x by y, makes no sense (objects more compicated).
1925//Subst first y and then x eliminates x
1926//In our situation we have triangular form: x->f(y,z), y->g(z).
1927//phi: x+y+z->f(y,z)+g(z)+z, phi(phi):x+y+z->f(g(z),z)+g(z)+z eliminates x,y
1928//subst x,y: x+y+z->f(g(z),z)+g(z)+z, eliminates x,y
1929//subst y,x: x+y+z->f(y,z)+g(z)+z eliminates only x
1930//HENCE: substitute vars depending on most other vars first
1931//However, if the sytem xi-fi is reduced then xi does not appear in any of the
1932//fj and hence the order does'nt matter when substitutinp xi by fi
1933
1934{
1935   def newRing = basering;
1936   int ii,jj;
1937   map phi = newRing,maxideal(1);    //identity map
1938   list Le = elimpart(endid);
1939   //this proc and the next loop try to substitute as many variables as
1940   //possible indices of substituted variables
1941
1942   int q = size(Le[2]);    //q vars, stored in Le[2], have been substitutet
1943   intvec rw1 = 0;         //will become indices of substituted variables
1944   rw1[nvars(basering)] = 0;
1945   rw1 = rw1+1;            //rw1=1,..,1 (as many 1 as nvars(basering))
1946
1947   while( size(Le[2]) != 0 )
1948   {
1949      endid = Le[1];
1950      if ( defined(ps) )
1951      { kill ps; }
1952      map ps = newRing,Le[5];
1953      phi = ps(phi);
1954      for(ii=1;ii<=size(Le[2]);ii++)
1955      {
1956         phi=phi(phi);
1957      }
1958      //eingefuegt wegen x2-y2z2+z3
1959
1960      for( ii=1; ii<=size(rw1); ii++ )
1961      {
1962         if( Le[4][ii]==0 )        //ii = index of var which was substituted
1963         {
1964            rw1[ii]=0;             //substituted vars have entry 0 in rw1
1965         }
1966      }
1967      Le=elimpart(endid);          //repeated application of elimpart
1968      q = q + size(Le[2]);
1969   }
1970   endphi = phi(endphi);
1971//---------- return -----------------------------------------------------------
1972// first the trivial case, where all variable have been eliminated
1973   if( nvars(newRing) == q )
1974   {
1975     ring lastRing = char(basering),T(1),dp;
1976     ideal endid = T(1);
1977     ideal endphi = T(1);
1978     for(ii=2; ii<=q; ii++ )
1979     {
1980        endphi[ii] = 0;
1981     }
1982     export(endid,endphi);
1983     list L = lastRing;
1984     setring newRing;
1985     return(L);
1986   }
1987
1988// in the homogeneous case put weights for the remaining vars correctly, i.e.
1989// delete from rw those weights for which the corresponding entry of rw1 is 0
1990
1991   if (homo==1 && nvars(newRing)-q >1 && size(endid) >0 )
1992   {
1993      jj=1;
1994      for( ii=2; ii<size(rw1); ii++)
1995      {
1996         jj++;
1997         if( rw1[ii]==0 )
1998         {
1999            rw=rw[1..jj-1],rw[jj+1..size(rw)];
2000            jj=jj-1;
2001         }
2002      }
2003      if( rw1[1]==0 ) { rw=rw[2..size(rw)]; }
2004      if( rw1[size(rw1)]==0 ){ rw=rw[1..size(rw)-1]; }
2005
2006      ring lastRing = char(basering),(T(1..nvars(newRing)-q)),(a(rw),dp);
2007   }
2008   else
2009   {
2010      ring lastRing = char(basering),(T(1..nvars(newRing)-q)),dp;
2011   }
2012   ideal lastmap;
2013   jj = 1;
2014
2015   for(ii=1; ii<=size(rw1); ii++ )
2016   {
2017      if ( rw1[ii]==1 ) { lastmap[ii] = T(jj); jj=jj+1; }
2018      if ( rw1[ii]==0 ) { lastmap[ii] = 0; }
2019   }
2020   map phi1 = newRing,lastmap;
2021   ideal endid  = phi1(endid);      //### bottelneck
2022   ideal endphi = phi1(endphi);
2023
2024/*
2025Versuch: subst statt phi
2026   for(ii=1; ii<=size(rw1); ii++ )
2027   {
2028      if ( rw1[ii]==1 ) { endid = subst(endid,var(ii),T(jj)); }
2029      if ( rw1[ii]==0 ) { endid = subst(endid,var(ii),0); }
2030   }
2031*/
2032   export(endid);
2033   export(endphi);
2034   list L = lastRing;
2035   setring newRing;
2036   return(L);
2037}
2038///////////////////////////////////////////////////////////////////////////////
2039
2040proc genus(ideal I,list #)
2041"USAGE:   genus(i) or genus(i,1); I a 1-dimensional ideal
2042RETURN:  an integer, the geometric genus p_g = p_a - delta of the projective
2043         curve defined by i, where p_a is the arithmetic genus.
2044NOTE:    delta is the sum of all local delta-invariants of the singularities,
2045         i.e. dim(R'/R), R' the normalization of the local ring R of the
2046         singularity. @*
2047         genus(i,1) uses the normalization to compute delta. Usually genus(i,1)
2048         is slower than genus(i) but sometimes not.
2049EXAMPLE: example genus; shows an example
2050"
2051{
2052   int w = printlevel-voice+2;  // w=printlevel (default: w=0)
2053
2054   def R0=basering;
2055   I=std(I);
2056   if(dim(I)!=1)
2057   {
2058      if(((homog(I))&&(dim(I)!=2))||(!homog(I)))
2059      {
2060        // ERROR("This is not a curve");
2061        if(w==1){"** WARNING: Input does not define a curve **"; "";}
2062      }
2063   }
2064   list L=elimpart(I);
2065   if(size(L[2])!=0)
2066   {
2067      map psi=R0,L[5];
2068      I=std(psi(I));
2069   }
2070   if(size(I)==0)
2071   {
2072      return(0);
2073   }
2074   list N=findvars(I,0);
2075   if(size(N[1])==1)
2076   {
2077
2078      poly p=I[1];
2079     // if(deg(squarefree(p))<deg(p)){ERROR("Curve is not reduced");}
2080      return(-deg(p)+1);
2081   }
2082   if(size(N[1]) < nvars(R0))
2083   {
2084      string newvar=string(N[1]);
2085      execute("ring R=("+charstr(R0)+"),("+newvar+"),dp;");
2086      ideal I =imap(R0,I);
2087      attrib(I,"isSB",1);
2088   }
2089   else
2090   {
2091      def R=basering;
2092   }
2093   if(dim(I)==2)
2094   {
2095      def newR=basering;
2096   }
2097   else
2098   {
2099      if(dim(I)==0)
2100      {
2101         execute("ring Rhelp=("+charstr(R0)+"),(@s,@t),dp;");
2102      }
2103      else
2104      {
2105         execute("ring Rhelp=("+charstr(R0)+"),(@s),dp;");
2106      }
2107      def newR=R+Rhelp;
2108      setring newR;
2109      ideal I=imap(R,I);
2110      I=homog(I,@s);
2111      attrib(I,"isSB",1);
2112   }
2113
2114   if((nvars(basering)<=3)&&(size(I)>1))
2115   {
2116       ERROR("This is not equidimensional");
2117   }
2118
2119   intvec hp=hilbPoly(I);
2120   int p_a=1-hp[1];
2121   int d=hp[2];
2122
2123   if(w>=1)
2124   {
2125      "";"The ideal of the projective curve:";"";I;"";
2126      "The coefficients of the Hilbert polynomial";hp;
2127      "arithmetic genus:";p_a;
2128      "degree:";d;"";
2129   }
2130
2131   intvec v = hilb(I,1);
2132   int i,o;
2133   if(nvars(basering)>3)
2134   {
2135      map phi=newR,maxideal(1);
2136      int de;
2137      ideal K,L1;
2138      matrix M;
2139      poly m=var(4);
2140      poly he;
2141      for(i=5;i<=nvars(basering);i++){m=m*var(i);}
2142      K=eliminate(I,m,v);
2143      if(size(K)==1){de=deg(K[1]);}
2144      m=var(1);
2145      for(i=2;i<=nvars(basering)-3;i++){m=m*var(i);}
2146      i=0;
2147      while(d!=de)
2148      {
2149         o=1;
2150         i++;
2151         K=phi(I);
2152         K=eliminate(K,m,v);
2153         if(size(K)==1){de=deg(K[1]);}
2154         if((i==5)&&(d!=de))
2155         {
2156            K=reduce(equidimMax(I),I);
2157            if(size(K)!=0){ERROR("This is not equidimensional");}
2158         }
2159         if(i==10)
2160         {
2161            J;K;
2162            ERROR("genus: did not find a good projection for to
2163                           the plain");
2164         }
2165         if(i<5)
2166         {
2167            M=sparsetriag(nvars(newR),nvars(newR),80-5*i,i);
2168         }
2169         else
2170         {
2171            if(i<8)
2172            {
2173               M=transpose(sparsetriag(nvars(newR),nvars(newR),80-5*i,i));
2174            }
2175            else
2176            {
2177               he=0;
2178               while(he==0)
2179               {
2180                  M=randommat(nvars(newR),nvars(newR),ideal(1),20);
2181                  he=det(M);
2182               }
2183            }
2184         }
2185         L1=M*transpose(maxideal(1));
2186         phi=newR,L1;
2187      }
2188      I=K;
2189   }
2190   poly p=I[1];
2191
2192   execute("ring S=("+charstr(R)+"),(x,y,t),dp;");
2193   ideal L=maxideal(1);
2194   execute("ring C=("+charstr(R)+"),(x,y),ds;");
2195   ideal I;
2196   execute("ring A=("+charstr(R)+"),(x,t),dp;");
2197   map phi=S,1,x,t;
2198   map psi=S,x,1,t;
2199   poly g,h;
2200   ideal I,I1;
2201   execute("ring B=("+charstr(R)+"),(x,t),ds;");
2202
2203   setring S;
2204   if(o)
2205   {
2206     for(i=1;i<=nvars(newR)-3;i++){L[i]=0;}
2207     L=L,maxideal(1);
2208   }
2209   map sigma=newR,L;
2210   poly F=sigma(p);
2211   if(w>=1){"the projected curve:";"";F;"";}
2212
2213   kill newR;
2214
2215   int genus=(d-1)*(d-2)/2;
2216   if(w>=1){"the arithmetic genus of the plane curve:";genus;pause();}
2217
2218   int delt,deltaloc,deltainf,tau,tauinf,cusps,iloc,iglob,l,nsing,
2219       tauloc,tausing,k,rat,nbranchinf,nbranch,nodes,cuspsinf,nodesinf;
2220   list inv;
2221
2222   if(w>=1)
2223     {"";"analyse the singularities at oo";"";"singular locus at (1,x,0):";"";}
2224   setring A;
2225   g=phi(F);
2226   h=psi(F);
2227   I=g,jacob(g),var(2);
2228   I=std(I);
2229   if(deg(I[1])>0)
2230   {
2231      list qr=minAssGTZ(I);
2232      if(w>=1){qr;"";}
2233
2234      for(k=1;k<=size(qr);k++)
2235      {
2236         if(w>=1){ nsing=nsing+vdim(std(qr[k]));}
2237         inv=deltaLoc(g,qr[k]);
2238         deltainf=deltainf+inv[1];
2239         tauinf=tauinf+inv[2];
2240         l=vdim(std(qr[k]));
2241         if(inv[2]==l){nodesinf=nodesinf+l;}
2242         if(inv[2]==2*l){cuspsinf=cuspsinf+l;}
2243         nbranchinf=nbranchinf+inv[3];
2244      }
2245   }
2246   else
2247   {
2248     if(w>=1){"            the curve is smooth at (1,x,0)";"";}
2249   }
2250   if(w>=1){"singular locus at (0,1,0):";"";}
2251   inv=deltaLoc(h,maxideal(1));
2252   if((w>=1)&&(inv[2]!=0)){ nsing++;}
2253   deltainf=deltainf+inv[1];
2254   tauinf=tauinf+inv[2];
2255   if(inv[2]==1){nodesinf++;}
2256   if(inv[2]==2){cuspsinf++;}
2257
2258   if((w>=1)&&(inv[2]==0)){"            the curve is smooth at (0,1,0)";"";}
2259   if(inv[2]>0){nbranchinf=nbranchinf+inv[3];}
2260
2261   if(w>=1)
2262   {
2263      if(tauinf==0)
2264      {
2265        "            the curve is smooth at oo";"";
2266      }
2267      else
2268      {
2269         "number of singularities at oo:";nsing;
2270         "nodes at oo:";nodesinf;
2271         "cusps at oo:";cuspsinf;
2272         "branches at oo:";nbranchinf;
2273         "Tjurina number at oo:";tauinf;
2274         "delta at oo:";deltainf;
2275         "Milnor number at oo:";2*deltainf-nbranchinf+nsing;
2276         pause();
2277      }
2278      "singularities at (x,y,1):";"";
2279   }
2280   execute("ring newR=("+charstr(R)+"),(x,y),dp;");
2281   //the singularities at the affine part
2282   map sigma=S,var(1),var(2),1;
2283   ideal I=sigma(F);
2284
2285   if(size(#)!=0)
2286   {                              //uses the normalization to compute delta
2287      list nor=normal(I);
2288      delt=nor[size(nor)][2];
2289      genus=genus-delt-deltainf;
2290      setring R0;
2291      return(genus);
2292   }
2293
2294   ideal I1=jacob(I);
2295   matrix Hess[2][2]=jacob(I1);
2296   ideal ID=I+I1+ideal(det(Hess));//singular locus of I+I1
2297
2298   ideal radID=std(radical(ID));//the non-nodal locus
2299   if(w>=1){"the non-nodal locus:";"";radID;pause();"";}
2300   if(deg(radID[1])==0)
2301   {
2302     ideal IDsing=1;
2303   }
2304   else
2305   {
2306     ideal IDsing=minor(jacob(ID),2)+radID;//singular locus of ID
2307   }
2308
2309   iglob=vdim(std(IDsing));
2310
2311   if(iglob!=0)//computation of the radical of IDsing
2312   {
2313      ideal radIDsing=reduce(IDsing,radID);
2314      if(size(radIDsing)==0)
2315      {
2316         radIDsing=radID;
2317         attrib(radIDsing,"isSB",1);
2318      }
2319      else
2320      {
2321         radIDsing=std(radical(IDsing));
2322      }
2323      iglob=vdim(radIDsing);
2324      if((w>=1)&&(iglob))
2325          {"the non-nodal-cuspidal locus:";radIDsing;pause();"";}
2326   }
2327   cusps=vdim(radID)-iglob;
2328   nsing=nsing+cusps;
2329
2330   if(iglob==0)
2331   {
2332      if(w>=1){"             there are only cusps and nodes";"";}
2333      tau=vdim(std(I+jacob(I)));
2334      tauinf=tauinf+tau;
2335      nodes=tau-2*cusps;
2336      delt=nodes+cusps;
2337      nbranch=2*tau-3*cusps;
2338      nsing=nsing+nodes;
2339   }
2340   else
2341   {
2342       if(w>=1){"the non-nodal-cuspidal singularities";"";}
2343       setring C;
2344       ideal I1=imap(newR,IDsing);
2345       iloc=vdim(std(I1));
2346       if(iglob==iloc)
2347       {
2348          if(w>=1){"only cusps and nodes outside (0,0,1)";}
2349          setring newR;
2350          tau=vdim(std(I+jacob(I)));
2351          tauinf=tauinf+tau;
2352          inv=deltaLoc(I[1],maxideal(1));
2353          delt=inv[1];
2354          tauloc=inv[2];
2355          nodes=tau-tauloc-2*cusps;
2356          nsing=nsing+nodes;
2357          nbranch=inv[3]+ 2*nodes+cusps;
2358          delt=delt+nodes+cusps;
2359          if((w>=1)&&(inv[2]==0)){"smooth at (0,0,1)";}
2360        }
2361        else
2362        {
2363           setring newR;
2364           list pr=minAssGTZ(IDsing);
2365           if(w>=1){pr;}
2366
2367           for(k=1;k<=size(pr);k++)
2368           {
2369              if(w>=1){nsing=nsing+vdim(std(pr[k]));}
2370              inv=deltaLoc(I[1],pr[k]);
2371              delt=delt+inv[1];
2372              tausing=tausing+inv[2];
2373              nbranch=nbranch+inv[3];
2374           }
2375           tau=vdim(std(I+jacob(I)));
2376           tauinf=tauinf+tau;
2377           nodes=tau-tausing-2*cusps;
2378           nsing=nsing+nodes;
2379           delt=delt+nodes+cusps;
2380           nbranch=nbranch+2*nodes+cusps;
2381        }
2382   }
2383   genus=genus-delt-deltainf;
2384   if(w>=1)
2385   {
2386      "The projected plane curve has locally:";"";
2387      "singularities:";nsing;
2388      "branches:";nbranch+nbranchinf;
2389      "nodes:"; nodes+nodesinf;
2390      "cusps:";cusps+cuspsinf;
2391      "Tjurina number:";tauinf;
2392      "Milnor number:";2*(delt+deltainf)-nbranch-nbranchinf+nsing;
2393      "delta of the projected curve:";delt+deltainf;
2394      "delta of the curve:";p_a-genus;
2395      "genus:";genus;
2396      "====================================================";
2397      "";
2398   }
2399   setring R0;
2400   return(genus);
2401}
2402example
2403{ "EXAMPLE:"; echo = 2;
2404   ring r=0,(x,y),dp;
2405   ideal i=y^9 - x^2*(x - 1)^9;
2406   genus(i);
2407}
2408
2409///////////////////////////////////////////////////////////////////////////////
2410proc deltaLoc(poly f,ideal singL)
2411"USAGE:  deltaLoc(f,J);  f poly, J ideal
2412ASSUME: f is reduced bivariate polynomial; basering has exactly two variables;
2413        J is irreducible prime component of the singular locus of f (e.g., one
2414        entry of the output of @code{minAssGTZ(I);}, I = <f,jacob(f)>).
2415RETURN:  list L:
2416@texinfo
2417@table @asis
2418@item @code{L[1]}; int:
2419         the sum of (local) delta invariants of f at the (conjugated) singular
2420         points given by J.
2421@item @code{L[2]}; int:
2422         the sum of (local) Tjurina numbers of f at the (conjugated) singular
2423         points given by J.
2424@item @code{L[3]}; int:
2425         the sum of (local) number of branches of f at the (conjugated)
2426         singular points given by J.
2427@end table
2428@end texinfo
2429NOTE:    procedure makes use of @code{execute}; increasing printlevel displays
2430         more comments (default: printlevel=0).
2431SEE ALSO: delta, tjurina
2432KEYWORDS: delta invariant; Tjurina number
2433EXAMPLE: example deltaLoc;  shows an example
2434"
2435{
2436   option(redSB);
2437   def R=basering;
2438   execute("ring S=("+charstr(R)+"),(x,y),lp;");
2439   map phi=R,x,y;
2440   ideal singL=phi(singL);
2441   singL=simplify(std(singL),1);
2442   attrib(singL,"isSB",1);
2443   int d=vdim(singL);
2444   poly f=phi(f);
2445   int i;
2446   int w = printlevel-voice+2;  // w=printlevel (default: w=0)
2447   if(d==1)
2448   {
2449      map alpha=S,var(1)-singL[2][2],var(2)-singL[1][2];
2450      f=alpha(f);
2451      execute("ring C=("+charstr(S)+"),("+varstr(S)+"),ds;");
2452      poly f=imap(S,f);
2453      ideal singL=imap(S,singL);
2454      if((w>=1)&&(ord(f)>=2))
2455      {
2456        "local analysis of the singularities";"";
2457        basering;
2458        singL;
2459        f;
2460        pause();
2461      }
2462   }
2463   else
2464   {
2465      poly p;
2466      poly c;
2467      map psi;
2468      number co;
2469
2470      while((deg(lead(singL[1]))>1)&&(deg(lead(singL[2]))>1))
2471      {
2472         psi=S,x,y+random(-100,100)*x;
2473         singL=psi(singL);
2474         singL=std(singL);
2475          f=psi(f);
2476      }
2477
2478      if(deg(lead(singL[2]))==1)
2479      {
2480         p=singL[1];
2481         c=singL[2]-lead(singL[2]);
2482         co=leadcoef(singL[2]);
2483      }
2484      if(deg(lead(singL[1]))==1)
2485      {
2486         psi=S,y,x;
2487         f=psi(f);
2488         singL=psi(singL);
2489         p=singL[2];
2490         c=singL[1]-lead(singL[1]);
2491         co=leadcoef(singL[1]);
2492      }
2493
2494      execute("ring B=("+charstr(S)+"),a,dp;");
2495      map beta=S,a,a;
2496      poly p=beta(p);
2497
2498      execute("ring C=("+charstr(S)+",a),("+varstr(S)+"),ds;");
2499      number p=number(imap(B,p));
2500
2501      minpoly=p;
2502      map iota=S,a,a;
2503      number c=number(iota(c));
2504      number co=iota(co);
2505
2506      map alpha=S,x-c/co,y+a;
2507      poly f=alpha(f);
2508      f=cleardenom(f);
2509      if((w>=1)&&(ord(f)>=2))
2510      {
2511        "local analysis of the singularities";"";
2512        basering;
2513        alpha;
2514        f;
2515        pause();
2516        "";
2517      }
2518   }
2519   option(noredSB);
2520   ideal fstd=std(ideal(f)+jacob(f));
2521   poly hc=highcorner(fstd);
2522   int tau=vdim(fstd);
2523   int o=ord(f);
2524   int delt,nb;
2525
2526   if(tau==0)                 //smooth case
2527   {
2528      setring R;
2529      return(list(0,0,1));
2530   }
2531   if((char(basering)>=181)||(char(basering)==0))
2532   {
2533      if(o==2)                //A_k-singularity
2534      {
2535        if(w>=1){"A_k-singularity";"";}
2536         setring R;
2537         delt=(tau+1)/2;
2538         return(list(d*delt,d*tau,d*(2*delt-tau+1)));
2539      }
2540      if((lead(f)==var(1)*var(2)^2)||(lead(f)==var(1)^2*var(2)))
2541      {
2542        if(w>=1){"D_k- singularity";"";}
2543
2544         setring R;
2545         delt=(tau+2)/2;
2546         return(list(d*delt,d*tau,d*(2*delt-tau+1)));
2547      }
2548
2549      int mu=vdim(std(jacob(f)));
2550      poly g=f+var(1)^mu+var(2)^mu;  //to obtain a convenient Newton-polygon
2551
2552      list NP=newtonpoly(g);
2553      if(w>=1){"Newton-Polygon:";NP;"";}
2554      int s=size(NP);
2555
2556      if(is_NND(f,mu,NP))
2557      { // the Newton-polygon is non-degenerate
2558        // compute nb, the number of branches
2559        for(i=1;i<=s-1;i++)
2560        {
2561          nb=nb+gcd(NP[i][2]-NP[i+1][2],NP[i][1]-NP[i+1][1]);
2562        }
2563        if(w>=1){"Newton-Polygon is non-degenerated";"";}
2564        return(list(d*(mu+nb-1)/2,d*tau,d*nb));
2565      }
2566
2567      if(w>=1){"Newton-Polygon is degenerated";"";}
2568
2569      // the following can certainly be made more efficient when replacing
2570      // 'hnexpansion' (used only for computing number of branches) by
2571      // successive blowing-up + test if Newton polygon degenerate:
2572      if(s>2)    //  splitting of f
2573      {
2574         if(w>=1){"Newton polygon can be used for splitting";"";}
2575         intvec v=NP[1][2]-NP[2][2],NP[2][1];
2576         int de=w_deg(g,v);
2577         int st=w_deg(hc,v)+v[1]+v[2];
2578         poly f1=var(2)^NP[2][2];
2579         poly f2=jet(g,de,v)/var(2)^NP[2][2];
2580         poly h=g-f1*f2;
2581         de=w_deg(h,v);
2582         poly k;
2583         ideal wi=var(2)^NP[2][2],f2;
2584         matrix li;
2585         while(de<st)
2586         {
2587           k=jet(h,de,v);
2588           li=lift(wi,k);
2589           f1=f1+li[2,1];
2590           f2=f2+li[1,1];
2591           h=g-f1*f2;
2592           de=w_deg(h,v);
2593         }
2594         nb=deltaLoc(f1,maxideal(1))[3]+deltaLoc(f2,maxideal(1))[3];
2595         setring R;
2596         return(list(d*(mu+nb-1)/2,d*tau,d*nb));
2597      }
2598
2599      f=jet(f,deg(hc)+2);
2600      if(w>=1){"now we have to use Hamburger-Noether (Puiseux) expansion";}
2601      ideal fac=factorize(f,1);
2602      if(size(fac)>1)
2603      {
2604         nb=0;
2605         for(i=1;i<=size(fac);i++)
2606         {
2607            nb=nb+deltaLoc(fac[i],maxideal(1))[3];
2608         }
2609         setring R;
2610         return(list(d*(mu+nb-1)/2,d*tau,d*nb));
2611      }
2612      list HNEXP=hnexpansion(f);
2613      if (typeof(HNEXP[1])=="ring") {
2614        def altring = basering;
2615        def HNEring = HNEXP[1]; setring HNEring;
2616        nb=size(hne);
2617        setring R;
2618        kill HNEring;
2619      }
2620      else
2621      {
2622        nb=size(HNEXP);
2623      }
2624      return(list(d*(mu+nb-1)/2,d*tau,d*nb));
2625   }
2626   else             //the case of small characteristic
2627   {
2628      f=jet(f,deg(hc)+2);
2629      if(w>=1){"now we have to use Hamburger-Noether (Puiseux) expansion";}
2630      delt=delta(f);
2631      return(list(d*delt,d*tau,d));
2632   }
2633}
2634example
2635{ "EXAMPLE:"; echo = 2;
2636  ring r=0,(x,y),dp;
2637  poly f=(x2+y^2-1)^3 +27x2y2;
2638  ideal I=f,jacob(f);
2639  I=std(I);
2640  list qr=minAssGTZ(I);
2641  size(qr);
2642  // each component of the singular locus either describes a cusp or a pair
2643  // of conjugated nodes:
2644  deltaLoc(f,qr[1]);
2645  deltaLoc(f,qr[2]);
2646  deltaLoc(f,qr[3]);
2647  deltaLoc(f,qr[4]);
2648  deltaLoc(f,qr[5]);
2649  deltaLoc(f,qr[6]);
2650}
2651///////////////////////////////////////////////////////////////////////////////
2652// compute the weighted degree of p
2653static proc w_deg(poly p, intvec v)
2654{
2655   if(p==0){return(-1);}
2656   int d=0;
2657   while(jet(p,d,v)==0){d++;}
2658   d=(transpose(leadexp(jet(p,d,v)))*v)[1];
2659   return(d);
2660}
2661
2662//proc hilbPoly(ideal J)
2663//{
2664//   poly hp;
2665//   int i;
2666//   if(!attrib(J,"isSB")){J=std(J);}
2667//   intvec v = hilb(J,2);
2668//   for(i=1; i<=size(v); i++){ hp=hp+v[i]*(var(1)-i+2);}
2669//   return(hp);
2670//}
2671
2672
2673//////////////////////////////////////////////////////////////////////////////
2674
2675proc primeClosure (list L, list #)
2676"USAGE:    primeClosure(L [,c]); L a list of a ring containing a prime ideal
2677                                 ker, c an optional integer
2678RETURN:   a list L (of size n+1) consisting of rings L[1],...,L[n] such that
2679          - L[1] is a copy of (not a reference to!) the input ring L[1]
2680          - all rings L[i] contain ideals ker, L[2],...,L[n] contain ideals phi
2681            such that
2682                    L[1]/ker --> ... --> L[n]/ker
2683            are injections given by the corresponding ideals phi, and L[n]/ker
2684            is the integral closure of L[1]/ker in its quotient field.
2685          - all rings L[i] contain a polynomial nzd such that elements of
2686            L[i]/ker are quotients of elements of L[i-1]/ker with denominator
2687            nzd via the injection phi.
2688            L[n+1] is the delta invariant
2689NOTE:     - L is constructed by recursive calls of primeClosure itself.
2690          - c determines the choice of nzd:
2691               - c not given or equal to 0: first generator of the ideal SL,
2692                 the singular locus of Spec(L[i]/ker)
2693               - c<>0: the generator of SL with least number of monomials.
2694EXAMPLE:  example primeClosure; shows an example
2695"
2696{
2697  //---- Start with a consistency check:
2698
2699  if (!(typeof(L[1])=="ring"))
2700  {
2701      "// Parameter must be a ring or a list containing a ring!";
2702      return(-1);
2703  }
2704
2705  int dblvl = printlevel-voice+2;
2706  list gnirlist = ringlist(basering);
2707
2708  //---- Some auxiliary variables:
2709  int delt;                      //finally the delta invariant
2710  if ( size(L) == 1 )
2711  {
2712      L[2] = delt;              //set delta to 0
2713  }
2714  int n = size(L)-1;            //L without delta invariant
2715
2716  //---- How to choose the non-zerodivisor later on?
2717
2718  int nzdoption=0;
2719  if (size(#)>0)
2720  {
2721      nzdoption=#[1];
2722  }
2723
2724// R0 is the ring to work with, if we are in step one, make a copy of the
2725// input ring, so that all objects are created in the copy, not in the original
2726// ring (therefore a copy, not a reference is defined).
2727
2728  if (n==1)
2729  {
2730      def R = L[1];
2731      list Rlist = ringlist(R);
2732      def BAS = basering;
2733      setring R;
2734      if (!(typeof(ker)=="ideal"))
2735      {
2736          "// No ideal ker in the input ring!";
2737          return (-1);
2738      }
2739      ker=simplify(interred(ker),15);
2740      //execute ("ring R0="+charstr(R)+",("+varstr(R)+"),("+ordstr(R)+");");
2741      // Rlist may be not defined in this new ring, so we define it again.
2742      list Rlist2 = ringlist(R);
2743      def R0 = ring(Rlist2);
2744      setring R0;
2745      ideal ker=fetch(R,ker);
2746
2747      // check whether we compute the normalization of the blow up of
2748      // an isolated singularity at the origin (checked in normalI)
2749
2750      if (typeof(attrib(L[1],"iso_sing_Rees"))=="int")
2751      {
2752        attrib(R0,"iso_sing_Rees",attrib(L[1],"iso_sing_Rees"));
2753      }
2754      L[1]=R0;
2755  }
2756  else
2757  {
2758      def R0 = L[n];
2759      setring R0;
2760  }
2761
2762
2763// In order to apply HomJJ from normal.lib, we need the radical of the singular
2764// locus of ker, J:=rad(ker):
2765
2766   list SM=mstd(ker);
2767
2768// In the first iteration, we have to compute the singular locus "from
2769// scratch".
2770// In further iterations, we can fetch it from the previous one but
2771// have to compute its radical
2772// the next rings R1 contain already the (fetched) ideal
2773
2774  if (n==1)                              //we are in R0=L[1]
2775  {
2776      if (typeof(attrib(R0,"iso_sing_Rees"))=="int")
2777      {
2778        ideal J;
2779        for (int s=1;s<=attrib(R0,"iso_sing_Rees");s++)
2780        {
2781          J=J,var(s);
2782        }
2783        J = J,SM[2];
2784        list JM = mstd(J);
2785      }
2786      else
2787      {
2788        if ( dblvl >= 1 )
2789        {"";
2790           "// compute the singular locus";
2791        }
2792        //### Berechnung des singulŠren Orts geŠndert (ist so schneller)
2793        ideal J = minor(jacob(SM[2]),nvars(basering)-dim(SM[1]),SM[1]);
2794        J = J,SM[2];
2795        list JM = mstd(J);
2796      }
2797
2798      if ( dblvl >= 1 )
2799      {"";
2800         "// dimension of singular locus is", dim(JM[1]);
2801         if (  dblvl >= 2 )
2802         {"";
2803            "// the singular locus is:"; JM[2];
2804         }
2805      }
2806
2807      if ( dblvl >= 1 )
2808      {"";
2809         "// compute radical of singular locus";
2810      }
2811
2812      J = simplify(radical(JM[2]),2);
2813      if ( dblvl >= 1 )
2814      {"";
2815         "// radical of singular locus is:"; J;
2816         pause();
2817      }
2818  }
2819  else
2820  {
2821      if ( dblvl >= 1 )
2822      {"";
2823         "// compute radical of test ideal in ideal of singular locus";
2824      }
2825      J = simplify(radical(J),2);
2826      if ( dblvl >= 1 )
2827      {"";
2828         "// radical of test ideal is:"; J;
2829         pause();
2830      }
2831  }
2832
2833  // having computed the radical J of/in the ideal of the singular locus,
2834  // we now need to pick an element nzd of J;
2835  // NOTE: nzd must be a non-zero divisor mod ker, i.e. not contained in ker
2836
2837  poly nzd = J[1];
2838  poly nzd1 = NF(nzd,SM[1]);
2839  if (nzd1 != 0)
2840  {
2841     if ( deg(nzd)>=deg(nzd1) && size(nzd)>size(nzd1) )
2842     {
2843        nzd = nzd1;
2844     }
2845  }
2846
2847  if (nzdoption || nzd1==0)
2848  {
2849    for (int ii=2;ii<=ncols(J);ii++)
2850    {
2851      nzd1 = NF(J[ii],SM[1]);
2852      if ( nzd1 != 0 )
2853      {
2854        if ( (deg(nzd)>=deg(J[ii])) && (size(nzd)>size(J[ii])) )
2855        {
2856          nzd=J[ii];
2857        }
2858        if ( deg(nzd)>=deg(nzd1) && size(nzd)>size(nzd1) )
2859        {
2860          nzd = nzd1;
2861        }
2862      }
2863    }
2864  }
2865
2866  export nzd;
2867  // In this case we do not eliminate variables, so that the maps
2868  // are well defined.
2869  list RR = SM[1],SM[2],J,nzd,1;
2870
2871  if ( dblvl >= 1 )
2872  {"";
2873     "// compute the first ring extension:";
2874     "RR: ";
2875     RR;
2876  }
2877
2878  list RS = HomJJ(RR);
2879
2880//-------------------------------------------------------------------------
2881// If we've reached the integral closure (as determined by the result of
2882// HomJJ), then we are done, otherwise we have to prepare the next iteration.
2883
2884  if (RS[2]==1)     // we've reached the integral closure, we are still in R0
2885    {
2886      kill J;
2887      if ( n== 1)
2888      {
2889        def R1 = RS[1];
2890        setring R1;
2891        ideal norid, normap = endid, endphi;
2892        kill endid,  endphi;
2893
2894        //"//### case: primeClosure, final";
2895        //"size norid:", size(norid), size(string(norid));
2896        //"interred:";
2897        //norid = interred(norid);
2898        //"size norid:", size(norid), size(string(norid));
2899
2900        export (norid, normap);
2901        L[1] = R1;
2902      }
2903      return(L);
2904    }
2905  else                        // prepare the next iteration
2906    {
2907      if (n==1)               // In the first iteration: keep only the data
2908      {                       // needed later on.
2909         kill RR,SM;
2910         export(ker);
2911      }
2912      if ( dblvl >= 1 )
2913      {"";
2914         "// computing the next ring extension, we are in loop"; n+1;
2915      }
2916
2917      def R1 = RS[1];         // The data of the next ring R1:
2918      delt = RS[3];           // the delta invariant of the ring extension
2919      setring R1;             // keep only what is necessary and kill
2920      ideal ker=endid;        // everything else.
2921      export(ker);
2922      ideal norid=endid;
2923
2924      //"//### case: primeClosure, loop", n+1;
2925      //"size norid:", size(norid), size(string(norid));
2926      //"interred:";
2927      //norid = interred(norid);        //????
2928      //"size norid:", size(norid), size(string(norid));
2929
2930      export(norid);
2931      kill endid;
2932
2933      map phi = R0,endphi;                        // fetch the singular locus
2934      ideal J = mstd(simplify(phi(J)+ker,4))[2];  // ideal J in R1
2935      export(J);
2936      if(n>1)
2937      {
2938         ideal normap=phi(normap);
2939      }
2940      else
2941      {
2942         ideal normap=endphi;
2943      }
2944      export(normap);
2945      kill phi;              // we save phi as ideal, not as map, so that
2946      ideal phi=endphi;      // we have more flexibility in the ring names
2947      kill endphi;           // later on.
2948      export(phi);
2949      L=insert(L,R1,n);       // Add the new ring R1 and go on with the
2950                              // next iteration
2951      if ( L[size(L)] >= 0 && delt >= 0 )
2952      {
2953         delt = L[size(L)] + delt;
2954      }
2955      else
2956      {
2957         delt = -1;
2958      }
2959      L[size(L)] = delt;
2960
2961      if (size(#)>0)
2962      {
2963          return (primeClosure(L,#));
2964      }
2965      else
2966      {
2967          return(primeClosure(L));         // next iteration.
2968      }
2969    }
2970}
2971example
2972{
2973  "EXAMPLE:"; echo=2;
2974  ring R=0,(x,y),dp;
2975  ideal I=x4,y4;
2976  def K=ReesAlgebra(I)[1];        // K contains ker such that K/ker=R[It]
2977  list L=primeClosure(K);
2978  def R(1)=L[1];                  // L[4] contains ker, L[4]/ker is the
2979  def R(4)=L[4];                  // integral closure of L[1]/ker
2980  setring R(1);
2981  R(1);
2982  ker;
2983  setring R(4);
2984  R(4);
2985  ker;
2986}
2987
2988///////////////////////////////////////////////////////////////////////////////
2989
2990proc closureFrac(list L)
2991"USAGE:    closureFrac (L); L a list of size n+1 as in the result of
2992          primeClosure, L[n] contains an additional polynomial f
2993CREATE:   a list fraction of two elements of L[1], such that
2994          f=fraction[1]/fraction[2] via the injections phi L[i]-->L[i+1].
2995EXAMPLE:  example closureFrac; shows an example
2996"
2997{
2998// Define some auxiliary variables:
2999
3000  int n=size(L)-1;
3001  int i,j,k,l;
3002  string mapstr;
3003  for (i=1; i<=n; i++) { def R(i) = L[i]; }
3004
3005// The quotient representing f is computed as in 'closureGenerators' with
3006// the differences that
3007//   - the loop is done twice: for the numerator and for the denominator;
3008//   - the result is stored in the list fraction and
3009//   - we have to make sure that no more objects of the rings R(i) survive.
3010
3011  for (j=1; j<=2; j++)
3012    {
3013      setring R(n);
3014      if (j==1)
3015      {
3016         poly p=f;
3017      }
3018      else
3019      {
3020         p=1;
3021      }
3022
3023      for (k=n; k>1; k--)
3024      {
3025          if (j==1)
3026          {
3027             map phimap=R(k-1),phi;
3028          }
3029
3030          p=p*phimap(nzd);
3031
3032          if (j==2)
3033          {
3034            kill phimap;
3035          }
3036
3037          if (j==1)
3038          {
3039             //### noch abfragen ob Z(i) definiert ist
3040             list gnirlist = ringlist(R(k));
3041             int n2 = size(gnirlist[2]);
3042             int n3 = size(gnirlist[3]);
3043             for( i=1; i<=ncols(phi); i++)
3044             {
3045               gnirlist[2][n2+i] = "Z("+string(i)+")";
3046             }
3047             intvec V;
3048             V[ncols(phi)]=0; V=V+1;
3049             gnirlist[3] = insert(gnirlist[3],list("dp",V),n3-1);
3050             def S(k) = ring(gnirlist);
3051             setring S(k);
3052
3053             //execute ("ring S(k) = "+charstr(R(k))+",("+varstr(R(k))+",
3054             //          Z(1.."+string(ncols(phi))+")),(dp("+string(nvars(R(k)))
3055             //          +"),dp("+string(ncols(phi))+"));");
3056
3057              ideal phi = imap(R(k),phi);
3058              ideal J = imap (R(k),ker);
3059              for (l=1;l<=ncols(phi);l++)
3060              {
3061                  J=J+(Z(l)-phi[l]);
3062              }
3063              J=groebner(J);
3064              poly h=NF(imap(R(k),p),J);
3065          }
3066          else
3067          {
3068              setring S(k);
3069              h=NF(imap(R(k),p),J);
3070              setring R(k);
3071              kill p;
3072          }
3073
3074          setring R(k-1);
3075
3076          if (j==1)
3077          {
3078              ideal maxi;
3079              maxi[nvars(R(k))] = 0;
3080              maxi = maxi,maxideal(1);
3081              map backmap = S(k),maxi;
3082
3083              //mapstr=" map backmap = S(k),";
3084              //for (l=1;l<=nvars(R(k));l++)
3085              //{
3086              //  mapstr=mapstr+"0,";
3087              //}
3088              //execute (mapstr+"maxideal(1);");
3089              poly p;
3090          }
3091          p=NF(backmap(h),std(ker));
3092          if (j==2)
3093          {
3094            kill backmap;
3095          }
3096        }
3097
3098      if (j==1)
3099        {
3100          if (defined(fraction))
3101            {
3102              kill fraction;
3103              list fraction=p;
3104            }
3105          else
3106            {
3107              list fraction=p;
3108            }
3109        }
3110      else
3111        {
3112          fraction=insert(fraction,p,1);
3113        }
3114    }
3115  export(fraction);
3116  return ();
3117}
3118example
3119{
3120  "EXAMPLE:"; echo=2;
3121  ring R=0,(x,y),dp;
3122  ideal ker=x2+y2;
3123  export ker;
3124  list L=primeClosure(R);          // We normalize R/ker
3125  for (int i=1;i<=size(L);i++) { def R(i)=L[i]; }
3126  setring R(2);
3127  kill R;
3128  phi;                             // The map R(1)-->R(2)
3129  poly f=T(2);                     // We will get a representation of f
3130  export f;
3131  L[2]=R(2);
3132  closureFrac(L);
3133  setring R(1);
3134  kill R(2);
3135  fraction;                        // f=fraction[1]/fraction[2] via phi
3136  kill R(1);
3137}
3138
3139///////////////////////////////////////////////////////////////////////////////
3140// closureGenerators is called inside proc normal (option "withGens" )
3141//
3142
3143// INPUT is the output of proc primeClosure (except for the last element, the
3144// delta invariant) : hence input is a list L consisting of rings
3145// L[1],...,L[n] (denoted R(1)...R(n) below) such that
3146// - L[1] is a copy of (not a reference to!) the input ring L[1]
3147// - all rings L[i] contain ideals ker, L[2],...,L[n] contain ideals phi
3148// such that
3149//                L[1]/ker --> ... --> L[n]/ker
3150// are injections given by the corresponding ideals phi, and L[n]/ker
3151// is the integral closure of L[1]/ker in its quotient field.
3152// - all rings L[i] contain a polynomial nzd such that elements of
3153// L[i]/ker are quotients of elements of L[i-1]/ker with denominator
3154// nzd via the injection phi.
3155
3156// COMPUTE: In the list L of rings R(1),...,R(n), compute representations of
3157// the ring variables of the last ring R(n) as fractions of elements of R(1):
3158// The proc returns an ideal preim s.t. preim[i]/preim[size(preim)] expresses
3159// the ith variable of R(n) as fraction of elements of the basering R(1)
3160// preim[size(preim)] is a non-zero divisor of basering/i.
3161
3162proc closureGenerators(list L);
3163{
3164  def Rees=basering;         // when called inside normalI (in reesclos.lib)
3165                             // the Rees Algebra is the current basering
3166
3167  // ------- First of all we need some variable declarations -----------
3168  int n = size(L);                // the number of rings R(1)-->...-->R(n)
3169  int length = nvars(L[n]);       // the number of variables of the last ring
3170  int j,k,l;
3171  string mapstr;
3172  list preimages;
3173  //Note: the empty list belongs to no ring, hence preimages can be used
3174  //later in R(1)
3175  //this is not possible for ideals (belong always to some ring)
3176
3177  for (int i=1; i<=n; i++)
3178  {
3179     def R(i)=L[i];          //give the rings from L a name
3180  }
3181
3182  // For each variable (counter j) and for each intermediate ring (counter k):
3183  // Find a preimage of var_j*phi(nzd(k-1)) in R(k-1).
3184  // Finally, do the same for nzd.
3185
3186  for (j=1; j <= length+1; j++ )
3187  {
3188      setring R(n);
3189      if (j==1)
3190      {
3191        poly p;
3192      }
3193      if (j <= length )
3194      {
3195        p=var(j);
3196      }
3197      else
3198      {
3199        p=1;
3200      }
3201      //i.e. p=j-th var of R(n) for j<=length and p=1 for j=length+1
3202
3203      for (k=n; k>1; k--)
3204      {
3205
3206        if (j==1)
3207        {
3208          map phimap=R(k-1),phi;   //phimap:R(k-1)-->R(n), k=2..n, is the map
3209                                   //belonging to phi in R(n)
3210        }
3211
3212        p = p*phimap(nzd);
3213
3214          // Compute the preimage of [p mod ker(k)] under phi in R(k-1):
3215          // As p is an element of Image(phi), there is a polynomial h such
3216          // that h is mapped to [p mod ker(k)], and h can be computed as the
3217          // normal form of p w.r.t. a Groebner basis of
3218          // J(k) := <ker(k),Z(l)-phi(k)(l)> in R(k)[Z]=:S(k)
3219
3220        if (j==1)   // In the first iteration: Create S(k), fetch phi and
3221                    // ker(k) and construct the ideal J(k).
3222        {
3223         //### noch abfragen ob Z(i) definiert ist
3224         list gnirlist = ringlist(R(k));
3225         int n2 = size(gnirlist[2]);
3226         int n3 = size(gnirlist[3]);
3227         for( i=1; i<=ncols(phi); i++)
3228         {
3229            gnirlist[2][n2+i] = "Z("+string(i)+")";
3230         }
3231         intvec V;
3232         V[ncols(phi)]=0;
3233         V=V+1;
3234         gnirlist[3] = insert(gnirlist[3],list("dp",V),n3-1);
3235         def S(k) = ring(gnirlist);
3236         setring S(k);
3237
3238        // execute ("ring S(k) = "+charstr(R(k))+",("+varstr(R(k))+",
3239        //           Z(1.."+string(ncols(phi))+")),(dp("+string(nvars(R(k)))
3240        //           +"),dp("+string(ncols(phi))+"));");
3241
3242          ideal phi = imap(R(k),phi);
3243          ideal J = imap (R(k),ker);
3244          for ( l=1; l<=ncols(phi); l++ )
3245          {
3246             J=J+(Z(l)-phi[l]);
3247          }
3248          J = groebner(J);
3249          poly h = NF(imap(R(k),p),J);
3250        }
3251        else
3252        {
3253           setring S(k);
3254           h = NF(imap(R(k),p),J);
3255        }
3256
3257        setring R(k-1);
3258
3259        if (j==1)  // In the first iteration: Compute backmap:S(k)-->R(k-1)
3260        {
3261           ideal maxi;
3262           maxi[nvars(R(k))] = 0;
3263           maxi = maxi,maxideal(1);
3264           map backmap = S(k),maxi;
3265
3266           //mapstr=" map backmap = S(k),";
3267           //for (l=1;l<=nvars(R(k));l++)
3268           //{
3269           //  mapstr=mapstr+"0,";
3270           //}
3271           //execute (mapstr+"maxideal(1);");
3272
3273           poly p;
3274        }
3275        p = NF(backmap(h),std(ker));
3276     }
3277     // Whe are down to R(1), store here the result in the list preimages
3278     preimages = insert(preimages,p,j-1);
3279  }
3280  ideal preim;                  //make the list preimages to an ideal preim
3281  for ( i=1; i<=size(preimages); i++ )
3282  {
3283     preim[i] = preimages[i];
3284  }
3285  // R(1) was a copy of Rees, so we have to get back to the basering Rees from
3286  // the beginning and fetch the result (the ideal preim) to this ring.
3287  setring Rees;
3288  return (fetch(R(1),preim));
3289}
3290
3291///////////////////////////////////////////////////////////////////////////////
3292//                From here: procedures for char p with Frobenius
3293///////////////////////////////////////////////////////////////////////////////
3294
3295proc normalP(ideal id,list #)
3296"USAGE:   normalP(id [,choose]); id a radical ideal, choose a comma separated
3297         list of optional strings \"withRing\", \"isPrim\", \"noFac\",
3298         \"noRed\", where@*
3299         - \"noFac\", factorization is avoided during the computation
3300         of the minimal associated primes.@*
3301         - \"isPrim\", disables the computation of the minimal associated
3302         primes (should only be used if the ideal is known to be prime).@*
3303         - \"withRing\", the ring structure of the normalization is
3304         computed. The number of variables in the new ring is reduced as much
3305         as possible.@*
3306         - \"noRed\", when computing the ring structure no reduction on the
3307         number of  variables is done, it creates one new variable for each
3308         of the new generators of the integral closure in the quotient field.@*
3309ASSUME:  The characteristic of the ground field must be positive. The ideal
3310         id is assumed to be radical. However, if choose does not contain
3311         \"isPrim\" the minimal associated primes of id are computed first
3312         and hence normal computes the normalization of the radical of id.
3313         If choose = \"isPrim\" the ideal must be a prime ideal (this is not
3314         tested) otherwise the result may be wrong.
3315RETURN:  a list, say 'nor' of size 2 (default) or, if \"withRing\" is given,
3316         of size 3. @*
3317         nor[1] (resp. nor[2] if \"withRing\" is given) is a list of ideals
3318         Ii, i=1..r, in the basering where r is the number of associated prime
3319         ideals P_i (irreducible components) of id.@*
3320         - Ii is an ideal given by polynomials g_1,...,g_k,g_k+1 such that
3321           g_1/g_k+1,...,g_k/g_k+1 generate the integral closure of
3322           basering/P_i as module (over the basering) in its quotient field.@*
3323
3324         nor[2] (resp. nor[3] if choose=\"withRing\") is a list of an intvec
3325         of size r, the delta invariants of the r components, and an integer,
3326         the total delta invariant of basering/id (-1 means infinite, and 0
3327         that basering/P_i resp. basering/input is normal). @*
3328
3329         If the optional string \"withRing\" is given, the ring structure of
3330         the normalization is computed too and nor[1] is a list of r rings.@*
3331         Each ring Ri = nor[1][i], i=1..r, contains two ideals with given names
3332         @code{norid} and @code{normap} such that @*
3333         - Ri/norid is the normalization of the i-th rime component P_i, i.e.
3334           isomorphic to the integral closure of basering/P_i in its field
3335           of fractions; @*
3336         - the direct sum of the rings Ri/norid is the normalization
3337           of basering/id; @*
3338         - @code{normap} gives the normalization map from basering/P_i to
3339           Ri/norid (for each i).@*
3340THEORY:  The delta invariant of a reduced ring K[x1,...,xn]/id is
3341             dim_K(normalization(K[x1,...,xn]/id) / K[x1,...,xn]/id)
3342         We call this number also the delta invariant of id. normalP uses
3343         the qth-power algorithm suggested by Leonard-Pellikaan (using the
3344         Frobenius) in part similair to an implementation by Singh-Swanson.
3345NOTE:    To use the i-th ring type: @code{def R=nor[1][i]; setring R;}.
3346@*       Increasing/decreasing printlevel displays more/less comments
3347         (default: printlevel = 0).
3348@*       Not implemented for local or mixed orderings or quotient rings.
3349@*       If the input ideal id is weighted homogeneous a weighted ordering may
3350         be used (qhweight(id); computes weights).
3351@*       works only in characteristic p > 0.
3352KEYWORDS: normalization; integral closure; delta invariant.
3353SEE ALSO: normal
3354EXAMPLE: example normalP; shows an example
3355"
3356{
3357   int i,j,y, sr, del, co;
3358   intvec deli;
3359   list resu, Resu, prim, Gens, mstdid;
3360   ideal gens;
3361
3362   // Default options
3363   int wring = 0;           // The ring structure is not computed.
3364   int noRed = 0;           // No reduction is done in the ring structure
3365   int isPrim = 0;          // Ideal is not assumed to be prime
3366   int noFac = 0;           // Use facstd when computing the decomposition
3367
3368
3369   y = printlevel-voice+2;
3370
3371   if ( ord_test(basering) != 1)
3372   {
3373     "";
3374     "// Not implemented for this ordering,";
3375     "// please change to global ordering!";
3376     return(resu);
3377   }
3378   if ( char(basering) <= 0)
3379   {
3380     "";
3381     "// Algorithm works only in positive characteristic,";
3382     "// use procedure 'normal' if the characteristic is 0";
3383     return(resu);
3384   }
3385
3386//--------------------------- define the method ---------------------------
3387   string method;                //make all options one string in order to use
3388                                 //all combinations of options simultaneously
3389   for ( i=1; i<= size(#); i++ )
3390   {
3391     if ( typeof(#[i]) == "string" )
3392     {
3393       method = method + #[i];
3394     }
3395   }
3396
3397   if ( find(method,"withring") or find(method,"withRing") )
3398   {
3399     wring=1;
3400   }
3401   if ( find(method,"noRed") or find(method,"nored") )
3402   {
3403     noRed=1;
3404   }
3405   if ( find(method,"isPrim") or find(method,"isprim") )
3406   {
3407     isPrim=1;
3408   }
3409   if ( find(method,"noFac") or find(method,"nofac"))
3410   {
3411     noFac=1;
3412   }
3413
3414   kill #;
3415   list #;
3416//--------------------------- start computation ---------------------------
3417   ideal II,K1,K2;
3418
3419   //----------- check first (or ignore) if input id is prime -------------
3420
3421   if ( isPrim )
3422   {
3423      prim[1] = id;
3424      if( y >= 0 )
3425      { "";
3426    "// ** WARNING: result is correct if ideal is prime (not checked) **";
3427    "// disable option \"isPrim\" to decompose ideal into prime components";"";
3428      }
3429   }
3430   else
3431   {
3432      if(y>=1)
3433      {  "// compute minimal associated primes"; }
3434
3435      if( noFac )
3436      { prim = minAssGTZ(id,1); }
3437      else
3438      { prim = minAssGTZ(id); }
3439
3440      if(y>=1)
3441      {
3442         prim;"";
3443         "// number of irreducible components is", size(prim);
3444      }
3445   }
3446
3447   //----------- compute integral closure for every component -------------
3448
3449      for(i=1; i<=size(prim); i++)
3450      {
3451         if(y>=1)
3452         {
3453            ""; pause(); "";
3454            "// start computation of component",i;
3455            "   --------------------------------";
3456         }
3457         if(y>=1)
3458         {  "// compute SB of ideal";
3459         }
3460         mstdid = mstd(prim[i]);
3461         if(y>=1)
3462         {  "// dimension of component is", dim(mstdid[1]);"";}
3463
3464      //------- 1-st main subprocedure: compute module generators ----------
3465         printlevel = printlevel+1;
3466         II = normalityTest(mstdid);
3467
3468      //------ compute also the ringstructure if "withRing" is given -------
3469         if ( wring )
3470         {
3471         //------ 2-nd main subprocedure: compute ring structure -----------
3472           if(noRed == 0){
3473             resu = list(computeRing(II,prim[i])) + resu;
3474           } else {
3475             resu = list(computeRing(II,prim[i], "noRed")) + resu;
3476           }
3477         }
3478         printlevel = printlevel-1;
3479
3480      //----- rearrange module generators s.t. denominator comes last ------
3481         gens=0;
3482         for( j=2; j<=size(II); j++ )
3483         {
3484            gens[j-1]=II[j];
3485         }
3486         gens[size(gens)+1]=II[1];
3487         Gens = list(gens) + Gens;
3488      //------------------------------ compute delta -----------------------
3489         K1 = mstdid[1]+II;
3490         K1 = std(K1);
3491         K2 = mstdid[1]+II[1];
3492         K2 = std(K2);
3493         // K1 = std(mstdid[1],II);      //### besser
3494         // K2 = std(mstdid[1],II[1]);   //### besser: Hannes, fixen!
3495         co = codim(K1,K2);
3496         deli = co,deli;
3497         if ( co >= 0 && del >= 0 )
3498         {
3499            del = del + co;
3500         }
3501         else
3502         { del = -1; }
3503      }
3504
3505      if ( del >= 0 )
3506      {
3507         int mul = iMult(prim);
3508         del = del + mul;
3509      }
3510      else
3511      { del = -1; }
3512
3513      deli = deli[1..size(deli)-1];
3514      if ( wring )
3515      { Resu = resu,Gens,list(deli,del); }
3516      else
3517      { Resu = Gens,list(deli,del); }
3518
3519   sr = size(prim);
3520
3521//-------------------- Finally print comments and return --------------------
3522   if(y >= 0)
3523   {"";
3524     if ( wring )
3525     {
3526"// 'normalP' created a list, say nor, of three lists:
3527// nor[1] resp. nor[2] are lists of",sr,"ring(s) resp. ideal(s)
3528// and nor[3] is a list of an intvec and an integer.
3529// To see the result, type
3530     nor;
3531// To access the i-th ring nor[1][i] give it a name, say Ri, and type e.g.
3532     def R1 = nor[1][1]; setring R1;  norid; normap;
3533// for the other rings type first setring r; (if r is the name of your
3534// original basering) and then continue as for the first ring;
3535// Ri/norid is the affine algebra of the normalization of the i-th
3536// component r/P_i (where P_i is an associated prime of the input ideal)
3537// and normap the normalization map from r to Ri/norid;
3538//    nor[2] is a list of",sr,"ideal(s), each ideal nor[2][i] consists of
3539// elements g1..gk of r such that the gj/gk generate the integral
3540// closure of r/P_i as (r/P_i)-module in the quotient field of r/P_i.
3541//    nor[3] shows the delta-invariant of each component and of the input
3542// ideal (-1 means infinite, and 0 that r/P_i is normal).";
3543     }
3544     else
3545     {
3546"// 'normalP' computed a list, say nor, of two lists:
3547//    nor[1] is a list of",sr,"ideal(s), where each ideal nor[1][i] consists
3548// of elements g1..gk of the basering such that gj/gk generate the integral
3549// closure of the i-th component as (basering/P_i)-module in the quotient
3550// field of basering/P_i (P_i an associated prime of the input ideal);
3551//    nor[2] shows the delta-invariant of each component and of the input ideal
3552// (-1 means infinite, and 0 that r/P_i is normal).";
3553     }
3554   }
3555
3556   return(Resu);
3557}
3558example
3559{ "EXAMPLE:"; echo = 2;
3560   ring r  = 11,(x,y,z),wp(2,1,2);
3561   ideal i = x*(z3 - xy4 + x2);
3562   list nor= normalP(i); nor;
3563   //the result says that both components of i are normal, but i itself
3564   //has infinite delta
3565   pause("hit return to continue");
3566
3567   ring s = 2,(x,y),dp;
3568   ideal i = y*((x-y^2)^2 - x^3);
3569   list nor = normalP(i,"withRing"); nor;
3570
3571   def R2  = nor[1][2]; setring R2;
3572   norid; normap;
3573}
3574
3575///////////////////////////////////////////////////////////////////////////////
3576// Assume: mstdid is the result of mstd(prim[i]), prim[i] a prime component of
3577// the input ideal id of normalP.
3578// Output is an ideal U s.t. U[i]/U[1] are module generators.
3579
3580static proc normalityTest(list mstdid)
3581{
3582   int y = printlevel-voice+2;
3583   intvec op = option(get);
3584   option(redSB);
3585   def R = basering;
3586   int n, p = nvars(R), char(R);
3587   int ii;
3588
3589   ideal J = mstdid[1];         //J is the SB of I
3590   ideal I = mstdid[2];
3591   int h = n-dim(J);            //codimension of V(I), I is a prime ideal
3592
3593   //-------------------------- compute singular locus ----------------------
3594   qring Q = J;                 //pass to quotient ring
3595   ideal I = imap(R,I);
3596   ideal J = imap(R,J);
3597   attrib(J,"isSB",1);
3598   if ( y >= 1)
3599   { "start normality test";  "compute singular locus";}
3600
3601   ideal M = minor(jacob(I),h,J); //use the command minor modulo J (hence J=0)
3602   M = std(M);                    //this makes M much smaller
3603   //keep only minors which are not 0 mod I (!) this is important since we
3604   //need a nzd mod I
3605
3606   //---------------- choose nzd from ideal of singular locus --------------
3607   ideal D = M[1];
3608   for( ii=2; ii<=size(M); ii++ )            //look for the shortest one
3609   {
3610      if( size(M[ii]) < size(D[1]) )
3611      {
3612          D = M[ii];
3613      }
3614   }
3615
3616   //--------------- start p-th power algorithm and return ----------------
3617   ideal F = var(1)^p;
3618   for(ii=2; ii<=n; ii++)
3619   {
3620      F=F,var(ii)^p;
3621   }
3622
3623   ideal Dp=D^(p-1);
3624   ideal U=1;
3625   ideal K,L;
3626   map phi=Q,F;
3627   if ( y >= 1)
3628   {  "compute module generators of integral closure";
3629      "denominator D is:";  D;
3630      pause();
3631   }
3632
3633   ii=0;
3634   list LK;
3635   while(1)
3636   {
3637      ii=ii+1;
3638      if ( y >= 1)
3639      { "iteration", ii; }
3640      L = U*Dp + I;
3641      //### L=interred(L) oder msdt(L)[2]?
3642      //Wird dadurch kleiner aber string(L) wird groesser
3643      K = preimage(Q,phi,L);    //### Improvement by block ordering?
3644      option(returnSB);
3645      K = intersect(U,K);          //K is the new U, it is a SB
3646      LK = mstd(K);
3647      K = LK[2];
3648
3649   //---------------------------- simplify output --------------------------
3650      if(size(reduce(U,LK[1]))==0)  //previous U coincides with new U
3651      {                             //i.e. we reached the integral closure
3652         U=simplify(reduce(U,groebner(D)),2);
3653         U = D,U;
3654         poly gg = gcd(U[1],U[size(U)]);
3655         for(ii=2; ii<=size(U)-1 ;ii++)
3656         {
3657            gg = gcd(gg,U[ii]);
3658         }
3659         for(ii=1; ii<=size(U); ii++)
3660         {
3661            U[ii]=U[ii]/gg;
3662         }
3663         U = simplify(U,6);
3664         //if ( y >= 1)
3665         //{ "module generators are U[i]/U[1], with U:"; U;
3666         //  ""; pause(); }
3667         option(set,op);
3668         setring R;
3669         ideal U = imap(Q,U);
3670         return(U);
3671      }
3672      U=K;
3673   }
3674}
3675
3676///////////////////////////////////////////////////////////////////////////////
3677
3678static proc substpartSpecial(ideal endid, ideal endphi)
3679{
3680   //Note: newRing is of the form (R the original basering):
3681   //char(R),(T(1..N),X(1..nvars(R))),(dp(N),...);
3682
3683   int ii,jj,kk;
3684   def BAS = basering;
3685   int n = nvars(basering);
3686
3687   list Le = elimpart(endid);
3688   int q = size(Le[2]);                   //q variables have been substituted
3689//Le;"";
3690   if ( q == 0 )
3691   {
3692      ideal normap = endphi;
3693      ideal norid = endid;
3694      export(norid);
3695      export(normap);
3696      list L = BAS;
3697      return(L);
3698   }
3699
3700      list gnirlist = ringlist(basering);
3701      endid = Le[1];
3702//endphi;"";
3703      for( ii=1; ii<=n; ii++)
3704      {
3705         if( Le[4][ii] == 0 )            //ii=index of substituted var
3706         {
3707            endphi = subst(endphi,var(ii),Le[5][ii]);
3708         }
3709      }
3710//endphi;"";
3711      list g2 = gnirlist[2];             //the varlist
3712      list g3 = gnirlist[3];             //contains blocks of orderings
3713      int n3 = size(g3);
3714
3715   //----------------- first identify module ordering ------------------
3716      if ( g3[n3][1]== "c" or g3[n3][1] == "C" )
3717      {
3718         list gm = g3[n3];              //last blockis module ordering
3719         g3 = delete(g3,n3);
3720         int m = 0;
3721      }
3722      else
3723      {
3724         list gm = g3[1];              //first block is module ordering
3725         g3 = delete(g3,1);
3726         int m = 1;
3727      }
3728   //---- delete variables which were substituted and weights  --------
3729      intvec V;
3730      int n(0);
3731      list newg2;
3732      list newg3;
3733      for ( ii=1; ii<=n3-1; ii++ )
3734      {
3735        // If order is a matrix ordering, it is replaced by dp ordering.
3736        // TODO: replace it only when some of the original
3737        //       variables are eliminated.
3738        if(g3[ii][1] == "M"){
3739          g3[ii][1] = "dp";
3740          g3[ii][2] = (1..sqroot(size(g3[ii][2])))*0+1;
3741        }
3742        V = V,g3[ii][2];           //copy weights for ordering in each block
3743        if ( ii==1 )               //into one intvector
3744        {
3745           V = V[2..size(V)];
3746        }
3747        // int n(ii) = size(g3[ii][2]);
3748        int n(ii) = size(V);
3749        intvec V(ii);
3750
3751        for ( jj = n(ii-1)+1; jj<=n(ii); jj++)
3752        {
3753          if( Le[4][jj] !=0 )     //jj=index of var which was not substituted
3754          {
3755            kk=kk+1;
3756            newg2[kk] = g2[jj];   //not substituted var from varlist
3757            V(ii)=V(ii),V[jj];    //weight of not substituted variable
3758          }
3759        }
3760        if ( size(V(ii)) >= 2 )
3761        {
3762           V(ii) = V(ii)[2..size(V(ii))];
3763           list g3(ii)=g3[ii][1],V(ii);
3764           newg3 = insert(newg3,g3(ii),size(newg3));
3765//"newg3"; newg3;
3766        }
3767      }
3768//"newg3"; newg3;
3769      //newg3 = delete(newg3,1);    //delete empty list
3770
3771/*
3772//### neue Ordnung, 1 Block fuer alle vars, aber Gewichte erhalten;
3773//vorerst nicht realisiert, da bei leonhard1 alte Version (neue Variable T(i)
3774//ein neuer Block) ein kuerzeres Ergebnis liefert
3775      kill g3;
3776      list g3;
3777      V=0;
3778      for ( ii= 1; ii<=n3-1; ii++ )
3779      {
3780        V=V,V(ii);
3781      }
3782      V = V[2..size(V)];
3783
3784      if ( V==1 )
3785      {
3786         g3[1] = list("dp",V);
3787      }
3788      else
3789      {
3790         g3[1] = lis("wp",V);
3791      }
3792      newg3 = g3;
3793
3794//"newg3";newg3;"";
3795//### Ende neue Ordnung
3796*/
3797
3798      if ( m == 0 )
3799      {
3800         newg3 = insert(newg3,gm,size(newg3));
3801      }
3802      else
3803      {
3804         newg3 = insert(newg3,gm);
3805      }
3806      gnirlist[2] = newg2;
3807      gnirlist[3] = newg3;
3808
3809//gnirlist;
3810      def newBAS = ring(gnirlist);            //change of ring to less vars
3811      setring newBAS;
3812      ideal normap = imap(BAS,endphi);
3813      //normap = simplify(normap,2);
3814      ideal norid =  imap(BAS,endid);
3815      export(norid);
3816      export(normap);
3817      list L = newBAS;
3818      return(L);
3819
3820   //Hier scheint interred gut zu sein, da es Ergebnis relativ schnell
3821   //verkleinert. Hier wird z.B. bei leonard1 size(norid) verkleinert aber
3822   //size(string(norid)) stark vergroessert, aber es hat keine Auswirkungen
3823   //da keine map mehr folgt.
3824   //### Bei Leonard2 haengt interred (BUG)
3825   //mstd[2] verkleinert norid nocheinmal um die Haelfte, dauert aber 3.71 sec
3826   //### Ev. Hinweis auf mstd in der Hilfe?
3827
3828}
3829
3830///////////////////////////////////////////////////////////////////////////////
3831// Computes the ring structure of a ring given by module generators.
3832// Assume: J[i]/J[1] are the module generators in the quotient field
3833// with J[1] as universal denominator.
3834// If option "noRed" is not given, a reduction in the number of variables is
3835// attempted.
3836static proc computeRing(ideal J, ideal I, list #)
3837{
3838  int i, ii,jj;
3839  intvec V;                          // to be used for variable weights
3840  int y = printlevel-voice+2;
3841  def R = basering;
3842  poly c = J[1];                     // the denominator
3843  list gnirlist = ringlist(basering);
3844  string svars = varstr(basering);
3845  int nva = nvars(basering);
3846  string svar;
3847  ideal maxid = maxideal(1);
3848
3849  int noRed = 0;     // By default, we try to reduce the number of generators.
3850  if(size(#) > 0){
3851    if ( typeof(#[1]) == "string" )
3852    {
3853      if (#[1] == "noRed"){noRed = 1;}
3854    }
3855  }
3856
3857  if ( y >= 1){"// computing the ring structure...";}
3858
3859  if(c==1)
3860  {
3861    if( defined(norid) )  { kill norid; }
3862    if( defined(normap) ) { kill normap; }
3863    ideal norid = I;
3864    ideal normap =  maxid;
3865    export norid;
3866    export normap;
3867    if(noRed == 1){
3868      setring R;
3869      return(R);
3870    } else {
3871      list L = substpartSpecial(norid,normap);
3872      def lastRing = L[1];
3873      setring R;
3874      return(lastRing);
3875    }
3876  }
3877
3878
3879  //-------------- Enlarge ring by creating new variables ------------------
3880  //check first whether variables T(i) and then whether Z(i),...,A(i) exist
3881  //old variable names are not touched
3882
3883  if ( find(svars,"T(") == 0 )
3884  {
3885    svar = "T";
3886  }
3887  else
3888  {
3889    for (ii=90; ii>=65; ii--)
3890    {
3891      if ( find(svars,ASCII(ii)+"(") == 0 )
3892      {
3893        svar = ASCII(ii);  break;
3894      }
3895    }
3896  }
3897
3898  int q = size(J)-1;
3899  if ( size(svar) != 0 )
3900  {
3901    for ( ii=q; ii>=1; ii-- )
3902    {
3903      gnirlist[2] = insert(gnirlist[2],svar+"("+string(ii)+")");
3904    }
3905  }
3906  else
3907  {
3908    for ( ii=q; ii>=1; ii-- )
3909    {
3910      gnirlist[2] = insert(gnirlist[2],"T("+string(100*nva+ii)+")");
3911    }
3912  }
3913
3914  V[q]=0;                        //create intvec of variable weights
3915  V=V+1;
3916  gnirlist[3] = insert(gnirlist[3],list("dp",V));
3917
3918  //this is a block ordering with one dp-block (1st block) for new vars
3919  //the remaining weights and blocks for old vars are kept
3920  //### perhaps better to make only one block, keeping weights ?
3921  //this might effect syz below
3922  //alt: ring newR = char(R),(X(1..nvars(R)),T(1..q)),dp;
3923  //Reihenfolge geŠndert:neue Variablen kommen zuerst, Namen ev. nicht T(i)
3924
3925  def newR = ring(gnirlist);
3926  setring newR;                //new extended ring
3927  ideal I = imap(R,I);
3928
3929  //------------- Compute linear and quadratic relations ---------------
3930  if(y>=1)
3931  {
3932     "// compute linear relations:";
3933  }
3934  qring newQ = std(I);
3935
3936  ideal f = imap(R,J);
3937  module syzf = syz(f);
3938  ideal pf = f[1]*f;
3939  //f[1] is the denominator D from normalityTest, a non zero divisor of R/I
3940
3941  ideal newT = maxideal(1);
3942  newT = 1,newT[1..q];
3943  //matrix T = matrix(ideal(1,T(1..q)),1,q+1);   //alt
3944  matrix T = matrix(newT,1,q+1);
3945  ideal Lin = ideal(T*syzf);
3946  //Lin=interred(Lin);
3947  //### interred reduziert ev size aber size(string(LIN)) wird groesser
3948
3949  if(y>=1)
3950  {
3951    if(y>=3)
3952    {
3953      "//   the linear relations:";  Lin; pause();"";
3954    }
3955      "// the ring structure of the normalization as affine algebra";
3956      "//   number of linear relations:", size(Lin);
3957  }
3958
3959  if(y>=1)
3960  {
3961    "// compute quadratic relations:";
3962  }
3963  matrix A;
3964  ideal Quad;
3965  poly ff;
3966  newT = newT[2..size(newT)];
3967  matrix u;  // The units for non-global orderings.
3968
3969  // Quadratic relations
3970  for (ii=2; ii<=q+1; ii++ )
3971  {
3972    for ( jj=2; jj<=ii; jj++ )
3973    {
3974      ff = NF(f[ii]*f[jj],std(0));     // this makes lift much faster
3975      // For non-global orderings, we have to take care of the units.
3976      if(ord_test(basering) != 1){
3977        A = lift(pf, ff, u);
3978        Quad = Quad,ideal(newT[jj-1]*newT[ii-1] * u[1, 1]- T*A);
3979      } else {
3980        A = lift(pf,ff);              // ff lin. comb. of elts of pf mod I
3981        Quad = Quad,ideal(newT[jj-1]*newT[ii-1] - T*A);
3982      }
3983      //A = lift(pf, f[ii]*f[jj]);
3984      //Quad = Quad, ideal(T(jj-1)*T(ii-1) - T*A);
3985    }
3986  }
3987  Quad = Quad[2..ncols(Quad)];
3988
3989  if(y>=1)
3990  {
3991    if(y>=3)
3992    {
3993      "//   the quadratic relations"; Quad; pause();"";
3994    }
3995      "//   number of quadratic relations:", size(Quad);
3996  }
3997  ideal Q1 = Lin,Quad;     //elements of Q1 are in NF w.r.t. I
3998
3999  //Q1 = mstd(Q1)[2];
4000  //### weglassen, ist sehr zeitaufwendig.
4001  //Ebenso interred, z.B. bei Leonard1 (1. Komponente von Leonard):
4002  //"size Q1:", size(Q1), size(string(Q1));   //75 60083
4003  //Q1 = interred(Q1);
4004  //"size Q1:", size(Q1), size(string(Q1));   //73 231956 (!)
4005  //### Speicherueberlauf bei substpartSpecial bei 'ideal norid  = phi1(endid)'
4006  //Beispiel fuer Hans um map zu testen!
4007
4008  setring newR;
4009  ideal endid  = imap(newQ,Q1),I;
4010  ideal endphi = imap(R,maxid);
4011
4012  if(noRed == 0){
4013    list L=substpartSpecial(endid,endphi);
4014    def lastRing=L[1];
4015    if(y>=1)
4016    {
4017      "//   number of substituted variables:", nvars(newR)-nvars(lastRing);
4018      pause();"";
4019    }
4020    return(lastRing);
4021  } else {
4022    ideal norid = endid;
4023    ideal normap = endphi;
4024    export(norid);
4025    export(normap);
4026    setring R;
4027    return(newR);
4028  }
4029}
4030
4031//                Up to here: procedures for char p with Frobenius
4032///////////////////////////////////////////////////////////////////////////////
4033
4034///////////////////////////////////////////////////////////////////////////////
4035//                From here: subprocedures for normal
4036
4037static proc normalM(ideal I, int decomp, int withDelta){
4038// Computes the normalization of a ring R / I using the module structure as far
4039// as possible.
4040// The ring R is the basering.
4041// Input: ideal I
4042// Output: a list of 3 elements (resp 4 if withDelta = 1), say nor.
4043// - nor[1] = U, an ideal of R.
4044// - nor[2] = c, an element of R.
4045// U and c satisfy that 1/c * U is the normalization of R / I in the
4046// quotient field Q(R/I).
4047// - nor[3] = ring say T, containing two ideals norid and normap such that
4048// normap gives the normalization map from R / I to T / norid.
4049// - nor[4] = the delta invariant, if withDelta = 1.
4050
4051// Details:
4052// --------
4053// Computes the ideal of the minors in the first step and then reuses it in all
4054// steps.
4055// In step s, the denominator is D^s, where D is a nzd of the original quotient
4056// ring, contained in the radical of the singular locus.
4057// This denominator is used except when the degree of D^i is greater than the
4058// degree of a conductor.
4059// The nzd is taken as the smallest degree polynomial in the radical of the
4060// singular locus.
4061
4062// It assumes that the ideal I is equidimensional radical. This is not checked
4063// in the procedure!
4064// If decomp = 0 or decomp = 3 it assumes further that I is prime. Therefore
4065// any non-zero element in the jacobian ideal is assumed to be a
4066// non-zerodivisor.
4067
4068// It works over the given basering.
4069// If it has a non-global ordering, it changes it to dp global only for
4070// computing radical.
4071
4072// The delta invariant is only computed if withDelta = 1, and decomp = 0 or
4073// decomp = 3 (meaning that the ideal is prime).
4074
4075  option("redSB");
4076  option("returnSB");
4077  int step = 0;                       // Number of steps. (for debugging)
4078  int dbg = printlevel - voice + 2;   // dbg = printlevel (default: dbg = 0)
4079  int i;                              // counter
4080  int isGlobal = ord_test(basering);
4081
4082  poly c;                     // The common denominator.
4083
4084  def R = basering;
4085
4086//------------------------ Groebner bases and dimension of I-----------------
4087  if(isGlobal == 1){
4088    list IM = mstd(I);
4089    I = IM[1];
4090    ideal IMin = IM[2];   // A minimal set of generators in the groebner basis.
4091  } else {
4092    // The minimal set of generators is not computed by mstd for
4093    // non-global orderings.
4094    I = groebner(I);
4095    ideal IMin = I;
4096  }
4097  int d = dim(I);
4098
4099  // ---------------- computation of the singular locus ---------------------
4100  // We compute the radical of the ideal of minors modulo the original ideal.
4101  // This is done only in the first step.
4102  qring Q = I;   // We work in the quotient by the groebner base of the ideal I
4103  option("redSB");
4104  option("returnSB");
4105  ideal I = fetch(R, I);
4106  attrib(I, "isSB", 1);
4107  ideal IMin = fetch(R, IMin);
4108
4109  dbprint(dbg, "Computing the jacobian ideal...");
4110
4111  ideal J = minor(jacob(IMin), nvars(basering) - d, I);
4112  J = groebner(J);
4113
4114  //------------------ We check if the singular locus is empty -------------
4115  if(J[1] == 1){
4116    // The original ring R/I was normal. Nothing to do.
4117    // We define anyway a new ring, equal to R, to be able to return it.
4118    setring R;
4119    list lR = ringlist(R);
4120    def ROut = ring(lR);
4121    setring ROut;
4122    ideal norid = fetch(R, I);
4123    ideal normap = maxideal(1);
4124    export norid;
4125    export normap;
4126    setring R;
4127    if(withDelta){
4128      list output = ideal(1), poly(1), ROut, 0;
4129    } else {
4130      list output = ideal(1), poly(1), ROut;
4131    }
4132    return(list(output));
4133  }
4134
4135
4136  // -------------------- election of the conductor -------------------------
4137  poly condu = getSmallest(J);   // Choses the polynomial of smallest degree
4138                                 // of J as universal denominator.
4139  if(dbg >= 1){
4140    "";
4141    "The universal denominator is ", condu;
4142  }
4143
4144  // ---------  splitting the ideal by the conductor (if possible) -----------
4145  // If the ideal is equidimensional, but not necessarily prime, we check if
4146  // the conductor is a non-zerodivisor of R/I.
4147  // If not, we split I.
4148  if((decomp == 1) or (decomp == 2)){
4149    ideal Id1 = quotient(0, condu);
4150    if(size(Id1) > 0){
4151      // We have to split.
4152      if(dbg >= 1){
4153        "A zerodivisor was found. We split the ideal. The zerodivisor is ", condu;
4154      }
4155      setring R;
4156      ideal Id1 = fetch(Q, Id1), I;
4157      Id1 = groebner(Id1);
4158      ideal Id2 = quotient(I, Id1);
4159      // I = I1 \cap I2
4160      printlevel = printlevel + 1;
4161      list nor1 = normalM(Id1, decomp, withDelta)[1];
4162      list nor2 = normalM(Id2, decomp, withDelta)[1];
4163      printlevel = printlevel - 1;
4164      return(list(nor1, nor2));
4165    }
4166  }
4167
4168  // --------------- computation of the first test ideal ---------------------
4169  // To compute the radical we go back to the original ring.
4170  // If we are using a non-global ordering, we must change to the global
4171  // ordering.
4172  if(isGlobal == 1){
4173    setring R;
4174    ideal J = fetch(Q, J);
4175    J = J, I;
4176    if(dbg >= 1){
4177      "The original singular locus is";
4178      groebner(J);
4179      if(dbg >= 2){pause();}
4180       "";
4181    }
4182    // We check if the only singular point is the origin.
4183    // If so, the radical is the maximal ideal at the origin.
4184    J = groebner(J);
4185    if(locAtZero(J)){
4186      J = maxideal(1);
4187    } else {
4188      J = radical(J);
4189    }
4190  } else {
4191    // We change to global dp ordering.
4192    list rl = ringlist(R);
4193    list origOrd = rl[3];
4194    list newOrd = list("dp", intvec(1:nvars(R))), list("C", 0);
4195    rl[3] = newOrd;
4196    def globR = ring(rl);
4197    setring globR;
4198    ideal J = fetch(Q, J);
4199    ideal I = fetch(R, I);
4200    J = J, I;
4201    if(dbg >= 1){
4202      "The original singular locus is";
4203      groebner(J);
4204      if(dbg>=2){pause();}
4205      "";
4206    }
4207    J = radical(J);
4208    setring R;
4209    ideal J = fetch(globR, J);
4210  }
4211
4212  if(dbg >= 1){
4213    "The radical of the original singular locus is";
4214    J;
4215    if(dbg>=2){pause();}
4216  }
4217
4218  // ---------------- election of the non zero divisor ---------------------
4219  setring Q;
4220  J = fetch(R, J);
4221  J = interred(J);
4222  poly D = getSmallest(J);    // Chooses the polynomial of smallest degree as
4223                              // non-zerodivisor.
4224  if(dbg >= 1){
4225    "The non zero divisor is ", D;
4226    "";
4227  }
4228
4229  // ------- splitting the ideal by the non-zerodivisor (if possible) --------
4230  // If the ideal is equidimensional, but not necessarily prime, we check if D
4231  // is actually a non-zerodivisor of R/I.
4232  // If not, we split I.
4233  if((decomp == 1) or (decomp == 2)){
4234    // We check if D is actually a non-zerodivisor of R/I.
4235    // If not, we split I.
4236    Id1 = quotient(0, D);
4237    if(size(Id1) > 0){
4238      // We have to split.
4239      if(dbg >= 1){
4240        "A zerodivisor was found. We split the ideal. The zerodivisor is ", D;
4241      }
4242      setring R;
4243      ideal Id1 = fetch(Q, Id1), I;
4244      Id1 = groebner(Id1);
4245      ideal I2 = quotient(I, Id1);
4246      // I = Id1 \cap Id2
4247      printlevel = printlevel + 1;
4248
4249      list nor1 = normalM(Id1, decomp, withDelta)[1];
4250      list nor2 = normalM(Id2, decomp, withDelta)[1];
4251      printlevel = printlevel - 1;
4252      return(list(nor1, nor2));
4253    }
4254  }
4255
4256  // --------------------- normalization ------------------------------------
4257  // We call normalMEqui to compute the normalization.
4258  setring R;
4259  poly D = fetch(Q, D);
4260  poly condu = fetch(Q, condu);
4261  J = fetch(Q, J);
4262  printlevel = printlevel + 1;
4263  list result = normalMEqui(I, J, condu, D, withDelta);
4264  printlevel = printlevel - 1;
4265  return(list(result));
4266}
4267
4268///////////////////////////////////////////////////////////////////////////////
4269
4270static proc normalMEqui(ideal I, ideal origJ, poly condu, poly D, int withDelta)
4271// Here is where the normalization is actually computed.
4272
4273// Computes the normalization of R/I. (basering is R)
4274// I is assumed to be radical and equidimensional.
4275// origJ is the first test ideal.
4276// D is a non-zerodivisor of R/I.
4277// condu is a non-zerodivisor in the conductor.
4278// If withDelta = 1, computes the delta invariant.
4279{
4280  int step = 0;                       // Number of steps. (for debugging)
4281  int dbg = printlevel - voice + 2;   // dbg = printlevel (default: dbg = 0)
4282  int i;                              // counter
4283  int isNormal = 0;                   // check for exiting the loop
4284  int isGlobal = ord_test(basering);
4285  int delt;
4286
4287  def R = basering;
4288  poly c = D;
4289  ideal U;
4290  ideal cJ;
4291  list testOut;                 // Output of proc testIdeal
4292                                // (the test ideal and the ring structure)
4293
4294  qring Q = groebner(I);
4295  option("redSB");
4296  option("returnSB");
4297  ideal J = imap(R, origJ);
4298  poly c = imap(R, c);
4299  poly D = imap(R, D);
4300  poly condu = imap(R, condu);
4301  ideal cJ;
4302  ideal cJMod;
4303
4304  dbprint(dbg, "Preliminar step begins.");
4305
4306  // --------------------- computation of A1 -------------------------------
4307  dbprint(dbg, "Computing the quotient (DJ : J)...");
4308  ideal U = groebner(quotient(D*J, J));
4309  ideal oldU = 1;
4310
4311  if(dbg >= 2) { "The quotient is"; U; }
4312
4313  // ----------------- Grauer-Remmert criterion check -----------------------
4314  // We check if the equality in Grauert - Remmert criterion is satisfied.
4315  isNormal = checkInclusions(D*oldU, U);
4316  if(isNormal == 0)
4317  {
4318    if(dbg >= 1)
4319    {
4320      "In this step, we have the ring 1/c * U, with c =", c;
4321      "and U = "; U;
4322    }
4323  }
4324  else
4325  {
4326    // The original ring R/I was normal. Nothing to do.
4327    // We define anyway a new ring, equal to R, to be able to return it.
4328    setring R;
4329    list lR = ringlist(R);
4330    def ROut = ring(lR);
4331    setring ROut;
4332    ideal norid = fetch(R, I);
4333    ideal normap = maxideal(1);
4334    export norid;
4335    export normap;
4336    setring R;
4337    if(withDelta)
4338    {
4339      list output = ideal(1), poly(1), ROut, 0;
4340    }
4341    else
4342    {
4343      list output = ideal(1), poly(1), ROut;
4344    }
4345    return(output);
4346  }
4347
4348  // ----- computation of the chain of ideals A1 c A2 c ... c An ------------
4349  while(isNormal == 0)
4350  {
4351    step++;
4352    if(dbg >= 1) { ""; "Step ", step, " begins."; }
4353    dbprint(dbg, "Computing the test ideal...");
4354
4355    // --------------- computation of the test ideal ------------------------
4356    // Computes a test ideal for the new ring.
4357    // The test ideal will be the radical in the new ring of the original
4358    // test ideal.
4359    setring R;
4360    U = imap(Q, U);
4361    c = imap(Q, c);
4362    testOut = testIdeal(I, U, origJ, c, D);
4363    cJ = testOut[1];
4364
4365    setring Q;
4366    cJ = imap(R, cJ);
4367    cJ = groebner(cJ);
4368
4369    // cJ / c is now the ideal mapped back.
4370    // We have the generators as an ideal in the new ring,
4371    // but we want the generators as an ideal in the original ring.
4372    cJMod = getGenerators(cJ, U, c);
4373
4374    if(dbg >= 2) { "The test ideal in this step is "; cJMod; }
4375
4376    cJ = cJMod;
4377
4378    // ------------- computation of the quotient (DJ : J)--------------------
4379    oldU = U;
4380    dbprint(dbg, "Computing the quotient (c*D*cJ : cJ)...");
4381    U = quotient(c*D*cJ, cJ);
4382    if(dbg >= 2){"The quotient is "; U;}
4383
4384    // ------------- Grauert - Remmert criterion check ----------------------
4385    // We check if the equality in Grauert - Remmert criterion is satisfied.
4386    isNormal = checkInclusions(D*oldU, U);
4387
4388    if(isNormal == 1)
4389    {
4390      // We go one step back. In the last step we didnt get antyhing new,
4391      // we just verified that the ring was already normal.
4392      dbprint(dbg, "The ring in the previous step was already normal.");
4393      dbprint(dbg, "");
4394      U = oldU;
4395    }
4396    else
4397    {
4398      // ------------- preparation for next iteration ----------------------
4399      // We have to go on.
4400      // The new denominator is chosen.
4401      c = D * c;
4402      if(deg(c) > deg(condu))
4403      {
4404        U = changeDenominatorQ(U, c, condu);
4405        c = condu;
4406      }
4407      if(dbg >= 1)
4408      {
4409        "In this step, we have the ring 1/c * U, with c =", c;
4410        "and U = ";
4411        U;
4412        if(dbg>=2){pause();}
4413      }
4414    }
4415  }
4416
4417  // ------------------------- delta computation ----------------------------
4418  if(withDelta)
4419  {
4420    ideal UD = groebner(U);
4421    delt = vdim(std(modulo(UD, c)));
4422  }
4423
4424  // -------------------------- prepare output -----------------------------
4425  setring R;
4426  U = fetch(Q, U);
4427  c = fetch(Q, c);
4428
4429  // Ring structure of the new ring
4430  def ere = testOut[2];
4431  if(withDelta)
4432  {
4433    list output = U, c, ere, delt;
4434  }
4435  else
4436  {
4437    list output = U, c, ere;
4438  }
4439  return(output);
4440}
4441
4442///////////////////////////////////////////////////////////////////////////////
4443
4444static proc lineUpLast(ideal U, poly c)
4445// Sets c as the last generator of U.
4446{
4447  int i;
4448  ideal newU;
4449  for (i = 1; i <= ncols(U); i++)
4450  {
4451    if(U[i] != c)
4452    {
4453      if(size(newU) == 0)
4454      { newU = U[i]; }
4455      else
4456      { newU = newU, U[i]; }
4457    }
4458  }
4459  if(size(newU) == 0)
4460  { newU = c; }
4461  else
4462  { newU = newU, c; }
4463  return(newU);
4464}
4465
4466///////////////////////////////////////////////////////////////////////////////
4467
4468static proc lineUp(ideal U, poly c)
4469// Sets c as the first generator of U.
4470{
4471  int i;
4472  ideal newU = c;
4473  for (i = 1; i <= ncols(U); i++)
4474  {
4475    if(U[i] != c)
4476    {
4477      newU = newU, U[i];
4478    }
4479  }
4480  return(newU);
4481}
4482
4483///////////////////////////////////////////////////////////////////////////////
4484
4485static proc getSmallest(ideal J)
4486{
4487// Computes the polynomial of smallest degree of J.
4488// If there are more than one, it chooses the one with smallest number
4489// of monomials.
4490  int i;
4491  poly p = J[1];
4492  int d = deg(p);
4493  int di;
4494  for(i = 2; i <= ncols(J); i++)
4495  {
4496    if(J[i] != 0)
4497    {
4498      di = deg(J[i]);
4499      if(di < d)
4500      {
4501        p = J[i];
4502        d = di;
4503      }
4504      else
4505      {
4506        if(di == d)
4507        {
4508          if(size(J[i]) < size(p))
4509          {
4510            p = J[i];
4511          }
4512        }
4513      }
4514    }
4515  }
4516  return(p);
4517}
4518
4519///////////////////////////////////////////////////////////////////////////////
4520
4521static proc getGenerators(ideal J, ideal U, poly c)
4522{
4523// Computes the generators of J as an ideal in the original ring,
4524// where J is given by generators in the new ring.
4525
4526// The new ring is given by 1/c * U in the total ring of fractions.
4527
4528  int i, j;                             // counters;
4529  int dbg = printlevel - voice + 2;     // dbg = printlevel (default: dbg = 0)
4530  poly p;                               // The lifted polynomial
4531  ideal JGr = groebner(J);              // Groebner base of J
4532
4533  if(dbg>1){"Checking for new generators...";}
4534  for(i = 1; i <= ncols(J); i++)
4535  {
4536    for(j = 1; j <= ncols(U); j++)
4537    {
4538      p = lift(c, J[i]*U[j])[1,1];
4539      p = reduce(p, JGr);
4540      if(p != 0)
4541      {
4542        if(dbg>1)
4543        {
4544          "New polynoial added:", p;
4545          if(dbg>4) {pause();}
4546        }
4547        JGr = JGr, p;
4548        JGr = groebner(JGr);
4549        J = J, p;
4550      }
4551    }
4552  }
4553  return(J);
4554}
4555
4556///////////////////////////////////////////////////////////////////////////////
4557
4558static proc testIdeal(ideal I, ideal U, ideal origJ, poly c, poly D)
4559{
4560// Internal procedure, used in normalM.
4561// Computes the test ideal in the new ring.
4562// It takes the original test ideal and computes the radical of it in the
4563// new ring.
4564
4565// The new ring is 1/c * U.
4566// The original test ideal is origJ.
4567// The original ring is R / I, where R is the basering.
4568  int i;                                // counter
4569  int dbg = printlevel - voice + 2;     // dbg = printlevel (default: dbg = 0)
4570  def R = basering;                      // We dont work in the quo
4571  ideal J = origJ;
4572
4573  // ---------- computation of the ring structure of 1/c * U ----------------
4574  U = lineUp(U, c);
4575
4576  if(dbg > 1){"Computing the new ring structure...";}
4577  list ele = computeRing(U, I, "noRed");
4578
4579  def origEre = ele[1];
4580  setring origEre;
4581  if(dbg > 1){"The relations are"; norid;}
4582
4583  // ---------------- setting the ring to work in  --------------------------
4584  int isGlobal = ord_test(origEre);      // Checks if the original ring has
4585                                         // global ordering.
4586  if(isGlobal != 1)
4587  {
4588    list rl = ringlist(origEre);
4589    list origOrd = rl[3];
4590    list newOrd = list("dp", intvec(1:nvars(origEre))), list("C", 0);
4591    rl[3] = newOrd;
4592    def ere = ring(rl);     // globR is the original ring but
4593                            // with a global ordering.
4594    setring ere;
4595    ideal norid = imap(origEre, norid);
4596  }
4597  else
4598  {
4599    def ere = origEre;
4600  }
4601
4602  ideal I = imap(R, I);
4603  ideal J = imap(R, J);
4604  J = J, norid, I;
4605
4606
4607  // ----- computation of the test ideal using the ring structure of Ai -----
4608  option("redSB");
4609  option("returnSB");
4610
4611  if(dbg > 1){"Computing the radical of J...";}
4612  J = radical(J);
4613  if(dbg > 1){"Computing the interreduction of the radical...";}
4614  J = groebner(J);
4615  //J = interred(J);
4616  if(dbg > 1)
4617  {
4618    "The radical in the generated ring is";
4619    J;
4620    if(dbg>4){pause();}
4621  }
4622
4623  setring ere;
4624
4625  // -------------- map from Ai to the total ring of fractions ---------------
4626  // Now we must map back this ideal J to U_i / c in the total ring of
4627  // fractions.
4628  // The map sends T_j -> u_j / c.
4629  // The map is built by the following steps:
4630  // 1) We compute the degree of the generators of J with respect to the
4631  //    new variables T_j.
4632  // 2) For each generator, we multiply each term by a power of c, as if
4633  //    taking c^n as a common denominator (considering the new variables as
4634  //    a polynomial in the old variables divided by c).
4635  // 3) We replace the new variables T_j by the corresponding numerator u_j.
4636  // 4) We lift the resulting polynomial to change the denominator
4637  //    from c^n to c.
4638  int nNewVars = nvars(ere) - nvars(R);      // Number of new variables
4639  poly c = imap(R, c);
4640  intvec @v = 1..nNewVars;    // Vector of the new variables.
4641                              // They must be the first ones.
4642  if(dbg > 1){"The indices of the new variables are", @v;}
4643
4644  // ---------------------- step 1 of the mapping ---------------------------
4645  intvec degs;
4646  for(i = 1; i<=ncols(J); i++)
4647  {
4648    degs[i] = degSubring(J[i], @v);
4649  }
4650  if(dbg > 1)
4651  {
4652    "The degrees with respect to the new variables are";
4653    degs;
4654  }
4655
4656  // ---------------------- step 2 of the mapping ---------------------------
4657  ideal mapJ = mapBackIdeal(J, c, @v);
4658
4659  setring R;
4660
4661  // ---------------------- step 3 of the mapping ---------------------------
4662  ideal z;                    // The variables of the original ring in order.
4663  for(i = 1; i<=nvars(R); i++)
4664  {
4665    z[i] = var(i);
4666  }
4667
4668  map f = ere, U[2..ncols(U)], z[1..ncols(z)]; // The map to the original ring.
4669  if(dbg > 1)
4670  {
4671    "The map is ";
4672    f;
4673    if(dbg>4){pause();}
4674  }
4675
4676  if(dbg > 1){ "Computing the map..."; }
4677
4678  J = f(mapJ);
4679  if(dbg > 1)
4680  {
4681    "The ideal J mapped back (before lifting) is";
4682    J;
4683    if(dbg>4){pause();}
4684  }
4685
4686  // ---------------------- step 4 of the mapping ---------------------------
4687  qring Q = groebner(I);
4688  ideal J = imap(R, J);
4689  poly c = imap(R, c);
4690  for(i = 1; i<=ncols(J); i++)
4691  {
4692    if(degs[i]>1)
4693    {
4694      J[i] = lift(c^(degs[i]-1), J[i])[1,1];
4695    }
4696    else
4697    {
4698      if(degs[i]==0) { J[i] = c*J[i]; }
4699    }
4700  }
4701
4702  if(dbg > 1)
4703  {
4704    "The ideal J lifted is";
4705    J;
4706    if(dbg>4){pause();}
4707  }
4708
4709  // --------------------------- prepare output ----------------------------
4710  J = groebner(J);
4711
4712  setring R;
4713  J = imap(Q, J);
4714
4715  return(list(J, ele[1]));
4716}
4717
4718///////////////////////////////////////////////////////////////////////////////
4719
4720static proc changeDenominator(ideal U1, poly c1, poly c2, ideal I)
4721{
4722// Given a ring in the form 1/c1 * U, it computes a new ideal U2 such that the
4723// ring is 1/c2 * U2.
4724// The base ring is R, but the computations are to be done in R / I.
4725  int a;      // counter
4726  def R = basering;
4727  qring Q = I;
4728  ideal U1 = fetch(R, U1);
4729  poly c1 = fetch(R, c1);
4730  poly c2 = fetch(R, c2);
4731  ideal U2 = changeDenominatorQ(U1, c1, c2);
4732  setring R;
4733  ideal U2 = fetch(Q, U2);
4734  return(U2);
4735}
4736
4737///////////////////////////////////////////////////////////////////////////////
4738
4739static proc changeDenominatorQ(ideal U1, poly c1, poly c2)
4740{
4741// Given a ring in the form 1/c1 * U, it computes a new U2 st the ring
4742// is 1/c2 * U2.
4743// The base ring is already a quotient ring R / I.
4744  int a;      // counter
4745  ideal U2;
4746  poly p;
4747  for(a = 1; a <= ncols(U1); a++)
4748  {
4749    p = lift(c1, c2*U1[a])[1,1];
4750    U2[a] = p;
4751  }
4752  return(U2);
4753}
4754
4755///////////////////////////////////////////////////////////////////////////////
4756
4757static proc checkInclusions(ideal U1, ideal U2)
4758{
4759// Checks if the identity A = Hom(J, J) of Grauert-Remmert criterion is
4760// satisfied.
4761  int dbg = printlevel - voice + 2;     // dbg = printlevel (default: dbg = 0)
4762  list reduction1;
4763  list reduction2;
4764
4765  // ---------------------- inclusion Hom(J, J) c A -------------------------
4766  if(dbg > 1){"Checking the inclusion Hom(J, J) c A:";}
4767  // This interred is used only because a bug in groebner!
4768  U1 = groebner(U1);
4769  reduction1 = reduce(U2, U1);
4770  if(dbg > 1){reduction1[1];}
4771
4772  // ---------------------- inclusion A c Hom(J, J) -------------------------
4773  // The following check should always be satisfied.
4774  // This is only used for debugging.
4775  if(dbg > 1)
4776  {
4777    "and the inclusion A c Hom(J, J): (this should always be satisfied)";
4778    // This interred is used only because a bug in groebner!
4779    U2 = groebner(U2);
4780    reduction2 = reduce(U1, groebner(U2));
4781    reduction2[1];
4782    if(size(reduction2[1]) > 0)
4783    {
4784      "Something went wrong... (this inclusion should always be satisfied)";
4785      ~;
4786    }
4787    else
4788    {
4789      if(dbg>4){pause();}
4790    }
4791  }
4792
4793  if(size(reduction1[1]) == 0)
4794  {
4795    // We are done! The ring computed in the last step was normal.
4796    return(1);
4797  }
4798  else
4799  {
4800    return(0);
4801  }
4802}
4803
4804///////////////////////////////////////////////////////////////////////////////
4805
4806static proc degSubring(poly p, intvec @v)
4807{
4808// Computes the degree of a polynomial taking only some variables as variables
4809// and the others as parameters.
4810
4811// The degree is taken w.r.t. the variables indicated in v.
4812  int i;      // Counter
4813  int d = 0;  // The degree
4814  int e;      // Degree (auxiliar variable)
4815  for(i = 1; i <= size(p); i++)
4816  {
4817    e = sum(leadexp(p[i]), @v);
4818    if(e > d){d = e;}
4819  }
4820  return(d);
4821}
4822
4823///////////////////////////////////////////////////////////////////////////////
4824
4825static proc mapBackIdeal(ideal I, poly c, intvec @v)
4826{
4827// Modifies all polynomials in I so that a map x(i) -> y(i)/c can be
4828// carried out.
4829
4830// v indicates wicih variables x(i) of the ring will be mapped to y(i)/c.
4831
4832  int i;  // counter
4833  for(i = 1; i <= ncols(I); i++)
4834  {
4835    I[i] = mapBackPoly(I[i], c, @v);
4836  }
4837  return(I);
4838}
4839
4840///////////////////////////////////////////////////////////////////////////////
4841
4842static proc mapBackPoly(poly p, poly c, intvec @v)
4843{
4844// Multiplies each monomial of p by a power of c so that a map x(i) -> y(i)/c
4845// can be carried out.
4846
4847// v indicates wicih variables x(i) of the ring will be mapped to y(i)/c.
4848  int i;  // counter
4849  int e;  // exponent
4850  int d = degSubring(p, @v);
4851  poly g = 0;
4852  int size_p=size(p);
4853  for(i = 1; i <= size_p; i++)
4854  {
4855    e = sum(leadexp(p[i]), @v);
4856    g = g + p[i] * c^(d-e);
4857  }
4858  return(g);
4859}
4860
4861//                Up to here: procedures for normal
4862///////////////////////////////////////////////////////////////////////////////
4863
4864
4865///////////////////////////////////////////////////////////////////////////////
4866//                From here: procedures for normalC
4867
4868// We first define resp. copy some attributes to be used in proc normal and
4869// static proc normalizationPrimes, and ..., to speed up computation in
4870// special cases
4871//NOTE:  We use the following attributes:
4872// 1     attrib(id,"isCohenMacaulay");         //--- Cohen Macaulay
4873// 2     attrib(id,"isCompleteIntersection");  //--- complete intersection
4874// 3     attrib(id,"isHypersurface");          //--- hypersurface
4875// 4     attrib(id,"isEquidimensional");       //--- equidimensional ideal
4876// 5     attrib(id,"isPrim");                  //--- prime ideal
4877// 6     attrib(id,"isRegInCodim2");           //--- regular in codimension 2
4878// 7     attrib(id,"isIsolatedSingularity");   //--- isolated singularities
4879// 8     attrib(id,"onlySingularAtZero");      //--- only singular at 0
4880// 9     attrib(id,"isRadical");               //--- radical ideal
4881//Recall: (attrib(id,"xy"),1) sets attrib xy to TRUE and
4882//        (attrib(id,"xy"),0) to FALSE
4883
4884static proc getAttrib (ideal id)
4885"USAGE:   getAttrib(id);  id=ideal
4886COMPUTE: check attributes for id. If the attributes above are defined,
4887         take its value, otherwise define it and set it to 0
4888RETURN:  intvec of size 9, with entries 0 or 1,  values of attributes defined
4889         above (in this order)
4890EXAMPLE: no example
4891"
4892{
4893  int isCoM,isCoI,isHy,isEq,isPr,isReg,isIso,oSAZ,isRad;
4894
4895  if( typeof(attrib(id,"isCohenMacaulay"))=="int" )
4896  {
4897    if( attrib(id,"isCohenMacaulay")==1 )
4898    { isCoM=1; isEq=1; }
4899  }
4900
4901  if( typeof(attrib(id,"isCompleteIntersection"))=="int" )
4902  {
4903    if(attrib(id,"isCompleteIntersection")==1)
4904    { isCoI=1; isCoM=1; isEq=1; }
4905  }
4906
4907  if( typeof(attrib(id,"isHypersurface"))=="int" )
4908  {
4909    if(attrib(id,"isHypersurface")==1)
4910    { isHy=1; isCoI=1; isCoM=1; isEq=1; }
4911  }
4912
4913  if( typeof(attrib(id,"isEquidimensional"))=="int" )
4914  {
4915    if(attrib(id,"isEquidimensional")==1)
4916    { isEq=1; }
4917  }
4918
4919  if( typeof(attrib(id,"isPrim"))=="int" )
4920  {
4921    if(attrib(id,"isPrim")==1)
4922    { isPr=1; }
4923  }
4924
4925  if( typeof(attrib(id,"isRegInCodim2"))=="int" )
4926  {
4927    if(attrib(id,"isRegInCodim2")==1)
4928    { isReg=1; }
4929  }
4930
4931  if( typeof(attrib(id,"isIsolatedSingularity"))=="int" )
4932  {
4933    if(attrib(id,"isIsolatedSingularity")==1)
4934    { isIso=1; }
4935  }
4936
4937  if( typeof(attrib(id,"onlySingularAtZero"))=="int" )
4938  {
4939    if(attrib(id,"onlySingularAtZero")==1)
4940    { oSAZ=1; }
4941  }
4942
4943  if( typeof(attrib(id,"isRad"))=="int" )
4944  {
4945    if(attrib(id,"isRad")==1)
4946    { isRad=1; }
4947  }
4948
4949  intvec atr = isCoM,isCoI,isHy,isEq,isPr,isReg,isIso,oSAZ,isRad;
4950  return(atr);
4951}
4952
4953///////////////////////////////////////////////////////////////////////////////
4954
4955static proc setAttrib (ideal id, intvec atr)
4956"USAGE:   setAttrib(id,atr);  id ideal, atr intvec
4957COMPUTE: set attributes to id specified by atr
4958RETURN:  id, with assigned attributes from atr
4959EXAMPLE: no example
4960"
4961{
4962  attrib(id,"isCohenMacaulay",atr[1]);         //--- Cohen Macaulay
4963  attrib(id,"isCompleteIntersection",atr[2]);  //--- complete intersection
4964  attrib(id,"isHypersurface",atr[3]);          //--- hypersurface
4965  attrib(id,"isEquidimensional",atr[4]);       //--- equidimensional ideal
4966  attrib(id,"isPrim",atr[5]);                  //--- prime ideal
4967  attrib(id,"isRegInCodim2",atr[6]);           //--- regular in codimension 2
4968  attrib(id,"isIsolatedSingularity",atr[7]);   //--- isolated singularities
4969  attrib(id,"onlySingularAtZero",atr[8]);      //--- only singular at 0
4970  attrib(id,"isRadical",atr[9]);               //--- radical ideal
4971
4972  return(id);
4973}
4974
4975///////////////////////////////////////////////////////////////////////////////
4976// copyAttribs is not used anywhere so far
4977
4978static proc copyAttribs (ideal id1, ideal id)
4979"USAGE:   copyAttribs(id1,id);  id1, id ideals
4980COMPUTE: copy attributes from id1 to id
4981RETURN:  id, with assigned attributes from id1
4982EXAMPLE: no example
4983"
4984{
4985  if( typeof(attrib(id1,"isCohenMacaulay"))=="int" )
4986  {
4987    if( attrib(id1,"isCohenMacaulay")==1 )
4988    {
4989      attrib(id,"isEquidimensional",1);
4990    }
4991  }
4992  else
4993  {
4994    attrib(id,"isCohenMacaulay",0);
4995  }
4996
4997  if( typeof(attrib(id1,"isCompleteIntersection"))=="int" )
4998  {
4999    if(attrib(id1,"isCompleteIntersection")==1)
5000    {
5001      attrib(id,"isCohenMacaulay",1);
5002      attrib(id,"isEquidimensional",1);
5003    }
5004  }
5005  else
5006  {
5007    attrib(id,"isCompleteIntersection",0);
5008  }
5009
5010  if( typeof(attrib(id1,"isHypersurface"))=="int" )
5011  {
5012    if(attrib(id1,"isHypersurface")==1)
5013    {
5014      attrib(id,"isCompleteIntersection",1);
5015      attrib(id,"isCohenMacaulay",1);
5016      attrib(id,"isEquidimensional",1);
5017    }
5018  }
5019  else
5020  {
5021    attrib(id,"isHypersurface",0);
5022  }
5023
5024  if( (typeof(attrib(id1,"isEquidimensional"))=="int") )
5025  {
5026    if(attrib(id1,"isEquidimensional")==1)
5027    {
5028      attrib(id,"isEquidimensional",1);
5029    }
5030  }
5031  else
5032  {
5033    attrib(id,"isEquidimensional",0);
5034  }
5035
5036  if( typeof(attrib(id1,"isPrim"))=="int" )
5037  {
5038    if(attrib(id1,"isPrim")==1)
5039    {
5040      attrib(id,"isEquidimensional",1);
5041    }
5042  }
5043  else
5044  {
5045    attrib(id,"isPrim",0);
5046  }
5047
5048  if( (typeof(attrib(id1,"isRegInCodim2"))=="int") )
5049  {
5050    if(attrib(id1,"isRegInCodim2")==1)
5051    {
5052      attrib(id,"isRegInCodim2",1);
5053    }
5054  }
5055  else
5056  {
5057    attrib(id,"isRegInCodim2",0);
5058  }
5059
5060  if( (typeof(attrib(id1,"isIsolatedSingularity"))=="int") )
5061  {
5062    if(attrib(id1,"isIsolatedSingularity")==1)
5063    {
5064      attrib(id,"isIsolatedSingularity",1);
5065    }
5066  }
5067  else
5068  {
5069    attrib(id,"isIsolatedSingularity",0);
5070  }
5071
5072  if( typeof(attrib(id1,"onlySingularAtZero"))=="int" )
5073  {
5074    if(attrib(id1,"onlySingularAtZero")==1)
5075    {
5076      attrib(id,"isIsolatedSingularity",1);
5077    }
5078  }
5079  else
5080  {
5081    attrib(id,"onlySingularAtZero",0);
5082  }
5083
5084  if( typeof(attrib(id1,"isRad"))=="int" )
5085  {
5086    if(attrib(id1,"isRad")==1)
5087    {
5088      attrib(id,"isRad",1);
5089    }
5090  }
5091  else
5092  {
5093    attrib(id,"isRad",0);
5094  }
5095  return(id);
5096}
5097
5098proc normalC(ideal id, list #)
5099"USAGE:   normalC(id [,choose]);  id = radical ideal, choose = optional string
5100         which may be a combination of \"equidim\", \"prim\", \"withGens\",
5101         \"isPrim\", \"noFac\".@*
5102         If choose is not given or empty, a default method is choosen@*
5103         If choose = \"prim\" resp. \"equidim\" normalC computes a prime resp.
5104         an equidimensional decomposition and then the normalization of each
5105         component; if choose = \"noFac\" factorization is avoided in the
5106         computation of the minimal associated primes; @*
5107         if choose = \"withGens\" the minimal associated primes P_i of id are
5108         computed and for each P_i, algebra generators of the integral closure
5109         of basering/P_i are computed as elements of its quotient field;@*
5110         \"isPrim\" disables \"equidim\" and \"prim\".@*
5111ASSUME:  The ideal must be radical, for non-radical ideals the output may
5112         be wrong (id=radical(id); makes id radical). However, if choose =
5113         \"prim\" the minimal associated primes of id are computed first
5114         and hence normalC computes the normalization of the radical of id.
5115         \"isPrim\" should only be used if id is known to be irreducible.
5116RETURN:  a list, say nor, of size 2 (resp. 3 if choose=\"withGens\").
5117         The first list nor[1] consists of r rings, where r is the number
5118         of irreducible components if choose = \"prim\" (resp. >= no of
5119         equidimenensional components if choose =  \"equidim\").
5120@format
5121         Each ring Ri=nor[1][i], i=1..r, contains two ideals with given
5122         names @code{norid} and @code{normap} such that @*
5123         - Ri/norid is the normalization of the i-th component, i.e. the
5124          integral closure in its field of fractions (as affine ring);
5125         - the direct sum of the rings Ri/norid is the normalization
5126           of basering/id; @*
5127         - @code{normap} gives the normalization map from basering/id to
5128           Ri/norid for each j.@*
5129
5130         If choose=\"withGens\", nor[2] is a list of size r of ideals Ii=
5131         nor[2][i] in the basering, generating the integral closure of
5132         basering/P_i in its quotient field, i=1..r, in two different ways:
5133         - Ii is given by polynomials
5134           g_1,...,g_k,g_k+1 such that the variables T(j) of the ring Ri
5135           satisfy T(1)=g_1/g_k+1,..,T(k)=g_k/g_k+1. Hence the g_j/g_k+1
5136           are algebra generators of the integral closure of basering/P_i
5137           as sub-algebra in the quotient field of basering/P_i.
5138
5139         nor[2] (resp. nor[3] if choose=\"withGens\") is a list of an intvec
5140         of size r, the delta invariants of the r components, and an integer,
5141         the total delta invariant of basering/id (-1 means infinite, and 0
5142         that basering/P_i resp. basering/input is normal).
5143         Return value -2 means that delta resp. delta of one of the components
5144         is not computed (which may happen if \"equidim\" is given) .
5145@end format
5146THEORY:  The delta invariant of a reduced ring K[x1,...,xn]/id is
5147             dim_K(normalization(K[x1,...,xn]/id) / K[x1,...,xn]/id)
5148         We call this number also the delta invariant of id.
5149         We use the algorithm described in [G.-M. Greuel, G. Pfister:
5150         A SINGULAR Introduction to Commutative Algebra, 2nd Edition.
5151         Springer Verlag (2007)].
5152NOTE:    To use the i-th ring type: @code{def R=nor[1][i]; setring R;}.
5153@*       Increasing/decreasing printlevel displays more/less comments
5154         (default: printlevel=0).
5155@*       Not implemented for local or mixed orderings and for quotient rings.
5156@*       If the input ideal id is weighted homogeneous a weighted ordering may
5157         be used (qhweight(id); computes weights).
5158KEYWORDS: normalization; integral closure; delta invariant.
5159EXAMPLE: example normalC; shows an example
5160"
5161{
5162   int i,j, wgens, withEqui, withPrim, isPrim, nfac;
5163   int y = printlevel-voice+2;
5164   int nvar = nvars(basering);
5165   int chara  = char(basering);
5166   list result,prim,keepresult;
5167
5168   if ( ord_test(basering) != 1 )
5169   {
5170     "";
5171     "// Not implemented for this ordering,";
5172     "// please change to global ordering!";
5173     return(result);
5174   }
5175
5176//--------------------------- define the method ---------------------------
5177   string method;                //make all options one string in order to use
5178                                 //all combinations of options simultaneously
5179   for ( i=1; i <= size(#); i++ )
5180   {
5181     if ( typeof(#[i]) == "string" )
5182     {
5183       method = method + #[i];
5184     }
5185   }
5186
5187   //--------------------------- choosen methods -----------------------
5188   //we have the methods
5189   // "withGens": computes algebra generators for each irreducible component
5190   // the general case: either "equidim" or not (then applying minAssGTZ)
5191
5192   if ( find(method,"withgens") or find(method,"withGens"))
5193   {
5194     wgens=1;
5195   }
5196   if ( find(method,"equidim") )
5197   {
5198     withEqui=1;
5199   }
5200   if ( find(method,"prim") )
5201   {
5202     withPrim=1;
5203   }
5204   if ( find(method,"isprim") or find(method,"isPrim") )
5205   {
5206     isPrim=1;
5207   }
5208   if ( find(method,"noFac") )
5209   {
5210     nfac=1;
5211   }
5212
5213   //------------------ default method, may be changed --------------------
5214   //Use a prime decomposition only for small no of variables otherwise equidim
5215   //Compute delta whenever possible.
5216
5217   if ( ((chara==0 || chara>30) && nvar>2 && !withPrim && !isPrim) ||
5218   ((chara==0 || chara>30) && size(#)  ==  0) )
5219   {
5220      withEqui=1;
5221   }
5222   kill #;
5223   list #;
5224
5225//------- Special algorithm with computation of the generators, RETURN -------
5226   //--------------------- method "withGens" ----------------------------------
5227   //the integral closure is computed in proc primeClosure. In the general case
5228   //it is computed in normalizationPrimes. The main difference is that  in
5229   //primeClosure the singular locus is only computed in the first iteration
5230   //that no attributes are used and that the generators are computed.
5231   //In primeClosure the (algebra) generators for each irreducible component
5232   //are computed in static proc closureGenerators
5233
5234   if( wgens )
5235   {
5236      if( y >= 1 )
5237      {  "";
5238         "// We use method 'withGens'";
5239      }
5240      if ( isPrim )
5241      {
5242         prim[1] = id;
5243         if( y >= 0 )
5244         {
5245           "";
5246           "// ** WARNING: result is correct if ideal is prime (not checked) **";
5247           "// if procedure is called with string \"prim\", primality is checked";
5248         }
5249      }
5250      else
5251      {
5252         if(y>=1)
5253         {  "// compute minimal associated primes"; }
5254
5255         if( nfac )
5256         { prim = minAssGTZ(id,1); }
5257         else
5258         { prim = minAssGTZ(id); }
5259
5260         if(y>=1)
5261         {
5262            prim;"";
5263            "// number of irreducible components is", size(prim);
5264         }
5265      }
5266   //----------- compute integral closure for every component -------------
5267      int del;
5268      intvec deli;
5269      list Gens,l,resu,Resu;
5270      ideal gens;
5271      def R = basering;
5272      poly gg;
5273
5274      for(i=1; i<=size(prim); i++)
5275      {
5276         if(y>=1)
5277         {
5278            ""; pause(); "";
5279            "// start computation of component",i;
5280            "   --------------------------------";
5281         }
5282
5283         if( defined(ker) ) { kill ker; }
5284         ideal ker = prim[i];
5285         export(ker);
5286         l = R;
5287         l = primeClosure(l,1);               //here the work is done
5288         //### ausprobieren ob primeClosure(l,1) schneller als primeClosure(l)
5289         // 1 bedeutet: kŸrzester nzd
5290
5291         if ( l[size(l)] >= 0 && del >= 0 )
5292         {
5293            del = del + l[size(l)];
5294         }
5295         else
5296         { del = -1; }
5297         deli = l[size(l)],deli;
5298
5299         l = l[1..size(l)-1];
5300         resu = list(l[size(l)]) + resu;
5301         gens = closureGenerators(l);         //computes algebra(!) generators
5302
5303         //NOTE: gens[i]/gens[size(gens)] expresses the ith variable of resu[1]
5304         //(the normalization) as fraction of elements of the basering;
5305         //the variables of resu[1] are algebra generators.
5306         //gens[size(gens)] is a non-zero divisor of basering/i
5307
5308         //divide by the greatest common divisor:
5309         gg = gcd( gens[1],gens[size(gens)] );
5310         for(j=2; j<=size(gens)-1; j++)
5311         {
5312            gg=gcd(gg,gens[j]);
5313         }
5314         for(j=1; j<=size(gens); j++)
5315         {
5316            gens[j]=gens[j]/gg;
5317         }
5318         Gens = list(gens) + Gens;
5319
5320/*       ### Da die gens Algebra-Erzeuger sind, ist reduce nach Bestimmung
5321         der Algebra-Variablen T(i) nicht zulŠssig!
5322         for(i=1;i<=size(gens)-1;i++)
5323         {
5324            gens[i]= reduce(gens[i],std(gens[size(gens)]));
5325         }
5326         for(i=size(gens)-1; i>=1; i--)
5327         {
5328            if(gens[i]==0)
5329            { gens = delete(gens,i); }
5330         }
5331*/
5332         if( defined(ker) ) { kill ker; }
5333      }
5334
5335      if ( del >= 0 )
5336      {
5337         int mul = iMult(prim);
5338         del = del + mul;
5339      }
5340      else
5341      { del = -1; }
5342      deli = deli[1..size(deli)-1];
5343      Resu = resu,Gens,list(deli,del);
5344      int sr = size(resu);
5345
5346      if ( y >= 0 )
5347      {"";
5348"// 'normalC' created a list, say nor, of three lists:
5349// nor[1] resp. nor[2] are lists of",sr,"ring(s) resp. ideal(s)
5350// and nor[3] is a list of an intvec and an integer.
5351// To see the result, type
5352     nor;
5353// To access the i-th ring nor[1][i] give it a name, say Ri, and type e.g.
5354     def R1 = nor[1][1]; setring R1;  norid; normap;
5355// for the other rings type first setring r; (if r is the name of your
5356// original basering) and then continue as for the first ring;
5357// Ri/norid is the affine algebra of the normalization of the i-th
5358// component r/P_i (where P_i is an associated prime of the input ideal)
5359// and normap the normalization map from r to Ri/norid;
5360//    nor[2] is a list of",sr,"ideal(s), each ideal nor[2][i] consists of
5361// elements g1..gk of r such that the gj/gk generate the integral
5362// closure of r/P_i as sub-algebra in the quotient field of r/P_i, with
5363// gj/gk being mapped by normap to the j-th variable of Ri;
5364//    nor[3] shows the delta-invariant of each component and of the input
5365// ideal (-1 means infinite, and 0 that r/P_i resp. r/input is normal).";
5366      }
5367      return(Resu);
5368   }
5369
5370//-------- The general case without computation of the generators -----------
5371// (attrib(id,"xy"),1) sets attrib xy to TRUE and (attrib(id,"xy"),0) to FALSE
5372// We use the following attributes:
5373//   attrib(id,"isCohenMacaulay");         //--- Cohen Macaulay
5374//   attrib(id,"isCompleteIntersection");  //--- complete intersection
5375//   attrib(id,"isHypersurface");          //--- hypersurface
5376//   attrib(id,"isEquidimensional",-1);    //--- equidimensional ideal
5377//   attrib(id,"isPrim");                  //--- prime ideal
5378//   attrib(id,"isRegInCodim2");           //--- regular in codimension 2
5379//   attrib(id,"isIsolatedSingularity";    //--- isolated singularities
5380//   attrib(id,"onlySingularAtZero");      //--- only singular at 0
5381
5382 //------------------- first set the attributes ----------------------
5383   if( typeof(attrib(id,"isCohenMacaulay"))=="int" )
5384   {
5385      if( attrib(id,"isCohenMacaulay")==1 )
5386      {
5387         attrib(id,"isEquidimensional",1);
5388      }
5389   }
5390   else
5391   {
5392      attrib(id,"isCohenMacaulay",0);
5393   }
5394
5395   if( typeof(attrib(id,"isCompleteIntersection"))=="int" )
5396   {
5397      if(attrib(id,"isCompleteIntersection")==1)
5398      {
5399         attrib(id,"isCohenMacaulay",1);
5400         attrib(id,"isEquidimensional",1);
5401      }
5402   }
5403   else
5404   {
5405      attrib(id,"isCompleteIntersection",0);
5406   }
5407
5408   if( typeof(attrib(id,"isHypersurface"))=="int" )
5409   {
5410      if(attrib(id,"isHypersurface")==1)
5411      {
5412         attrib(id,"isCompleteIntersection",1);
5413         attrib(id,"isCohenMacaulay",1);
5414         attrib(id,"isEquidimensional",1);
5415      }
5416   }
5417   else
5418   {
5419      attrib(id,"isHypersurface",0);
5420   }
5421
5422   if( ! (typeof(attrib(id,"isEquidimensional"))=="int") )
5423   {
5424         attrib(id,"isEquidimensional",0);
5425   }
5426
5427   if( typeof(attrib(id,"isPrim"))=="int" )
5428   {
5429      if(attrib(id,"isPrim")==1)
5430      {
5431         attrib(id,"isEquidimensional",1);
5432      }
5433   }
5434   else
5435   {
5436      attrib(id,"isPrim",0);
5437   }
5438
5439   if( ! (typeof(attrib(id,"isRegInCodim2"))=="int") )
5440   {
5441         attrib(id,"isRegInCodim2",0);
5442   }
5443
5444   if( ! (typeof(attrib(id,"isIsolatedSingularity"))=="int") )
5445   {
5446         attrib(id,"isIsolatedSingularity",0);
5447   }
5448
5449   if( typeof(attrib(id,"onlySingularAtZero"))=="int" )
5450   {
5451      if(attrib(id,"onlySingularAtZero")==1)
5452      {
5453         attrib(id,"isIsolatedSingularity",1);
5454      }
5455   }
5456   else
5457   {
5458      attrib(id,"onlySingularAtZero",0);
5459   }
5460
5461   //-------------- compute equidimensional decomposition --------------------
5462   //If the method "equidim" is given, compute the equidim decomposition
5463   //and goto the next step (no normalization
5464   //ACHTUNG: equidim berechnet bei nicht reduzierten id die eingebetteten
5465   //Komponenten als niederdim Komponenten, waehrend diese bei primdecGTZ
5466   //nicht auftauchen: ideal(x,y)*xy
5467   //this is default for nvars > 2 and char = 0 or car > 30
5468
5469   if( withEqui )
5470   {
5471      withPrim = 0;                 //this is used to check later that prim
5472                                    //contains equidim but not prime components
5473      if( y >= 1 )
5474      {
5475         "// We use method 'equidim'";
5476      }
5477      if( typeof(attrib(id,"isEquidimensional"))=="int" )
5478      {
5479         if(attrib(id,"isEquidimensional")==1)
5480         {
5481            prim[1] = id;
5482         }
5483         else
5484         {
5485            prim = equidim(id);
5486         }
5487      }
5488      else
5489      {
5490         prim = equidim(id);
5491      }
5492      if(y>=1)
5493      {  "";
5494         "// number of equidimensional components:", size(prim);
5495      }
5496      if ( !nfac )
5497      {
5498        intvec opt = option(get);
5499        option(redSB);
5500        for(j=1; j<=size(prim); j++)
5501        {
5502           keepresult = keepresult+facstd(prim[j]);
5503        }
5504        prim = keepresult;
5505        if ( size(prim) == 0 )
5506        {
5507          prim=ideal(0);     //Bug in facstd, liefert leere Liste bei 0-Ideal
5508        }
5509
5510        if(y>=1)
5511        {  "";
5512         "// number of components after application of facstd:", size(prim);
5513        }
5514        option(set,opt);
5515      }
5516   }
5517
5518   //------------------- compute associated primes -------------------------
5519   //the case where withEqui = 0, here the min. ass. primes are computed
5520   //start with the computation of the minimal associated primes:
5521
5522   else
5523   {
5524    if( isPrim )
5525    {
5526      if( y >= 0 )
5527      {
5528         "// ** WARNING: result is correct if ideal is prime";
5529         "// or equidimensional (not checked) **";
5530         "// disable option \"isPrim\" to decompose ideal into prime";
5531         "// or equidimensional components";"";
5532      }
5533      if( y >= 1 )
5534      {
5535        "// We use method 'isPrim'";"";
5536      }
5537      prim[1]=id;
5538    }
5539    else
5540    {
5541      withPrim = 1;                 //this is used to check later that prim
5542                                    //contains prime but not equidim components
5543      if( y >= 1 )
5544      {
5545         "// We use method 'prim'";
5546      }
5547
5548      if( typeof(attrib(id,"isPrim"))=="int" )
5549      {
5550         if(attrib(id,"isPrim")==1)
5551         {
5552            prim[1]=id;
5553         }
5554         else
5555         {
5556            if( nfac )
5557            { prim=minAssGTZ(id,1); }     //does not use factorizing groebner
5558            else
5559            { prim=minAssGTZ(id); }       //uses factorizing groebner
5560         }
5561      }
5562      else
5563      {
5564            if( nfac )
5565            { prim=minAssGTZ(id,1); }
5566            else
5567            { prim=minAssGTZ(id); }
5568      }
5569      if(y>=1)
5570      {  "";
5571         "// number of irreducible components:", size(prim);
5572      }
5573    }
5574   }
5575
5576   //----- for each component (equidim or irred) compute normalization -----
5577   int sr, skr, del;
5578   intvec deli;
5579   int sp = size(prim);     //size of list prim (# irred or equidim comp)
5580
5581   for(i=1; i<=sp; i++)
5582   {
5583      if(y>=1)
5584      {  "";
5585         "// computing the normalization of component",i;
5586         "   ----------------------------------------";
5587      }
5588      //-------------- first set attributes for components ------------------
5589      attrib(prim[i],"isEquidimensional",1);
5590      if( withPrim )
5591      {
5592         attrib(prim[i],"isPrim",1);
5593      }
5594      else
5595      { attrib(prim[i],"isPrim",0); }
5596
5597      if(attrib(id,"onlySingularAtZero")==1)
5598      { attrib(prim[i],"onlySingularAtZero",1); }
5599      else
5600      { attrib(prim[i],"onlySingularAtZero",0); }
5601
5602      if(attrib(id,"isIsolatedSingularity")==1)
5603      { attrib(prim[i],"isIsolatedSingularity",1); }
5604      else
5605      { attrib(prim[i],"isIsolatedSingularity",0); }
5606
5607      if( attrib(id,"isHypersurface")==1 )
5608      {
5609         attrib(prim[i],"isHypersurface",1);
5610         attrib(prim[i],"isCompleteIntersection",1);
5611         attrib(prim[i],"isCohenMacaulay",1);
5612      }
5613      else
5614      { attrib(prim[i],"isHypersurface",0); }
5615
5616      if ( sp == 1)         //the case of one component: copy attribs from id
5617      {
5618        if(attrib(id,"isRegInCodim2")==1)
5619        {attrib(prim[i],"isRegInCodim2",1); }
5620        else
5621        {attrib(prim[i],"isRegInCodim2",0); }
5622
5623        if(attrib(id,"isCohenMacaulay")==1)
5624        {attrib(prim[i],"isCohenMacaulay",1); }
5625        else
5626        {attrib(prim[i],"isCohenMacaulay",0); }
5627
5628        if(attrib(id,"isCompleteIntersection")==1)
5629        {attrib(prim[i],"isCompleteIntersection",1); }
5630        else
5631        {attrib(prim[i],"isCompleteIntersection",0); }
5632      }
5633      else
5634      {
5635        attrib(prim[i],"isRegInCodim2",0);
5636        attrib(prim[i],"isCohenMacaulay",0);
5637        attrib(prim[i],"isCompleteIntersection",0);
5638      }
5639
5640      //------ Now compute the normalization of each component ---------
5641      //note: for equidimensional components the "splitting tools" can
5642      //create further decomposition
5643      //We now start normalizationPrimes with
5644      //ihp = partial normalisation map = identity map = maxideal(1)
5645      //del = partial delta invariant = 0
5646      //deli= intvec of partial delta invariants of components
5647      //in normalizationPrimes all the work is done:
5648
5649      keepresult = normalizationPrimes(prim[i],maxideal(1),0,0);
5650
5651      for(j=1; j<=size(keepresult)-1; j++)
5652      {
5653         result=insert(result,keepresult[j]);
5654      }
5655      skr = size(keepresult);
5656
5657      //compute delta:
5658      if( del >= 0 && keepresult[skr][1] >=0 )
5659      {
5660         del = del + keepresult[skr][1];
5661      }
5662      else
5663      {
5664         del = -1;
5665      }
5666      deli = keepresult[skr][2],deli;
5667
5668      if ( y>=1 )
5669      {
5670           "// delta of component",i; keepresult[skr][1];
5671      }
5672   }
5673   sr = size(result);
5674
5675   // -------------- Now compute intersection multiplicities -------------
5676   //intersection multiplicities of list prim, sp=size(prim).
5677      if ( y>=1 )
5678      {
5679        "// Sum of delta for all components"; del;
5680        if ( sp>1 )
5681        {
5682           "// Compute intersection multiplicities of the components";
5683        }
5684      }
5685
5686      if ( sp > 1 )
5687      {
5688        int mul = iMult(prim);
5689        if ( mul < 0 )
5690        {
5691           del = -1;
5692        }
5693        else
5694        {
5695           del = del + mul;
5696        }
5697      }
5698   deli = deli[1..size(deli)-1];
5699   result = result,list(deli,del);
5700
5701//--------------- Finally print comments and return ------------------
5702   if ( y >= 0)
5703   {"";
5704"// 'normalC' created a list, say nor, of two lists:
5705// nor[1] is a list of",sr,"ring(s), nor[2] a list of an intvec and an int.
5706// To see the result, type
5707      nor;
5708// To access the i-th ring nor[1][i] give it a name, say Ri, and type e.g.
5709      def R1 = nor[1][1];  setring R1;  norid;  normap;
5710// and similair for the other rings nor[1][i];
5711// Ri/norid is the affine algebra of the normalization of the i-th component
5712// r/P_i (where P_i is a prime or an equidimensional ideal of the input ideal)
5713// and normap the normalization map from the basering to Ri/norid;
5714//    nor[2] shows the delta-invariant of each component and of the input
5715// ideal (-1 means infinite, -2 that delta of a component was not computed).";
5716   }
5717   return(result);
5718}
5719
5720example
5721{ "EXAMPLE:";
5722   printlevel = printlevel+1;
5723   echo = 2;
5724   ring s = 0,(x,y),dp;
5725   ideal i = (x2-y3)*(x2+y2)*x;
5726
5727   list nor = normalC(i);
5728
5729   nor;
5730   // 2 branches have delta = 1, and 1 branch has delta = 0
5731   // the total delta invariant is 13
5732
5733   def R2 = nor[1][2];  setring R2;
5734   norid; normap;
5735
5736   echo = 0;
5737   printlevel = printlevel-1;
5738   pause("   hit return to continue"); echo=2;
5739
5740   ring r = 2,(x,y,z),dp;
5741   ideal i = z3-xy4;
5742   nor = normalC(i);  nor;
5743   // the delta invariant is infinite
5744   // xy2z/z2 and xy3/z2 generate the integral closure of r/i as r/i-module
5745   // in its quotient field Quot(r/i)
5746
5747   // the normalization as affine algebra over the ground field:
5748   def R = nor[1][1]; setring R;
5749   norid; normap;
5750
5751   echo = 0;
5752   pause("   hit return to continue");echo = 2;
5753
5754   setring r;
5755   nor = normalC(i, "withGens", "prim");    // a different algorithm
5756   nor;
5757}
5758
5759//////////////////////////////////////////////////////////////////////////////
5760//closureRingtower seems not to be used anywhere
5761static proc closureRingtower(list L)
5762"USAGE:    closureRingtower(list L); L a list of rings
5763CREATE:   rings R(1),...,R(n) such that R(i)=L[i] for all i
5764EXAMPLE:  example closureRingtower; shows an example
5765"
5766{
5767  int n=size(L);
5768  for (int i=1;i<=n;i++)
5769    {
5770      if (defined(R(i)))
5771      {
5772        string s="Fixed name R("+string(i)+") leads to conflict with existing "
5773              +"object having this name";
5774        ERROR(s);
5775      }
5776      def R(i)=L[i];
5777      export R(i);
5778    }
5779
5780  return();
5781}
5782example
5783{
5784  "EXAMPLE:"; echo=2;
5785  ring R=0,(x,y),dp;
5786  ideal I=x4,y4;
5787  list L=primeClosure(ReesAlgebra(I)[1]);
5788  L=delete(L,size(L));
5789  L;
5790  closureRingtower(L);
5791  R(1);
5792  R(4);
5793  kill R(1),R(2),R(3),R(4);
5794}
5795
5796//                Up to here: procedures for normalC
5797///////////////////////////////////////////////////////////////////////////////
5798
5799///////////////////////////////////////////////////////////////////////////////
5800//                From here: miscellaneous procedures
5801
5802// Used for timing and comparing the different normalization procedures.
5803// Option (can be entered in any order)
5804// "normal"   -> uses the new algortihm (normal)
5805// "normalP"  -> uses normalP
5806// "normalC"  -> uses normalC, without "withGens" option
5807// "primCl"   -> uses normalC, with option "withGens".
5808// "111"      -> checks the output of normalM using norTest.
5809// "p"        -> compares the output of norM with the output of normalP
5810//               ("normalP" option must also be set).
5811// "pc"       -> compares the output of norM with the output of normalC with
5812//               option "withGens"
5813//               ("primCl" option must also be set).
5814
5815proc timeNormal(ideal I, list #)
5816{
5817  def r = basering;
5818
5819  //--------------------------- define the method ---------------------------
5820  int isPrim, useRing;
5821  int decomp = -1;
5822  int norM, norC, norP, primCl;
5823  int checkP, check111, checkPC;
5824  int i;
5825  ideal U1, U2, W;
5826  poly c1, c2;
5827  int ch;
5828  string check;
5829  string method;                //make all options one string in order to use
5830                                //all combinations of options simultaneously
5831  for ( i=1; i <= size(#); i++ )
5832  {
5833    if ( typeof(#[i]) == "string" )
5834    {
5835      method = method + #[i];
5836    }
5837  }
5838  if ( find(method, "normal"))
5839  {norM = 1;}
5840  if ( find(method, "normalP") and (char(basering) > 0))
5841  {norP = 1;}
5842  if ( find(method, "normalC"))
5843  {norC = 1;}
5844  if ( find(method, "primCl"))
5845  {primCl = 1;}
5846  if ( find(method, "isprim") or find(method,"isPrim") )
5847  {decomp = 0;}
5848  if ( find(method, "p") )
5849  {checkP = 1;}
5850  if ( find(method, "pc") )
5851  {checkPC = 1;}
5852  if ( find(method, "111") )
5853  {check111 = 1;}
5854
5855  int tt;
5856  if(norM)
5857  {
5858    tt = timer;
5859    if(decomp == 0)
5860    {
5861      "Running normal(useRing, isPrim)...";
5862      list a1 = normal(I, "useRing", "isPrim");
5863      "Time normal(useRing, isPrim): ", timer - tt;
5864    }
5865    else
5866    {
5867      "Running normal(useRing)...";
5868      list a1 = normal(I, "useRing");
5869      "Time normal(useRing): ", timer - tt;
5870    }
5871    "";
5872  }
5873  if(norP)
5874  {
5875    tt = timer;
5876    if(decomp == 0)
5877    {
5878      "Running normalP(isPrim)...";
5879      list a2 = normalP(I, "isPrim");
5880      "Time normalP(isPrim): ", timer - tt;
5881    }
5882    else
5883    {
5884      "Running normalP()...";
5885      list a2 = normalP(I);
5886      "Time normalP(): ", timer - tt;
5887    }
5888    "";
5889  }
5890
5891  if(norC)
5892  {
5893    tt = timer;
5894    if(decomp == 0)
5895    {
5896      "Running normalC(isPrim)...";
5897      list a3 = normalC(I, "isPrim");
5898      "Time normalC(isPrim): ", timer - tt;
5899    }
5900    else
5901    {
5902      "Running normalC()...";
5903      list a3 = normalC(I);
5904      "Time normalC(): ", timer - tt;
5905    }
5906    "";
5907  }
5908
5909  if(primCl)
5910  {
5911    tt = timer;
5912    if(decomp == 0)
5913    {
5914      "Running normalC(withGens, isPrim)...";
5915      list a4 = normalC(I, "isPrim", "withGens");
5916      "Time normalC(withGens, isPrim): ", timer - tt;
5917    }
5918    else
5919    {
5920      "Running normalC(withGens)...";
5921      list a4 = normalC(I, "withGens");
5922      "Time normalC(withGens): ", timer - tt;
5923    }
5924    "";
5925  }
5926
5927  if(check111 and norM)
5928  {
5929    "Checking output with norTest...";
5930    "WARNING: this checking only works if the original ideal was prime.";
5931    norTest(I, a1);
5932    "";
5933  }
5934
5935  if(checkP and norP and norM)
5936  {
5937    "Comparing with normalP output...";
5938    if(size(a2) > 0)
5939    {
5940      "WARNING: this checking only works if the original ideal was prime.";
5941      U1 = a1[2][1];
5942      c1 = U1[size(U1)];
5943      U2 = a2[1][1];
5944      c2 = a2[1][1][size(a2[1][1])];
5945      W = changeDenominator(U1, c1, c2, groebner(I));
5946      qring q = groebner(I);
5947      ideal U2 = fetch(r, U2);
5948      ideal W = fetch(r, W);
5949      ch = 0;
5950      if(size(reduce(U2, groebner(W))) == 0)
5951      {
5952        "U2 c U1";
5953        ch = 1;
5954      }
5955      if(size(reduce(W, groebner(U2))) == 0)
5956      {
5957        "U1 c U2";
5958        ch = ch + 1;
5959      }
5960      if(ch == 2)
5961      {
5962        "Output of normalP is equal.";
5963      }
5964      else
5965      {
5966        "ERROR: Output of normalP is different.";
5967      }
5968      setring r;
5969      kill q;
5970    }
5971    else
5972    {
5973      "normalP returned no output. Comparison is not possible.";
5974    }
5975    "";
5976  }
5977
5978  if(checkPC and norM and primCl)
5979  {
5980    "Comparing with primeClosure output...";
5981    if(size(a4) > 0)
5982    {
5983      "WARNING: this checking only works if the original ideal was prime.";
5984      // primeClosure check
5985      U1 = a1[2][1];
5986      c1 = U1[size(U1)];
5987      U2 = a4[2][1];
5988      c2 = a4[2][1][size(a4[2][1])];
5989      W = changeDenominator(U1, c1, c2, groebner(I));
5990      qring q = groebner(I);
5991      ideal U2 = fetch(r, U2);
5992      ideal W = fetch(r, W);
5993      ch = 0;
5994      if(size(reduce(U2, groebner(W))) == 0)
5995      {
5996        "U2 c U1";
5997        ch = 1;
5998      }
5999      if(size(reduce(W, groebner(U2))) == 0)
6000      {
6001        "U1 c U2";
6002        ch = ch + 1;
6003      }
6004      if(ch == 2)
6005      {
6006        "Output of normalC(withGens) is equal.";
6007      }
6008      else
6009      {
6010        "ERROR: Output of normalC(withGens) is different.";
6011      }
6012      setring r;
6013      kill q;
6014    }
6015    else
6016    {
6017      "normalC(withGens) returned no output. Comparison is not possible.";
6018    }
6019    "";
6020  }
6021}
6022
6023///////////////////////////////////////////////////////////////////////////
6024static proc sqroot(int n);
6025{
6026  int s = 1;
6027  while(s*s < n) { s++; }
6028  return(s);
6029}
6030
6031///////////////////////////////////////////////////////////////////////////
6032proc norTest (ideal i, list nor, list #)
6033"USAGE:   norTest(i,nor,[n]); i=prime ideal, nor=list, n=optional integer
6034ASSUME:  nor is the output of normal(i) (any options) or
6035         normalP(i,"withRing") or normalC(i) (any options).
6036         In particular, the ring nor[1][1] contains the ideal norid
6037         and the map normap: basering/i --> nor[1][1]/norid.
6038RETURN:  an intvec v such that:
6039@format
6040         v[1] = 1 if the normap is injective and 0 otherwise
6041         v[2] = 1 if the normap is finite and 0 otherwise
6042         v[3] = 1 if nor[1][1]/norid is normal and 0 otherwise
6043@end format
6044         If n=1 (resp n=2) only v[1] (resp. v[2]) is computed and returned
6045THEORY:  The procedure can be used to test whether the computation of the
6046         normalization was correct: basering/i --> nor[1][1]/norid is the
6047         normalization of basering/i if and only if v=1,1,0.
6048NOTE:    For big examples it can be hard to fully test correctness; the
6049         partial test norTest(i,nor,2) is usually fast
6050EXAMPLE: example norTest; shows an example
6051"
6052{
6053//### Sollte erweitert werden auf den reduziblen Fall: einen neuen affinen
6054// Ring nor[1][1]+...+nor[1][r] (direkte Summe) erzeugen, map dorthin
6055// definieren und dann testen.
6056
6057    int prl = printlevel - voice + 2;
6058    int a,b,d;
6059    int n,ii;
6060    if (size(#) > 0) {  n = #[1];  }
6061
6062    def BAS = basering;
6063
6064    //### make a copy of nor to have a cpoy of nor[1][1]  (not a reference to)
6065    // in order not to override norid and normap.
6066    // delete nor[2] (if it contains the module generators, which are not used)
6067    // s.t. newnor does not belong to a ring.
6068
6069    list newnor = nor;
6070    if ( size(newnor) == 3 )
6071    {
6072       newnor = delete(newnor,2);
6073    }
6074    def R = newnor[1][1];
6075    qring QAS = std(i);
6076
6077
6078    setring R;
6079    int nva = nvars(R);
6080    string svars = varstr(R);
6081    string svar;
6082
6083    norid = interred(norid);
6084
6085    //--------- create new ring with one dp block keeping weights ------------
6086    list LR = ringlist(R);
6087    list g3 = LR[3];
6088    int n3 = size(g3);
6089    list newg3;
6090    intvec V;
6091
6092    //--------- check first whether variables Z(i),...,A(i) exist -----------
6093    for (ii=90; ii>=65; ii--)
6094    {
6095       if ( find(svars,ASCII(ii)+"(") == 0 )
6096       {
6097          svar = ASCII(ii);  break;
6098       }
6099    }
6100    if ( size(svar) != 0 )
6101    {
6102        for ( ii = 1; ii <= nva; ii++ )
6103        {
6104            LR[2][ii] = svar+"("+string(ii)+")";
6105            V[ii] = 1;
6106        }
6107    }
6108    else
6109    {
6110        for ( ii = 1; ii <= nva; ii++ )
6111        {
6112           LR[2][ii] = "Z("+string(100*nva+ii)+")";
6113           V[ii] = 1;
6114        }
6115    }
6116
6117    if ( g3[n3][1]== "c" or g3[n3][1] == "C" )
6118    {
6119       list gm = g3[n3];       //last blockis module ordering
6120       newg3[1] = list("dp",V);
6121       newg3 = insert(newg3,gm,size(newg3));
6122    }
6123    else
6124    {
6125       list gm = g3[1];              //first block is module ordering
6126       newg3[1] = list("dp",V);
6127       newg3 = insert(newg3,gm);
6128    }
6129    LR[3] = newg3;
6130//LR;"";
6131    def newR = ring(LR);
6132
6133    setring newR;
6134    ideal norid = fetch(R,norid);
6135    ideal normap = fetch(R,normap);
6136    if( defined(lnorid) )  { kill lnorid; }     //um ** redefinig zu beheben
6137    if( defined(snorid) )  { kill snorid; }     //sollte nicht noetig sein
6138
6139    //----------- go to quotient ring for checking injectivity -------------
6140//"mstd";
6141    list lnorid = mstd(norid);
6142    ideal snorid = lnorid[1];
6143//"size mstdnorid:", size(snorid),size(lnorid[2]);
6144//"size string mstdnorid:", size(string(snorid)),size(string(lnorid[2]));
6145    qring QR = snorid;
6146    ideal qnormap = fetch(newR,normap);
6147    //ideal qnormap = imap(newR,normap);
6148    //ideal qnormap = imap(R,normap);
6149    map Qnormap = QAS,qnormap;    //r/id --> R/norid
6150
6151    //------------------------ check injectivity ---------------------------
6152//"injective:";
6153    a = is_injective(Qnormap,QAS);          //a. Test for injectivity of Qnormap
6154    dbprint ( prl, "injective: "+string(a) );
6155    if ( n==1 ) { return (a); }
6156   a;
6157
6158    //------------------------ check finiteness ---------------------------
6159    setring newR;
6160    b = mapIsFinite(normap,BAS,lnorid[2]);  //b. Test for finiteness of normap
6161    dbprint ( prl, "finite: "+string(b) );
6162    if ( n==2 ) { return (intvec(a,b)); }
6163   b;
6164
6165    //------------------------ check normality ---------------------------
6166    list testnor = normal(lnorid[2],"isPrim","noFac", "withDelta");
6167    //### Problem: bei mehrfachem Aufruf von norTest gibt es
6168    // ** redefining norid & ** redefining normap
6169    //Dies produziert Fehler, da alte norid und normap ueberschrieben werden
6170    //norid und normap werden innnerhalb von proc computeRing ueberschrieben
6171    //Die Kopie newR scheint das Problem zu loesen
6172
6173    printlevel=prl;
6174
6175    d = testnor[3][2];             //d = delta
6176    kill testnor;                              //### sollte ueberfluessig sein
6177    int d1 = (d==0);                           //d1=1 if delta=0
6178    dbprint ( prl, "delta: "+string(d) );
6179    return(intvec(a,b,d1));
6180}
6181example
6182{ "EXAMPLE:"; echo = 2;
6183   int prl = printlevel;
6184   printlevel = -1;
6185   ring r = 0,(x,y),dp;
6186   ideal i = (x-y^2)^2 - y*x^3;
6187   list nor = normal(i);
6188   norTest(i,nor);                //1,1,1 means that normal was correct
6189
6190   nor = normalC(i);
6191   norTest(i,nor);                //1,1,1 means that normal was correct
6192
6193   ring s = 2,(x,y),dp;
6194   ideal i = (x-y^2)^2 - y*x^3;
6195   nor = normalP(i,"withRing");
6196   norTest(i,nor);               //1,1,1 means that normalP was correct
6197   printlevel = prl;
6198}
6199
6200///////////////////////////////////////////////////////////////////////////
6201//
6202//                            EXAMPLES
6203//
6204///////////////////////////////////////////////////////////////////////////
6205/*
6206//commands for computing the normalization:
6207// options for normal:  "equidim", "prim"
6208//                      "noDeco", "isPrim", "noFac"
6209//                       (prim by default)
6210// options for normalP: "withRing", "isPrim" or "noFac"
6211// options for normalC: "equidim", "prim", "withGens",
6212//                      "noDeco", "isPrim", "noFac"
6213
6214//Commands for testing 'normal'
6215 list nor = normal(i); nor;
6216 list nor = normal(i,"isPrim");nor;
6217 list nor = normal(i,"equidim");nor;
6218 list nor = normal(i,"prim");nor;
6219 list nor = normal(i,"equidim","noFac");nor;
6220 list nor = normal(i,"prim","noFac");nor;
6221
6222//Commands for testing 'normalP' in positive char
6223 list nor = normalP(i);nor;              //withGens but no ringstructure
6224 list nor = normalP(i,"withRing"); nor;  //compute the ringstructure
6225 list nor = normalP(i,"isPrim"); nor;    //if i is known to be prime
6226
6227//Commands for testing 'normalC'
6228 list nor = normal(i); nor;
6229 list nor = normal(i,"withGens");nor;
6230 list nor = normal(i,"isPrim");nor;
6231 list nor = normal(i,"equidim");nor;
6232 list nor = normal(i,"prim");nor;
6233 list nor = normal(i,"equidim","noFac");nor;
6234 list nor = normal(i,"prim","noFac");nor;
6235
6236//Commands for testing correctness (i must be prime):
6237list nor = normalP(i,"withRing","isPrim");
6238list nor = normal(i,"isPrim");
6239norTest(i,nor);       //full test for not too big examples (1,1,1 => ok)
6240norTest(i,nor,2);     //partial test for big examples (1,1 => ok)
6241factorize(i[1]);      //checks for irreducibility
6242
6243/////////////////////////////////////////////////////////////////////////////
6244
6245//----------------------Examples for normal (new algorithm)------------------
6246// Timings with Computeserver Dual AMD Opteron 242 1.60GHz.
6247// Examples from "Normalization of Rings" paper.
6248
6249// Example 1
6250// char 0 : normal = 0 secs (7 steps) - normalC = 75 secs
6251// char 2 : normal = 0 secs (7 steps) - normalP = 0 secs - normalC = 0 secs
6252// char 5 : normal = 1 secs (7 steps) - normalP = 71 - normalC = 1 secs
6253// char 11 : normal = 2 secs (7 steps) - normalP = 12 secs - normalC doesn't finish
6254// char 32003 : normal = 1 secs (7 steps) - normalP doesn't finish - normalC = 1 sec
6255LIB"normal.lib";
6256ring r = 2, (x, y), dp;
6257ideal i = (x-y)*x*(y+x^2)^3-y^3*(x^3+x*y-y^2);
6258timeNormal(i, "normal", "normalC", "normalP", "isPrim", "p");
6259
6260// Example 2
6261// char 0  : normal = 1 sec (7 steps) - normalC doesn't finish
6262// char 3 : normal = 1 secs (8 steps) - normalP = 0 secs - normalC = 4 secs
6263// char 13 : normal = 1 sec (7 steps) - normalP doesn't finish - normalC = 13 secs
6264// char 32003 : normal = 1 secs (7 steps) - normalP doesn't finish - normalC = 10 sec
6265LIB"normal.lib";
6266ring r = 13, (x, y), dp;
6267ideal i = 55*x^8+66*y^2*x^9+837*x^2*y^6-75*y^4*x^2-70*y^6-97*y^7*x^2;
6268timeNormal(i, "normal", "normalC", "normalP", "p", "isPrim");
6269
6270// Example 3
6271// char 0 : normal = 3 secs (6 steps) - normalC doesn't finish
6272// char 2 : normal = 1 secs (13 steps) - normalP = 0 secs - normalC doesn't finish
6273// char 5 : normal = 0 secs (6 steps) - normalP = 8 secs - normalC doesn't finish
6274LIB"normal.lib";
6275ring r=5,(x, y),dp;
6276ideal i=y9+y8x+y8+y5+y4x+y3x2+y2x3+yx8+x9;
6277timeNormal(i, "normal", "normalC", "normalP", "isPrim");
6278
6279// Example 4
6280// char 0 : normal = 0 secs (1 step) - normalC = 0 secs
6281// char 5 : normal = 0 secs (1 step) - normalP = 3 secs - normalC = 0 secs
6282// char 11 : normal = 0 secs (1 step) - normalP doesn't finish - normalC = 0 secs
6283// char 32003 : normal = 0 secs (1 step) - normalP doesn't finish - normalC = 0 secs
6284LIB"normal.lib";
6285ring r=11,(x,y),dp;   // genus 0 4 nodes and 6 cusps im P2
6286ideal i=(x2+y^2-1)^3 +27x2y2;
6287timeNormal(i, "normal", "normalC", "normalP", "isPrim");
6288
6289// Example 5
6290// char 0 : normal = 0 secs (1 step) - normalC = 0 secs
6291// char 5 : normal = 1 secs (3 step) - normalP doesn't finish - normalC doesn't finish
6292// char 11 : normal = 0 secs (1 step) - normalP 0 secs - normalC = 0 secs
6293// char 32003 : normal = 0 secs (1 step) - normalP doesn't finish - normalC = 0 secs
6294LIB"normal.lib";
6295ring r=11,(x,y),dp;    //24 sing, delta 24
6296ideal i=-x10+x8y2-x6y4-x2y8+2y10-x8+2x6y2+x4y4-x2y6-y8+2x6-x4y2+x2y4+2x4+2x2y2-y4-x2+y2-1;
6297timeNormal(i, "normal", "normalC", "normalP", "isPrim", "p");
6298
6299// Example 6
6300// char 2 : normal = 5 secs (2 steps) - normalP = 25 secs - normalC = 166 secs
6301LIB"normal.lib";
6302ring r=2,(v,u,z,y,x),dp;
6303ideal i = z3+zyx+y3x2+y2x3, uyx+z2,uz+z+y2x+yx2, u2+u+zy+zx, v3+vux+vz2+vzyx+vzx+uz3+uz2y+z3+z2yx2;
6304timeNormal(i, "normal", "normalC", "normalP", "isPrim", "p");
6305
6306// Example 7
6307// char 0 : normal = 11 secs (6 steps) - normalC = 11 secs
6308// char 2 : normal = 11 secs (6 steps) - normalP = 0 secs - normalC = 11 secs
6309// char 5 : normal = 11 secs (6 steps) - normalP = 3 secs - normalC = 11 secs
6310// char 11 : normal = 11 secs (6 steps) - normalP = 43 secs - normalC = 11 secs
6311// char 32003 : normal = 11 secs (6 steps) - normalP doesn't finish - normalC = 11 secs
6312LIB"normal.lib";
6313ring r=11,(x,y,z,w,t),dp;   //dim 2, dim s_locus 1
6314ideal i= x2+zw, y3+xwt, xw3+z3t+ywt2, y2w4-xy2z2t-w3t3;
6315timeNormal(i, "normal", "normalC", "normalP", "isPrim");
6316
6317////////////////////////////////////////////////////////////////////////////////
6318
6319// Other examples with new algorithm
6320
6321// Example 1
6322// char 0 : normal = 1 secs (13 steps) - normalC doesn't finish
6323// char 2 : normal = 1 secs (13 steps) - normalP = 0 secs - normalC doesn't finish
6324// char 5 : normal = 1 secs (13 steps) - normalP = 29 secs - normalC doesn't finish
6325ring r=2,(x,y),dp;  //genus 35
6326ideal i=y30+y13x+x4y5+x3*(x+1)^2;
6327timeNormal(i, "normal", "normalC", "normalP");
6328
6329// Example 2
6330// char 0 : normal = 1 secs (13 steps) - normalC doesn't finish
6331// char 3 : normal = 2 secs (13 steps) - normalP = 0 secs - normalC doesn't finish
6332ring r=3,(x,y),dp;  //genus 19, delta 21
6333ideal i=y20+y13x+x4y5+x3*(x+1)^2;
6334timeNormal(i, "normal", "normalC", "normalP");
6335
6336// Example 3
6337// Very fast with all algorithms
6338ring r = 3, (x, y), dp;
6339ideal I = (x-y^2)^2-x*y^3;
6340timeNormal(I, "normal", "normalC", "normalP", "primCl", "111", "p", "pc");
6341
6342
6343
6344//----------------------Test Example for charp -------------------
6345//Zu tun:
6346//### nach minor nur std statt mstd verwenden
6347//***hat bei keinem Beisp etwas gebracht -> wieder zurueck
6348//### wenn interred ok, dann wieder einsetzen (am Schluss)
6349//### bottelnecks bei maps beheben
6350//### minor verbessern
6351//### preimage verbessern (Ist imm Kern map oder imap verwendet?)
6352//### Gleich in Ordnung dp wechseln, ringlist verwenden
6353//### interred ev nur zum Schluss
6354//    (z.B. wenn nacher std; wenn nacher minor: testen )
6355
6356//Zeiten mit normalV5.lib (mstd aktiv, interred inaktiv)
6357
6358//SWANSON EXAMPLES: (Macaulay2, icFracP=normalP, icFractions<->normal)
6359//---------------------------------------------------------------------
6360//1. Series Fp[x,y,u,v]/(x2v-y2u)
6361//-------------------------------
6362//characteristic p   2   3    5    7    11   13   17   37   97
6363//icFracP          0.04 0.03 0.04 0.04 0.04 0.05 0.05 0.13 0.59  Mac
6364//normalP           0   0    0    0     0    0    0    0   1    Sing
6365//icFractions      0.08 0.09 0.09 0.09 0.14 0.15 0.15 0.15 0.15  Mac
6366//normal             0   0    0    0     0    0    0    0    0   Sing
6367
63682. Series Fp[u, v, w, x, y, z]/u2x4+uvy4+v2z4
6369//--------------------------------------------
6370//characteristic p 2    3    5    7   11
6371//icFracP         0.07 0.22 9.67 143 12543
6372//normalP          0    0    5   42  1566
6373//icFractions     1.16   *    *   *    *       *: > 6h
6374//normal            0    0    0   0    0
6375
6376//3. Series Fp[u, v, w, x, y, z]/(u2xp+uvyp+v2zp)
6377//-----------------------------------------------
6378//characteristic p  2    3    5    7    11   13  17 19 23
6379//icFracP          0.06 0.07 0.09 0.27 1.81 4.89 26 56 225
6380//normalP          0     0    0    0    1    2  6  10  27
6381//icFractions      0.16 1.49 75.00 4009  *    *   *  *  *
6382//normal            0     0    2    836
6383//### p=7 normal braucht 807 sec in:
6384// ideal endid  = phi1(endid);      //### bottelneck'
6385
6386//1.
6387int p = 2;  ring r = p,(u,v,x,y,z),dp; ideal i = x2v-y2u;
6388//2.
6389int p = 7; ring r=p,(u,v,w,x,y,z),dp; ideal i=u2x4+uvy4+v2z4;
6390//3.
6391int p=23; ring r=p,(u,v,w,x,y,z),dp; ideal i=u2*x^p+uv*y^p+v2*z^p;
6392
6393//IRREDUCIBLE EXAMPLES:
6394//---------------------
6395//timing for MacBookPro 2.2GHz Intel Core 2 Duo, 4GB Ram
6396//Sing. ix86Mac-darwin version 3-1-0 (3100-2008101314)  Oct 13 2008 14:46:59
6397//if no time is given: < 1  sec
6398
6399//Apply:
6400list nor = normal(i,"isPrim"); nor;
6401list nor = normalP(i,"withRing","isPrim"); nor;
6402def R=nor[1][1]; setring R; norid; normap;
6403setring r;
6404norTest(i,nor);
6405
6406int tt = timer;
6407list nor = normalP(i,"withRing","isPrim"); nor;
6408timer-tt;
6409int tt = timer;
6410list nor = normal(i,"isPrim");
6411timer-tt;
6412
6413ring r=19,(x,y,u,v),dp;    //delta -1
6414ideal i=x2v-y2u;
6415//norTest 2 sec
6416
6417ring r=2,(y,x2,x1),lp;     //delta -1
6418ideal i=y^4+y^2*x2*x1+x2^3*x1^2+x2^2*x1^3;
6419//### norid hat 1 Element nach interred
6420
6421ring r  = 11,(x,y,z),wp(2,1,2); //alles < 1 sec
6422ideal i=z3 - xy4 + x2;          //not reduced, delta =0 ok
6423ideal i=y4+x5+y2x;              //not reduced, delta -1
6424//interred verkleinert norid
6425
6426ring r=3,(u,v,x,y,z),dp;   //delta -1
6427ideal i=u2x3+uvy3+v2z3;
6428
6429ring r=3,(u,v,x,y,z),dp;   //delta -1
6430ideal i=u2x4+uvy4+v2z4;
6431//norTest(i,nor);  0 sec, norTest(i,nor) haengt!
6432
6433ring r=5,(u,v,x,y,z),dp;   //delta -1
6434ideal i=u2x6+uvy6+v2z6;
6435//normalP 5sec, normalC 1sec
6436//V5: norTest(i,nor); 45 sec bei normalP, V6 12 sec
6437//28 sec bei normal
6438
6439ring r=5,(u,v,x,y,z),dp;   //delta -1
6440ideal i=u2x5+uvy5+v2z5;
6441//normalP 1sec, normalC 1 sec,
6442//norTest lange: minor(jacob(I),h,J) 193 (308)sec, haengt dann bei M = std(M);
6443//norTest(i,nor,2); verwenden!
6444//Sing 3.0-4 orig  >9h! hŠngt bei Q = mstd(Q)[2];
6445
6446ring r=2,(y,x),wp(12,5);  //delta 3
6447ideal i=y5+y2x4+y2x+yx2+x12;
6448//normalP 0 sec (Test 0 sec), normalC 2 sec (Test 2 sec)
6449//normalC withGens (ohne interred) 0sec
6450
6451ring r=2,(y,x),dp;       //delta= 22
6452ideal i=y9+y8x+y8+y5+y4x+y3x2+y2x3+yx8+x9;
6453//normalP 1sec, interred verkleinert norid betraechtlich
6454//normalC haengt bei minor, ideal im loop wird zu gross ###
6455//interred bei normalC vergroeesert string um Faktor 4000!
6456//withGens haengt bei interred in loop 4 (> 10 h) oder
6457//(nach Ausschalten von interred) bei
6458//int delt=vdim(std(modulo(f,ideal(p)))); (>?h)
6459
6460//Leonard1: (1. Komponente von Leonard),  delta -1
6461ring r=2,(v,u,z,y,x),dp;
6462ideal i = z3+zyx+y3x2+y2x3, uyx+z2,uz+z+y2x+yx2, u2+u+zy+zx,
6463          v3+vux+vz2+vzyx+vzx+uz3+uz2y+z3+z2yx2;
6464//normalP 5 sec (withRing 9 sec), norTest(i,nor,2); 45 sec
6465//normalC 102sec, 99sec
6466//### Zeit wird bei ideal Ann = quotient(SM[2],SL[1]); und bei
6467// f  = quotient(p*J,J); verbraucht
6468//withGens (ohne interred) 131sec, norTest(i,nor,2); 2min25sec
6469//norTest(i,nor,2);  45 sec
6470
6471 ring r=2,(y,x),wp(25,21); //Leonard2, delta 232
6472 ring r=2,(y,x),dp;
6473 ideal i=
6474 y^21+y^20*x +y^18*(x^3+x+1) +y^17*(x^3+1) +y^16*(x^4+x)
6475 +y^15*(x^7+x^6+x^3+x+1) +y^14*x^7 +y^13*(x^8+x^7+x^6+x^4+x^3+1)
6476 +y^12*(x^9+x^8+x^4+1) +y^11*(x^11+x^9+x^8+x^5+x^4+x^3+x^2)
6477 +y^10*(x^12+x^9+x^8+x^7+x^5+x^3+x+1)
6478 +y^9*(x^14+x^13+x^10+x^9+x^8+x^7+x^6+x^3+x^2+1)
6479 +y^8*(x^13+x^9+x^8+x^6+x^4+x^3+x) +y^7*(x^16+x^15+x^13+x^12+x^11+x^7+x^3+x)
6480 +y^6*(x^17+x^16+x^13+x^9+x^8+x) +y^5*(x^17+x^16+x^12+x^7+x^5+x^2+x+1)
6481 +y^4*(x^19+x^16+x^15+x^12+x^6+x^5+x^3+1)
6482 +y^3*(x^18+x^15+x^12+x^10+x^9+x^7+x^4+x)
6483 +y^2*(x^22+x^21+x^20+x^18+x^13+x^12+x^9+x^8+x^7+x^5+x^4+x^3)
6484 +y*(x^23+x^22+x^20+x^17+x^15+x^14+x^12+x^9)
6485 +(x^25+x^23+x^19+x^17+x^15+x^13+x^11+x^5);
6486//normalP: dp 2sec withRing 8sec,
6487//wp 4sec, withRing:51sec Zeit in lin = subst(lin, var(ii), vip); in elimpart ),
6488//norTest(i,nor,2): haengt bei mstd(norid);
6489//### normalC: (m. interred): haengt bei endid = interred(endid);
6490//GEFIXTES INTERRED ABWARTEN. Dann interred aktivieren
6491//interred(norid) haengt u. mst(norid) zu lange
6492//(o.interred): haengt bei  haengt bei list SM = mstd(i);
6493//ideal in der Mitte zu gross
6494//i = Ideal (size 118, 13 var) fuer die neue Normalisierung
6495
6496REDUCIBLE EXAMPLES:
6497------------------
6498//Apply:
6499int tt = timer;
6500list nor=normalP(i,"isPrim","withRing");
6501timer-tt;
6502
6503list nor = normal(i); nor;
6504list nor = normalC(i); nor;
6505list nor = normalC(i, "withGens"); nor;
6506list nor = normalP(i,"withRing"); nor;
6507list nor = normalP(i); nor;
6508def R=nor[1][1]; setring R; norid; normap;
6509
6510//Leonhard 4 Komponenten, dim=2, delta: 0,0,0,-1
6511ring r=2,(v,u,z,y,x),dp;      //lp zu lange
6512ideal i=z3+zyx+y3x2+y2x3, uyx+z2, v3+vuyx+vux+vzyx+vzx+uy3x2+uy2x+zy3x+zy2x2;
6513//normalP: 19 sec, withRing: 22 sec
6514//normalC ohne (mit) interred: 112 (113)sec, equidim: 99sec
6515//normalC 1. mal 111 sec, (2.mal) 450sec!! 3.mal 172 sec
6516//(unterschiedlich lange primdec, mit Auswirkungen)
6517//char 19: normalC: 15sec , withGens: 14sec (o.interr.)
6518
6519//----------------------Test Example for special cases -------------------
6520int tt = timer;
6521list nor=normalP(i,"withRing");nor;
6522//list nor=normalP(i,"withRing", "isPrim");nor;
6523timer-tt;
6524def R1 = nor[1][1]; setring R1;  norid; normap; interred(norid);
6525setring r;
6526
6527int tt = timer;
6528list nor=normal(i,"isPrim");nor;
6529timer-tt;
6530
6531ring r = 29,(x,y,z),dp;
6532ideal i = x2y2,x2z2;       //Nicht equidimensional, equidim reduziert nicht, ok
6533ideal i  = xyz*(z3-xy4);   //### interred(norid) verkuerzt
6534//je 0 sec
6535
6536ideal j = x,y;
6537ideal i = j*xy;
6538equidim(i);
6539//hat eingebettete Komponente, equidim rechnet wie in Beschreibung (ok)
6540
6541ring r  = 19,(x,y),dp;
6542   ideal i = x3-y4;                   //delta = 3
6543   ideal i = y*x*(x3-y4);             //delta = 11; 0,0,3
6544   ideal i = (x2-y3)*(x3-y4);         //delta = 13; 1,3
6545   ideal i = (x-y)*(x3+y2)*(x3-y4);   //delta = 23; 0,1,3
6546   ideal i = (x-1)*(x3+y2)*(x2-y3);   //delta = 16; 0,1,1
6547   ideal i = (x-y^2)^2 - y*x^3;       //delta = 3
6548   //singularities at not only at 0, hier rechnet equidim falsch
6549
6550// -------------------------- General Examples  ---------------------------//Huneke, irred., delta=2 (Version 3-0-4: < 1sec)
6551//Version 3-0-6 default: 1sec, mit gens 2sec, mit delta 5 sec
6552//(prim,noFac):ca 7 Min, prim:ca 10 min(wg facstd)
6553//
6554// "equidim" < 1sec irred. 5sec
6555// ring r=31991,(a,b,c,d,e),dp;
6556ring r=2,(a,b,c,d,e),dp;                    //delta=2
6557ideal i=
65585abcde-a5-b5-c5-d5-e5,
6559ab3c+bc3d+a3be+cd3e+ade3,
6560a2bc2+b2cd2+a2d2e+ab2e2+c2de2,
6561abc5-b4c2d-2a2b2cde+ac3d2e-a4de2+bcd2e3+abe5,
6562ab2c4-b5cd-a2b3de+2abc2d2e+ad4e2-a2bce3-cde5,
6563a3b2cd-bc2d4+ab2c3e-b5de-d6e+3abcd2e2-a2be4-de6,
6564a4b2c-abc2d3-ab5e-b3c2de-ad5e+2a2bcde2+cd2e4,
6565b6c+bc6+a2b4e-3ab2c2de+c4d2e-a3cde2-abd3e2+bce5;
6566//normalC: char 2, 31991: 0 sec (isPrim); char 2, equidim: 7 sec
6567//norTest(i,nor,2); 1sec
6568//normalP char 2: 1sec (isPrim)
6569//size(norid); size(string(norid));21 1219 interred(norid): 21 1245 (0 sec)
6570
6571int tt = timer;
6572list nor=normalC(i);nor;
6573timer-tt;
6574
6575list nor = normalP(i,"isPrim");
6576
6577//Vasconcelos irred., delta -1 (dauert laenger)
6578//auf macbook pro = 20 sec mit alter Version,
6579//Sing 3-0-6:
6580// Char 32003: "equidim" 30 sec, "noFac": 30sec
6581//gens: nach 9 min abgebr (haengt in Lin = ideal(T*syzf);) !!!! Hans zu tun
6582//Char 2: default (charp) 2 sec, normalC ca 30 sec
6583//ring r=32003,(x,y,z,w,t),dp;   //dim 2, dim s_locus 1
6584ring r=2,(x,y,z,w,t),dp;   //dim 2, dim s_locus 1
6585ideal i= x2+zw, y3+xwt, xw3+z3t+ywt2, y2w4-xy2z2t-w3t3;
6586//normalC: char 2: 22,  sec (mit und ohne isPrim)
6587//normalP char 2: 0sec (isPrim)      o. interred
6588//char 32003: ### haengt in ideal endid  = phi1(endid);
6589
6590//-------------------------------------------------------
6591//kleine Beispiele:
6592
6593//Theo1, irred, delta=-1
6594//normalC: 1sec, normalP: 3 sec
6595ring r=32003,(x,y,z),wp(2,3,6); //dim 2,dim slocus 1
6596ideal i=zy2-zx3-x6;
6597//normalC: char 2,19,32003: 0  sec (isPrim)
6598//normalP (isPrim) char 2,19: 0sec, char 29: 1sec
6599
6600//Theo1a, CohenMacaulay regular in codim 2, dim slocus=1, delta=0
6601//normalC: 0 sec, normalP: haegt in K=preimage(R,phi,L);
6602ring r=32003,(x,y,z,u),dp;
6603ideal i=zy2-zx3-x6+u2;
6604//normalC: char 2,32003: 0  sec (isPrim)
6605//normalP (isPrim) char 2: 0sec, char 19: haengt in K = preimage(Q,phi,L);
6606
6607//Theo2, irreduzibel, reduziert, < 1sec, delta -1
6608ring r=0,(x,y,z),wp(3,4,12);
6609ideal i=z*(y3-x4)+x8;
6610//normalC: char 2,32003,0: 0  sec (isPrim)
6611//normalP (isPrim) char 2: 0 1sec, char 19: 1sec char 29: 7 sec
6612
6613//Theo2a, reduiziert, 2-dim, dim_slocus=1, alte Version 3 sec,
6614//normalP ca 30 sec, normalC ca 4sec, delta -1
6615//ring r=32003,(T(1..4)),wp(3,4,12,17);
6616//ring r=11,(T(1..4)),dp;
6617ring r=11,(T(1..4)),wp(3,4,12,17);
6618ideal i=
6619T(1)^8-T(1)^4*T(3)+T(2)^3*T(3),
6620T(1)^4*T(2)^2-T(2)^2*T(3)+T(1)*T(4),
6621T(1)^7+T(1)^3*T(2)^3-T(1)^3*T(3)+T(2)*T(4),
6622T(1)^6*T(2)*T(3)+T(1)^2*T(2)^4*T(3)+T(1)^3*T(2)^2*T(4)-T(1)^2*T(2)*T(3)^2+T(4)^2;
6623//normalC: char 2,32003: 0  sec (isPrim)
6624//normalP (isPrim) char 2: 0sec, char 11 2se, char 19: 13sec
6625//norTest 48sec in char11
6626//### interred verkuerzt
6627//char 29: haengt in K = preimage(Q,phi,L);
6628
6629//Theo3, irred, 2-dim, 1-dim sing, < 1sec
6630ring r=11,(x,y,z),wp(3,5,15);
6631ideal i=z*(y3-x5)+x10;
6632//normalC: char 2,0: 0  sec (withRing)
6633//normalP (withRing) char 2,11: 0sec, char 19: 13sec norTest 12sec(char 11)
6634
6635//Theo4 reducible, delta (0,0,0) -1
6636ring r=29,(x,y,z),dp;
6637ideal i=(x-y)*(x-z)*(y-z);
6638//normalC: char 2,32003: 0  sec
6639//normalP char withRing 2, 29: 0sec, 6sec
6640
6641//Theo6
6642ring r=32003,(x,y,z),dp;
6643ideal i=x2y2+x2z2+y2z2;
6644//normalC: char 2,32003: 0  sec
6645//normalP char withRing 2, 29: 0sec, 4sec
6646
6647//Sturmfels, CM, 15 componenten, alle glatt
6648ring r=0,(b,s,t,u,v,w,x,y,z),dp;
6649ideal i= bv+su, bw+tu, sw+tv, by+sx, bz+tx, sz+ty,uy+vx,uz+wx,vz+wy,bvz;
6650//normalC car 11, 0: 1sec, normalP 0 sec
6651
6652//riemenschneider, , dim 3, 5 Komp. delta (0,0,0,0,0), -1
6653ring r=2,(p,q,s,t,u,v,w,x,y,z),wp(1,1,1,1,1,1,2,1,1,1);
6654ideal i=xz,vx,ux,su,qu,txy,stx,qtx,uv2z-uwz,uv3-uvw,puv2-puw;
6655//alles 0 sec in char 2
6656
6657//4 Komponenten, alle glatt, 0sec
6658ring r=11,(x,y,z,t),dp;
6659ideal i=x2z+xzt,xyz,xy2-xyt,x2y+xyt;
6660
6661//dim 3, 2 Komponenten delta (-1,0), -1
6662ring r=2,(u,v,w,x,y,z),wp(1,1,1,3,2,1);
6663ideal i=wx,wy,wz,vx,vy,vz,ux,uy,uz,y3-x2;
6664//alles 0 sec in char 2
6665//---------------------------------------------------------
6666int tt = timer;
6667list nor=normalP(i,"normalC","withRing");nor;
6668timer-tt;
6669
6670//St_S/Y, 3 Komponenten, 2 glatt, 1 normal
6671//charp haengt (in char 20) in K=preimage(R,phi,L);
6672//ring r=32003,(b,s,t,u,v,w,x,y,z),dp;
6673ring r=11,(b,s,t,u,v,w,x,y,z),dp;
6674ideal i=wy-vz,vx-uy,tv-sw,su-bv,tuy-bvz;
6675//normalC: char 2,32003: 0  sec
6676//normalP char withRing 2: 1sec, char 11: 40sec
6677
6678//Horrocks: cahr 0: 17 (8 in char 11) Komponenten alle normal, delta 1
6679//char 11: 8 Komponenten alle normal, delta -1
6680ring r=0,(a,b,c,d,e,f),dp;
6681//ring r=11,(a,b,c,d,e,f),dp; //Charp bis p = 200 ca 3sec
6682ideal i=
6683adef-16000be2f+16001cef2, ad2f+8002bdef+8001cdf2, abdf-16000b2ef+16001bcf2,
6684a2df+8002abef+8001acf2, ad2e-8000bde2-7999cdef, acde-16000bce2+16001c2ef,
6685a2de-8000abe2-7999acef, acd2+8002bcde+8001c2df, abd2-8000b2de-7999bcdf,
6686a2d2+9603abde-10800b2e2-9601acdf+800bcef+11601c2f2,
6687abde-8000b2e2-acdf-16001bcef-8001c2f2, abcd-16000b2ce+16001bc2f,
6688a2cd+8002abce+8001ac2f, a2bd-8000ab2e-7999abcf, ab3f-3bdf3,
6689a2b2f-2adf3-16000bef3+16001cf4, a3bf+4aef3, ac3e-10668cde3,
6690a2c2e+10667ade3+16001be4+5334ce3f, a3ce+10669ae3f, bc3d+8001cd3e,
6691ac3d+8000bc3e+16001cd2e2+8001c4f, b2c2d+16001ad4+4000bd3e+12001cd3f,
6692b2c2e-10668bc3f-10667cd2ef, abc2e-cde2f, b3cd-8000bd3f, b3ce-10668b2c2f-10667bd2ef, abc2f-cdef2, a2bce-16000be3f+16001ce2f2,
6693ab3d-8000b4e-8001b3cf+16000bd2f2, ab2cf-bdef2,
6694a2bcf-16000be2f2+16001cef3, a4d-8000a3be+8001a3cf-2ae2f2;
6695//normalC: char 0: 1sec char 11: 0sec
6696//normalP: char 11: 0sec
6697
6698//2sec mit normalC, in char 2 ebenfalls (char 20 mit charp >1 min)
6699//4 Komp. in char 2, delta (0,0,0,0) -1, char 11:delta (-1,0,0,0) -1
6700ring r=32003,(b,s,t,u,v,w,x,y,z),dp;
6701ideal i=
6702wx2y3-vx2y2z+wx2yz2+wy3z2-vx2z3-vy2z3,
6703vx3y2-ux2y3+vx3z2-ux2yz2+vxy2z2-uy3z2,
6704tvx2y2-swx2y2+tvx2z2-swx2z2+tvy2z2-swy2z2,
6705sux2y2-bvx2y2+sux2z2-bvx2z2+suy2z2-bvy2z2,
6706tux2y3-bvx2y2z+tux2yz2+tuy3z2-bvx2z3-bvy2z3;
6707//normalC: char 2,32003: 1 sec
6708//normalP char withRing 2: 1sec, char 11: 40sec
6709
6710//---------------------------------------------------------
6711//genus:
6712int tt = timer;
6713list nor=normal(i, "noFac");nor;
6714timer-tt;
6715
6716//Yoshihiko Sakai, irred, 0sec, delta = 8
6717ring r=0,(x,y),dp;                    //genus 0 4 nodes and 6 cusps im P2
6718//ring r=7,(x,y),dp;                  //charp haengt in K = preimage(Q,phi,L)
6719ideal i=(x2+y^2-1)^3 +27x2y2;
6720
6721ring r=0,(x,y),dp;   //genus 0
6722ideal i=(x-y^2)^2 - y*x^3;
6723
6724ring r=0,(x,y),dp;  //genus 4
6725ideal i=y3-x6+1;
6726
6727int m=9;           // q=9: genus 0
6728int p=2;
6729int q=9;//2,...,9
6730ring r=0,(x,y),dp;
6731ideal i=y^m - x^p*(x - 1)^q;
6732
6733ring r=0,(x,y),dp;  //genus 19
6734ideal i=55*x^8+66*y^2*x^9+837*x^2*y^6-75*y^4*x^2-70*y^6-97*y^7*x^2;
6735
6736ring r=23,(x,y),dp;  //genus 34, delta 2
6737ideal i=y10+(-2494x2+474)*y8+(84366+2042158x4-660492)*y6
6738        +(128361096x4-47970216x2+6697080-761328152x6)*y4
6739        +(-12024807786x4-506101284x2+15052058268x6+202172841-3212x8)*y2
6740        +34263110700x4-228715574724x6+5431439286x2+201803238
6741        -9127158539954x10-3212722859346x8;
6742//normalC, normalP 0 sec
6743
6744//Rob Koelman
6745//ring r=0,(x,y,z),dp;      //dim sing = 1 (nach ca 15 min abgebrochen)
6746ring r=32003,(x,y,z),dp;
6747ideal i=
6748761328152*x^6*z^4-5431439286*x^2*y^8+2494*x^2*z^8+228715574724*x^6*y^4+
6749 9127158539954*x^10-15052058268*x^6*y^2*z^2+3212722859346*x^8*y^2-
6750 134266087241*x^8*z^2-202172841*y^8*z^2-34263110700*x^4*y^6-6697080*y^6*z^4-
6751 2042158*x^4*z^6-201803238*y^10+12024807786*x^4*y^4*z^2-128361096*x^4*y^2*z^4+
6752 506101284*x^2*z^2*y^6+47970216*x^2*z^4*y^4+660492*x^2*z^6*y^2-
6753 z^10-474*z^8*y^2-84366*z^6*y^4;
6754//normalC char 32003: 10 sec, char 0 :
6755
6756//ring r=0,(x,y),dp;//genus 10  with 26 cusps (nach ca 4 min abgebrochen)
6757ring r=32003,(x,y),dp;    //24 sing, delta 24
6758ideal i=9127158539954x10+3212722859346x8y2+228715574724x6y4-34263110700x4y6
6759-5431439286x2y8-201803238y10-134266087241x8-15052058268x6y2+12024807786x4y4
6760+506101284x2y6-202172841y8+761328152x6-128361096x4y2+47970216x2y4-6697080y6
6761-2042158x4+660492x2y2-84366y4+2494x2-474y2-1;
6762//normalC 32003: 4 sec, char 0: abgebrochen bei pr = facstd(i); ###
6763
6764ring r=0,(x,y),dp;   //irred, genus 1  with 5 cusps, delta 5
6765ideal i=57y5+516x4y-320x4+66y4-340x2y3+73y3+128x2-84x2y2-96x2y;
6766//normalC 0 sec
6767
6768ring r=2,(x,y),dp;  //genus 4, 2 Zweige, delta (13,9) 89
6769ideal i=((x2+y3)^2+xy6)*((x3+y2)^2+x10y);
6770//normalC: char 2 : 1sec, char 0: lange
6771//normalP char 2 withRing: 0sec
6772
6773ring r=2,(y,z,w,u),dp; //2 Komp. genus -5
6774ideal i=y2+z2+w2+u2,w4-u4;
6775//normalC: char 2 : 0sec, char 0: 1sec
6776//normalP char 2 withRing: 0sec
6777
6778ring r=0,(y,z,w,u),dp; //irred. genus 9
6779ideal i=y2+z2+w2+u2,z4+w4+u4;
6780//char 0: 0sec
6781
6782ring r=0,(x,y,t),dp;  //irred, delta -1
6783ideal i= 25x8+200x7y+720x6y2+1520x5y3+2064x4y4+1856x3y5+1088x2y6+384xy7+64y8-12x6t2-72x5yt2-184x4y2t2-256x3y3t2-192x2y4t2-64xy5t2-2x4t4-8x3yt4+16xy3t4+16y4t4+4x2t6+8xyt6+8y2t6+t8;
6784//char 0: 0sec
6785
6786ring r=0,(x,y,z,w,u),dp;
6787ideal i=x2+y2+z2+w2+u2,x3+y3+z3,z4+w4+u4;
6788//char 0: 0sec
6789
6790//---------------------------------------------------------
6791//Probleme mit normalC in char 2 und char 0
6792
6793int tt = timer;
6794list nor=normalC(i,"withRing");nor;
6795timer-tt;
6796
6797//Mark van Hoeij
6798ring r=3,(x,y),dp;  //genus 19, delta 21
6799ideal i=y20+y13x+x4y5+x3*(x+1)^2;
6800//normalC: char 2 > 10 min   bei list SM = mstd(i);###
6801//normalP char 2 withRing: 0sec, char 11: haengt bei K = preimage(Q,phi,L);
6802
6803ring r=2,(x,y),dp;  //genus 35
6804ideal i=y30+y13x+x4y5+x3*(x+1)^2;
6805//char 0 abgebrochen bei list SM = mstd(i); ###
6806//char 2 nach ca 30 min
6807//normalC: char 2: abgebr. bei list SM = mstd(i);  //Now the work starts'
6808//normalC, withGens, char 2: abgebrochen bei Q=mstd(Q)[2];
6809//normalP char 2 withRing: 0sec
6810
6811ring r=0,(x,y),dp;   //irred, genus 55, delta 21
6812ideal i=y40+y13x+x4y5+x3*(x+1)^2;
6813//normalC: char 2 lange
6814//normalP char 2 withRing: 0sec
6815
6816ring r=29,(x,y,t),dp; //char 0: genus -5, 4 Komp, delta (-1,-1,0,0), -1
6817ideal i=x8+8x7y+32x6y2+80x5y3+136x4y4+160x3y5+128x2y6+64xy7+16y8+4x6t2+24x5yt2+72x4y2t2+128x3y3t2+144x2y4t2+96xy5t2+32y6t2+14x4t4+56x3yt4+112x2y2t4+112xy3t4+40y4t4+20x2t6+40xyt6+8y2t6+9t8;
6818//normalC: char 29 : 0sec, char 0: 0sec  //char 29 6 Komponenten
6819//normalP char 29 withRing: 1sec
6820
6821//-------------------------- problematic examples ------------------------
6822//ring r=0,(x,y,t),dp;
6823ring r=32003,(x,y,t),dp;
6824ideal i=
682532761x8+786264x7y+8314416x6y2+50590224x5y3+193727376x4y4+478146240x3y5+742996800x2y6+664848000xy7+262440000y8+524176x7t+11007696x6yt+99772992x5y2t+505902240x4y3t+1549819008x3y4t+2868877440x2y5t+2971987200xy6t+1329696000y7t+3674308x6t2+66137544x5yt2+499561128x4y2t2+2026480896x3y3t2+4656222144x2y4t2+5746386240xy5t2+2976652800y6t2+14737840x5t3+221067600x4yt3+1335875904x3y2t3+4064449536x2y3t3+6226336512xy4t3+3842432640y5t3+36997422x4t4+443969064x3yt4+2012198112x2y2t4+4081745520xy3t4+3126751632y4t4+59524208x3t5+535717872x2yt5+1618766208xy2t5+1641991392y3t5+59938996x2t6+359633976xyt6+543382632y2t6+34539344xt7+103618032yt7+8720497t8;
6826//char 0: lange (es liegt an den grossen Zahlen), char 32003: 0 sec
6827
6828//dasselbe Beipiel in char 19: irred
6829ring r=0,(x,y,t),dp;
6830ideal i=
68315x8+6x7y-3x6y2+7x5y3-6x4y4-8x3y5-5x2y6-8y8+4x7t+8x6yt+2x5y2t-6x4y3t+9x3y4t+9x2y5t-xy6t-7x6t2+7x5yt2-x4y2t2+5x3y3t2+7x2y4t2+xy5t2-3y6t2-4x5t3 -3x4yt3+2x3y2t3-7x2y3t3-6xy4t3-3y5t3-5x4t4-3x3yt4-4x2y2t4-8xy3t4 +7y4t4+x3t5+9x2yt5+9xy2t5-8y3t5-2y2t6+4xt7-7yt7-9t8;
6832//normalP: char 2,3: 0sec, norTest 0,2 sec, char 11 haengt bei peimage
6833//normalC: char 3: 0 sec, char 0: 1sec
6834
6835//ring r=0,(x,y),dp;
6836ring r=32003,(x,y),dp;
6837ideal i=
6838x30y21+21x29y20+210x28y19+10x27y19+1330x27y18+190x26y18+5985x26y17
6839+1710x25y17+20349x25y16+45x24y17+9690x24y16+54264x24y15+765x23y16
6840+38760x23y15+116280x23y14+6120x22y15+116280x22y14+120x21y15
6841+203490x22y13+30600x21y14+271320x21y13+1799x20y14+293930x21y12+107100x20y13
6842+503880x20y12+12586x19y13+352716x20y11+278460x19y12+210x18y13+755820x19y11
6843+54509x18y12+352716x19y10+556920x18y11+2723x17y12+923780x18y10+163436x17y11
6844+293930x18y9+875160x17y10+16296x16y11+923780x17y9+359359x16y10+252x15y11
6845+203490x17y8+1093950x16y9+59598x15y10+755820x16y8+598598x15y9+2751x14y10
6846+116280x16y7+1093950x15y8+148610x14y9+503880x15y7+769197x14y8+13650x13y9
6847+54264x15y6+875160x14y7+266805x13y8+210x12y9+271320x14y6+768768x13y7
6848+40635x12y8+20349x14y5+556920x13y6+354816x12y7+1855x11y8+116280x13y5
6849+597597x12y6+80640x11y7+5985x13y4+278460x12y5+353892x11y6+7280x10y7+38760x12y4
6850+358358x11y5+112014x10y6+120x9y7+1330x12y3+107100x11y4+264726x10y5+16660x9y6
6851+9690x11y3+162799x10y4+111132x9y5+805x8y6+210x11y2+30600x10y3+146685x9y4
6852+24500x8y5+1710x10y2+54236x9y3+78750x8y4+2310x7y5+21x10y+6120x9y2+58520x8y3
6853+24010x7y4+45x6y5+190x9y+12509x8y2+39060x7y3+3675x6y4+x9+765x8y+15918x7y2
6854+15680x6y3+204x5y4+10x8+1786x7y+12915x6y2+3500x5y3+45x7+2646x6y+6580x5y2
6855+366x4y3+119x6+2562x5y+1995x4y2+10x3y3+203x5+1610x4y+324x3y2+231x4+630x3y
6856+23x2y2+175x3+141x2y+85x2+16xy+24x+y+4;
6857list nor = normal(i);
6858//normalC: char 0: ### hŠngt in SB of singular locus JM = mstd(J);
6859//normalC: char 32003,"noFac","equidim": 0sec, "noFac": 1sec
6860// ev neues interred
6861genus(i);         // haengt bei int mu=vdim(std(jacob(f)));
6862                  //### ist das noetig?
6863
6864//Singular rechnet genus richtig, auch im Fall, dass Kurve irreduzibel,
6865//aber nicht absolut irreduzibel ist:
6866ring r = 0,(x,y),dp;
6867ideal i = x2+y2;      //irreduzibel /Q aber reduzibel /C (x-iy)*(x+iy)
6868factorize( x2+y2);    //liefert irreduzibel
6869genus(i);             //sollte 0+0-2+1= -1 sein
6870genus(i,1);           //beides ist korrekt in Singular
6871
6872*/
6873
Note: See TracBrowser for help on using the repository browser.