source: git/Singular/LIB/normal.lib @ 0723d5

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