source: git/Singular/LIB/normal.lib @ 1288ef

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