source: git/Singular/LIB/hnoether.lib @ 0dd77c2

spielwiese
Last change on this file since 0dd77c2 was 341696, checked in by Hans Schönemann <hannes@…>, 15 years ago
Adding Id property to all files git-svn-id: file:///usr/local/Singular/svn/trunk@12231 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 153.1 KB
Line 
1version="$Id$";
2// (GMG, last modified 08.06.08: comments to Newton non-degenerate added)
3///////////////////////////////////////////////////////////////////////////////
4
5category="Singularities";
6info="
7LIBRARY:  hnoether.lib   Hamburger-Noether (Puiseux) Expansion
8AUTHORS:   Martin Lamm,      lamm@mathematik.uni-kl.de
9           Christoph Lossen, lossen@mathematik.uni-kl.de
10
11OVERVIEW:
12 A library for computing the Hamburger-Noether expansion (analogue of
13 Puiseux expansion over fields of arbitrary characteristic) of a reduced
14 plane curve singularity following [Campillo, A.: Algebroid curves in
15 positive characteristic, Springer LNM 813 (1980)]. @*
16 The library contains also procedures for computing the (topological)
17 numerical invariants of plane curve singularities.
18
19MAIN PROCEDURES:
20 hnexpansion(f [,\"ess\"]); Hamburger-Noether (HN) expansion of f
21 develop(f [,n]);           HN expansion of irreducible plane curve germs
22 extdevelop(hne,n);         extension of the H-N expansion hne of f
23 param(hne [,s]);           parametrization of branches described by HN data
24 displayHNE(hne);           display HN expansion as an ideal
25 invariants(hne);           invariants of f, e.g. the characteristic exponents
26 displayInvariants(hne);    display invariants of f
27 multsequence(hne);         sequence of multiplicities
28 displayMultsequence(hne);  display sequence of multiplicities
29 intersection(hne1,hne2);   intersection multiplicity of two local branches
30 is_irred(f);               test whether f is irreducible as power series
31 delta(f);                  delta invariant of f
32 newtonpoly(f);             (local) Newton polygon of f
33 is_NND(f);                 test whether f is Newton non-degenerate
34
35
36AUXILIARY PROCEDURES:
37 stripHNE(hne);             reduce amount of memory consumed by hne
38 puiseux2generators(m,n);   convert Puiseux pairs to generators of semigroup
39 separateHNE(hne1,hne2);    number of quadratic transf. needed for separation
40 squarefree(f);             a squarefree divisor of the polynomial f
41 allsquarefree(f,l);        the maximal squarefree divisor of the polynomial f
42 further_hn_proc();         show further procedures useful for interactive use
43
44KEYWORDS: Hamburger-Noether expansion; Puiseux expansion; curve singularities
45";
46
47// essdevelop(f);             HN expansion of essential branches
48// multiplicities(hne);       multiplicities of blowed up curves
49
50///////////////////////////////////////////////////////////////////////////////
51LIB "primitiv.lib";
52LIB "inout.lib";
53LIB "sing.lib";
54
55///////////////////////////////////////////////////////////////////////////////
56
57proc further_hn_proc()
58"USAGE: further_hn_proc();
59NOTE:  The library @code{hnoether.lib} contains some more procedures which
60       are not shown when typing @code{help hnoether.lib;}. They may be useful
61       for interactive use (e.g. if you want to do the calculation of an HN
62       development \"by hand\" to see the intermediate results), and they
63       can be enumerated by calling @code{further_hn_proc()}. @*
64       Use @code{help <procedure>;} for detailed information about each of
65       them.
66"
67{
68 "
69 The following procedures are also part of `hnoether.lib':
70
71 getnm(f);           intersection pts. of Newton polygon with axes
72 T_Transform(f,Q,N); returns f(y,xy^Q)/y^NQ (f: poly, Q,N: int)
73 T1_Transform(f,d,M); returns f(x,y+d*x^M)  (f: poly,d:number,M:int)
74 T2_Transform(f,d,M,N,ref);   a composition of T1 & T
75 koeff(f,I,J);       gets coefficient of indicated monomial of polynomial f
76 redleit(f,S,E);     restriction of monomials of f to line (S-E)
77 leit(f,n,m);        special case of redleit (for irred. polynomials)
78 testreducible(f,n,m); tests whether f is reducible
79 charPoly(f,M,N);    characteristic polynomial of f
80 find_in_list(L,p);  find int p in list L
81 get_last_divisor(M,N); last divisor in Euclid's algorithm
82 factorfirst(f,M,N); try to factor f without `factorize'
83 factorlist(L);      factorize a list L of polynomials
84 referencepoly(D);   a polynomial f s.t. D is the Newton diagram of f";
85
86//       static procedures not useful for interactive use:
87// polytest(f);        tests coefficients and exponents of polynomial f
88// extractHNEs(H,t);   extracts output H of HN to output of hnexpansion
89// HN(f,grenze);       recursive subroutine for hnexpansion
90// constructHNEs(...); subroutine for HN
91}
92example
93{ echo=2;
94  further_hn_proc();
95}
96///////////////////////////////////////////////////////////////////////////////
97
98proc getnm (poly f)
99"USAGE:   getnm(f); f bivariate polynomial
100RETURN:  intvec(n,m) : (0,n) is the intersection point of the Newton
101         polygon of f with the y-axis, n=-1 if it doesn't exist
102         (m,0) is its intersection point with the x-axis,
103         m=-1 if this point doesn't exist
104ASSUME:  ring has ordering `ls' or `ds'
105EXAMPLE: example getnm; shows an example
106"
107{
108 // assume being called by develop ==> ring ordering is ls (ds would also work)
109 return(ord(subst(f,var(1),0)),ord(subst(f,var(2),0)));
110}
111example
112{ "EXAMPLE:"; echo = 2;
113   ring r = 0,(x,y),ds;
114   poly f = x5+x4y3-y2+y4;
115   getnm(f);
116}
117///////////////////////////////////////////////////////////////////////////////
118
119proc leit (poly f, int n, int m)
120"USAGE:   leit(f,n,m);  poly f, int n,m
121RETURN:  all monomials on the line from (0,n) to (m,0) in the Newton diagram
122EXAMPLE: example leit;  shows an example
123"
124{
125 return(jet(f,m*n,intvec(n,m))-jet(f,m*n-1,intvec(n,m)))
126}
127example
128{ "EXAMPLE:"; echo = 2;
129   ring r = 0,(x,y),ds;
130   poly f = x5+x4y3-y2+y4;
131   leit(f,2,5);
132}
133///////////////////////////////////////////////////////////////////////////////
134proc testreducible (poly f, int n, int m)
135"USAGE:   testreducible(f,n,m);  f poly, n,m int
136RETURN:  1 if there are points in the Newton diagram below the line (0,n)-(m,0)
137         0 else
138EXAMPLE: example testreducible;  shows an example
139"
140{
141 return(size(jet(f,m*n-1,intvec(n,m))) != 0)
142}
143example
144{ "EXAMPLE:"; echo = 2;
145  ring rg=0,(x,y),ls;
146  testreducible(x2+y3-xy4,3,2);
147}
148///////////////////////////////////////////////////////////////////////////////
149proc T_Transform (poly f, int Q, int N)
150"USAGE:   T_Transform(f,Q,N);  f poly, Q,N int
151RETURN:  f(y,xy^Q)/y^NQ   if x,y are the ring variables
152NOTE:    this is intended for irreducible power series f
153EXAMPLE: example T_Transform;  shows an example
154"
155{
156 map T = basering,var(2),var(1)*var(2)^Q;
157 return(T(f)/var(2)^(N*Q));
158}
159example
160{ "EXAMPLE:"; echo = 2;
161  ring exrg=0,(x,y),ls;
162  export exrg;
163  T_Transform(x3+y2-xy3,1,2);
164  kill exrg;
165}
166///////////////////////////////////////////////////////////////////////////////
167proc T1_Transform (poly f, number d, int Q)
168"USAGE:   T1_Transform(f,d,Q);  f poly, d number, Q int
169RETURN:  f(x,y+d*x^Q)   if x,y are the ring variables
170EXAMPLE: example T1_Transform;  shows an example
171"
172{
173 map T1 = basering,var(1),var(2)+d*var(1)^Q;
174 return(T1(f));
175}
176example
177{ "EXAMPLE:"; echo = 2;
178  ring exrg=0,(x,y),ls;
179  export exrg;
180  T1_Transform(y2-2xy+x2+x2y,1,1);
181  kill exrg;
182}
183///////////////////////////////////////////////////////////////////////////////
184
185proc T2_Transform (poly f_neu, number d, int M, int N, poly refpoly)
186"USAGE:   T2_Transform(f,d,M,N,ref); f poly, d number; M,N int; ref poly
187RETURN:  list: poly T2(f,d',M,N), number d' in \{ d, 1/d \}
188ASSUME:  ref has the same Newton polygon as f (but can be simpler)
189         for this you can e.g. use the proc `referencepoly' or simply f again
190COMMENT: T2 is a composition of T_Transform and T1_Transform; the exact
191         definition can be found in  Rybowicz: `Sur le calcul des places ...'
192         or in  Lamm: `Hamburger-Noether-Entwicklung von Kurvensingularitaeten'
193SEE ALSO: T_Transform, T1_Transform, referencepoly
194EXAMPLE: example T2_Transform;  shows an example
195"
196{
197 //---------------------- compute gcd and extgcd of N,M -----------------------
198  int ggt=gcd(M,N);
199  M=M/ggt; N=N/ggt;
200  list ts=extgcd(M,N);
201  int tau,sigma=ts[2],-ts[3];
202  int s,t;
203  poly xp=var(1);
204  poly yp=var(2);
205  poly hilf;
206  if (sigma<0) { tau=-tau; sigma=-sigma;}
207 // es gilt: 0<=tau<=N, 0<=sigma<=M, |N*sigma-M*tau| = 1 = ggT(M,N)
208  if (N*sigma < M*tau) { d = 1/d; }
209 //--------------------------- euklid. Algorithmus ----------------------------
210  int R;
211  int M1,N1=M,N;
212  for ( R=M1%N1; R!=0; ) { M1=N1; N1=R; R=M1%N1;}
213  int Q=M1 / N1;
214  map T1 = basering,xp,yp+d*xp^Q;
215  map Tstar=basering,xp^(N-Q*tau)*yp^tau,xp^(M-sigma*Q)*yp^sigma;
216  if (defined(HNDebugOn)) {
217   "Trafo. T2: x->x^"+string(N-Q*tau)+"*y^"+string(tau)+", y->x^"
218    +string(M-sigma*Q)+"*y^"+string(sigma);
219   "delt =",d,"Q =",Q,"tau,sigma =",tau,sigma;
220  }
221 //------------------- Durchfuehrung der Transformation T2 --------------------
222  f_neu=Tstar(f_neu);
223  refpoly=Tstar(refpoly);
224  //--- dividiere f_neu so lange durch x & y, wie die Division aufgeht,
225  //    benutze ein Referenzpolynom mit gleichem Newtonpolynom wie f_neu zur
226  //    Beschleunigung: ---
227  for (hilf=refpoly/xp; hilf*xp==refpoly; hilf=refpoly/xp) {refpoly=hilf; s++;}
228  for (hilf=refpoly/yp; hilf*yp==refpoly; hilf=refpoly/yp) {refpoly=hilf; t++;}
229  f_neu=f_neu/(xp^s*yp^t);
230  return(list(T1(f_neu),d));
231}
232example
233{ "EXAMPLE:"; echo = 2;
234  ring exrg=0,(x,y),ds;
235  export exrg;
236  poly f=y2-2x2y+x6-x5y+x4y2;
237  T2_Transform(f,1/2,4,1,f);
238  T2_Transform(f,1/2,4,1,referencepoly(newtonpoly(f,1)));
239  // if  size(referencepoly) << size(f)  the 2nd example would be faster
240  referencepoly(newtonpoly(f,1));
241  kill exrg;
242}
243///////////////////////////////////////////////////////////////////////////////
244
245proc koeff (poly f, int I, int J)
246"USAGE:   koeff(f,I,J); f bivariate polynomial, I,J integers
247RETURN:  if f = sum(a(i,j)*x^i*y^j), then koeff(f,I,J)= a(I,J) (of type number)
248NOTE:    J must be in the range of the exponents of the 2nd ring variable
249EXAMPLE: example koeff;  shows an example
250"
251{
252  matrix mat = coeffs(coeffs(f,var(2))[J+1,1],var(1));
253  if (size(mat) <= I) { return(0);}
254  else { return(leadcoef(mat[I+1,1]));}
255}
256example
257{ "EXAMPLE:"; echo = 2;
258  ring r=0,(x,y),dp;
259  koeff(x2+2xy+3xy2-x2y-2y3,1,2);
260}
261///////////////////////////////////////////////////////////////////////////////
262
263proc squarefree (poly f)
264"USAGE:  squarefree(f);  f poly
265ASSUME:  f is a bivariate polynomial (in the first 2 ring variables).
266RETURN:  poly, a squarefree divisor of f.
267NOTE:    Usually, the return value is the greatest squarefree divisor, but
268         there is one exception: factors with a p-th root, p the
269         characteristic of the basering, are lost.
270SEE ALSO: allsquarefree
271EXAMPLE: example squarefree; shows some examples.
272"
273{
274 //----------------- Wechsel in geeigneten Ring & Variablendefinition ---------
275  if (nvars(basering)!=2)
276  { ERROR("basering must have exactly 2 variables for Hnoether::squarefree"); }
277  def altring = basering;
278  int e;
279  int gcd_ok=1;
280  string mipl="0";
281  if (size(parstr(altring))==1) { mipl=string(minpoly); }
282 //---- test: char = (p^k,a) (-> gcd not implemented) or (p,a) (gcd works) ----
283  if ((char(basering)!=0) and (charstr(basering)!=string(char(basering)))) {
284    string tststr=charstr(basering);
285    tststr=tststr[1..find(tststr,",")-1];           //-> "p^k" bzw. "p"
286    gcd_ok=(tststr==string(char(basering)));
287  }
288  execute("ring rsqrf = ("+charstr(altring)+"),(x,y),dp;");
289  if ((gcd_ok!=0) && (mipl!="0")) { execute("minpoly="+mipl+";"); }
290  poly f=fetch(altring,f);
291  poly dif,g,l;
292  if ((char(basering)==0) and (charstr(basering)!=string(char(basering)))
293      and (mipl!="0")) {
294    gcd_ok=0;                   // since Singular 1.2 gcd no longer implemented
295  }
296  if (gcd_ok!=0) {
297 //--------------------- Berechne f/ggT(f,df/dx,df/dy) ------------------------
298    dif=diff(f,x);
299    if (dif==0) { g=f; }        // zur Beschleunigung
300    else { g=gcd(f,dif); }
301    if (g!=1) {                 // sonst schon sicher, dass f quadratfrei
302     dif=diff(f,y);
303     if (dif!=0) { g=gcd(g,dif); }
304    }
305    if (g!=1) {
306     e=0;
307     if (g==f) { l=1; }         // zur Beschleunigung
308     else {
309       module m=syz(ideal(g,f));
310       if (deg(m[2,1])>0) {
311         "!! The Singular command 'syz' has returned a wrong result !!";
312         l=1;                   // Division f/g muss aufgehen
313       }
314       else { l=m[1,1]; }
315     }
316    }
317    else { e=1; }
318  }
319  else {
320 //------------------- Berechne syz(f,df/dx) oder syz(f,df/dy) ----------------
321 //-- Achtung: Ist f reduzibel, koennen Faktoren mit Ableitung Null verloren --
322 //-- gehen! Ist aber nicht weiter schlimm, weil char (p^k,a) nur im irred.  --
323 //-- Fall vorkommen kann. Wenn f nicht g^p ist, wird auf jeden Fall         --
324 //------------------------ ein Faktor gefunden. ------------------------------
325    dif=diff(f,x);
326    if (dif == 0) {
327     dif=diff(f,y);
328     if (dif==0) { e=2; l=1; } // f is of power divisible by char of basefield
329     else { l=syz(ideal(dif,f))[1,1];  // x^p+y^(p-1) abgedeckt
330            if (subst(f,x,0)==0) { l=l*x; }
331            if (deg(l)==deg(f))  { e=1;}
332            else {e=0;}
333     }
334    }
335    else { l=syz(ideal(dif,f))[1,1];
336           if (subst(f,y,0)==0) { l=l*y; }
337           if (deg(l)==deg(f))  { e=1;}
338           else {e=0;}
339    }
340  }
341 //--------------- Wechsel in alten Ring und Rueckgabe des Ergebnisses --------
342  setring altring;
343  if (e==1) { return(f); }    // zur Beschleunigung
344  else {
345   poly l=fetch(rsqrf,l);
346   return(l);
347  }
348}
349example
350{ "EXAMPLE:"; echo = 2;
351 ring exring=3,(x,y),dp;
352 squarefree((x3+y)^2);
353 squarefree((x+y)^3*(x-y)^2); // Warning: (x+y)^3 is lost
354 squarefree((x+y)^4*(x-y)^2); // result is (x+y)*(x-y)
355}
356///////////////////////////////////////////////////////////////////////////////
357
358proc allsquarefree (poly f, poly l)
359"USAGE : allsquarefree(f,g);  f,g poly
360ASSUME: g is the output of @code{squarefree(f)}.
361RETURN: the greatest squarefree divisor of f.
362NOTE  : This proc uses factorize to get the missing factors of f not in g and,
363        therefore, may be slow.
364SEE ALSO: squarefree
365EXAMPLE: example allsquarefree;  shows an example
366"
367{
368 //------------------------ Wechsel in geeigneten Ring ------------------------
369 def altring = basering;
370 string mipl="0";
371 if (size(parstr(altring))==1) { mipl=string(minpoly); }
372 if ((char(basering)!=0) and (charstr(basering)!=string(char(basering)))) {
373   string tststr=charstr(basering);
374   tststr=tststr[1..find(tststr,",")-1];           //-> "p^k" bzw. "p"
375   if (tststr!=string(char(basering))) {
376     " Sorry -- not implemented for this ring (gcd doesn't work)";
377     return(l);
378   }
379 }
380 execute("ring rsqrf = ("+charstr(altring)+"),(x,y),dp;");
381 if (mipl!="0") { execute("minpoly="+mipl+";"); }
382 poly f=fetch(altring,f);
383 poly l=fetch(altring,l);
384 //---------- eliminiere bereits mit squarefree gefundene Faktoren ------------
385 poly g=l;
386 while (deg(g)!=0) {
387   f=syz(ideal(g,f))[1,1];                         // f=f/g;
388   g=gcd(f,l);
389 }                                                 // jetzt f=h^p
390 //--------------- Berechne uebrige Faktoren mit factorize --------------------
391 if (deg(f)>0) {
392  g=1;
393//*CL old:  ideal factf=factorize(f,1);
394//*         for (int i=1; i<=size(factf); i++) { g=g*factf[i]; }
395  ideal factf=factorize(f)[1];
396  for (int i=2; i<=size(factf); i++) { g=g*factf[i]; }
397  poly testp=squarefree(g);
398  if (deg(testp)<deg(g)) {
399    "!! factorize has not worked correctly !!";
400    if (testp==1) {" We cannot proceed ..."; g=1;}
401    else {" But we could recover some factors..."; g=testp;}
402  }
403  l=l*g;
404 }
405 //--------------- Wechsel in alten Ring und Rueckgabe des Ergebnisses --------
406 setring altring;
407 l=fetch(rsqrf,l);
408 return(l);
409}
410example
411{ "EXAMPLE:"; echo = 2;
412  ring exring=7,(x,y),dp;
413  poly f=(x+y)^7*(x-y)^8;
414  poly g=squarefree(f);
415  g;                      // factor x+y lost, since characteristic=7
416  allsquarefree(f,g);     // all factors (x+y)*(x-y) found
417}
418///////////////////////////////////////////////////////////////////////////////
419
420proc is_irred (poly f)
421"USAGE:   is_irred(f); f poly
422ASSUME:  f is a squarefree bivariate polynomial (in the first 2 ring
423         variables).
424RETURN:  int (0 or 1): @*
425         - @code{is_irred(f)=1} if f is irreducible as a formal power
426         series over the algebraic closure of its coefficient field (f
427         defines an analytically irreducible curve at zero), @*
428         - @code{is_irred(f)=0} otherwise.
429NOTE:    0 and units in the ring of formal power series are considered to be
430         not irreducible.
431KEYWORDS: irreducible power series
432EXAMPLE: example is_irred;  shows an example
433"
434{
435  int pl=printlevel;
436  printlevel=-1;
437  list hnl=develop(f,-1);
438  printlevel=pl;
439  return(hnl[5]);
440}
441example
442{ "EXAMPLE:"; echo = 2;
443  ring exring=0,(x,y),ls;
444  is_irred(x2+y3);
445  is_irred(x2+y2);
446  is_irred(x2+y3+1);
447}
448///////////////////////////////////////////////////////////////////////////////
449
450static proc polytest(poly f)
451"USAGE : polytest(f); f poly in x and y
452RETURN: a monomial of f with |coefficient| > 16001
453          or exponent divisible by 32003, if there is one
454        0 else (in this case computing a squarefree divisor
455                in characteristic 32003 could make sense)
456NOTE:   this procedure is only useful in characteristic zero, because otherwise
457        there is no appropriate ordering of the leading coefficients
458"
459{
460 poly verbrecher=0;
461 intvec leitexp;
462 for (; (f<>0) and (verbrecher==0); f=f-lead(f)) {
463  if ((leadcoef(f)<-16001) or (leadcoef(f)>16001)) {verbrecher=lead(f);}
464  leitexp=leadexp(f);
465  if (( ((leitexp[1] % 32003) == 0)   and (leitexp[1]<>0))
466     or ( ((leitexp[2] % 32003) == 0) and (leitexp[2]<>0)) )
467       {verbrecher=lead(f);}
468 }
469 return(verbrecher);
470}
471
472//////////////////////////////////////////////////////////////////////////////
473
474
475proc develop
476"USAGE:   develop(f [,n]); f poly, n int
477ASSUME:  f is a bivariate polynomial (in the first 2 ring variables) and
478         irreducible as power series (for reducible f use @code{hnexpansion}).
479RETURN:  list @code{L} with:
480@texinfo
481@table @asis
482@item @code{L[1]}; matrix:
483         Each row contains the coefficients of the corresponding line of the
484         Hamburger-Noether expansion (HNE). The end of the line is marked in
485         the matrix by the first ring variable (usually x).
486@item @code{L[2]}; intvec:
487         indicating the length of lines of the HNE
488@item @code{L[3]}; int:
489         0  if the 1st ring variable was transversal (with respect to f), @*
490         1  if the variables were changed at the beginning of the
491            computation, @*
492        -1  if an error has occurred.
493@item @code{L[4]}; poly:
494         the transformed polynomial of f to make it possible to extend the
495         Hamburger-Noether development a posteriori without having to do
496         all the previous calculation once again (0 if not needed)
497@item @code{L[5]}; int:
498         1  if the curve has exactly one branch (i.e., is irreducible), @*
499         0  else (i.e., the curve has more than one HNE, or f is not valid).
500@end table
501@end texinfo
502DISPLAY: The (non zero) elements of the HNE (if not called by another proc).
503NOTE:    The optional parameter @code{n} affects only the computation of
504         the LAST line of the HNE. If it is given, the HN-matrix @code{L[1]}
505         will have at least @code{n} columns. @*
506         Otherwise, the number of columns will be chosen minimal such that the
507         matrix contains all necessary information (i.e., all lines of the HNE
508         but the last (which is in general infinite) have place). @*
509         If @code{n} is negative, the algorithm is stopped as soon as the
510         computed information is sufficient for @code{invariants(L)}, but the
511         HN-matrix @code{L[1]} may still contain undetermined elements, which
512         are marked with the 2nd variable (of the basering). @*
513         For time critical computations it is recommended to use
514         @code{ring ...,(x,y),ls} as basering - it increases the algorithm's
515         speed. @*
516         If @code{printlevel>=0} comments are displayed (default is
517         @code{printlevel=0}).
518SEE ALSO: hnexpansion, extdevelop, displayHNE
519EXAMPLES: example develop;         shows an example
520          example parametrize;     shows an example for using the 2nd parameter
521"
522{
523 //--------- Abfangen unzulaessiger Ringe: 1) nur eine Unbestimmte ------------
524 poly f=#[1];
525 if (size(#) > 1) {int maxspalte=#[2];}
526 else             {int maxspalte= 1 ; }
527 if (nvars(basering) < 2) {
528   " Sorry. I need two variables in the ring.";
529   return(list(matrix(maxideal(1)[1]),intvec(0),-1,poly(0),0));}
530 if (nvars(basering) > 2) {
531   dbprint(printlevel-voice+2,
532   " Warning! You have defined too many variables!
533 All variables except the first two will be ignored!"
534           );
535 }
536
537 string namex=varstr(1); string namey=varstr(2);
538 list return_error=matrix(maxideal(1)[2]),intvec(0),int(-1),poly(0),int(0);
539
540 //------------- 2) mehrere Unbestimmte, weitere unzulaessige Ringe -----------
541 // Wir koennen einheitlichen Rueckgabewert benutzen, aus dem ersichtlich ist,
542 // dass ein Fehler aufgetreten ist: return_error.
543 //----------------------------------------------------------------------------
544
545 if (charstr(basering)=="real") {
546  " The algorithm doesn't work with 'real' as coefficient field.";
547                     // denn : map from characteristic -1 to -1 not implemented
548  return(return_error);
549 }
550 if ((char(basering)!=0) and (charstr(basering)!=string(char(basering)))) {
551 //-- teste, ob char = (p^k,a) (-> a primitiv; erlaubt) oder (p,a[,b,...]) ----
552    string tststr=charstr(basering);
553    tststr=tststr[1..find(tststr,",")-1];           //-> "p^k" bzw. "p"
554    int primit=(tststr==string(char(basering)));
555    if (primit!=0) {
556      " Such extensions of Z/p are not implemented.";
557      " Please try (p^k,a) as ground field or use `hnexpansion'.";
558      return(return_error);
559    }
560 }
561 //---- Ende der unzulaessigen Ringe; Ringwechsel in einen guenstigen Ring: ---
562
563 int ringwechsel=(varstr(basering)!="x,y") or (ordstr(basering)!="ls(2),C");
564
565 def altring = basering;
566 if (ringwechsel) {
567   string mipl=string(minpoly);
568   execute("ring guenstig = ("+charstr(altring)+"),(x,y),ls;");
569   if ((char(basering)==0) && (mipl!="0")) {
570     execute("minpoly="+mipl+";");
571   }}
572 else { def guenstig=basering; }
573 export guenstig;
574
575 //-------------------------- Initialisierungen -------------------------------
576 map m=altring,x,y;
577 if (ringwechsel) { poly f=m(f); }
578 if (defined(HNDebugOn))
579 {"received polynomial: ",f,", where x =",namex,", y =",namey;}
580 kill m;
581 int M,N,Q,R,l,e,hilf,eps,getauscht,Abbruch,zeile,exponent,Ausgabe;
582
583 // Werte von Ausgabe: 0 : normale HNE-Matrix,
584 // 1 : Fehler aufgetreten - Matrix (namey) zurueck
585 // 2 : Die HNE ist eine Nullzeile - Matrix (0) zurueck
586 // int maxspalte=1; geaendert: wird jetzt am Anfang gesetzt
587
588 int minimalHNE=0;          // Flag fuer minimale HNE-Berechnung
589 int einzweig=1;            // Flag fuer Irreduzibilit"at
590 intvec hqs;                // erhaelt die Werte von h(zeile)=Q;
591
592 if (maxspalte<0) {
593   minimalHNE=1;
594   maxspalte=1;
595 }
596
597 number c,delt;
598 int p = char(basering);
599 string ringchar=charstr(basering);
600 map xytausch = basering,y,x;
601 if ((p!=0) and (ringchar != string(p))) {
602                            // coefficient field is extension of Z/pZ
603   execute("int n_elements="+
604           ringchar[1,size(ringchar)-size(parstr(basering))-1]+";");
605                            // number of elements of actual ring
606   number generat=par(1);   // generator of the coefficient field of the ring
607 }
608
609
610 //========= Abfangen von unzulaessigen oder trivialen Eingaben ===============
611 //------------ Nullpolynom oder Einheit im Potenzreihenring: -----------------
612 if (f == 0) {
613   dbprint(printlevel+1,"The given polynomial is the zero-polynomial !");
614   Abbruch=1; Ausgabe=1;
615 }
616 else {
617   intvec nm = getnm(f);
618   N = nm[1]; M = nm[2]; // Berechne Schnittpunkte Newtonpolygon mit Achsen
619   if (N == 0) {
620     dbprint(printlevel+1,"The given polynomial is a unit as power series !");
621     Abbruch=1; Ausgabe=1;
622   }
623   else {
624    if (N == -1) {
625      if ((voice==2) && (printlevel > -1)) { "The HNE is x = 0"; }
626      Abbruch=1; Ausgabe=2; getauscht=1;
627      if (M <> 1) { einzweig=0; }
628    }
629    else {
630     if (M == -1) {
631       if ((voice==2) && (printlevel > -1)) { "The HNE is y = 0"; }
632       Abbruch=1; Ausgabe=2;
633       if (N <> 1) { einzweig=0; }
634   }}}
635 }
636 //--------------------- Test auf Quadratfreiheit -----------------------------
637 if (Abbruch==0) {
638
639 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
640 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
641 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring guenstig
642 //----------------------------------------------------------------------------
643
644  if ((p==0) and (size(charstr(basering))==1)) {
645   int testerg=(polytest(f)==0);
646   ring zweitring = 32003,(x,y),dp;
647   map polyhinueber=guenstig,x,y;     // fetch geht nicht
648   poly f=polyhinueber(f);
649   poly test_sqr=squarefree(f);
650   if (test_sqr != f) {
651    if (printlevel>0) {
652      "Most probably the given polynomial is not squarefree. But the test was";
653      "made in characteristic 32003 and not 0 to improve speed. You can";
654      "(r) redo the test in char 0 (but this may take some time)";
655      "(c) continue the development, if you're sure that the polynomial",
656      "IS squarefree";
657      if (testerg==1) {
658        "(s) continue the development with a squarefree factor (*)";}
659      "(q) or just quit the algorithm (default action)";
660      "";"Please enter the letter of your choice:";
661      string str=read("")[1];
662    }
663    else { string str="r"; }      // printlevel <= 0: non-interactive behaviour
664    setring guenstig;
665    map polyhinueber=zweitring,x,y;
666    if (str=="r") {
667      poly test_sqr=squarefree(f);
668      if (test_sqr != f) {
669       if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
670       else              { "The given polynomial is not squarefree!"; }
671       "I'll continue with the radical.";
672       if (printlevel>0) { pause("Hit RETURN to continue:"); }
673       f=test_sqr;
674      }
675      else {
676       dbprint(printlevel,
677        "everything is ok -- the polynomial is squarefree in char(k)=0");
678      }
679    }
680    else {
681      if ((str=="s") and (testerg==1)) {
682       "(*) attention: it could be that the factor is only one in char 32003!";
683        f=polyhinueber(test_sqr);
684      }
685      else {
686        if (str<>"c") {
687          setring altring;kill guenstig;kill zweitring;
688          return(return_error);}
689        else { "if the algorithm doesn't terminate, you were wrong...";}
690    }}
691    kill zweitring;
692    nm = getnm(f);             // N,M haben sich evtl. veraendert
693    N = nm[1]; M = nm[2];      // Berechne Schnittpunkte Newtonpolynom mit Achsen
694    if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
695   }
696   else {
697     setring guenstig;
698     kill zweitring;
699   }
700  }
701 // ------------------- Fall Charakteristik > 0 -------------------------------
702  else {
703   poly test_sqr=squarefree(f);
704   if (test_sqr == 1) {
705    "The given polynomial is of the form g^"+string(p)+", therefore",
706    "reducible.";"Please try again.";
707    setring altring;
708    kill guenstig;
709    return(return_error);}
710   if (test_sqr != f) {
711    "The given polynomial is not squarefree. I'll continue with the radical.";
712    if (p != 0)
713     {"But if the polynomial contains a factor of the form g^"+string(p)+",";
714      "this factor will be lost.";}
715    if (printlevel>0) { pause("Hit RETURN to continue:"); }
716    f=test_sqr;
717    nm = getnm(f);              // N,M haben sich veraendert
718    N = nm[1]; M = nm[2];       // Berechne Schnittpunkte Newtonpolynom mit Achsen
719    if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
720   }
721
722  }                             // endelse(p==0)
723
724  if (N==0) {
725    " Sorry. The remaining polynomial is a unit in the power series ring...";
726    setring altring;kill guenstig;return(return_error);
727  }
728 //---------------------- gewaehrleiste, dass x transvers ist -----------------
729  if (M < N)
730  { f = xytausch(f);            // Variablentausch : x jetzt transvers
731    getauscht = 1;              // den Tausch merken
732    M = M+N; N = M-N; M = M-N;  // M, N auch vertauschen
733  }
734  if (defined(HNDebugOn)) {
735   if (getauscht) {"x<->y were exchanged; polynomial is now ",f;}
736   else           {"x , y were not exchanged";}
737   "M resp. N are now",M,N;
738  }
739 }                              // end(if Abbruch==0)
740
741 ideal a(0);
742 while (Abbruch==0) {
743
744 //================= Beginn der Schleife (eigentliche Entwicklung) ============
745
746 //------------------- ist das Newtonpolygon eine gerade Linie? ---------------
747  if (testreducible(f,N,M)) {
748    dbprint(printlevel+1," The given polynomial is not irreducible");
749    kill guenstig;
750    setring altring;
751    return(return_error);       // Abbruch der Prozedur!
752  }
753  R = M%N;
754  Q = M / N;
755
756 //-------------------- Fall Rest der Division R = 0 : ------------------------
757  if (R == 0) {
758    c = koeff(f,0,N);
759    if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
760    e = gcd(M,N);
761 //----------------- Test, ob leitf = c*(y^N - delta*x^(m/e))^e ist -----------
762    if (p==0) {
763      delt = koeff(f,M/ e,N - N/ e) / (-1*e*c);
764      if (defined(HNDebugOn)) {"quasihomogeneous leading form:",
765         leit(f,N,M)," = ",c,"* (y -",delt,"* x^"+string(M/ e)+")^",e," ?";}
766      if (leit(f,N,M) != c*(y^(N/ e) - delt*x^(M/ e))^e) {
767        dbprint(printlevel+1," The given polynomial is reducible !");
768        Abbruch=1; Ausgabe=1; }
769    }
770    else {                     // p!=0
771      if (e%p != 0) {
772        delt = koeff(f,M/ e,N - N/ e) / (-1*e*c);
773        if (defined(HNDebugOn)) {"quasihomogeneous leading form:",
774           leit(f,N,M)," = ",c,"* (y -",delt,"* x^"+string(M/ e)+")^",e," ?";}
775        if (leit(f,N,M) != c*(y^(N/ e) - delt*x^(M/ e))^e) {
776           dbprint(printlevel+1," The given polynomial is reducible !");
777           Abbruch=1; Ausgabe=1; }
778      }
779
780      else {                   // e%p == 0
781        eps = e;
782        for (l = 0; eps%p == 0; l=l+1) { eps=eps/ p;}
783        if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
784        delt = koeff(f,(M/ e)*p^l,(N/ e)*p^l*(eps-1)) / (-1*eps*c);
785
786        if ((ringchar != string(p)) and (delt != 0)) {
787 //- coeff. field is not Z/pZ => we`ve to correct delta by taking (p^l)th root-
788          if (delt == generat) {exponent=1;}
789          else {
790           if (delt == 1) {exponent=0;}
791           else {
792            exponent=pardeg(delt);
793
794 //-- an dieser Stelle kann ein Fehler auftreten, wenn wir eine transzendente -
795 //-- Erweiterung von Z/pZ haben: dann ist das hinzuadjungierte Element kein  -
796 //-- Erzeuger der mult. Gruppe, d.h. in Z/pZ (a) gibt es i.allg. keinen      -
797 //-- Exponenten mit z.B. a2+a = a^exp                                        -
798 //----------------------------------------------------------------------------
799          }}
800          delt = generat^(extgcd(n_elements-1,p^l)[3]*exponent);
801        }
802
803        if (defined(HNDebugOn)) {"quasihomogeneous leading form:",
804          leit(f,N,M)," = ",c,"* (y^"+string(N/ e),"-",delt,"* x^"
805          +string(M/ e)+")^",e,"  ?";}
806        if (leit(f,N,M) != c*(y^(N/ e) - delt*x^(M/ e))^e) {
807          dbprint(printlevel+1," The given polynomial is reducible !");
808          Abbruch=1; Ausgabe=1; }
809      }
810    }
811    if (Abbruch == 0) {
812      f = T1_Transform(f,delt,M/ e);
813      dbprint(printlevel-voice+2,"a("+string(zeile)+","+string(Q)+") = "
814              +string(delt));
815      a(zeile)[Q]=delt;
816      if (defined(HNDebugOn)) {"transformed polynomial: ",f;}}
817
818      nm=getnm(f); N=nm[1]; M=nm[2];        // Neuberechnung des Newtonpolygons
819  }
820 //--------------------------- Fall R > 0 : -----------------------------------
821  else {
822    dbprint(printlevel-voice+2, "h("+string(zeile)+ ") ="+string(Q));
823    hqs[zeile+1]=Q;                  // denn zeile beginnt mit dem Wert 0
824    a(zeile)[Q+1]=x;                 // Markierung des Zeilenendes der HNE
825    maxspalte=maxspalte*((Q+1) < maxspalte) + (Q+1)*((Q+1) >= maxspalte);
826                                     // Anpassung der Sp.zahl der HNE-Matrix
827    f = T_Transform(f,Q,N);
828    if (defined(HNDebugOn)) {"transformed polynomial: ",f;}
829    zeile=zeile+1;
830 //------------ Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
831    ideal a(zeile);
832    M=N;N=R;
833  }
834
835 //--------------- schneidet das Newtonpolygon beide Achsen? ------------------
836  if (M==-1) {
837     dbprint(printlevel-voice+2,"The HNE is finite!");
838     a(zeile)[Q+1]=x;   // Markiere das Ende der Zeile
839     hqs[zeile+1]=Q;
840     maxspalte=maxspalte*((Q+1) < maxspalte) + (Q+1)*((Q+1) >= maxspalte);
841     if (N <> 1) { einzweig=0; }
842     f=0;               // transformiertes Polynom wird nicht mehr gebraucht
843     Abbruch=1;
844  }
845  else {if (M<N) {"Something has gone wrong: M<N";}}
846  if(defined(HNDebugOn)) {"new M,N:",M,N;}
847
848 //----------------- Abbruchbedingungen fuer die Schleife: --------------------
849  if ((N==1) and (Abbruch!=1) and ((M > maxspalte) or (minimalHNE==1))
850      and (size(a(zeile))>0))
851 //----------------------------------------------------------------------------
852 // Abbruch, wenn die Matrix so voll ist, dass eine neue Spalte angefangen
853 // werden muesste und die letzte Zeile nicht nur Nullen enthaelt
854 // oder wenn die Matrix nicht voll gemacht werden soll (minimale Information)
855 //----------------------------------------------------------------------------
856   { Abbruch=1; hqs[zeile+1]=-1;
857     if (maxspalte < ncols(a(zeile))) { maxspalte=ncols(a(zeile));}
858     if ((minimalHNE==1) and (M <= maxspalte)) {
859 // teile param mit, dass Eintraege der letzten Zeile nur teilw. richtig sind:-
860       hqs[zeile+1]=-M;
861 //------------- markiere den Rest der Zeile als unbekannt: -------------------
862       for (R=M; R <= maxspalte; R++) { a(zeile)[R]=y;}
863     }                  // R wird nicht mehr gebraucht
864   }
865 //========================= Ende der Schleife ================================
866
867 }
868 setring altring;
869 if (Ausgabe == 0) {
870 //-------------------- Ergebnis in den alten Ring transferieren: -------------
871   map zurueck=guenstig,maxideal(1)[1],maxideal(1)[2];
872   matrix amat[zeile+1][maxspalte];
873   ideal uebergabe;
874   for (e=0; e<=zeile; e=e+1) {
875     uebergabe=zurueck(a(e));
876     if (ncols(uebergabe) > 1) {
877      amat[e+1,1..ncols(uebergabe)]=uebergabe;}
878     else {amat[e+1,1]=uebergabe[1];}
879   }
880   if (ringwechsel) {
881     if (nvars(altring)==2) { f=fetch(guenstig,f); }
882     else                   { f=zurueck(f); }
883   }
884 }
885
886 kill guenstig;
887 if ((einzweig==0) && (voice==2) && (printlevel > -1)) {
888    "// Note: The curve is reducible, but we were able to compute a HNE.";
889    "// This means the result is only one of several existing HNE's.";
890 }
891 if (Ausgabe == 0) { return(list(amat,hqs,getauscht,f,einzweig));}
892 if (Ausgabe == 1) { return(return_error);}             // error has occurred
893 if (Ausgabe == 2) { return(list(matrix(ideal(0,x)),intvec(1),getauscht,
894                                 poly(0),einzweig));}   // HNE is x=0 or y=0
895}
896example
897{ "EXAMPLE:"; echo = 2;
898  ring exring = 7,(x,y),ds;
899  list Hne=develop(4x98+2x49y7+x11y14+2y14);
900  print(Hne[1]);
901  // therefore the HNE is:
902  // z(-1)= 3*z(0)^7 + z(0)^7*z(1),
903  // z(0) = z(1)*z(2),       (there is 1 zero in the 2nd row before x)
904  // z(1) = z(2)^3*z(3),     (there are 3 zeroes in the 3rd row)
905  // z(2) = z(3)*z(4),
906  // z(3) = -z(4)^2 + 0*z(4)^3 +...+ 0*z(4)^8 + ?*z(4)^9 + ...
907  // (the missing x in the last line indicates that it is not complete.)
908  Hne[2];
909  param(Hne);
910  // parametrization:   x(t)= -t^14+O(t^21),  y(t)= -3t^98+O(t^105)
911  // (the term -t^109 in y may have a wrong coefficient)
912  displayHNE(Hne);
913}
914
915///////////////////////////////////////////////////////////////////////////////
916//               procedures to extract information out of HNE                //
917///////////////////////////////////////////////////////////////////////////////
918
919proc param (list L, list #)
920"USAGE:  param(L [,s]); L list, s any type (optional)
921ASSUME:  L is the output of @code{develop(f)}, or of
922        @code{extdevelop(develop(f),n)}, or (one entry in) the list of HN
923        data created by @code{hnexpansion(f[,\"ess\"])}.
924RETURN: If L are the HN data of an irreducible plane curve singularity f: a
925        parametrization for f in the following format: @*
926        - if only the list L is given, the result is an ideal of two
927        polynomials p[1],p[2]: if the HNE was finite then f(p[1],p[2])=0};
928        if not, the true parametrization will be given by two power series,
929        and p[1],p[2] are truncations of these series.@*
930        - if the optional parameter s is given, the result is a list l:
931        l[1]=param(L) (ideal) and l[2]=intvec with two entries indicating
932        the highest degree up to which the coefficients of the monomials in
933        l[1] are exact (entry -1 means that the corresponding parametrization
934        is exact).
935        If L collects the HN data of a reducible plane curve singularity f,
936        the return value is a list of parametrizations in the respective
937        format.
938NOTE:   If the basering has only 2 variables, the first variable is chosen
939        as indefinite. Otherwise, the 3rd variable is chosen.
940SEE ALSO: develop, extdevelop
941KEYWORDS: parametrization
942EXAMPLE: example param;     shows an example
943         example develop;   shows another example
944"
945{
946 //-------------------------- Initialisierungen -------------------------------
947 int return_list;
948 if (size(#)>0) { return_list=1; }
949
950 if (typeof(L[1])=="list") { // output of hnexpansion (> 1 branch)
951   list Ergebnis;
952   for (int i=1; i<=size(L); i++) {
953     dbprint(printlevel-voice+4,"// Parametrization of branch number "
954       +string(i)+" computed.");
955     printlevel=printlevel+1;
956     if (return_list==1) { Ergebnis[i]=param(L[i],1); }
957     else                { Ergebnis[i]=param(L[i]); }
958     printlevel=printlevel-1;
959   }
960   return(Ergebnis);
961 }
962 else {
963   matrix m=L[1];
964   intvec v=L[2];
965   int switch=L[3];
966 }
967 if (switch==-1) {
968   "An error has occurred in develop, so there is no HNE.";
969   return(ideal(0,0));
970 }
971 int fehler,fehlervor,untergrad,untervor,beginn,i,zeile,hilf;
972
973 if (nvars(basering) > 2) { poly z(size(v)+1)=var(3); }
974 else                     { poly z(size(v)+1)=var(1); }
975 poly z(size(v));
976 zeile=size(v);
977 //------------- Parametrisierung der untersten Zeile der HNE -----------------
978 if (v[zeile] > 0) {
979   fehler=0;           // die Parametrisierung wird exakt werden
980   for (i=1; i<=v[zeile]; i++) {
981     z(zeile)=z(zeile)+m[zeile,i]*z(zeile+1)^i;
982   }
983 }
984 else {
985   untervor=1;         // = Untergrad der vorhergehenden Zeile
986   if (v[zeile]==-1) {
987     fehler=ncols(m)+1;
988     for (i=1; i<=ncols(m); i++) {
989       z(zeile)=z(zeile)+m[zeile,i]*z(zeile+1)^i;
990       if ((untergrad==0) and (m[zeile,i]!=0)) {untergrad=i;}
991                       // = Untergrad der aktuellen Zeile
992     }
993   }
994   else {
995     fehler= -v[zeile];
996     for (i=1; i<-v[zeile]; i++) {
997       z(zeile)=z(zeile)+m[zeile,i]*z(zeile+1)^i;
998       if ((untergrad==0) and (m[zeile,i]!=0)) {untergrad=i;}
999     }
1000   }
1001 }
1002 //------------- Parametrisierung der restlichen Zeilen der HNE ---------------
1003 for (zeile=size(v)-1; zeile>0; zeile--) {
1004   poly z(zeile);
1005   beginn=0;             // Beginn der aktuellen Zeile
1006   for (i=1; i<=v[zeile]; i++) {
1007     z(zeile)=z(zeile)+m[zeile,i]*z(zeile+1)^i;
1008     if ((beginn==0) and (m[zeile,i]!=0)) { beginn=i;}
1009   }
1010   z(zeile)=z(zeile) + z(zeile+1)^v[zeile] * z(zeile+2);
1011   if (beginn==0) {
1012     if (fehler>0) {     // damit fehler=0 bleibt bei exakter Param.
1013     fehlervor=fehler;   // Fehler der letzten Zeile
1014     fehler=fehler+untergrad*(v[zeile]-1)+untervor;   // Fehler dieser Zeile
1015     hilf=untergrad;
1016     untergrad=untergrad*v[zeile]+untervor;
1017     untervor=hilf;}     // untervor = altes untergrad
1018   }
1019   else {
1020     fehlervor=fehler;
1021     fehler=fehler+untergrad*(beginn-1);
1022     untervor=untergrad;
1023     untergrad=untergrad*beginn;
1024   }
1025 }
1026 //--------------------- Ausgabe der Fehlerabschaetzung -----------------------
1027 if (switch==0) {
1028   if (fehler>0) {
1029     if (fehlervor>0) {
1030       dbprint(printlevel-voice+4,""+
1031         "// ** Warning: result is exact up to order "+string(fehlervor-1)+
1032         " in "+ string(var(1))+" and "+string(fehler-1)+" in " +
1033         string(var(2))+" !");
1034     }
1035     else {
1036       dbprint(printlevel-voice+4,""+
1037         "// ** Warning: result is exact up to order "+ string(fehler-1)+
1038         " in "+string(var(2))+" !");
1039     }
1040   }
1041   if (return_list==0) { return(ideal(z(2),z(1))); }
1042   else   { return(list(ideal(z(2),z(1)),intvec(fehlervor-1,fehler-1))); }
1043 }
1044 else {
1045   if (fehler>0) {
1046     if (fehlervor>0) {
1047       dbprint(printlevel-voice+4,""+
1048         "// ** Warning: result is exact up to order "+string(fehler-1)+
1049         " in "+ string(var(1))+" and "+string(fehlervor-1)+" in " +
1050         string(var(2))+" !");
1051     }
1052     else {
1053       dbprint(printlevel-voice+4,""+
1054        "// ** Warning: result is exact up to order "+ string(fehler-1)+
1055         " in "+string(var(1))+" !");
1056     }
1057   }
1058   if (return_list==0) { return(ideal(z(1),z(2))); }
1059   else   { return(list(ideal(z(1),z(2)),intvec(fehler-1,fehlervor-1))); }
1060 }
1061}
1062example
1063{ "EXAMPLE:"; echo = 2;
1064 ring exring=0,(x,y,t),ds;
1065 poly f=x3+2xy2+y2;
1066 list Hne=develop(f);
1067 list hne_extended=extdevelop(Hne,10);
1068            //   compare the HNE matrices ...
1069 print(Hne[1]);
1070 print(hne_extended[1]);
1071            // ... and the resulting parametrizations:
1072 param(Hne);
1073 param(hne_extended);
1074 param(hne_extended,0);
1075
1076 // An example with more than one branch:
1077 list L=hnexpansion(f*(x2+y4));
1078 def HNring = L[1]; setring HNring;
1079 param(hne);
1080}
1081
1082///////////////////////////////////////////////////////////////////////////////
1083
1084proc invariants
1085"USAGE:   invariants(INPUT); INPUT list or poly
1086ASSUME:  @code{INPUT} is the output of @code{develop(f)}, or of
1087         @code{extdevelop(develop(f),n)}, or one entry of the list of HN data
1088         computed by @code{hnexpansion(f[,\"ess\"])}.
1089RETURN:  list @code{INV} of the following format:
1090@format
1091    INV[1]:  intvec    (characteristic exponents)
1092    INV[2]:  intvec    (generators of the semigroup)
1093    INV[3]:  intvec    (Puiseux pairs, 1st components)
1094    INV[4]:  intvec    (Puiseux pairs, 2nd components)
1095    INV[5]:  int       (degree of the conductor)
1096    INV[6]:  intvec    (sequence of multiplicities)
1097@end format
1098         If @code{INPUT} contains no valid HN expansion, the empty list is
1099         returned.
1100ASSUME:  @code{INPUT} is a bivariate polynomial f, or the output of
1101         @code{hnexpansion(f)}, or the list of HN data computed by
1102         @code{hnexpansion(f [,\"ess\"])}.
1103RETURN:  list @code{INV}, such that @code{INV[i]} coincides with the output of
1104         @code{invariants(develop(f[i]))}, where f[i] is the i-th branch of
1105         f, and the last entry of @code{INV} contains further invariants of
1106         f in the format:
1107@format
1108    INV[last][1] : intmat    (contact matrix of the branches)
1109    INV[last][2] : intmat    (intersection multiplicities of the branches)
1110    INV[last][3] : int       (delta invariant of f)
1111@end format
1112NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
1113         for other purposes as well it is better to calculate this first
1114         with the aid of @code{hnexpansion} and use it as input instead of
1115         the polynomial itself.
1116SEE ALSO: hnexpansion, develop, displayInvariants, multsequence, intersection
1117KEYWORDS: characteristic exponents; semigroup of values; Puiseux pairs;
1118          conductor, degree; multiplicities, sequence of
1119EXAMPLE:  example invariants; shows an example
1120"
1121{
1122 //---- INPUT = poly, or HNEring, or hne of reducible curve  -----------------
1123 if (typeof(#[1])!="matrix") {
1124   if (typeof(#[1])=="poly") {
1125      list L=hnexpansion(#[1]);
1126      if (typeof(L[1])=="ring") {
1127        def altring = basering;
1128        def HNring = L[1]; setring HNring;
1129        list Ergebnis = invariants(hne);
1130        setring altring;
1131        kill HNring;
1132        return(Ergebnis);
1133      }
1134      else {
1135        return(invariants(L));
1136      }
1137   }
1138   if (typeof(#[1])=="ring") {
1139     def altring = basering;
1140     def HNring = #[1]; setring HNring;
1141     list Ergebnis = invariants(hne);
1142     setring altring;
1143     kill HNring;
1144     return(Ergebnis);
1145   }
1146   if (typeof(#[1])=="list") {
1147     list hne=#;
1148     list Ergebnis;
1149     for (int lauf=1;lauf<=size(hne);lauf++) {
1150       Ergebnis[lauf]=invariants(hne[lauf]);
1151     }
1152     // Calculate the intersection matrix and the intersection multiplicities.
1153     intmat contact[size(hne)][size(hne)];
1154     intmat intersectionmatrix[size(hne)][size(hne)];
1155     int Lauf;
1156     for (lauf=1;lauf<=size(hne);lauf++) {
1157       for (Lauf=lauf+1;Lauf<=size(hne);Lauf++) {
1158         contact[lauf,Lauf]=separateHNE(hne[lauf],hne[Lauf]);
1159         contact[Lauf,lauf]=contact[lauf,Lauf];
1160         intersectionmatrix[lauf,Lauf]=intersection(hne[lauf],hne[Lauf]);
1161         intersectionmatrix[Lauf,lauf]=intersectionmatrix[lauf,Lauf];
1162       }
1163     }
1164     // Calculate the delta invariant.
1165     int inters;
1166     int del=Ergebnis[size(hne)][5]/2;
1167     for(lauf=1;lauf<=size(hne)-1;lauf++) {
1168       del=del+Ergebnis[lauf][5]/2;
1169       for(Lauf=lauf+1;Lauf<=size(hne);Lauf++) {
1170         inters=inters+intersectionmatrix[lauf,Lauf];
1171       }
1172     }
1173     del=del+inters;
1174     list LAST=contact,intersectionmatrix,del;
1175     Ergebnis[size(hne)+1]=LAST;
1176     return(Ergebnis);
1177   }
1178 }
1179 //-------------------------- Initialisierungen -------------------------------
1180 matrix m=#[1];
1181 intvec v=#[2];
1182 int switch=#[3];
1183 list ergebnis;
1184 if (switch==-1) {
1185   "An error has occurred in develop, so there is no HNE.";
1186   return(ergebnis);
1187 }
1188 intvec beta,s,svorl,ordnung,multseq,mpuiseux,npuiseux,halbgr;
1189 int genus,zeile,i,j,k,summe,conductor,ggT;
1190 string Ausgabe;
1191 int nc=ncols(m); int nr=nrows(m);
1192 ordnung[nr]=1;
1193         // alle Indizes muessen (gegenueber [Ca]) um 1 erhoeht werden,
1194         // weil 0..r nicht als Wertebereich erlaubt ist (aber nrows(m)==r+1)
1195
1196 //---------------- Bestimme den Untergrad der einzelnen Zeilen ---------------
1197 for (zeile=nr; zeile>1; zeile--) {
1198   if ((size(ideal(m[zeile,1..nc])) > 1) or (zeile==nr)) { // keine Nullzeile
1199      k=1;
1200      while (m[zeile,k]==0) {k++;}
1201      ordnung[zeile-1]=k*ordnung[zeile]; // vgl. auch Def. von untergrad in
1202      genus++;                           // proc param
1203      svorl[genus]=zeile;} // werden gerade in umgekehrter Reihenfolge abgelegt
1204   else {
1205      ordnung[zeile-1]=v[zeile]*ordnung[zeile]+ordnung[zeile+1];
1206 }}
1207 //----------------- charakteristische Exponenten (beta) ----------------------
1208 s[1]=1;
1209 for (k=1; k <= genus; k++) { s[k+1]=svorl[genus-k+1];} // s[2]==s(1), u.s.w.
1210 beta[1]=ordnung[1]; //charakt. Exponenten: Index wieder verschoben
1211 for (k=1; k <= genus; k++) {
1212   summe=0;
1213   for (i=1; i <= s[k]; i++) {summe=summe+v[i]*ordnung[i];}
1214   beta[k+1]=summe+ordnung[s[k]]+ordnung[s[k]+1]-ordnung[1];
1215 }
1216 //--------------------------- Puiseuxpaare -----------------------------------
1217 int produkt=1;
1218 for (i=1; i<=genus; i++) {
1219   ggT=gcd(beta[1],beta[i+1]*produkt);
1220   mpuiseux[i]=beta[i+1]*produkt / ggT;
1221   npuiseux[i]=beta[1] / ggT;
1222   produkt=produkt*npuiseux[i];
1223 }
1224 //---------------------- Grad des Konduktors ---------------------------------
1225 summe=1-ordnung[1];
1226 if (genus > 0) {
1227   for (i=2; i <= genus+1; i++) {
1228     summe=summe + beta[i] * (ordnung[s[i-1]] - ordnung[s[i]]);
1229   }                              // n.b.: Indizierung wieder um 1 verschoben
1230 }
1231 conductor=summe;
1232 //------------------- Erzeuger der Halbgruppe: -------------------------------
1233 halbgr=puiseux2generators(mpuiseux,npuiseux);
1234
1235 //------------------- Multiplizitaetensequenz: -------------------------------
1236 k=1;
1237 for (i=1; i<size(v); i++) {
1238   for (j=1; j<=v[i]; j++) {
1239     multseq[k]=ordnung[i];
1240     k++;
1241 }}
1242 multseq[k]=1;
1243 //--- fuelle die Multipl.seq. mit den notwendigen Einsen auf -- T.Keilen ----
1244 int tester=k;
1245 while((multseq[tester]==1) and (tester>1))
1246 {
1247   tester=tester-1;
1248 }
1249 if ((multseq[tester]!=1) and (multseq[tester]!=k-tester))
1250 {
1251   for (i=k+1; i<=tester+multseq[tester]; i++)
1252   {
1253     multseq[i]=1;
1254   }
1255 }
1256 //--- Ende T.Keilen --- 06.05.02
1257 //------------------------- Rueckgabe ----------------------------------------
1258 ergebnis=beta,halbgr,mpuiseux,npuiseux,conductor,multseq;
1259 return(ergebnis);
1260}
1261example
1262{ "EXAMPLE:"; echo = 2;
1263 ring exring=0,(x,y),dp;
1264 list Hne=develop(y4+2x3y2+x6+x5y);
1265 list INV=invariants(Hne);
1266 INV[1];                   // the characteristic exponents
1267 INV[2];                   // the generators of the semigroup of values
1268 INV[3],INV[4];            // the Puiseux pairs in packed form
1269 INV[5] / 2;               // the delta-invariant
1270 INV[6];                   // the sequence of multiplicities
1271                           // To display the invariants more 'nicely':
1272 displayInvariants(Hne);
1273 /////////////////////////////
1274 INV=invariants((x2-y3)*(x3-y5));
1275 INV[1][1];                // the characteristic exponents of the first branch
1276 INV[2][6];                // the sequence of multiplicities of the second branch
1277 print(INV[size(INV)][1]);         // the contact matrix of the branches
1278 print(INV[size(INV)][2]);         // the intersection numbers of the branches
1279 INV[size(INV)][3];                // the delta invariant of the curve
1280}
1281
1282///////////////////////////////////////////////////////////////////////////////
1283
1284proc displayInvariants
1285"USAGE:  displayInvariants(INPUT); INPUT list or poly
1286ASSUME:  @code{INPUT} is a bivariate polynomial, or the output of
1287         @code{develop(f)}, resp. of @code{extdevelop(develop(f),n)}, or (one
1288         entry of) the list of HN data computed by
1289         @code{hnexpansion(f[,\"ess\"])}.
1290RETURN:  none
1291DISPLAY: invariants of the corresponding branch, resp. of all branches,
1292         in a better readable form.
1293NOTE:    If the Hamburger-Noether expansion of the curve f is needed
1294         for other purposes as well it is better to calculate this first
1295         with the aid of @code{hnexpansion} and use it as input instead of
1296         the polynomial itself.
1297SEE ALSO: invariants, intersection, develop, hnexpansion
1298EXAMPLE: example displayInvariants;  shows an example
1299"
1300{
1301 // INPUT = polynomial or ring
1302 if (typeof(#[1])=="poly") {
1303   list L=hnexpansion(#[1]);
1304   if (typeof(L[1])=="ring") {
1305     def HNring = L[1]; setring HNring;
1306     displayInvariants(hne);
1307     return();
1308   }
1309   else {
1310     displayInvariants(L);
1311     return();
1312   }
1313 }
1314 if (typeof(#[1])=="ring")
1315 {
1316   def HNring = #[1]; setring HNring;
1317   displayInvariants(hne);
1318   return();
1319 }
1320 // INPUT = hne of a plane curve
1321 int i,j,k,mul;
1322 string Ausgabe;
1323 list ergebnis;
1324 //-- entferne ueberfluessige Daten zur Erhoehung der Rechengeschwindigkeit: --
1325 #=stripHNE(#);
1326 //-------------------- Ausgabe eines Zweiges ---------------------------------
1327 if (typeof(#[1])=="matrix") {
1328   ergebnis=invariants(#);
1329   if (size(ergebnis)!=0) {
1330    " characteristic exponents  :",ergebnis[1];
1331    " generators of semigroup   :",ergebnis[2];
1332    if (size(ergebnis[1])>1) {
1333     for (i=1; i<=size(ergebnis[3]); i++) {
1334       Ausgabe=Ausgabe+"("+string(ergebnis[3][i])+","
1335       +string(ergebnis[4][i])+")";
1336    }}
1337    " Puiseux pairs             :",Ausgabe;
1338    " degree of the conductor   :",ergebnis[5];
1339    " delta invariant           :",ergebnis[5]/2;
1340    " sequence of multiplicities:",ergebnis[6];
1341 }}
1342 //-------------------- Ausgabe aller Zweige ----------------------------------
1343 else {
1344  ergebnis=invariants(#);
1345  intmat contact=ergebnis[size(#)+1][1];
1346  intmat intersectionmatrix=ergebnis[size(#)+1][2];
1347  for (j=1; j<=size(#); j++) {
1348    " --- invariants of branch number",j,": ---";
1349    " characteristic exponents  :",ergebnis[j][1];
1350    " generators of semigroup   :",ergebnis[j][2];
1351    Ausgabe="";
1352    if (size(ergebnis[j][1])>1) {
1353     for (i=1; i<=size(ergebnis[j][3]); i++) {
1354       Ausgabe=Ausgabe+"("+string(ergebnis[j][3][i])+","
1355       +string(ergebnis[j][4][i])+")";
1356    }}
1357    " Puiseux pairs             :",Ausgabe;
1358    " degree of the conductor   :",ergebnis[j][5];
1359    " delta invariant           :",ergebnis[j][5]/2;
1360    " sequence of multiplicities:",ergebnis[j][6];
1361    "";
1362  }
1363  if (size(#)>1)
1364  {
1365    " -------------- contact numbers : -------------- ";"";
1366    Ausgabe="branch |   ";
1367    for (j=size(#); j>1; j--)
1368    {
1369      if (size(string(j))==1) { Ausgabe=Ausgabe+" "+string(j)+"    "; }
1370      else                    { Ausgabe=Ausgabe+string(j)+"    "; }
1371    }
1372    Ausgabe;
1373    Ausgabe="-------+";
1374    for (j=2; j<size(#); j++) { Ausgabe=Ausgabe+"------"; }
1375    Ausgabe=Ausgabe+"-----";
1376    Ausgabe;
1377  }
1378  for (j=1; j<size(#); j++)
1379  {
1380    if (size(string(j))==1) { Ausgabe="    "+string(j)+"  |"; }
1381    else                    { Ausgabe="   " +string(j)+"  |"; }
1382    for (k=size(#); k>j; k--)
1383    {
1384      mul=contact[j,k];//separateHNE(#[j],#[k]);
1385      for (i=1; i<=5-size(string(mul)); i++) { Ausgabe=Ausgabe+" "; }
1386      Ausgabe=Ausgabe+string(mul);
1387      if (k>j+1) { Ausgabe=Ausgabe+","; }
1388    }
1389    Ausgabe;
1390  }
1391  "";
1392  if (size(#)>1)
1393  {
1394    " -------------- intersection multiplicities : -------------- ";"";
1395    Ausgabe="branch |   ";
1396    for (j=size(#); j>1; j--)
1397    {
1398      if (size(string(j))==1) { Ausgabe=Ausgabe+" "+string(j)+"    "; }
1399      else                    { Ausgabe=Ausgabe+string(j)+"    "; }
1400    }
1401    Ausgabe;
1402    Ausgabe="-------+";
1403    for (j=2; j<size(#); j++) { Ausgabe=Ausgabe+"------"; }
1404    Ausgabe=Ausgabe+"-----";
1405    Ausgabe;
1406  }
1407  for (j=1; j<size(#); j++)
1408  {
1409    if (size(string(j))==1) { Ausgabe="    "+string(j)+"  |"; }
1410    else                    { Ausgabe="   " +string(j)+"  |"; }
1411    for (k=size(#); k>j; k--)
1412    {
1413      mul=intersectionmatrix[j,k];//intersection(#[j],#[k]);
1414      for (i=1; i<=5-size(string(mul)); i++) { Ausgabe=Ausgabe+" "; }
1415      Ausgabe=Ausgabe+string(mul);
1416      if (k>j+1) { Ausgabe=Ausgabe+","; }
1417    }
1418    Ausgabe;
1419  }
1420  "";
1421  " -------------- delta invariant of the curve : ",ergebnis[size(#)+1][3];
1422
1423 }
1424 return();
1425}
1426example
1427{ "EXAMPLE:"; echo = 2;
1428 ring exring=0,(x,y),dp;
1429 list Hne=develop(y4+2x3y2+x6+x5y);
1430 displayInvariants(Hne);
1431}
1432///////////////////////////////////////////////////////////////////////////////
1433
1434proc multiplicities
1435"USAGE:   multiplicities(L); L list
1436ASSUME:  L is the output of @code{develop(f)}, or of
1437         @code{extdevelop(develop(f),n)}, or one entry in the list @code{hne}
1438         in the ring created by @code{hnexpansion(f[,\"ess\"])}.
1439RETURN:  intvec of the different multiplicities that occur when successively
1440         blowing-up the curve singularity corresponding to f.
1441SEE ALSO: multsequence, develop
1442EXAMPLE: example multiplicities;  shows an example
1443"
1444{
1445 matrix m=#[1];
1446 intvec v=#[2];
1447 int switch=#[3];
1448 list ergebnis;
1449 if (switch==-1) {
1450   "An error has occurred in develop, so there is no HNE.";
1451   return(intvec(0));
1452 }
1453 intvec ordnung;
1454 int zeile,k;
1455 int nc=ncols(m); int nr=nrows(m);
1456 ordnung[nr]=1;
1457 //---------------- Bestimme den Untergrad der einzelnen Zeilen ---------------
1458 for (zeile=nr; zeile>1; zeile--) {
1459   if ((size(ideal(m[zeile,1..nc])) > 1) or (zeile==nr)) { // keine Nullzeile
1460      k=1;
1461      while (m[zeile,k]==0) {k++;}
1462      ordnung[zeile-1]=k*ordnung[zeile];
1463   }
1464   else {
1465      ordnung[zeile-1]=v[zeile]*ordnung[zeile]+ordnung[zeile+1];
1466 }}
1467 return(ordnung);
1468}
1469example
1470{ "EXAMPLE:"; echo = 2;
1471  int p=printlevel; printlevel=-1;
1472  ring r=0,(x,y),dp;
1473  multiplicities(develop(x5+y7));
1474  // The first value is the multiplicity of the curve itself, here it's 5
1475  printlevel=p;
1476}
1477///////////////////////////////////////////////////////////////////////////////
1478
1479proc puiseux2generators (intvec m, intvec n)
1480"USAGE:   puiseux2generators(m,n); m,n intvec
1481ASSUME:  m, resp. n, represent the 1st, resp. 2nd, components of Puiseux pairs
1482         (e.g., @code{m=invariants(L)[3]}, @code{n=invariants(L)[4]}).
1483RETURN:  intvec of the generators of the semigroup of values.
1484SEE ALSO: invariants
1485EXAMPLE: example puiseux2generators;  shows an example
1486"
1487{
1488 intvec beta;
1489 int q=1;
1490 //------------ glatte Kurve (eigentl. waeren m,n leer): ----------------------
1491 if (m==0) { return(intvec(1)); }
1492 //------------------- singulaere Kurve: --------------------------------------
1493 for (int i=1; i<=size(n); i++) { q=q*n[i]; }
1494 beta[1]=q; // == q_0
1495 m=1,m; n=1,n; // m[1] ist damit m_0 usw., genau wie beta[1]==beta_0
1496 for (i=2; i<=size(n); i++) {
1497  beta[i]=m[i]*q/n[i] - m[i-1]*q + n[i-1]*beta[i-1];
1498  q=q/n[i]; // == q_i
1499 }
1500 return(beta);
1501}
1502example
1503{ "EXAMPLE:"; echo = 2;
1504  // take (3,2),(7,2),(15,2),(31,2),(63,2),(127,2) as Puiseux pairs:
1505  puiseux2generators(intvec(3,7,15,31,63,127),intvec(2,2,2,2,2,2));
1506}
1507///////////////////////////////////////////////////////////////////////////////
1508
1509proc intersection (list hn1, list hn2)
1510"USAGE:   intersection(hne1,hne2); hne1, hne2 lists
1511ASSUME: @code{hne1, hne2} represent an HN expansion of an irreducible plane
1512        curve singularity (that is, are the output of @code{develop(f)}, or of
1513        @code{extdevelop(develop(f),n)}, or one entry of the list of HN data
1514        computed by @code{hnexpansion(f[,\"ess\"])}).
1515RETURN:  int, the intersection multiplicity of the irreducible plane curve
1516         singularities corresponding to @code{hne1} and @code{hne2}.
1517SEE ALSO: hnexpansion, displayInvariants
1518KEYWORDS: intersection multiplicity
1519EXAMPLE: example intersection;  shows an example
1520"
1521{
1522 //------------------ `intersect' ist schon reserviert ... --------------------
1523 int i,j,s,sum,schnitt,unterschied;
1524 matrix a1=hn1[1];
1525 matrix a2=hn2[1];
1526 intvec h1=hn1[2];
1527 intvec h2=hn2[2];
1528 intvec n1=multiplicities(hn1);
1529 intvec n2=multiplicities(hn2);
1530 if (hn1[3]!=hn2[3]) {
1531 //-- die jeweils erste Zeile von hn1,hn2 gehoert zu verschiedenen Parametern -
1532 //---------------- d.h. beide Kurven schneiden sich transversal --------------
1533   schnitt=n1[1]*n2[1];        // = mult(hn1)*mult(hn2)
1534 }
1535 else {
1536 //--------- die jeweils erste Zeile gehoert zum gleichen Parameter -----------
1537   unterschied=0;
1538   for (s=1; (h1[s]==h2[s]) && (s<size(h1)) && (s<size(h2))
1539              && (unterschied==0); s++) {
1540     for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]); i++) {;}
1541     if (i<=h1[s]) {
1542       unterschied=1;
1543       s--;                    // um s++ am Schleifenende wieder auszugleichen
1544     }
1545   }
1546   if (unterschied==0) {
1547     if ((s<size(h1)) && (s<size(h2))) {
1548       for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]) && (i<=h2[s]); i++) {;}
1549     }
1550     else {
1551 //-------------- Sonderfall: Unterschied in letzter Zeile suchen -------------
1552 // Beachte: Es koennen undefinierte Stellen auftreten, bei abbrechender HNE
1553 // muss die Ende-Markierung weg, h_[r] ist unendlich, die Matrix muss mit
1554 // Nullen fortgesetzt gedacht werden
1555 //----------------------------------------------------------------------------
1556       if (ncols(a1)>ncols(a2)) { j=ncols(a1); }
1557       else                     { j=ncols(a2); }
1558       unterschied=0;
1559       if ((h1[s]>0) && (s==size(h1))) {
1560         a1[s,h1[s]+1]=0;
1561         if (ncols(a1)<=ncols(a2)) { unterschied=1; }
1562       }
1563       if ((h2[s]>0) && (s==size(h2))) {
1564         a2[s,h2[s]+1]=0;
1565         if (ncols(a2)<=ncols(a1)) { unterschied=1; }
1566       }
1567       if (unterschied==1) {                   // mind. eine HNE war endlich
1568         matrix ma1[1][j]=a1[s,1..ncols(a1)];  // und bedarf der Fortsetzung
1569         matrix ma2[1][j]=a2[s,1..ncols(a2)];  // mit Nullen
1570       }
1571       else {
1572         if (ncols(a1)>ncols(a2)) { j=ncols(a2); }
1573         else                     { j=ncols(a1); }
1574         matrix ma1[1][j]=a1[s,1..j];          // Beschr. auf vergleichbaren
1575         matrix ma2[1][j]=a2[s,1..j];          // Teil (der evtl. y's enth.)
1576       }
1577       for (i=1; (ma1[1,i]==ma2[1,i]) && (i<j) && (ma1[1,i]!=var(2)); i++) {;}
1578       if (ma1[1,i]==ma2[1,i]) {
1579         "//** The two HNE's are identical!";
1580         "//** You have either tried to intersect a branch with itself,";
1581         "//** or the two branches have been developed separately.";
1582         "//   In the latter case use `extdevelop' to extend the HNE's until",
1583         "they differ.";
1584         return(-1);
1585       }
1586       if ((ma1[1,i]==var(2)) || (ma2[1,i]==var(2))) {
1587         "//** The two HNE's are (so far) identical. This is because they",
1588         "have been";
1589         "//** computed separately. I need more data; use `extdevelop' to",
1590         "extend them,";
1591         if (ma1[1,i]==var(2)) {"//** at least the first one.";}
1592         else                  {"//** at least the second one.";}
1593         return(-1);
1594       }
1595     }
1596   }
1597   sum=0;
1598   h1[size(h1)]=ncols(a1)+42;        // Ersatz fuer h1[r]=infinity
1599   h2[size(h2)]=ncols(a2)+42;
1600   for (j=1; j<s; j++) {sum=sum+h1[j]*n1[j]*n2[j];}
1601   if ((i<=h1[s]) && (i<=h2[s]))    { schnitt=sum+i*n1[s]*n2[s]; }
1602   if (i==h2[s]+1) { schnitt=sum+h2[s]*n1[s]*n2[s]+n2[s+1]*n1[s]; }
1603   if (i==h1[s]+1) { schnitt=sum+h1[s]*n2[s]*n1[s]+n1[s+1]*n2[s]; }
1604 // "s:",s-1,"i:",i,"S:",sum;
1605 }
1606 return(schnitt);
1607}
1608example
1609{
1610  "EXAMPLE:"; echo = 2;
1611  ring r=0,(x,y),dp;
1612  list Hne=hnexpansion((x2-y3)*(x2+y3));
1613  intersection(Hne[1],Hne[2]);
1614}
1615///////////////////////////////////////////////////////////////////////////////
1616
1617proc multsequence
1618"USAGE:   multsequence(INPUT); INPUT list or poly
1619ASSUME:  @code{INPUT} is the output of @code{develop(f)}, or of
1620         @code{extdevelop(develop(f),n)}, or one entry of the list of HN data
1621         computed by @code{hnexpansion(f[,\"ess\"])}.
1622RETURN:  intvec corresponding to the multiplicity sequence of the irreducible
1623         plane curve singularity described by the HN data (return value
1624         coincides with @code{invariants(INPUT)[6]}).
1625
1626ASSUME:  @code{INPUT} is a bivariate polynomial f, or the output of
1627         @code{hnexpansion(f)}, or the list of HN data computed by
1628         @code{hnexpansion(f [,\"ess\"])}.
1629RETURN:  list of two integer matrices:
1630@texinfo
1631@table @asis
1632@item  @code{multsequence(INPUT)[1][i,*]}
1633   contains the multiplicities of the branches at their infinitely near point
1634   of 0 in its (i-1) order neighbourhood (i.e., i=1: multiplicity of the
1635   branches themselves, i=2: multiplicity of their 1st quadratic transform,
1636   etc., @*
1637   Hence, @code{multsequence(INPUT)[1][*,j]} is the multiplicity sequence
1638   of branch j.
1639@item  @code{multsequence(INPUT)[2][i,*]}:
1640   contains the information which of these infinitely near points coincide.
1641@end table
1642@end texinfo
1643NOTE:  The order of the elements of the list of HN data obtained from
1644       @code{hnexpansion(f [,\"ess\"])} must not be changed (because otherwise
1645       the coincident infinitely near points couldn't be grouped together,
1646       see the meaning of the 2nd intmat in the example).
1647       Hence, it is not wise to compute the HN expansion of polynomial factors
1648       separately, put them into a list INPUT and call
1649       @code{multsequence(INPUT)}. @*
1650       Use @code{displayMultsequence} to produce a better readable output for
1651       reducible curves on the screen. @*
1652       In case the Hamburger-Noether expansion of the curve f is needed
1653       for other purposes as well it is better to calculate this first
1654       with the aid of @code{hnexpansion} and use it as input instead of
1655       the polynomial itself.
1656SEE ALSO: displayMultsequence, develop, hnexpansion, separateHNE
1657KEYWORDS: multiplicity sequence
1658EXAMPLE: example multsequence;  shows an example
1659"
1660{
1661 //---- INPUT = poly, or HNEring --------------------
1662 if (typeof(#[1])=="poly") {
1663   list L=hnexpansion(#[1]);
1664   if (typeof(L[1])=="ring") {
1665     def altring = basering;
1666     def HNring = L[1]; setring HNring;
1667     list Ergebnis = multsequence(hne);
1668     setring altring;
1669     kill HNring;
1670     return(Ergebnis);
1671   }
1672   else {
1673     return(multsequence(L));
1674   }
1675 }
1676 if (typeof(#[1])=="ring") {
1677   def altring = basering;
1678   def HNring = #[1]; setring HNring;
1679   list Ergebnis = multsequence(hne);
1680   setring altring;
1681   kill HNring;
1682   return(Ergebnis);
1683 }
1684 //-- entferne ueberfluessige Daten zur Erhoehung der Rechengeschwindigkeit: --
1685 #=stripHNE(#);
1686 int k,i,j;
1687 //----------------- Multiplizitaetensequenz eines Zweiges --------------------
1688 if (typeof(#[1])=="matrix") {
1689  intvec v=#[2];
1690  list ergebnis;
1691  if (#[3]==-1) {
1692    "An error has occurred in develop, so there is no HNE.";
1693   return(intvec(0));
1694  }
1695  intvec multips,multseq;
1696  multips=multiplicities(#);
1697  k=1;
1698  for (i=1; i<size(v); i++) {
1699    for (j=1; j<=v[i]; j++) {
1700      multseq[k]=multips[i];
1701      k++;
1702  }}
1703  multseq[k]=1;
1704  //--- fuelle die Multipl.seq. mit den notwendigen Einsen auf -- T.Keilen ----
1705  int tester=k;
1706  while((multseq[tester]==1) and (tester>1))
1707  {
1708    tester=tester-1;
1709  }
1710  if((multseq[tester]!=1) and (multseq[tester]!=k-tester))
1711  {
1712    for (i=k+1; i<=tester+multseq[tester]; i++)
1713    {
1714      multseq[i]=1;
1715    }
1716  }
1717  //--- Ende T.Keilen --- 06.05.02
1718  return(multseq);
1719 }
1720 //---------------------------- mehrere Zweige --------------------------------
1721 else {
1722   list HNEs=#;
1723   int anzahl=size(HNEs);
1724   int maxlength=0;
1725   int bisher;
1726   intvec schnitt,ones;
1727   ones[anzahl]=0;
1728   ones=ones+1;                  // = 1,1,...,1
1729   for (i=1; i<anzahl; i++) {
1730     schnitt[i]=separateHNE(HNEs[i],HNEs[i+1]);
1731     j=size(multsequence(HNEs[i]));
1732     maxlength=maxlength*(j < maxlength) + j*(j >= maxlength);
1733     maxlength=maxlength*(schnitt[i]+1 < maxlength)
1734               + (schnitt[i]+1)*(schnitt[i]+1 >= maxlength);
1735   }
1736   j=size(multsequence(HNEs[anzahl]));
1737   maxlength=maxlength*(j < maxlength) + j*(j >= maxlength);
1738
1739//-------------- Konstruktion der ersten zu berechnenden Matrix ---------------
1740   intmat allmults[maxlength][anzahl];
1741   for (i=1; i<=maxlength; i++)  { allmults[i,1..anzahl]=ones[1..anzahl]; }
1742   for (i=1; i<=anzahl; i++) {
1743     ones=multsequence(HNEs[i]);
1744     allmults[1..size(ones),i]=ones[1..size(ones)];
1745   }
1746//---------------------- Konstruktion der zweiten Matrix ----------------------
1747   intmat separate[maxlength][anzahl];
1748   for (i=1; i<=maxlength; i++) {
1749     k=1;
1750     bisher=0;
1751     if (anzahl==1) { separate[i,1]=1; }
1752     for (j=1; j<anzahl; j++)   {
1753       if (schnitt[j]<i) {
1754         separate[i,k]=j-bisher;
1755         bisher=j;
1756         k++;
1757       }
1758       separate[i,k]=anzahl-bisher;
1759     }
1760   }
1761  return(list(allmults,separate));
1762 }
1763}
1764example
1765{
1766  "EXAMPLE:"; echo = 2;
1767  ring r=0,(x,y),dp;
1768  list Hne=hnexpansion((x6-y10)*(x+y2-y3)*(x+y2+y3));
1769  multsequence(Hne[1]),"  |  ",multsequence(Hne[2]),"  |  ",
1770  multsequence(Hne[3]),"  |  ",multsequence(Hne[4]);
1771  multsequence(Hne);
1772  // The meaning of the entries of the 2nd matrix is as follows:
1773  displayMultsequence(Hne);
1774}
1775///////////////////////////////////////////////////////////////////////////////
1776
1777proc displayMultsequence
1778"USAGE:   displayMultsequence(INPUT); INPUT list or poly
1779ASSUME:  @code{INPUT} is a bivariate polynomial, or the output of
1780         @code{develop(f)}, resp. of @code{extdevelop(develop(f),n)}, or (one
1781         entry of) the list of HN data computed by @code{hnexpansion(f[,\"ess\"])},
1782         or the output of @code{hnexpansion(f)}.
1783RETURN:  nothing
1784DISPLAY: the sequence of multiplicities:
1785@format
1786 - if @code{INPUT=develop(f)} or @code{INPUT=extdevelop(develop(f),n)} or @code{INPUT=hne[i]}:
1787                      @code{a , b , c , ....... , 1}
1788 - if @code{INPUT=f} or @code{INPUT=hnexpansion(f)} or @code{INPUT=hne}:
1789                      @code{[(a_1, .... , b_1 , .... , c_1)],}
1790                      @code{[(a_2, ... ), ... , (... , c_2)],}
1791                      @code{ ........................................ ,}
1792                      @code{[(a_n),(b_n), ....., (c_n)]}
1793     with:
1794       @code{a_1 , ... , a_n} the sequence of multiplicities of the 1st branch,
1795       @code{[...]} the multiplicities of the j-th transform of all branches,
1796       @code{(...)} indicating branches meeting in an infinitely near point.
1797@end format
1798NOTE:  The Same restrictions as in @code{multsequence} apply for the input.@*
1799       In case the Hamburger-Noether expansion of the curve f is needed
1800       for other purposes as well it is better to calculate this first
1801       with the aid of @code{hnexpansion} and use it as input instead of
1802       the polynomial itself.
1803SEE ALSO: multsequence, develop, hnexpansion, separateHNE
1804EXAMPLE: example displayMultsequence;  shows an example
1805"
1806{
1807 //---- INPUT = poly, or HNEring --------------------
1808 if (typeof(#[1])=="poly") {
1809   list L=hnexpansion(#[1]);
1810   if (typeof(L[1])=="ring") {
1811     def HNring = L[1]; setring HNring;
1812     displayMultsequence(hne);
1813     return();
1814   }
1815   else {
1816     displayMultsequence(L);
1817     return();
1818   }
1819 }
1820 if (typeof(#[1])=="ring") {
1821   def HNring = #[1]; setring HNring;
1822   displayMultsequence(hne);
1823   return();
1824 }
1825
1826 //-- entferne ueberfluessige Daten zur Erhoehung der Rechengeschwindigkeit: --
1827 #=stripHNE(#);
1828 //----------------- Multiplizitaetensequenz eines Zweiges --------------------
1829 if (typeof(#[1])=="matrix") {
1830   if (#[3]==-1) {
1831     "An error has occurred in develop, so there is no HNE.";
1832   }
1833   else {
1834     "The sequence of multiplicities is  ",multsequence(#);
1835 }}
1836 //---------------------------- mehrere Zweige --------------------------------
1837 else {
1838   list multips=multsequence(#);
1839   int i,j,k,l;
1840   string output;
1841   for (i=1; i<=nrows(multips[1]); i++) {
1842     output="[";
1843     k=1;
1844     for (l=1; k<=ncols(multips[1]); l++) {
1845       output=output+"(";
1846       for (j=1; j<=multips[2][i,l]; j++) {
1847         output=output+string(multips[1][i,k]);
1848         k++;
1849         if (j<multips[2][i,l]) { output=output+","; }
1850       }
1851       output=output+")";
1852       if ((k-1) < ncols(multips[1])) { output=output+","; }
1853      }
1854     output=output+"]";
1855     if (i<nrows(multips[1])) { output=output+","; }
1856     output;
1857   }
1858 }
1859}
1860example
1861{
1862  "EXAMPLE:"; echo = 2;
1863  ring r=0,(x,y),dp;
1864  // Example 1: Input = output of develop
1865  displayMultsequence(develop(x3-y5));
1866
1867  // Example 2: Input = bivariate polynomial
1868  displayMultsequence((x6-y10)*(x+y2-y3)*(x+y2+y3));
1869}
1870
1871///////////////////////////////////////////////////////////////////////////////
1872
1873proc separateHNE (list hn1,list hn2)
1874"USAGE:    separateHNE(hne1,hne2);  hne1, hne2 lists
1875ASSUME:   hne1, hne2 are HNEs (=output of
1876          @code{develop(f)}, @code{extdevelop(develop(f),n)}, or
1877          one entry in the list @code{hne} in the ring created by
1878          @code{hnexpansion(f[,\"ess\"])}.
1879RETURN:   number of quadratic transformations needed to separate both curves
1880          (branches).
1881SEE ALSO: develop, hnexpansion, multsequence, displayMultsequence
1882EXAMPLE:  example separateHNE;  shows an example
1883"
1884{
1885 int i,j,s,unterschied,separated;
1886 matrix a1=hn1[1];
1887 matrix a2=hn2[1];
1888 intvec h1=hn1[2];
1889 intvec h2=hn2[2];
1890 if (hn1[3]!=hn2[3]) {
1891 //-- die jeweils erste Zeile von hn1,hn2 gehoert zu verschiedenen Parametern -
1892 //---------------- d.h. beide Kurven schneiden sich transversal --------------
1893   separated=1;
1894 }
1895 else {
1896 //--------- die jeweils erste Zeile gehoert zum gleichen Parameter -----------
1897   unterschied=0;
1898   for (s=1; (h1[s]==h2[s]) && (s<size(h1)) && (s<size(h2))
1899              && (unterschied==0); s++) {
1900     for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]); i++) {;}
1901     if (i<=h1[s]) {
1902       unterschied=1;
1903       s--;                    // um s++ am Schleifenende wieder auszugleichen
1904     }
1905   }
1906   if (unterschied==0) {
1907     if ((s<size(h1)) && (s<size(h2))) {
1908       for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]) && (i<=h2[s]); i++) {;}
1909     }
1910     else {
1911 //-------------- Sonderfall: Unterschied in letzter Zeile suchen -------------
1912 // Beachte: Es koennen undefinierte Stellen auftreten, bei abbrechender HNE
1913 // muss die Ende-Markierung weg, h_[r] ist unendlich, die Matrix muss mit
1914 // Nullen fortgesetzt gedacht werden
1915 //----------------------------------------------------------------------------
1916       if (ncols(a1)>ncols(a2)) { j=ncols(a1); }
1917       else                     { j=ncols(a2); }
1918       unterschied=0;
1919       if ((h1[s]>0) && (s==size(h1))) {
1920         a1[s,h1[s]+1]=0;
1921         if (ncols(a1)<=ncols(a2)) { unterschied=1; }
1922       }
1923       if ((h2[s]>0) && (s==size(h2))) {
1924         a2[s,h2[s]+1]=0;
1925         if (ncols(a2)<=ncols(a1)) { unterschied=1; }
1926       }
1927       if (unterschied==1) {                   // mind. eine HNE war endlich
1928         matrix ma1[1][j]=a1[s,1..ncols(a1)];  // und bedarf der Fortsetzung
1929         matrix ma2[1][j]=a2[s,1..ncols(a2)];  // mit Nullen
1930       }
1931       else {
1932         if (ncols(a1)>ncols(a2)) { j=ncols(a2); }
1933         else                     { j=ncols(a1); }
1934         matrix ma1[1][j]=a1[s,1..j];          // Beschr. auf vergleichbaren
1935         matrix ma2[1][j]=a2[s,1..j];          // Teil (der evtl. y's enth.)
1936       }
1937       for (i=1; (ma1[1,i]==ma2[1,i]) && (i<j) && (ma1[1,i]!=var(2)); i++) {;}
1938       if (ma1[1,i]==ma2[1,i]) {
1939         "//** The two HNE's are identical!";
1940         "//** You have either tried to compare a branch with itself,";
1941         "//** or the two branches have been developed separately.";
1942         "//   In the latter case use `extdevelop' to extend the HNE's until",
1943         "they differ.";
1944         return(-1);
1945       }
1946       if ((ma1[1,i]==var(2)) || (ma2[1,i]==var(2))) {
1947         "//** The two HNE's are (so far) identical. This is because they",
1948         "have been";
1949         "//** computed separately. I need more data; use `extdevelop' to",
1950         "extend them,";
1951         if (ma1[1,i]==var(2)) {"//** at least the first one.";}
1952         else                  {"//** at least the second one.";}
1953         return(-1);
1954       }
1955     }
1956   }
1957   separated=i;
1958   for (j=1; j<s; j++) { separated=separated+h1[j]; }
1959 }
1960 return(separated);
1961}
1962example
1963{ "EXAMPLE:"; echo = 2;
1964  int p=printlevel; printlevel=-1;
1965  ring r=0,(x,y),dp;
1966  list hne1=develop(x);
1967  list hne2=develop(x+y);
1968  list hne3=develop(x+y2);
1969  separateHNE(hne1,hne2);  // two transversal lines
1970  separateHNE(hne1,hne3);  // one quadratic transform. gives 1st example
1971  printlevel=p;
1972}
1973///////////////////////////////////////////////////////////////////////////////
1974
1975proc displayHNE(list ldev,list #)
1976"USAGE:   displayHNE(L[,n]); L list, n int
1977ASSUME:  L is the output of @code{develop(f)}, or of @code{exdevelop(f,n)},
1978         or of @code{hnexpansion(f[,\"ess\"])}, or (one entry in) the list
1979         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
1980RETURN:  - if only one argument is given and if the input are the HN data
1981         of an irreducible plane curve singularity, no return value, but
1982         display an ideal HNE of the following form:
1983     @example
1984       y = []*x^1+[]*x^2   +...+x^<>*z(1)
1985       x =        []*z(1)^2+...+z(1)^<>*z(2)
1986       z(1) =     []*z(2)^2+...+z(2)^<>*z(3)
1987       .......             ..........................
1988       z(r-1) =   []*z(r)^2+[]*z(r)^3+......
1989     @end example
1990        where @code{x},@code{y} are the first 2 variables of the basering.
1991        The values of @code{[]} are the coefficients of the Hamburger-Noether
1992        matrix, the values of @code{<>} are represented by @code{x} in the
1993        HN matrix.@*
1994        - if a second argument is given and if the input are the HN data
1995        of an irreducible plane curve singularity, return a ring containing
1996        an ideal @code{HNE} as described above.@*
1997        - if L corresponds to the output of @code{hnexpansion(f)}
1998        or to the list of HN data computed by @code{hnexpansion(f[,\"ess\"])},
1999        @code{displayHNE(L[,n])} shows the HNE's of all branches of f in the
2000        format described above. The optional parameter is then ignored.
2001NOTE:  The 1st line of the above ideal (i.e., @code{HNE[1]}) means that
2002     @code{y=[]*z(0)^1+...}, the 2nd line (@code{HNE[2]}) means that
2003     @code{x=[]*z(1)^2+...}, so you can see which indeterminate
2004     corresponds to which line (it's also possible that @code{x} corresponds
2005     to the 1st line and @code{y} to the 2nd).
2006
2007SEE ALSO: develop, hnexpansion
2008EXAMPLE: example displayHNE; shows an example
2009"
2010{
2011 if ((typeof(ldev[1])=="list") || (typeof(ldev[1])=="none")) {
2012   for (int i=1; i<=size(ldev); i++) {
2013     "// Hamburger-Noether development of branch nr."+string(i)+":";
2014     displayHNE(ldev[i]);"";
2015   }
2016   return();
2017 }
2018 //--------------------- Initialisierungen und Ringwechsel --------------------
2019 matrix m=ldev[1];
2020 intvec v=ldev[2];
2021 int switch=ldev[3];
2022 if (switch==-1) {
2023   "An error has occurred throughout the expansion, so there is no HNE.";
2024   return(ideal(0));
2025 }
2026 def altring=basering;
2027 /////////////////////////////////////////////////////////
2028 //  Change by T. Keilen 08.06.2002
2029 //  ring + ring does not work if one ring is an algebraic extension
2030/*
2031 if (parstr(basering)!="") {
2032   if (charstr(basering)!=string(char(basering))+","+parstr(basering)) {
2033     execute
2034      ("ring dazu=("+charstr(basering)+"),z(0.."+string(size(v)-1)+"),ls;");
2035   }
2036   else { ring dazu=char(altring),z(0..size(v)-1),ls; }
2037 }
2038 else   { ring dazu=char(altring),z(0..size(v)-1),ls; }
2039 def displayring=dazu+altring;
2040*/
2041 execute("ring displayring=("+charstr(basering)+"),(z(0.."+string(size(v)-1)+"),"+varstr(basering)+"),(ls("+string(size(v))+"),"+ordstr(basering)+");");
2042 // End change by T. Keilen
2043 //////////////////////////////////////////////////////////////
2044 setring displayring;
2045 map holematrix=altring,0;        // mappt nur die Monome vom Grad Null
2046 matrix m=holematrix(m);
2047 int i,j;
2048
2049 // lossen: check the last row for finiteness (06/2004)
2050 int rowM=nrows(m);
2051 int colM=ncols(m);
2052 int undef_bd=v[size(v)];
2053 if ( undef_bd<-1 ){
2054   for (j=-undef_bd; j<=colM; j++) { m[rowM,j]=0; }
2055 }
2056
2057 //--------------------- Erzeuge Matrix n mit n[i,j]=z(j-1)^i -----------------
2058 matrix n[colM][rowM];
2059 for (j=1; j<=rowM; j++) {
2060    for (i=1; i<=colM; i++) { n[i,j]=z(j-1)^i; }
2061 }
2062 matrix displaymat=m*n;
2063 ideal HNE;
2064 for (i=1; i<rowM; i++) { HNE[i]=displaymat[i,i]+z(i)*z(i-1)^v[i]; }
2065 HNE[rowM]=displaymat[rowM,rowM];
2066
2067 // lossen: output modified (06/2004)
2068 if (size(#) == 0)
2069 {
2070   if (switch==0) {
2071     HNE=subst(HNE,z(0),var(size(v)+1));
2072   }
2073   else  {
2074     HNE=subst(HNE,z(0),var(size(v)+2));
2075   }
2076
2077   for (j=1; j<=ncols(HNE); j++){
2078     string stHNE(j)=string(HNE[j]);
2079   }
2080   if (undef_bd<-1)
2081   {
2082     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2083                                 +string(-undef_bd)+")";
2084   }
2085   if (undef_bd==-1)
2086   {
2087     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2088                                 +string(colM+1)+")";
2089   }
2090
2091   if (switch==0) {
2092     stHNE(1) = "  "+string(var(size(v)+2))+" = "+stHNE(1);
2093   }
2094   else {
2095     stHNE(1) = "  "+string(var(size(v)+1))+" = "+stHNE(1);
2096   }
2097   stHNE(1);
2098   if (ncols(HNE)==1) {return();}
2099
2100   if (switch==0) {
2101     stHNE(2) = "  "+string(var(size(v)+1))+" = "+stHNE(2);
2102   }
2103   else {
2104     stHNE(2) = "  "+string(var(size(v)+2))+" = "+stHNE(2);
2105   }
2106   stHNE(2);
2107
2108   for (j=3; j<=ncols(HNE); j++){
2109     stHNE(j)= "  "+"z(" +string(j-2)+ ") = "+stHNE(j);
2110     stHNE(j);
2111   }
2112   return();
2113 }
2114
2115 if (rowM<2) { HNE[2]=z(0); }
2116
2117 if (switch==0) {
2118    HNE[1] = HNE[1]-var(size(v)+2);
2119    HNE[2] = HNE[2]-var(size(v)+1);
2120 }
2121 else {
2122    HNE[1] = HNE[1]-var(size(v)+1);
2123    HNE[2] = HNE[2]-var(size(v)+2);
2124 }
2125if (size(#) == 0) {
2126   HNE;
2127   return();
2128 }
2129if (size(#) != 0) {
2130   HNE;
2131   export(HNE);
2132   return(displayring);
2133 }
2134}
2135example
2136{ "EXAMPLE:"; echo = 2;
2137  ring r=0,(x,y),dp;
2138  poly f=x3+2xy2+y2;
2139  list hn=develop(f);
2140  displayHNE(hn);
2141}
2142///////////////////////////////////////////////////////////////////////////////
2143//                      procedures for reducible curves                      //
2144///////////////////////////////////////////////////////////////////////////////
2145
2146// proc newtonhoehne (poly f)
2147// USAGE:   newtonhoehne(f);   f poly
2148// ASSUME:  basering = ...,(x,y),ds  or ls
2149// RETURN:  list of intvec(x,y) of coordinates of the newtonpolygon of f
2150// NOTE:    This proc is only available in versions of Singular that know the
2151//         command  system("newton",f);  f poly
2152// {
2153// intvec nm = getnm(f);
2154//  if ((nm[1]>0) && (nm[2]>0)) { f=jet(f,nm[1]*nm[2],nm); }
2155//  list erg=system("newton",f);
2156//  int i; list Ausgabe;
2157//  for (i=1; i<=size(erg); i++) { Ausgabe[i]=leadexp(erg[i]); }
2158// return(Ausgabe);
2159// }
2160///////////////////////////////////////////////////////////////////////////////
2161
2162proc newtonpoly (poly f, int #)
2163"USAGE:   newtonpoly(f);   f poly
2164ASSUME:  basering has exactly two variables; @*
2165         f is convenient, that is, f(x,0) != 0 != f(0,y).
2166RETURN:  list of intvecs (= coordinates x,y of the Newton polygon of f).
2167NOTE:    Procedure uses @code{execute}; this can be avoided by calling
2168         @code{newtonpoly(f,1)} if the ordering of the basering is @code{ls}.
2169KEYWORDS: Newton polygon
2170EXAMPLE: example newtonpoly;  shows an example
2171"
2172{
2173  if (size(#)>=1)
2174  {
2175    if (typeof(#[1])=="int")
2176    {
2177      // this is done to avoid the "execute" command for procedures in
2178      //  hnoether.lib
2179      def is_ls=#[1];
2180    }
2181  }
2182  if (defined(is_ls)<=0)
2183  {
2184    def @Rold=basering;
2185    execute("ring @RR=("+charstr(basering)+"),("+varstr(basering)+"),ls;");
2186    poly f=imap(@Rold,f);
2187  }
2188  intvec A=(0,ord(subst(f,var(1),0)));
2189  intvec B=(ord(subst(f,var(2),0)),0);
2190  intvec C,H; list L;
2191  int abbruch,i;
2192  poly hilf;
2193  L[1]=A;
2194  f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]));
2195  if (defined(is_ls))
2196  {
2197    map xytausch=basering,var(2),var(1);
2198  }
2199  else
2200  {
2201    map xytausch=@RR,var(2),var(1);
2202  }
2203  for (i=2; f!=0; i++)
2204  {
2205     abbruch=0;
2206     while (abbruch==0)
2207     {
2208        C=leadexp(f);
2209        if(jet(f,A[2]*C[1]-A[1]*C[2]-1,intvec(A[2]-C[2],C[1]-A[1]))==0)
2210        {
2211           abbruch=1;
2212        }
2213        else
2214        {
2215           f=jet(f,-C[1]-1,intvec(-1,0));
2216        }
2217    }
2218    hilf=jet(f,A[2]*C[1]-A[1]*C[2],intvec(A[2]-C[2],C[1]-A[1]));
2219    H=leadexp(xytausch(hilf));
2220    A=H[2],H[1];
2221    L[i]=A;
2222    f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]-A[1]));
2223  }
2224  L[i]=B;
2225  if (defined(is_ls))
2226  {
2227    return(L);
2228  }
2229  else
2230  {
2231    setring @Rold;
2232    return(L);
2233  }
2234}
2235example
2236{
2237 "EXAMPLE:"; echo = 2;
2238  ring r=0,(x,y),ls;
2239  poly f=x5+2x3y-x2y2+3xy5+y6-y7;
2240  newtonpoly(f);
2241}
2242///////////////////////////////////////////////////////////////////////////////
2243
2244proc is_NND (poly f, list #)
2245"USAGE:   is_NND(f[,mu,NP]);   f poly, mu int, NP list of intvecs
2246ASSUME:  f is convenient, that is, f(x,0) != 0 != f(0,y);@*
2247         mu (optional) is Milnor number of f.@*
2248         NP (optional) is output of @code{newtonpoly(f)}.
2249RETURN:  int: 1 if f is Newton non-degenerate, 0 otherwise.
2250SEE ALSO: newtonpoly
2251KEYWORDS: Newton non-degenerate; Newton polygon
2252EXAMPLE: example is_NND;  shows examples
2253"
2254{
2255  int i;
2256  int i_print=printlevel-voice+2;
2257
2258  if (size(#)==0)
2259  {
2260    int mu=milnor(f);
2261    list NP=newtonpoly(f);
2262  }
2263  else
2264  {
2265    if (typeof(#[1])=="int")
2266    {
2267      def mu=#[1];
2268      def NP=#[2];
2269      for (i=1;i<=size(NP);i++)
2270      {
2271        if (typeof(NP[i])!="intvec")
2272        {
2273          print("third input cannot be Newton polygon ==> ignored ")
2274          NP=newtonpoly(f);
2275          i=size(NP)+1;
2276        }
2277      }
2278    }
2279    else
2280    {
2281      print("second input cannot be Milnor number ==> ignored ")
2282      int mu=milnor(f);
2283      NP=newtonpoly(f);
2284    }
2285  }
2286
2287  // computation of the Newton number:
2288  int s=size(NP);
2289  int nN=-NP[1][2]-NP[s][1]+1;
2290  intmat m[2][2];
2291  for(i=1;i<=s-1;i++)
2292  {
2293    m=NP[i+1],NP[i];
2294    nN=nN+det(m);
2295  }
2296
2297  if(mu==nN)
2298  { // the Newton-polygon is non-degenerate
2299    // REFERENCE? (tfuer mehr als 2 Variable gilt nicht, dass mu=nu impliziert,
2300    // dass NP nicht ausgeartet ist!, Siehe KOMMENTAR in equising.lib in esIdeal)
2301    return(1);
2302  }
2303  else
2304  {
2305    return(0);
2306  }
2307}
2308example
2309{
2310 "EXAMPLE:"; echo = 2;
2311  ring r=0,(x,y),ls;
2312  poly f=x5+y3;
2313  is_NND(f);
2314  poly g=(x-y)^5+3xy5+y6-y7;
2315  is_NND(g);
2316
2317  // if already computed, one should give the Minor number and Newton polygon
2318  // as second and third input:
2319  int mu=milnor(g);
2320  list NP=newtonpoly(g);
2321  is_NND(g,mu,NP);
2322}
2323
2324
2325///////////////////////////////////////////////////////////////////////////////
2326
2327proc charPoly(poly f, int M, int N)
2328"USAGE:  charPoly(f,M,N);  f bivariate poly,  M,N int: length and height
2329                          of Newton polygon of f, which has to be only one line
2330RETURN:  the characteristic polynomial of f
2331EXAMPLE: example charPoly;  shows an example
2332"
2333{
2334 poly charp;
2335 int Np=N/ gcd(M,N);
2336 f=subst(f,var(1),1);
2337 for(charp=0; f<>0; f=f-lead(f))
2338  { charp=charp+leadcoef(f)*var(2)^(leadexp(f)[2]/ Np);}
2339 return(charp);
2340}
2341example
2342{ "EXAMPLE:"; echo = 2;
2343  ring exring=0,(x,y),dp;
2344  charPoly(y4+2y3x2-yx6+x8,8,4);
2345  charPoly(y6+3y3x2-x4,4,6);
2346}
2347///////////////////////////////////////////////////////////////////////////////
2348
2349proc find_in_list(list L,int p)
2350"USAGE:   find_in_list(L,p); L: list of intvec(x,y)
2351         (sorted in y: L[1][2]>=L[2][2]), int p >= 0
2352RETURN:  int i: L[i][2]=p if existent; otherwise i with L[i][2]<p if existent;
2353         otherwise i = size(L)+1;
2354EXAMPLE: example find_in_list;  shows an example
2355"
2356{
2357 int i;
2358 L[size(L)+1]=intvec(0,-1);          // falls p nicht in L[.][2] vorkommt
2359 for (i=1; L[i][2]>p; i++) {;}
2360 return(i);
2361}
2362example
2363{ "EXAMPLE:"; echo = 2;
2364  list L = intvec(0,4), intvec(1,2), intvec(2,1), intvec(4,0);
2365  find_in_list(L,1);
2366  L[find_in_list(L,2)];
2367}
2368///////////////////////////////////////////////////////////////////////////////
2369
2370proc get_last_divisor(int M, int N)
2371"USAGE:   get_last_divisor(M,N); int M,N
2372RETURN:  int Q: M=q1*N+r1, N=q2*r1+r2, ..., ri=Q*r(i+1) (Euclidean alg.)
2373EXAMPLE: example get_last_divisor; shows an example
2374"
2375{
2376 int R=M%N; int Q=M / N;
2377 while (R!=0) {M=N; N=R; R=M%N; Q=M / N;}
2378 return(Q)
2379}
2380example
2381{ "EXAMPLE"; echo = 2;
2382  ring r=0,(x,y),dp;
2383  get_last_divisor(12,10);
2384}
2385///////////////////////////////////////////////////////////////////////////////
2386proc redleit (poly f,intvec S, intvec E)
2387"USAGE:   redleit(f,S,E);  f poly, S,E intvec(x,y)
2388         S,E are two different points on a line in the Newton diagram of f
2389RETURN:  poly g: all monomials of f which lie on or below that line
2390NOTE:    The main purpose is that if the line defined by S and E is part of the
2391         Newton polygon, the result is the quasihomogeneous leading form of f
2392         w.r.t. that line.
2393SEE ALSO: newtonpoly
2394EXAMPLE: example redleit;  shows an example
2395"
2396{
2397 if (E[1]<S[1]) { intvec H=E; E=S; S=H; } // S,E verkehrt herum eingegeben
2398 return(jet(f,E[1]*S[2]-E[2]*S[1],intvec(S[2]-E[2],E[1]-S[1])));
2399}
2400example
2401{ "EXAMPLE"; echo = 2;
2402  ring exring=0,(x,y),dp;
2403  redleit(y6+xy4-2x3y2+x4y+x6,intvec(3,2),intvec(4,1));
2404}
2405///////////////////////////////////////////////////////////////////////////////
2406
2407
2408proc extdevelop (list l, int Exaktheit)
2409"USAGE:   extdevelop(L,N); list L, int N
2410ASSUME:  L is the output of @code{develop(f)}, or of @code{extdevelop(l,n)},
2411         or one entry in the list @code{hne} in the ring created by
2412          @code{hnexpansion(f[,\"ess\"])}.
2413RETURN:  an extension of the Hamburger-Noether development of f as a list
2414         in the same format as L has (up to the last entry in the output
2415         of @code{develop(f)}).@*
2416         Type @code{help develop;}, resp. @code{help hnexpansion;} for more
2417         details.
2418NOTE:    The new HN-matrix will have at least N columns (if the HNE is not
2419         finite). In particular, if f is irreducible then (in most cases)
2420         @code{extdevelop(develop(f),N)} will produce the same result as
2421         @code{develop(f,N)}.@*
2422         If the matrix M of L has n columns then, compared with
2423         @code{parametrization(L)}, @code{paramametrize(extdevelop(L,N))} will increase the
2424         exactness by at least (N-n) more significant monomials.
2425SEE ALSO: develop, hnexpansion, param
2426EXAMPLE: example extdevelop;  shows an example
2427"
2428{
2429 //------------ Initialisierungen und Abfangen unzulaessiger Aufrufe ----------
2430 matrix m=l[1];
2431 intvec v=l[2];
2432 int switch=l[3];
2433 if (nvars(basering) < 2) {
2434   " Sorry. I need two variables in the ring.";
2435   return(list(matrix(maxideal(1)[1]),intvec(0),-1,poly(0)));}
2436 if (switch==-1) {
2437   "An error has occurred in develop, so there is no HNE and no extension.";
2438   return(l);
2439 }
2440 poly f=l[4];
2441 if (f==0) {
2442   " No extension is possible";
2443   return(l);
2444 }
2445 int Q=v[size(v)];
2446 if (Q>0) {
2447   " The HNE was already exact";
2448   return(l);
2449 }
2450 else {
2451   if (Q==-1) { Q=ncols(m); }
2452   else { Q=-Q-1; }
2453 }
2454 int zeile=nrows(m);
2455 int spalten,i,M;
2456 ideal lastrow=m[zeile,1..Q];
2457 int ringwechsel=(varstr(basering)!="x,y") or (ordstr(basering)!="ls(2),C");
2458
2459 //------------------------- Ringwechsel, falls noetig ------------------------
2460 if (ringwechsel) {
2461  def altring = basering;
2462  int p = char(basering);
2463  if (charstr(basering)!=string(p)) {
2464     string tststr=charstr(basering);
2465     tststr=tststr[1..find(tststr,",")-1];     //-> "p^k" bzw. "p"
2466     if (tststr==string(p)) {
2467       if (size(parstr(basering))>1) {         // ring (p,a,..),...
2468        execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2469       }
2470       else {                                  // ring (p,a),...
2471        string mipl=string(minpoly);
2472        ring extdguenstig=(p,`parstr(basering)`),(x,y),ls;
2473        if (mipl!="0") { execute("minpoly="+mipl+";"); }
2474       }
2475     }
2476     else {
2477       execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2478     }
2479  }
2480  else {                               // charstr(basering)== p : no parameter
2481     ring extdguenstig=p,(x,y),ls;
2482  }
2483  export extdguenstig;
2484  map hole=altring,x,y;
2485 //----- map kann sehr zeitaufwendig sein, daher Vermeidung, wo moeglich: -----
2486  if (nvars(altring)==2) { poly f=fetch(altring,f); }
2487  else                   { poly f=hole(f);          }
2488  ideal a=hole(lastrow);
2489 }
2490 else { ideal a=lastrow; }
2491 list Newton=newtonpoly(f,1);
2492 int M1=Newton[size(Newton)-1][1];     // konstant
2493 number delt;
2494 if (Newton[size(Newton)-1][2]!=1) {
2495    " *** The transformed polynomial was not valid!!";}
2496 else {
2497 //--------------------- Fortsetzung der HNE ----------------------------------
2498  while (Q<Exaktheit) {
2499    M=ord(subst(f,y,0));
2500    Q=M-M1;
2501 //------ quasihomogene Leitform ist c*x^M1*y+d*x^(M1+Q) => delta=-d/c: -------
2502    delt=-koeff(f,M,0)/koeff(f,M1,1);
2503    a[Q]=delt;
2504    dbprint(printlevel-voice+2,"a("+string(zeile-1)+","+string(Q)+") = "+string(delt));
2505    if (Q<Exaktheit) {
2506     f=T1_Transform(f,delt,Q);
2507     if (defined(HNDebugOn)) { "transformed polynomial:",f; }
2508     if (subst(f,y,0)==0) {
2509       dbprint(printlevel-voice+2,"The HNE is finite!");
2510       a[Q+1]=x; Exaktheit=Q;
2511       f=0;                        // Speicherersparnis: f nicht mehr gebraucht
2512     }
2513    }
2514  }
2515 }
2516 //------- Wechsel in alten Ring, Zusammensetzung alte HNE + Erweiterung ------
2517 if (ringwechsel) {
2518  setring altring;
2519  map zurueck=extdguenstig,var(1),var(2);
2520  if (nvars(altring)==2) { f=fetch(extdguenstig,f); }
2521  else                   { f=zurueck(f);            }
2522  lastrow=zurueck(a);
2523 }
2524 else { lastrow=a; }
2525 if (ncols(lastrow)>ncols(m)) { spalten=ncols(lastrow); }
2526 else { spalten=ncols(m); }
2527 matrix mneu[zeile][spalten];
2528 for (i=1; i<nrows(m); i++) {
2529  mneu[i,1..ncols(m)]=m[i,1..ncols(m)];
2530 }
2531 mneu[zeile,1..ncols(lastrow)]=lastrow;
2532 if (lastrow[ncols(lastrow)]!=var(1)) {
2533  if (ncols(lastrow)==spalten) { v[zeile]=-1; }  // keine undefinierten Stellen
2534  else {
2535   v[zeile]=-Q-1;
2536   for (i=ncols(lastrow)+1; i<=spalten; i++) {
2537    mneu[zeile,i]=var(2);           // fuelle nicht def. Stellen der Matrix auf
2538 }}}
2539 else { v[zeile]=Q; }               // HNE war exakt
2540 if (ringwechsel)
2541 {
2542   kill extdguenstig;
2543 }
2544
2545 return(list(mneu,v,switch,f));
2546}
2547example
2548{
2549  "EXAMPLE:"; echo = 2;
2550  ring exring=0,(x,y),dp;
2551  list Hne=hnexpansion(x14-3y2x11-y3x10-y2x9+3y4x8+y5x7+3y4x6+x5*(-y6+y5)
2552                      -3y6x3-y7x2+y8);
2553  displayHNE(Hne);    // HNE of 1st,3rd branch is finite
2554  print(extdevelop(Hne[1],5)[1]);
2555  list ehne=extdevelop(Hne[2],5);
2556  displayHNE(ehne);
2557  param(Hne[2]);
2558  param(ehne);
2559
2560}
2561///////////////////////////////////////////////////////////////////////////////
2562
2563proc stripHNE (list l)
2564"USAGE:   stripHNE(L);  L list
2565ASSUME:  L is the output of @code{develop(f)}, or of
2566         @code{extdevelop(develop(f),n)}, or (one entry of) the list
2567         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2568RETURN:  list in the same format as L, but all polynomials L[4], resp.
2569         L[i][4], are set to zero.
2570NOTE:    The purpose of this procedure is to remove huge amounts of data
2571         no longer needed. It is useful, if one or more of the polynomials
2572         in L consume much memory. It is still possible to compute invariants,
2573         parametrizations etc. with the stripped HNE(s), but it is not possible
2574         to use @code{extdevelop} with them.
2575SEE ALSO: develop, hnexpansion, extdevelop
2576EXAMPLE: example stripHNE;  shows an example
2577"
2578{
2579 list h;
2580 if (typeof(l[1])=="matrix") { l[4]=poly(0); }
2581 else {
2582  for (int i=1; i<=size(l); i++) {
2583    h=l[i];
2584    h[4]=poly(0);
2585    l[i]=h;
2586  }
2587 }
2588 return(l);
2589}
2590example
2591{
2592  "EXAMPLE:"; echo = 2;
2593  ring r=0,(x,y),dp;
2594  list Hne=develop(x2+y3+y4);
2595  Hne;
2596  stripHNE(Hne);
2597}
2598///////////////////////////////////////////////////////////////////////////////
2599static proc extractHNEs(list HNEs, int transvers)
2600"USAGE:  extractHNEs(HNEs,transvers);  list HNEs (output from HN),
2601        int transvers: 1 if x,y were exchanged, 0 else
2602RETURN: list of Hamburger-Noether-Extensions in the form of hne in hnexpansion
2603NOTE:   This procedure is only for internal purpose; examples don't make sense
2604"
2605{
2606 int i,maxspalte,hspalte,hnezaehler;
2607 list HNEaktu,Ergebnis;
2608 for (hnezaehler=1; hnezaehler<=size(HNEs); hnezaehler++) {
2609  maxspalte=0;
2610  HNEaktu=HNEs[hnezaehler];
2611  if (defined(HNDebugOn)) {"To process:";HNEaktu;}
2612  if (size(HNEaktu)!=size(HNEaktu[1])+2) {
2613     "The ideals and the hqs in HNEs[",hnezaehler,"] don't match!!";
2614     HNEs[hnezaehler];
2615  }
2616 //------------ ermittle  maximale Anzahl benoetigter Spalten: ----------------
2617  for (i=2; i<size(HNEaktu); i++) {
2618    hspalte=ncols(HNEaktu[i]);
2619    maxspalte=maxspalte*(hspalte < maxspalte)+hspalte*(hspalte >= maxspalte);
2620  }
2621 //------------- schreibe Ausgabe fuer hnezaehler-ten Zweig: ------------------
2622  matrix ma[size(HNEaktu)-2][maxspalte];
2623  for (i=1; i<=(size(HNEaktu)-2); i++) {
2624    if (ncols(HNEaktu[i+1]) > 1) {
2625      ma[i,1..ncols(HNEaktu[i+1])]=HNEaktu[i+1]; }
2626    else { ma[i,1]=HNEaktu[i+1][1];}
2627  }
2628  Ergebnis[hnezaehler]=list(ma,HNEaktu[1],transvers,HNEaktu[size(HNEaktu)]);
2629  kill ma;
2630 }
2631 return(Ergebnis);
2632}
2633///////////////////////////////////////////////////////////////////////////////
2634
2635proc factorfirst(poly f, int M, int N)
2636"USAGE : factorfirst(f,M,N); f poly, M,N int
2637RETURN: number d such that f=const*(y^(N/e) - d*x^(M/e))^e, where e=gcd(M,N),
2638        0 if such a d does not exist
2639EXAMPLE: example factorfirst;  shows an example
2640"
2641{
2642 number c = koeff(f,0,N);
2643 number delt;
2644 int eps,l;
2645 int p=char(basering);
2646 string ringchar=charstr(basering);
2647
2648 if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
2649 int e = gcd(M,N);
2650
2651 if (p==0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2652 else {
2653   if (e%p != 0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2654   else {
2655     eps = e;
2656     for (l = 0; eps%p == 0; l=l+1) { eps=eps/ p;}
2657     if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
2658     delt = koeff(f,(M/ e)*p^l,(N/ e)*p^l*(eps-1)) / (-1*eps*c);
2659
2660     if ((charstr(basering) != string(p)) and (delt != 0)) {
2661 //------ coefficient field is not Z/pZ => (p^l)th root is not identity -------
2662       delt=0;
2663       if (defined(HNDebugOn)) {
2664         "trivial factorization not implemented for",
2665         "parameters---I've to use 'factorize'";
2666       }
2667     }
2668   }
2669 }
2670 if (defined(HNDebugOn)) {"quasihomogeneous leading form:",f," = ",c,
2671        "* (y^"+string(N/ e),"-",delt,"* x^"+string(M/ e)+")^",e," ?";}
2672 if (f != c*(var(2)^(N/ e) - delt*var(1)^(M/ e))^e) {return(0);}
2673 else {return(delt);}
2674}
2675example
2676{ "EXAMPLE:"; echo = 2;
2677  ring exring=7,(x,y),dp;
2678  factorfirst(2*(y3-3x4)^5,20,15);
2679  factorfirst(x14+y7,14,7);
2680  factorfirst(x14+x8y3+y7,14,7);
2681}
2682
2683///////////////////////////////////////////////////////////////////////////
2684
2685proc hnexpansion(poly f,list #)
2686"USAGE:   hnexpansion(f[,\"ess\"]);   f poly
2687ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2688RETURN:  list @code{L}, containing Hamburger-Noether data of @code{f}:
2689         If the computation of the HNE required no field extension, @code{L}
2690         is a list of lists @code{L[i]} (corresponding to the output of
2691         @code{develop}, applied to a branch of @code{f}, but the last entry
2692         being omitted):
2693@texinfo
2694@table @asis
2695@item @code{L[i][1]}; matrix:
2696         Each row contains the coefficients of the corresponding line of the
2697         Hamburger-Noether expansion (HNE) for the i-th branch. The end of
2698         the line is marked in the matrix by the first ring variable
2699         (usually x).
2700@item @code{L[i][2]}; intvec:
2701         indicating the length of lines of the HNE
2702@item @code{L[i][3]}; int:
2703         0  if the 1st ring variable was transversal (with respect to the
2704            i-th branch), @*
2705         1  if the variables were changed at the beginning of the
2706            computation, @*
2707        -1  if an error has occurred.
2708@item @code{L[i][4]}; poly:
2709         the transformed equation of the i-th branch to make it possible
2710         to extend the Hamburger-Noether data a posteriori without having
2711         to do all the previous calculation once again (0 if not needed).
2712@end table
2713@end texinfo
2714         If the computation of the HNE required a field extension, the first
2715         entry @code{L[1]} of the list is a ring, in which a list @code{hne}
2716         of lists (the HN data, as above) and a polynomial @code{f} (image of
2717         @code{f} over the new field) are stored.
2718         @*
2719         If called with an additional input parameter, @code{hnexpansion}
2720         computes only one representative for each class of conjugate
2721         branches (over the ground field active when calling the procedure).
2722         In this case, the returned list @code{L} always has only two
2723         entries: @code{L[1]} is either a list of lists (the HN data) or a
2724         ring (as above), and @code{L[2]} is an integer vector (the number
2725         of branches in the respective conjugacy classes).
2726
2727NOTE:    If f is known to be irreducible as a power series, @code{develop(f)}
2728         could be chosen instead to avoid a change of basering during the
2729         computations. @*
2730         Increasing  @code{printlevel} leads to more and more comments. @*
2731         Having defined a variable @code{HNDebugOn} leads to a maximum
2732         number of comments.
2733
2734SEE ALSO: develop, extdevelop, param, displayHNE
2735EXAMPLE: example hnexpansion;  shows an example
2736"
2737{
2738 int essential;
2739 if (size(#)==1) { essential=1; }
2740 int field_ext;
2741 def altring=basering;
2742
2743 //--------- Falls Ring (p^k,a),...: Wechsel in (p,a),... + minpoly -----------
2744 if ( (find(charstr(basering),string(char(basering)))!=1) &&
2745      (charstr(basering)<>"real")&&
2746      (charstr(basering)<>"complex") ) {
2747   string strmip=string(minpoly);
2748   string strf=string(f);
2749   execute("ring tempr=("+string(char(basering))+","+parstr(basering)+"),("
2750           +varstr(basering)+"),dp;");
2751   execute("minpoly="+strmip+";");
2752   execute("poly f="+strf+";");
2753   field_ext=1;
2754   def L=pre_HN(f,essential);
2755   if (size(L)==0) { return(list()); }
2756   def HNEring=L[1];
2757   setring HNEring;
2758   if ((typeof(hne[1])=="ideal")) { return(list()); }
2759   if ((voice==2) && (printlevel > -1)) {
2760     "// Attention: The parameter",par(1),"may have changed its meaning!";
2761     "// It needs no longer be a generator of the cyclic group of unities!";
2762   }
2763   dbprint(printlevel-voice+2,
2764     "// result: "+string(size(hne))+" branch(es) successfully computed.");
2765 }
2766 else {
2767   def L=pre_HN(f,essential);
2768   if (size(L)==0) { return(list()); }
2769   if (L[2]==1) { field_ext=1; }
2770   intvec hne_conj=L[3];
2771   def HNEring=L[1];
2772   setring HNEring;
2773   if ((typeof(hne[1])=="ideal")) { return(list()); }
2774   dbprint(printlevel-voice+2,
2775      "// result: "+string(size(hne))+" branch(es) successfully computed.");
2776 }
2777
2778 // ----- Lossen 10/02 : the branches have to be resorted to be able to
2779 // -----                display the multsequence in a nice way
2780 if (size(hne)>2)
2781 {
2782   int i,j,k,m;
2783   list dummy;
2784   int nbsave;
2785   int no_br = size(hne);
2786   intmat nbhd[no_br][no_br];
2787   for (i=1;i<no_br;i++)
2788   {
2789     for (j=i+1;j<=no_br;j++)
2790     {
2791       nbhd[i,j]=separateHNE(hne[i],hne[j]);
2792       k=i+1;
2793       while ( (nbhd[i,k] >= nbhd[i,j]) and (k<j) )
2794       {
2795         k++;
2796       }
2797       if (k<j)  // branches have to be resorted
2798       {
2799         dummy=hne[j];
2800         nbsave=nbhd[i,j];
2801         for (m=k; m<j; m++)
2802         {
2803           hne[m+1]=hne[m];
2804           nbhd[i,m+1]=nbhd[i,m];
2805         }
2806         hne[k]=dummy;
2807         nbhd[i,k]=nbsave;
2808       }
2809     }
2810   }
2811 }
2812 // -----
2813
2814 if (field_ext==1) {
2815   dbprint(printlevel-voice+3,"
2816// 'hnexpansion' created a list of one ring.
2817// To see the ring and the data stored in the ring, type (if you assigned
2818// the name L to the list):
2819     show(L);
2820// To display the computed HN expansion, type
2821     def HNring = L[1]; setring HNring;  displayHNE(hne); ");
2822   if (essential==1) {
2823     dbprint(printlevel-voice+3,""+
2824"// As second entry of the returned list L, you obtain an integer vector,
2825// indicating the number of conjugates for each of the computed branches.");
2826     return(list(HNEring,hne_conj));
2827   }
2828   return(list(HNEring));
2829 }
2830 else { // no change of basering necessary --> map data to original ring
2831   setring altring;
2832   if ((npars(altring)==1) and (minpoly!=0)) {
2833     ring HNhelpring=char(altring),(a,x,y),ls;
2834     list hne=imap(HNEring,hne);
2835     setring altring;
2836     map mmm=HNhelpring,par(1),var(1),var(2);
2837     list hne=mmm(hne);
2838     kill mmm,HNhelpring;
2839   }
2840   else {
2841     list hne=fetch(HNEring,hne);
2842   }
2843   kill HNEring;
2844   if (essential==1) {
2845     dbprint(printlevel-voice+3,""+
2846"// No change of ring necessary, return value is a list:
2847//   first entry  =  list :  HN expansion of essential branches.
2848//   second entry =  intvec: numbers of conjugated branches ");
2849     return(list(hne,hne_conj));
2850   }
2851   else {
2852     dbprint(printlevel-voice+3,""+
2853"// No change of ring necessary, return value is HN expansion.");
2854     return(hne);
2855   }
2856 }
2857}
2858example
2859{
2860  "EXAMPLE:"; echo = 2;
2861  ring r=0,(x,y),dp;
2862  // First, an example which requires no field extension:
2863  list Hne=hnexpansion(x4-y6);
2864  size(Hne);           // number of branches
2865  displayHNE(Hne);     // HN expansion of branches
2866  param(Hne[1]);       // parametrization of 1st branch
2867  param(Hne[2]);       // parametrization of 2nd branch
2868
2869  // An example which requires a field extension:
2870  list L=hnexpansion((x4-y6)*(y2+x4));
2871  def R=L[1]; setring R; displayHNE(hne);
2872  basering;
2873  setring r; kill R;
2874
2875  // Computing only one representative per conjugacy class:
2876  L=hnexpansion((x4-y6)*(y2+x4),"ess");
2877  def R=L[1]; setring R; displayHNE(hne);
2878  L[2];     // number of branches in respective conjugacy classes
2879}
2880
2881///////////////////////////////////////////////////////////////////////////////
2882
2883static proc pre_HN (poly f, int essential)
2884"NOTE: This procedure is only for internal use, it is called via
2885       hnexpansion
2886RETURN: list:  first entry = HNEring  (containing list hne, poly f)
2887               second entry = 0  if no change of base ring necessary
2888                              1  if change of base ring necessary
2889               third entry = numbers of conjugates ( if essential = 1 )
2890        if some error has occured, the empty list is returned
2891"
2892{
2893 def altring = basering;
2894 int p = char(basering);
2895 int field_ext;
2896 intvec hne_conj;
2897
2898 //-------------------- Tests auf Zulaessigkeit von basering ------------------
2899 if (charstr(basering)=="real") {
2900   " Singular cannot factorize over 'real' as ground field";
2901   return(list());
2902 }
2903 if (size(maxideal(1))<2) {
2904   " A univariate polynomial ring makes no sense !";
2905   return(list());
2906 }
2907 if (size(maxideal(1))>2) {
2908   dbprint(printlevel-voice+2,
2909   " Warning: all variables except the first two will be ignored!");
2910 }
2911 if (find(charstr(basering),string(char(basering)))!=1) {
2912   " ring of type (p^k,a) not implemented";
2913 //----------------------------------------------------------------------------
2914 // weder primitives Element noch factorize noch map "char p^k" -> "char -p"
2915 // [(p^k,a)->(p,a) ground field] noch fetch
2916 //----------------------------------------------------------------------------
2917   return(list());
2918 }
2919 //----------------- Definition eines neuen Ringes: HNEring -------------------
2920 string namex=varstr(1); string namey=varstr(2);
2921 if (string(char(altring))==charstr(altring)) { // kein Parameter, nicht 'real'
2922   ring HNEring = char(altring),(x,y),ls;
2923   map m=altring,x,y;
2924   poly f=m(f);
2925   export f;
2926   kill m;
2927 }
2928 else {
2929   string mipl=string(minpoly);
2930   if (mipl=="0") {
2931     "// ** WARNING: Algebraic extension of given ground field not possible!";
2932     "// ** We try to develop this polynomial, but if the need for a field";
2933     "// ** extension occurs during the calculation, we cannot proceed with";
2934     "// ** the corresponding branches.";
2935     execute("ring HNEring=("+charstr(basering)+"),(x,y),ls;");
2936   }
2937   else {
2938    string pa=parstr(altring);
2939    ring HNhelpring=p,`pa`,dp;
2940    execute("poly mipo="+mipl+";");  // Minimalpolynom in Polynom umgewandelt
2941    ring HNEring=(p,a),(x,y),ls;
2942    map getminpol=HNhelpring,a;
2943    mipl=string(getminpol(mipo));    // String umgewandelt mit 'a' als Param.
2944    execute("minpoly="+mipl+";");    // "minpoly=poly is not supported"
2945    kill HNhelpring, getminpol;
2946   }
2947   if (nvars(altring)==2) {
2948     poly f=fetch(altring,f);
2949     export f;
2950   }
2951   else {
2952     if (defined(pa)) { // Parameter hatte vorher anderen Namen als 'a'
2953       ring HNhelpring=p,(`pa`,x,y),ls;
2954       poly f=imap(altring,f);
2955       setring HNEring;
2956       map m=HNhelpring,a,x,y;
2957       poly f=m(f);
2958       kill HNhelpring;
2959     }
2960     else {
2961       map m=altring,x,y;
2962       poly f=m(f);
2963     }
2964     export f;
2965     kill m;
2966   }
2967 }
2968
2969 if (defined(HNDebugOn))
2970 {"received polynomial: ",f,", with x =",namex,", y =",namey;}
2971
2972 //----------------------- Variablendefinitionen ------------------------------
2973 int Abbruch,i,NullHNEx,NullHNEy;
2974 string str;
2975 list Newton,hne;
2976
2977 // --- changed for SINGULAR 3: ---
2978 hne=ideal(0);
2979 export hne;
2980
2981 //====================== Tests auf Zulaessigkeit des Polynoms ================
2982
2983 //-------------------------- Test, ob Einheit oder Null ----------------------
2984 if (subst(subst(f,x,0),y,0)!=0) {
2985   dbprint(printlevel+1,
2986           "The given polynomial is a unit in the power series ring!");
2987   setring altring; kill HNEring;
2988   return(list());                   // there are no HNEs
2989 }
2990 if (f==0) {
2991   dbprint(printlevel+1,"The given polynomial is zero!");
2992   setring altring; kill HNEring;
2993   return(list());                   // there are no HNEs
2994 }
2995
2996 //-----------------------  Test auf Quadratfreiheit --------------------------
2997
2998 if ((p==0) and (size(charstr(basering))==1)) {
2999
3000 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
3001 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
3002 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring HNEring
3003 //----------------------------------------------------------------------------
3004  int testerg=(polytest(f)==0);
3005  ring zweitring = 32003,(x,y),dp;
3006
3007  map polyhinueber=HNEring,x,y;         // fetch geht nicht
3008  poly f=polyhinueber(f);
3009  poly test_sqr=squarefree(f);
3010  if (test_sqr != f) {
3011   if (printlevel>0) {
3012     "Most probably the given polynomial is not squarefree. But the test was";
3013     "made in characteristic 32003 and not 0 to improve speed. You can";
3014     "(r) redo the test in char 0 (but this may take some time)";
3015     "(c) continue the development, if you're sure that the polynomial IS",
3016     "squarefree";
3017     if (testerg==1) {
3018       "(s) continue the development with a squarefree factor (*)";}
3019     "(q) or just quit the algorithm (default action)";
3020     "";"Please enter the letter of your choice:";
3021     str=read("")[1];             // reads one character
3022   }
3023   else { str="r"; }              // printlevel <= 0: non-interactive behaviour
3024   setring HNEring;
3025   map polyhinueber=zweitring,x,y;
3026   if (str=="r") {
3027     poly test_sqr=squarefree(f);
3028     if (test_sqr != f) {
3029      if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
3030      else              { "The given polynomial is not squarefree!"; }
3031      "I'll continue with the radical.";
3032      f=test_sqr;
3033     }
3034     else {
3035      dbprint(printlevel,
3036       "everything is ok -- the polynomial is squarefree in characteristic 0");
3037     }
3038   }
3039   else {
3040     if ((str=="s") and (testerg==1)) {
3041       "(*)attention: it could be that the factor is only one in char 32003!";
3042       f=polyhinueber(test_sqr);
3043     }
3044     else {
3045       if (str<>"c") {
3046         setring altring;
3047         kill HNEring;kill zweitring;
3048         return(list());}
3049       else { "if the algorithm doesn't terminate, you were wrong...";}
3050   }}
3051   kill zweitring;
3052   if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3053  }
3054  else {
3055    setring HNEring;
3056    kill zweitring;
3057  }
3058 }
3059 //------------------ Fall Char > 0 oder Ring hat Parameter -------------------
3060 else {
3061  poly test_sqr=squarefree(f);
3062  if (test_sqr != f) {
3063   if (printlevel>0) {
3064    if (test_sqr == 1) {
3065     "The given polynomial is of the form g^"+string(p)+",";
3066     "therefore not squarefree.  You can:";
3067     " (q) quit the algorithm (recommended) or";
3068     " (f) continue with the full radical (using a factorization of the";
3069     "     pure power part; this could take much time)";
3070     "";"Please enter the letter of your choice:";
3071     str=read("")[1];
3072     if (str<>"f") { str="q"; }
3073    }
3074    else {
3075     "The given polynomial is not squarefree.";
3076     if (p != 0)
3077      {
3078       " You can:";
3079       " (c) continue with a squarefree divisor (but factors of the form g^"
3080       +string(p);
3081       "     are lost; this is recommended, takes no extra time)";
3082       " (f) continue with the full radical (using a factorization of the";
3083       "     pure power part; this could take some time)";
3084       " (q) quit the algorithm";
3085       "";"Please enter the letter of your choice:";
3086       str=read("")[1];
3087       if ((str<>"f") && (str<>"q")) { str="c"; }
3088      }
3089     else { "I'll continue with the radical."; str="c"; }
3090    }                                // endelse (test_sqr!=1)
3091   }
3092   else {
3093     "//** Error: The given polynomial is not squarefree!";
3094     "//** Since the global variable `printlevel' has the value",printlevel,
3095       "we stop here.";
3096     "//   Either call me again with a squarefree polynomial f or assign";
3097     "            printlevel=1;";
3098     "//   before calling me with a non-squarefree f.";
3099     "//   If printlevel > 0, I present some possibilities how to proceed.";
3100     str="q";
3101   }
3102   if (str=="q") {
3103    setring altring;kill HNEring;
3104    return(list());
3105   }
3106   if (str=="c") { f=test_sqr; }
3107   if (str=="f") { f=allsquarefree(f,test_sqr); }
3108  }
3109  if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3110
3111 }
3112 //====================== Ende Test auf Quadratfreiheit =======================
3113 if (subst(subst(f,x,0),y,0)!=0) {
3114   "The polynomial is a unit in the power series ring. No HNE computed.";
3115   setring altring;kill HNEring;
3116   return(list());
3117 }
3118 //---------------------- Test, ob f teilbar durch x oder y -------------------
3119 if (subst(f,y,0)==0) {
3120   f=f/y; NullHNEy=1; }             // y=0 is a solution
3121 if (subst(f,x,0)==0) {
3122   f=f/x; NullHNEx=1; }             // x=0 is a solution
3123
3124 Newton=newtonpoly(f,1);
3125 i=1; Abbruch=0;
3126 //----------------------------------------------------------------------------
3127 // finde Eckpkt. des Newtonpolys, der den Teil abgrenzt, fuer den x transvers:
3128 // Annahme: Newton ist sortiert, s.d. Newton[1]=Punkt auf der y-Achse,
3129 // Newton[letzt]=Punkt auf der x-Achse
3130 //----------------------------------------------------------------------------
3131 while ((i<size(Newton)) and (Abbruch==0)) {
3132  if ((Newton[i+1][1]-Newton[i][1])>=(Newton[i][2]-Newton[i+1][2]))
3133   {Abbruch=1;}
3134  else {i=i+1;}
3135 }
3136 int grenze1=Newton[i][2];
3137 int grenze2=Newton[i][1];
3138 //----------------------------------------------------------------------------
3139 // Stelle Ring bereit zur Uebertragung der Daten im Fall einer Koerperer-
3140 // weiterung. Definiere Objekte, die spaeter uebertragen werden.
3141 // Binde die Listen (azeilen,...) an den Ring (um sie nicht zu ueberschreiben
3142 // bei Def. in einem anderen Ring).
3143 //----------------------------------------------------------------------------
3144 ring HNE_noparam = char(altring),(a,x,y),ls;
3145 poly f;
3146 list azeilen=ideal(0);
3147 list HNEs=ideal(0);
3148 list aneu=ideal(0);
3149 list faktoren=ideal(0);
3150
3151 ideal deltais;
3152 poly delt;
3153
3154 //----- hier steht die Anzahl bisher benoetigter Ringerweiterungen drin: -----
3155 int EXTHNEnumber=0;
3156
3157 list EXTHNEring;
3158 list HNE_RingDATA;
3159 int number_of_letztring;
3160 setring HNEring;
3161 number_of_letztring=0;
3162
3163 // ================= Die eigentliche Berechnung der HNE: =====================
3164
3165 // ------- Berechne HNE von allen Zweigen, fuer die x transversal ist: -------
3166 if (defined(HNDebugOn))
3167   {"1st step: Treat Newton polygon until height",grenze1;}
3168 if (grenze1>0) {
3169  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3170  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3171                      number_of_letztring);
3172
3173  list hilflist=HN(HNE_RingDATA,f,grenze1,1,essential,0,hne_conj,1);
3174  kill HNEring, HNE_noparam;
3175  if (EXTHNEnumber>0) { kill EXTHNEring(1..EXTHNEnumber);}
3176  def HNEring = hilflist[1][1];
3177  def HNE_noparam = hilflist[1][2];
3178  EXTHNEnumber = hilflist[1][3];
3179  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3180  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3181  else                { setring EXTHNEring(hilflist[2]);}
3182  if (hilflist[3]==1){field_ext=1;}
3183  hne_conj=hilflist[5];
3184
3185  if (number_of_letztring != hilflist[2])
3186  {  // Ringwechsel in Prozedur HN
3187     map hole=HNE_noparam,transfproc,x,y;
3188     setring HNE_noparam;
3189     if (not(defined(f))) {poly f;}
3190     f=imap(HNEring,f);
3191     setring EXTHNEring(EXTHNEnumber);
3192     if (not(defined(f))) {poly f; f=hole(f); export f;}
3193     else                 {f=hole(f);}
3194  }
3195  number_of_letztring = hilflist[2];
3196  kill hilflist;
3197 }
3198
3199 if (NullHNEy==1) {
3200  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3201  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(0),poly(0)));
3202  if (hne_conj==0) { hne_conj=1; }
3203  else { hne_conj = hne_conj, 1; }
3204 }
3205 // --------------- Berechne HNE von allen verbliebenen Zweigen: --------------
3206 if (defined(HNDebugOn))
3207    {"2nd step: Treat Newton polygon until height",grenze2;}
3208 if (grenze2>0) {
3209
3210  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3211
3212  if (essential==1) { number_of_letztring=0; }
3213  if (number_of_letztring==0) { setring HNEring; }
3214  else                        { setring EXTHNEring(number_of_letztring); }
3215  map xytausch=basering,y,x;
3216
3217  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3218                      number_of_letztring);
3219  list hilflist=HN(HNE_RingDATA,xytausch(f),grenze2,1,essential,1,hne_conj,1);
3220  kill HNEring, HNE_noparam;
3221  if (EXTHNEnumber>0){ kill EXTHNEring(1..EXTHNEnumber); }
3222  def HNEring = hilflist[1][1];
3223  def HNE_noparam = hilflist[1][2];
3224  EXTHNEnumber = hilflist[1][3];
3225  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3226  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3227  else                { setring EXTHNEring(hilflist[2]);
3228                        number_of_letztring=hilflist[2]; }
3229  if (hilflist[3]==1){field_ext=1;}
3230  hne_conj=hilflist[5];
3231  kill hilflist;
3232 }
3233 if (NullHNEx==1) {
3234  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3235  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(1),poly(0)));
3236  if (hne_conj==0) { hne_conj=1; }
3237  else { hne_conj = hne_conj, 1; }
3238 }
3239
3240
3241 // --- aufraeumen ---
3242 if (defined(HNEakut)){
3243   kill HNEakut,faktoren,deltais,transformiert,teiler,leitf;
3244 }
3245 if (defined(hilflist)) {kill hilflist;}
3246 if (defined(erg)) {kill erg;}
3247 if (defined(delt)) {kill delt;}
3248 if (defined(azeilen)) { kill azeilen;}
3249 if (defined(aneu)) { kill aneu;}
3250 if (defined(transfproc)) { kill transfproc;}
3251 if (defined(transf)) { kill transf;}
3252 if (not(defined(f))) { poly f = imap(HNEring,f); export f; }
3253
3254 return(list(basering,field_ext,hne_conj));
3255}
3256
3257//////////////////////////////////////////////////////////////////////////////
3258proc essdevelop (poly f)
3259"USAGE:   essdevelop(f); f poly
3260NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.
3261SEE ALSO: hnexpansion, develop, extdevelop, param
3262"
3263{
3264 printlevel=printlevel+1;
3265 list Ergebnis=hnexpansion(f,1);
3266 printlevel=printlevel-1;
3267 return(Ergebnis);
3268}
3269
3270///////////////////////////////////////////////////////////////////////////////
3271static proc HN (list HNE_RingDATA,poly fneu,int grenze,Aufruf_Ebene,
3272                     essential,getauscht,intvec hne_conj,int conj_factor)
3273"NOTE: This procedure is only for internal use, it is called via pre_HN
3274RETURN: list: first entry = list of HNErings,
3275              second entry = number of new base ring (0 for HNEring,
3276                                                      -1 for HNE_noparam,
3277                                                      i for EXTHNEring(i))
3278              third entry = 0 if no field extension necessary
3279                            1 if field extension necessary
3280              forth entry = HNEs (only if no change of basering)
3281"
3282{
3283 //---------- Variablendefinitionen fuer den unverzweigten Teil: --------------
3284 if (defined(HNDebugOn)) {"procedure HN",Aufruf_Ebene;}
3285 int Abbruch,ende,i,j,k,e,M,N,Q,R,zeiger,zeile,zeilevorher,dd,ii;
3286 intvec hqs;
3287 int field_ext;
3288 int ring_changed, hneshift;
3289 intvec conjugates,conj2,conj1;
3290
3291 list EXTHNEring;
3292 def HNEring = HNE_RingDATA[1];
3293 def HNE_noparam = HNE_RingDATA[2];
3294 int EXTHNEnumber = HNE_RingDATA[3];
3295 for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=HNE_RingDATA[4][i]; }
3296 int number_of_letztring = HNE_RingDATA[5];
3297 if (defined(basering))
3298 {
3299   if (number_of_letztring==0) { kill HNEring; def HNEring=basering; }
3300   else                 { kill EXTHNEring(number_of_letztring);
3301                          def EXTHNEring(number_of_letztring)=basering; }
3302 }
3303 else
3304 {
3305   if ( number_of_letztring==0) { setring HNEring; }
3306   else                         { setring EXTHNEring(number_of_letztring); }
3307 }
3308 if (not(defined(hne))) {list hne;}
3309 poly fvorher;
3310 list erg=ideal(0); list HNEs=ideal(0); // um die Listen an den Ring zu binden
3311
3312 //-------------------- Bedeutung von Abbruch: --------------------------------
3313 //------- 0:keine Verzweigung | 1:Verzweigung,nicht fertig | 2:fertig --------
3314 //
3315 // Struktur von HNEs : Liste von Listen L (fuer jeden Zweig) der Form
3316 // L[1]=intvec (hqs), L[2],L[3],... ideal (die Zeilen (0,1,...) der HNE)
3317 // L[letztes]=poly (transformiertes f)
3318 //----------------------------------------------------------------------------
3319 list Newton;
3320 number delt;
3321 int p = char(basering);                // Ringcharakteristik
3322 list azeilen=ideal(0);
3323
3324 ideal hilfid; intvec hilfvec;
3325
3326 // ======================= der unverzweigte Teil: ============================
3327 while (Abbruch==0) {
3328  Newton=newtonpoly(fneu,1);
3329  zeiger=find_in_list(Newton,grenze);
3330  if (Newton[zeiger][2] != grenze)
3331    {"Didn't find an edge in the Newton polygon!";}
3332  if (zeiger==size(Newton)-1) {
3333    if (defined(HNDebugOn)) {"only one relevant side in Newton polygon";}
3334    M=Newton[zeiger+1][1]-Newton[zeiger][1];
3335    N=Newton[zeiger][2]-Newton[zeiger+1][2];
3336    R = M%N;
3337    Q = M / N;
3338
3339    //-------- 1. Versuch: ist der quasihomogene Leitterm reine Potenz ? ------
3340    //              (dann geht alles wie im irreduziblen Fall)
3341    //-------------------------------------------------------------------------
3342    e = gcd(M,N);
3343    delt=factorfirst(redleit(fneu,Newton[zeiger],Newton[zeiger+1])
3344                      /x^Newton[zeiger][1],M,N);
3345    if (delt==0) {
3346      if (defined(HNDebugOn)) {" The given polynomial is reducible !";}
3347      Abbruch=1;
3348    }
3349    if (Abbruch==0) {
3350      //----------- fneu,zeile retten fuer den Spezialfall (###): -------------
3351      fvorher=fneu;zeilevorher=zeile;
3352      if (R==0) {
3353        //-------- transformiere fneu mit T1, wenn kein Abbruch nachher: ------
3354        if (N>1) { fneu = T1_Transform(fneu,delt,M/ e); }
3355        else     { ende=1; }
3356        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3357        azeilen[zeile+1][Q]=delt;
3358      }
3359      else {
3360        //------------- R > 0 : transformiere fneu mit T2 ---------------------
3361        erg=T2_Transform(fneu,delt,M,N,referencepoly(Newton));
3362        fneu=erg[1];delt=erg[2];
3363        //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ----
3364        while (R!=0) {
3365         if (defined(HNDebugOn)) { "h("+string(zeile)+") =",Q; }
3366         hqs[zeile+1]=Q;         // denn zeile beginnt mit dem Wert 0
3367         //--------------- markiere das Zeilenende der HNE: -------------------
3368         azeilen[zeile+1][Q+1]=x;
3369         zeile=zeile+1;
3370         //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ----
3371         azeilen[zeile+1]=ideal(0);
3372         M=N; N=R; R=M%N; Q=M / N;
3373        }
3374        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3375        azeilen[zeile+1][Q]=delt;
3376      }
3377      if (defined(HNDebugOn)) {"transformed polynomial: ",fneu;}
3378      grenze=e;
3379      //----------------------- teste Abbruchbedingungen: ---------------------
3380      if (subst(fneu,y,0)==0) {              // <==> y|fneu
3381        dbprint(printlevel-voice+3,"finite HNE of one branch found");
3382           // voice abzufragen macht bei rekursiven procs keinen Sinn
3383        azeilen[zeile+1][Q+1]=x;
3384        //----- Q wird nur in hqs eingetragen, wenn der Spezialfall nicht
3385        //      eintritt (siehe unten) -----
3386        Abbruch=2;
3387        if (grenze>1) {
3388         if (jet(fneu,1,intvec(0,1))==0) {
3389           //- jet(...)=alle Monome von fneu, die nicht durch y2 teilbar sind -
3390           "THE TEST FOR SQUAREFREENESS WAS BAD!!";
3391           " The polynomial was NOT squarefree!!!";}
3392         else {
3393           //----------------------- Spezialfall (###): -----------------------
3394           // Wir haben das Problem, dass die HNE eines Zweiges hier abbricht,
3395           // aber ein anderer Zweig bis hierher genau die gleiche HNE hat, die
3396           // noch weiter geht
3397           // Loesung: mache Transform. rueckgaengig und behandle fneu im
3398           // Verzweigungsteil
3399           //------------------------------------------------------------------
3400          Abbruch=1;
3401          fneu=fvorher;zeile=zeilevorher;grenze=Newton[zeiger][2];
3402        }}
3403        else {fneu=0;}     // fneu nicht mehr gebraucht - spare Speicher
3404        if (Abbruch==2) { hqs[zeile+1]=Q; }
3405      }                 // Spezialfall nicht eingetreten
3406      else {
3407        if (ende==1) {
3408          dbprint(printlevel-voice+2,"HNE of one branch found");
3409          Abbruch=2; hqs[zeile+1]=-Q-1;}
3410      }
3411    }                   // end(if Abbruch==0)
3412  }                     // end(if zeiger...)
3413  else { Abbruch=1;}
3414 }                      // end(while Abbruch==0)
3415
3416 // ===================== der Teil bei Verzweigung: ===========================
3417 if (Abbruch==1) {
3418  //---------- Variablendefinitionen fuer den verzweigten Teil: ---------------
3419  poly leitf,teiler,transformiert;
3420  list aneu=ideal(0);
3421  list faktoren;
3422  ideal deltais;
3423  list HNEakut=ideal(0);
3424  intvec eis;
3425  int zaehler,hnezaehler,zl,zl1,M1,N1,R1,Q1,needext;
3426  int numberofRingchanges,lastRingnumber,ringischanged,flag;
3427  string letztringname;
3428
3429  zeiger=find_in_list(Newton,grenze);
3430  if (defined(HNDebugOn)) {
3431    "Branching part reached---Newton polygon :",Newton;
3432    "relevant part until height",grenze,", from",Newton[zeiger],"on";
3433  }
3434  azeilen=list(hqs)+azeilen; // hat jetzt Struktur von HNEs: hqs in der 1.Zeile
3435
3436  //======= Schleife fuer jede zu betrachtende Seite des Newtonpolygons: ======
3437  for(i=zeiger; i<size(Newton); i++) {
3438   if ((essential==1) and (EXTHNEnumber>number_of_letztring)) {
3439     // ----- setze ring zurueck fuer neue Kante  -----
3440     // ---- (damit konjugierte Zweige erkennbar) -----
3441     hneshift=hneshift+hnezaehler;
3442     hnezaehler=0;
3443     ring_changed=0;
3444     def SaveRing = EXTHNEring(EXTHNEnumber);
3445     setring SaveRing;
3446     if (not(defined(HNEs))) { // HN wurde zum 2.Mal von pre_HN aufgerufen
3447       list HNEs=ideal(0);
3448     }
3449     for (k=number_of_letztring+1; k<=EXTHNEnumber; k++) { kill EXTHNEring(k);}
3450     EXTHNEnumber=number_of_letztring;
3451     if (EXTHNEnumber==0) { setring HNEring; }
3452     else                 { setring EXTHNEring(EXTHNEnumber); }
3453     if (not(defined(HNEs))) { list HNEs; }
3454     HNEs=ideal(0);
3455     deltais=0;
3456     delt=0;
3457     if (defined(zerlege)) { kill zerlege; }
3458   }
3459
3460   if (defined(HNDebugOn)) { "we consider side",Newton[i],Newton[i+1]; }
3461   M=Newton[i+1][1]-Newton[i][1];
3462   N=Newton[i][2]-Newton[i+1][2];
3463   R = M%N;
3464   Q = M / N;
3465   e=gcd(M,N);
3466   needext=1;
3467   letztringname=nameof(basering);
3468   lastRingnumber=EXTHNEnumber;
3469   faktoren=list(ideal(charPoly(redleit(fneu,Newton[i],Newton[i+1])
3470                       /(x^Newton[i][1]*y^Newton[i+1][2]),M,N)  ),
3471                 intvec(1));                  // = (zu faktoriserendes Poly, 1)
3472   conjugates=conj_factor;
3473
3474   //-- wechsle so lange in Ringerweiterungen, bis Leitform vollstaendig
3475   //   in Linearfaktoren zerfaellt -----
3476   for (numberofRingchanges=1; needext==1; numberofRingchanges++) {
3477    leitf=redleit(fneu,Newton[i],Newton[i+1])/
3478                     (x^Newton[i][1]*y^Newton[i+1][2]);
3479    delt=factorfirst(leitf,M,N);
3480    needext=0;
3481    if (delt==0) {
3482     //---------- Sonderbehandlung: faktorisiere einige Polynome ueber Q(a): --
3483     if ((charstr(basering)=="0,a") and (essential==0)) {
3484        // ====================================================
3485        // neu CL:  06.10.05
3486        poly CHPOLY=charPoly(leitf,M,N);
3487        poly tstpoly;
3488        if (defined(faktoren)!=0) {
3489          // Test, damit kein Fehler eingebaut (vermutlich nicht notwendig)
3490          tstpoly = faktoren[1][1]^faktoren[2][1];
3491          for (k=2; k<=size(faktoren[1]); k++) {
3492            tstpoly = tstpoly * faktoren[1][k]^faktoren[2][k];
3493          }
3494          tstpoly = CHPOLY-tstpoly*(CHPOLY/tstpoly);
3495          kill CHPOLY;
3496        }
3497        if ((numberofRingchanges>1) and (defined(faktoren)!=0) and (tstpoly==0)) {
3498          def L_help=factorlist(faktoren,conjugates);
3499          faktoren=L_help[1];
3500          conjugates=L_help[2];
3501          kill L_help;
3502        }
3503        else {
3504          faktoren=factorize(charPoly(leitf,M,N));
3505          conjugates=conj_factor;
3506          for (k=2;k<=size(faktoren[2]);k++) {conjugates=conjugates,conj_factor;}
3507        }
3508        kill tstpoly;
3509        // Ende neu (vorher nur else Fall)
3510        // ====================================================
3511     }
3512     else {
3513       //------------------ faktorisiere das charakt. Polynom: ----------------
3514       if ((numberofRingchanges==1) or (essential==0)) {
3515         def L_help=factorlist(faktoren,conjugates);
3516         faktoren=L_help[1];
3517         conjugates=L_help[2];
3518         kill L_help;
3519       }
3520       else {     // eliminiere alle konjugierten Nullstellen bis auf eine:
3521         ideal hilf_id;
3522         for (zaehler=1; zaehler<=size(faktoren[1]); zaehler++) {
3523           hilf_id=factorize(faktoren[1][zaehler],1);
3524           if (size(hilf_id)>1) {
3525             poly fac=hilf_id[1];
3526             dd=deg(fac);
3527             // Zur Sicherheit:
3528             if (deg(fac)==0) { fac=hilf_id[2]; }
3529             for (k=2;k<=size(hilf_id);k++) {
3530               dd=dd+deg(hilf_id[k]);
3531               if (deg(hilf_id[k])<deg(fac)) { fac=hilf_id[k]; }
3532             }
3533             faktoren[1][zaehler]=fac;
3534             kill fac;
3535             if (conjugates[zaehler]==conj_factor) {
3536               // number of conjugates not yet determined for this factor
3537               conjugates[zaehler]=conjugates[zaehler]*dd;
3538             }
3539           }
3540           else {
3541             faktoren[1][zaehler]=hilf_id[1];
3542           }
3543         }
3544       }
3545     }
3546
3547     zaehler=1; eis=0;
3548     for (j=1; j<=size(faktoren[2]); j++) {
3549      teiler=faktoren[1][j];
3550      if (teiler/y != 0) {         // sonst war's eine Konstante --> wegwerfen!
3551        if (defined(HNDebugOn)) {"factor of leading form found:",teiler;}
3552        if (teiler/y2 == 0) {      // --> Faktor hat die Form cy+d
3553          deltais[zaehler]=-subst(teiler,y,0)/koeff(teiler,0,1); //=-d/c
3554          eis[zaehler]=faktoren[2][j];
3555          conj2[zaehler]=conjugates[j];
3556          zaehler++;
3557        }
3558        else {
3559          dbprint(printlevel-voice+2,
3560             " Change of basering (field extension) necessary!");
3561          if (defined(HNDebugOn)) { teiler,"is not yet properly factorized!"; }
3562          if (needext==0) { poly zerlege=teiler; }
3563          needext=1;
3564          field_ext=1;
3565        }
3566      }
3567     }  // end(for j)
3568    }
3569    else { deltais=ideal(delt); eis=e; conj2=conj_factor; }
3570    if (defined(HNDebugOn)) {"roots of char. poly:";deltais;
3571                             "with multiplicities:",eis;}
3572    if (needext==1) {
3573      //--------------------- fuehre den Ringwechsel aus: ---------------------
3574      ringischanged=1;
3575      if ((size(parstr(basering))>0) && string(minpoly)=="0") {
3576        " ** We've had bad luck! The HNE cannot be calculated completely!";
3577        // HNE in transzendenter Erweiterung fehlgeschlagen
3578        kill zerlege;
3579        ringischanged=0; break;    // weiter mit gefundenen Faktoren
3580      }
3581      if (parstr(basering)=="") {
3582        EXTHNEnumber++;
3583        def EXTHNEring(EXTHNEnumber) = splitring(zerlege);
3584        setring EXTHNEring(EXTHNEnumber);
3585
3586        poly transf=0;
3587        poly transfproc=0;
3588        ring_changed=1;
3589        export transfproc;
3590      }
3591      else {
3592        if (numberofRingchanges>1) {  // ein Ringwechsel hat nicht gereicht
3593         def helpring = splitring(zerlege,list(transf,transfproc,faktoren));
3594         kill EXTHNEring(EXTHNEnumber);
3595         def EXTHNEring(EXTHNEnumber)=helpring;
3596         setring EXTHNEring(EXTHNEnumber);
3597         kill helpring;
3598
3599         poly transf=erg[1];
3600         poly transfproc=erg[2];
3601         ring_changed=1;
3602         list faktoren=erg[3];
3603         export transfproc;
3604         kill erg;
3605        }
3606        else {
3607         if (ring_changed==1) { // in dieser proc geschah schon Ringwechsel
3608          EXTHNEnumber++;
3609          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,list(a,transfproc));
3610          setring EXTHNEring(EXTHNEnumber);
3611          poly transf=erg[1];
3612          poly transfproc=erg[2];
3613          export transfproc;
3614          kill erg;
3615         }
3616         else { // parameter war vorher da
3617          EXTHNEnumber++;
3618          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,a);
3619          setring EXTHNEring(EXTHNEnumber);
3620          poly transf=erg[1];
3621          poly transfproc=transf;
3622          ring_changed=1;
3623          export transfproc;
3624          kill erg;
3625        }}
3626      }
3627      //-----------------------------------------------------------------------
3628      // transf enthaelt jetzt den alten Parameter des Ringes, der aktiv war
3629      // vor Beginn der Schleife (evtl. also ueber mehrere Ringwechsel
3630      // weitergereicht),
3631      // transfproc enthaelt den alten Parameter des Ringes, der aktiv war zu
3632      // Beginn der Prozedur, und der an die aufrufende Prozedur zurueckgegeben
3633      // werden muss
3634      // transf ist Null, falls der alte Ring keinen Parameter hatte,
3635      // das gleiche gilt fuer transfproc
3636      //-----------------------------------------------------------------------
3637
3638      //---- Neudef. von Variablen, Uebertragung bisher errechneter Daten: ----
3639      poly leitf,teiler,transformiert;
3640      list aneu=ideal(0);
3641      ideal deltais;
3642      number delt;
3643      setring HNE_noparam;
3644      if (defined(letztring)) { kill letztring; }
3645      if (EXTHNEnumber>1) { def letztring=EXTHNEring(EXTHNEnumber-1); }
3646      else                { def letztring=HNEring; }
3647      if (not defined(fneu)) {poly fneu;}
3648      fneu=imap(letztring,fneu);
3649      if (not defined(f)) {poly f;}
3650      f=imap(letztring,f);
3651      if (not defined(hne)) {list hne;}
3652      hne=imap(letztring,hne);
3653
3654      if (not defined(faktoren)) {list faktoren; }
3655      faktoren=imap(letztring,faktoren);
3656
3657      if (not(defined(azeilen))){list azeilen,HNEs;}
3658      azeilen=imap(letztring,azeilen);
3659      HNEs=imap(letztring,HNEs);
3660
3661      setring EXTHNEring(EXTHNEnumber);
3662      if (not(defined(hole))) { map hole; }
3663      hole=HNE_noparam,transf,x,y;
3664      poly fneu=hole(fneu);
3665      if (not defined(faktoren)) {
3666        list faktoren;
3667        faktoren=hole(faktoren);
3668      }
3669      if (not(defined(f)))
3670      {
3671        poly f=hole(f);
3672        list hne=hole(hne);
3673        export f,hne;
3674      }
3675    }
3676   }    // end (while needext==1) bzw. for (numberofRingchanges)
3677
3678   if (eis==0) { i++; continue; }
3679   if (ringischanged==1) {
3680    list erg,HNEakut;            // dienen nur zum Sp. von Zwi.erg.
3681
3682    ideal hilfid;
3683    erg=ideal(0); HNEakut=erg;
3684
3685    hole=HNE_noparam,transf,x,y;
3686    setring HNE_noparam;
3687    if (not(defined(azeilen))){list azeilen,HNEs;}
3688    azeilen=imap(letztring,azeilen);
3689    HNEs=imap(letztring,HNEs);
3690
3691    setring EXTHNEring(EXTHNEnumber);
3692    list azeilen=hole(azeilen);
3693    list HNEs=hole(HNEs);
3694    kill letztring;
3695    ringischanged=0;
3696   }
3697
3698   //============ Schleife fuer jeden gefundenen Faktor der Leitform: =========
3699   for (j=1; j<=size(eis); j++) {
3700     //---- Mache Transformation T1 oder T2, trage Daten in HNEs ein,
3701     //     falls HNE abbricht: ----
3702
3703    //------------------------ Fall R==0: -------------------------------------
3704    if (R==0) {
3705      transformiert = T1_Transform(fneu,number(deltais[j]),M/ e);
3706      if (defined(HNDebugOn)) {
3707        "a("+string(zeile)+","+string(Q)+") =",deltais[j];
3708        "transformed polynomial: ",transformiert;
3709      }
3710      if (subst(transformiert,y,0)==0) {
3711       dbprint(printlevel-voice+3,"finite HNE found");
3712       hnezaehler++;
3713       //-------- trage deltais[j],x ein in letzte Zeile, fertig: -------------
3714       HNEakut=azeilen+list(poly(0));        // =HNEs[hnezaehler];
3715       hilfid=HNEakut[zeile+2]; hilfid[Q]=deltais[j]; hilfid[Q+1]=x;
3716       HNEakut[zeile+2]=hilfid;
3717       HNEakut[1][zeile+1]=Q;                // aktualisiere Vektor mit den hqs
3718       HNEs[hnezaehler]=HNEakut;
3719       conj1[hneshift+hnezaehler]=conj2[j];
3720       if (eis[j]>1) {
3721        transformiert=transformiert/y;
3722        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3723                                  +"! The polynomial was NOT squarefree!!!";}
3724        else {
3725          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3726          eis[j]=eis[j]-1;
3727        }
3728       }
3729      }
3730    }
3731    else {
3732      //------------------------ Fall R <> 0: ---------------------------------
3733      erg=T2_Transform(fneu,number(deltais[j]),M,N,referencepoly(Newton));
3734      transformiert=erg[1];delt=erg[2];
3735      if (defined(HNDebugOn)) {"transformed polynomial: ",transformiert;}
3736      if (subst(transformiert,y,0)==0) {
3737       dbprint(printlevel-voice+3,"finite HNE found");
3738       hnezaehler++;
3739       //---------------- trage endliche HNE in HNEs ein: ---------------------
3740       HNEakut=azeilen;           // dupliziere den gemeins. Anfang der HNE's
3741       zl=2;                      // (kommt schliesslich nach HNEs[hnezaehler])
3742       //----------------------------------------------------------------------
3743       // Werte von:  zeile: aktuelle Zeilennummer der HNE (gemeinsamer Teil)
3744       //             zl : die HNE spaltet auf; zeile+zl ist der Index fuer die
3745       //                  Zeile des aktuellen Zweigs; (zeile+zl-2) ist die
3746       //                  tatsaechl. Zeilennr. (bei 0 angefangen) der HNE
3747       //                  ([1] <- intvec(hqs), [2] <- 0. Zeile usw.)
3748       //----------------------------------------------------------------------
3749
3750       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3751       M1=M;N1=N;R1=R;Q1=M1/ N1;
3752       while (R1!=0) {
3753        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3754        HNEakut[1][zeile+zl-1]=Q1;
3755        HNEakut[zeile+zl][Q1+1]=x;
3756                                  // markiere das Zeilenende der HNE
3757        zl=zl+1;
3758        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3759        HNEakut[zeile+zl]=ideal(0);
3760
3761        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3762       }
3763       if (defined(HNDebugOn)) {
3764         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3765       }
3766       HNEakut[zeile+zl][Q1]  =delt;
3767       HNEakut[zeile+zl][Q1+1]=x;
3768       HNEakut[1][zeile+zl-1] =Q1;     // aktualisiere Vektor mit hqs
3769       HNEakut[zeile+zl+1]=poly(0);
3770       HNEs[hnezaehler]=HNEakut;
3771       conj1[hneshift+hnezaehler]=conj2[j];
3772
3773       //-------------------- Ende der Eintragungen in HNEs -------------------
3774
3775       if (eis[j]>1) {
3776        transformiert=transformiert/y;
3777        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3778                               +" The polynomial was NOT squarefree!!!";}
3779         else {
3780          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3781          eis[j]=eis[j]-1;
3782       }}
3783      }                           // endif (subst()==0)
3784    }                             // endelse (R<>0)
3785
3786    //========== Falls HNE nicht abbricht: Rekursiver Aufruf von HN: ==========
3787    //------------------- Berechne HNE von transformiert ----------------------
3788    if (subst(transformiert,y,0)!=0) {
3789     lastRingnumber=EXTHNEnumber;
3790
3791     if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3792     HNE_RingDATA = list( HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3793                          lastRingnumber);
3794     if (defined(HNerg)) {kill HNerg;}
3795     list HNerg=HN(HNE_RingDATA,transformiert,eis[j],Aufruf_Ebene+1,
3796                                essential,getauscht,hne_conj,conj2[j]);
3797     HNE_RingDATA = HNerg[1];
3798     if (conj1==0) { conj1=HNerg[5]; }
3799     else  { conj1 = conj1,HNerg[5]; }
3800
3801     if (HNerg[3]==1) { field_ext=1; }
3802     if (HNerg[2]==lastRingnumber) { // kein Ringwechsel in HN aufgetreten
3803       if (not(defined(aneu))) { list aneu; }
3804       aneu = HNerg[4];
3805     }
3806     else { // Ringwechsel aufgetreten
3807       if (defined(HNDebugOn))
3808          {" ring change in HN(",Aufruf_Ebene+1,") detected";}
3809       EXTHNEnumber = HNerg[1][3];
3810       for (ii=lastRingnumber+1; ii<=EXTHNEnumber; ii++) {
3811         def EXTHNEring(ii)=HNerg[1][4][ii];
3812       }
3813       if (HNerg[2]==0) { setring HNEring; }
3814       else             { setring EXTHNEring(HNerg[2]); }
3815       def tempRing=HNerg[4];
3816       def aneu=imap(tempRing,HNEs);
3817       kill tempRing;
3818
3819       //--- stelle lokale Variablen im neuen Ring wieder her, und rette
3820       //    gegebenenfalls ihren Inhalt: ----
3821       list erg,faktoren,HNEakut;
3822       ideal hilfid;
3823       erg=ideal(0); faktoren=erg; HNEakut=erg;
3824       poly leitf,teiler,transformiert;
3825       map hole=HNE_noparam,transfproc,x,y;
3826       setring HNE_noparam;
3827       if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3828       else                  { def letztring=HNEring; }
3829       if (not defined(HNEs)) {list HNEs;}
3830       HNEs=imap(letztring,HNEs);
3831       if (not defined(azeilen)) {list azeilen;}
3832       azeilen=imap(letztring,azeilen);
3833       if (not defined(deltais)) {ideal deltais;}
3834       deltais=imap(letztring,deltais);
3835       if (not defined(delt)) {poly delt;}
3836       delt=imap(letztring,delt);
3837       if (not defined(fneu)) {poly fneu;}
3838       fneu=imap(letztring,fneu);
3839       if (not defined(f)) {poly f;}
3840       f=imap(letztring,f);
3841       if (not defined(hne)) {list hne;}
3842       hne=imap(letztring,hne);
3843
3844       setring EXTHNEring(EXTHNEnumber);
3845       list HNEs=hole(HNEs);
3846       list azeilen=hole(azeilen);
3847       ideal deltais=hole(deltais);
3848       number delt=number(hole(delt));
3849       poly fneu=hole(fneu);
3850       if (not(defined(f)))
3851       {
3852         poly f=hole(f);
3853         list hne=hole(hne);
3854         export f,hne;
3855       }
3856     }
3857
3858     //========== Verknuepfe bisherige HNE mit von HN gelieferten HNEs: ======
3859     if (R==0) {
3860       HNEs,hnezaehler=constructHNEs(HNEs,hnezaehler,aneu,azeilen,zeile,
3861                       deltais,Q,j);
3862       kill aneu;
3863     }
3864     else {
3865      for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3866       hnezaehler++;
3867       HNEakut=azeilen;          // dupliziere den gemeinsamen Anfang der HNE's
3868       zl=2;                     // (kommt schliesslich nach HNEs[hnezaehler])
3869       //------------ Trage Beitrag dieser Transformation T2 ein: -------------
3870       //------ Zur Bedeutung von zeile, zl: siehe Kommentar weiter oben ------
3871
3872       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3873       M1=M;N1=N;R1=R;Q1=M1/ N1;
3874       while (R1!=0) {
3875        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3876        HNEakut[1][zeile+zl-1]=Q1;
3877        HNEakut[zeile+zl][Q1+1]=x;    // Markierung des Zeilenendes der HNE
3878        zl=zl+1;
3879        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3880        HNEakut[zeile+zl]=ideal(0);
3881        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3882       }
3883       if (defined(HNDebugOn)) {
3884         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3885       }
3886       HNEakut[zeile+zl][Q1]=delt;
3887
3888       //-- Daten aus T2_Transform sind eingetragen; haenge Daten von HN an: --
3889       hilfid=HNEakut[zeile+zl];
3890       for (zl1=Q1+1; zl1<=ncols(aneu[zaehler][2]); zl1++) {
3891        hilfid[zl1]=aneu[zaehler][2][zl1];
3892       }
3893       HNEakut[zeile+zl]=hilfid;
3894       // ------ vorher HNEs[.][zeile+zl]<-aneu[.][2],
3895       //        jetzt [zeile+zl+1] <- [3] usw.: --------
3896       for (zl1=3; zl1<=size(aneu[zaehler]); zl1++) {
3897         HNEakut[zeile+zl+zl1-2]=aneu[zaehler][zl1];
3898       }
3899       //--- setze hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] --
3900       hilfvec=HNEakut[1],aneu[zaehler][1];
3901       HNEakut[1]=hilfvec;
3902       //-------- weil nicht geht: liste[1]=liste[1],aneu[zaehler][1] ---------
3903       HNEs[hnezaehler]=HNEakut;
3904      }                     // end(for zaehler)
3905     kill aneu;
3906     }                      // endelse (R<>0)
3907    }                       // endif (subst()!=0)  (weiteres Aufblasen mit HN)
3908
3909   }                        // end(for j) (Behandlung der einzelnen delta_i)
3910
3911
3912   // ------------------------- new for essdevelop ----------------------------
3913   if ((essential==1) and (defined(SaveRing))) {
3914     // ----- uebertrage Daten in gemeinsame Koerpererweiterung ---------------
3915     if (EXTHNEnumber>number_of_letztring) {
3916       // ----- fuer aktuelle Kante war Koerpererweiterung erforderlich -------
3917       EXTHNEnumber++;
3918       if (not(defined(minPol))) { poly miniPol; }
3919       miniPol=minpoly;
3920       setring SaveRing;
3921       if (not(defined(miniPol))) { poly miniPol; }
3922       miniPol=minpoly;
3923       setring HNE_noparam;
3924       if (not(defined(a_x))){ map a_x,a_y; poly mp_save, mp_new; }
3925       mp_save=imap(SaveRing,miniPol);
3926       mp_new=imap(EXTHNEring(EXTHNEnumber-1),miniPol);
3927       if (mp_save==mp_new) { // Sonderfall: wieder gleicher Ring
3928         def EXTHNEring(EXTHNEnumber)=SaveRing;
3929         setring EXTHNEring(EXTHNEnumber);
3930         if (not(defined(f))) {poly f; f=hole(f); export f;}
3931         list dummyL=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3932         if (not(defined(HNEs))) { def HNEs=list(); }
3933         if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3934         HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3935         kill dummyL,SaveRing;
3936       }
3937       else { // verschiedene Ringe
3938         a_x=HNE_noparam,x,0,0;
3939         a_y=HNE_noparam,y,0,0;
3940         mp_save=a_x(mp_save); // minpoly aus SaveRing mit a --> x
3941         mp_new=a_y(mp_new);   // minpoly aus SaveRing mit a --> y
3942         setring SaveRing;
3943         poly mp_new=imap(HNE_noparam,mp_new);
3944         list Lfac=factorize(mp_new,1);
3945         poly fac=Lfac[1][1];
3946         for (k=2;k<=size(Lfac[1]);k++) {
3947           if (deg(Lfac[1][k])<deg(fac)) { fac=Lfac[1][k]; }
3948         }
3949
3950         if (deg(fac)==1) { // keine Erweiterung noetig
3951           def EXTHNEring(EXTHNEnumber)=SaveRing;
3952           setring HNE_noparam;
3953           HNEs=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3954           setring EXTHNEring(EXTHNEnumber);
3955           if (not(defined(f))) {poly f; f=hole(f); export f;}
3956           map phi=HNE_noparam,-subst(fac,y,0)/koeff(fac,0,1),x,y;
3957           list dummyL=phi(HNEs);
3958           if (not(defined(HNEs))) { def HNEs=list(); }
3959           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3960           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3961           kill dummyL,phi,SaveRing;
3962         }
3963         else { // Koerpererweiterung noetig
3964           def EXTHNEring(EXTHNEnumber) = splitring(fac,list(a,transfproc));
3965           setring EXTHNEring(EXTHNEnumber);
3966           poly transf=erg[1];  // image of parameter from SaveRing
3967           poly transfproc=erg[2];
3968           poly transb=erg[3];  // image of parameter from EXTHNEring(..)
3969           export transfproc;
3970           kill erg;
3971           setring HNE_noparam;
3972           if (not(defined(HNEs1))) { list HNEs1=ideal(0); }
3973           HNEs1=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3974           if (not(defined(hne))) { list hne=ideal(0); }
3975           hne=imap(SaveRing,hne);
3976           HNEs=imap(SaveRing,HNEs);
3977           setring EXTHNEring(EXTHNEnumber);
3978           map hole=HNE_noparam,transf,x,y;
3979           poly fneu=hole(fneu);
3980           poly f=hole(f);
3981           map phi=HNE_noparam,transb,x,y;
3982           list HNEs=hole(HNEs);
3983           list hne=hole(hne);
3984           export f,hne;
3985           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3986           list dummyL=phi(HNEs1);
3987           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3988           kill dummyL,phi,SaveRing;
3989         }
3990       }
3991     }
3992     else { // nur bei letzter Kante muss was getan werden
3993       if (i==size(Newton)-1) {
3994         EXTHNEnumber++;
3995         if (number_of_letztring==0) { def letztring=HNEring; }
3996         else       { def letztring=EXTHNEring(EXTHNEnumber); }
3997         if (minpoly==0) {
3998           def EXTHNEring(EXTHNEnumber)=SaveRing;
3999           setring EXTHNEring(EXTHNEnumber);
4000           if (not(defined(f))) {poly f; f=hole(f); export f;}
4001           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
4002           list dummyL=imap(letztring,HNEs);
4003           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
4004           kill dummyL,letztring,SaveRing;
4005         }
4006         else { // muessen Daten nach SaveRing uebertragen;
4007           setring HNE_noparam;
4008           if (not(defined(HNEs))) { list HNEs; }
4009           HNEs=imap(letztring,HNEs);
4010           def EXTHNEring(EXTHNEnumber)=SaveRing;
4011           setring EXTHNEring(EXTHNEnumber);
4012           if (not(defined(hole))) { map hole; }
4013           hole=HNE_noparam,transfproc,x,y;
4014           list dummyL=hole(HNEs);
4015           if (not(defined(HNEs))) { def HNEs=list(); }
4016           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
4017           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
4018           kill dummyL, letztring,SaveRing;
4019         }
4020       }
4021     }
4022   }
4023   // -----------------end of new part (loop for essential=1) ----------------
4024  } // end (Loop uber Kanten)
4025  if (defined(SaveRing)) { kill SaveRing; }
4026 }
4027 else {
4028  HNEs[1]=list(hqs)+azeilen+list(fneu); // fneu ist transform. Polynom oder Null
4029  conj1[1]=conj_factor;
4030 }
4031
4032 if (Aufruf_Ebene == 1)
4033 {
4034   if ((number_of_letztring!=EXTHNEnumber) and (not(defined(hne))))
4035   {
4036     //----- falls Zweige in transz. Erw. berechnet werden konnten ---------
4037     if (defined(transfproc))
4038     { // --- Ringwechsel hat stattgefunden ---
4039       if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
4040       if (not(defined(hole))) { map hole; }
4041       hole=HNE_noparam,transfproc,x,y;
4042       setring HNE_noparam;
4043       f=imap(HNEring,f);
4044       if (number_of_letztring==0) { def letztring=HNEring; }
4045       else                        { def letztring=EXTHNEring(EXTHNEnumber); }
4046       if (not(defined(hne))) { list hne; }
4047       hne=imap(letztring,hne);
4048       setring EXTHNEring(EXTHNEnumber);
4049       if (not(defined(f))) { poly f=hole(f); export f; }
4050       list hne=hole(hne);
4051       export hne;
4052     }
4053   }
4054   if (size(HNEs)>0) {
4055     if ((size(HNEs)>1) or (typeof(HNEs[1])!="ideal") or (size(HNEs[1])>0)) {
4056       if ((typeof(hne[1])=="ideal")) { hne=list(); }
4057       hne=hne+extractHNEs(HNEs,getauscht);
4058       if (hne_conj==0) { hne_conj=conj1; }
4059       else { hne_conj = hne_conj, conj1; }
4060     }
4061   }
4062 }
4063 else
4064 { // HN wurde rekursiv aufgerufen
4065   if (number_of_letztring!=EXTHNEnumber)
4066   { // Ringwechsel hatte stattgefunden
4067     string mipl_alt = string(minpoly);
4068     execute("ring tempRing = ("+charstr(basering)+"),("+varstr(basering)+
4069                              "),("+ordstr(basering)+");");
4070     execute("minpoly="+ mipl_alt +";");
4071     list HNEs=imap(EXTHNEring(EXTHNEnumber),HNEs);
4072     export HNEs;
4073     if (defined(HNDebugOn)) {" ! tempRing defined ! ";}
4074   }
4075   if (conj1!=0) { hne_conj=conj1; }
4076   else          { hne_conj=conj_factor; }
4077 }
4078 if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
4079 HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring);
4080 if (number_of_letztring==EXTHNEnumber) {
4081   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,HNEs,hne_conj));
4082 }
4083 else {
4084   if (defined(tempRing)) {
4085     return(list(HNE_RingDATA,EXTHNEnumber,field_ext,tempRing,hne_conj));
4086   }
4087   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,0,hne_conj));
4088 }
4089}
4090
4091///////////////////////////////////////////////////////////////////////////////
4092
4093static proc constructHNEs (list HNEs,int hnezaehler,list aneu,list azeilen,
4094                    int zeile,ideal deltais,int Q,int j)
4095"NOTE: This procedure is only for internal use, it is called via HN"
4096{
4097  int zaehler,zl;
4098  ideal hilfid;
4099  list hilflist;
4100  intvec hilfvec;
4101  for (zaehler=1; zaehler<=size(aneu); zaehler++) {
4102     hnezaehler++;
4103     // HNEs[hnezaehler]=azeilen;            // dupliziere gemeins. Anfang
4104 //----------------------- trage neu berechnete Daten ein ---------------------
4105     hilfid=azeilen[zeile+2];
4106     hilfid[Q]=deltais[j];
4107     for (zl=Q+1; zl<=ncols(aneu[zaehler][2]); zl++) {
4108      hilfid[zl]=aneu[zaehler][2][zl];
4109     }
4110     hilflist=azeilen; hilflist[zeile+2]=hilfid;
4111 //------------------ haenge uebrige Zeilen von aneu[] an: --------------------
4112     for (zl=3; zl<=size(aneu[zaehler]); zl++) {
4113      hilflist[zeile+zl]=aneu[zaehler][zl];
4114     }
4115 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
4116     if (hilflist[1]==0) { hilflist[1]=aneu[zaehler][1]; }
4117     else { hilfvec=hilflist[1],aneu[zaehler][1]; hilflist[1]=hilfvec; }
4118     HNEs[hnezaehler]=hilflist;
4119  }
4120  return(HNEs,hnezaehler);
4121}
4122///////////////////////////////////////////////////////////////////////////////
4123
4124proc referencepoly (list newton)
4125"USAGE:   referencepoly(newton);
4126         newton is list of intvec(x,y) which represents points in the Newton
4127         diagram (e.g. output of the proc newtonpoly)
4128RETURN:  a polynomial which has newton as Newton diagram
4129SEE ALSO: newtonpoly
4130EXAMPLE: example referencepoly;  shows an example
4131"
4132{
4133 poly f;
4134 for (int i=1; i<=size(newton); i++) {
4135   f=f+var(1)^newton[i][1]*var(2)^newton[i][2];
4136 }
4137 return(f);
4138}
4139example
4140{ "EXAMPLE:"; echo = 2;
4141 ring exring=0,(x,y),ds;
4142 referencepoly(list(intvec(0,4),intvec(2,3),intvec(5,1),intvec(7,0)));
4143}
4144///////////////////////////////////////////////////////////////////////////////
4145
4146proc factorlist (list L, list #)
4147"USAGE:   factorlist(L);   L a list in the format of `factorize'
4148RETURN:  the nonconstant irreducible factors of
4149         L[1][1]^L[2][1] * L[1][2]^L[2][2] *...* L[1][size(L[1])]^...
4150         with multiplicities (same format as factorize)
4151SEE ALSO: factorize
4152EXAMPLE: example factorlist;  shows an example
4153"
4154{
4155 int k;
4156 if ((size(#)>=1) and ((typeof(#[1])=="intvec") or (typeof(#[1])=="int"))) {
4157   int with_conj = 1; intvec C = #[1];
4158 }
4159 else {
4160   int with_conj = 0; intvec C = L[2];
4161 }
4162 // eine Sortierung der Faktoren eruebrigt sich, weil keine zwei versch.
4163 // red.Fakt. einen gleichen irred. Fakt. haben koennen (I.3.27 Diplarb.)
4164 int i,gross;
4165 list faktoren,hilf;
4166 intvec conjugates;
4167 ideal hil1,hil2;
4168 intvec v,w,hilf_conj;
4169 for (i=1; (L[1][i] == jet(L[1][i],0)) && (i<size(L[1])); i++) {;}
4170 if (L[1][i] != jet(L[1][i],0)) {
4171   hilf=factorize(L[1][i]);
4172 // Achtung!!! factorize(..,2) wirft entgegen der Beschreibung nicht nur
4173 // konstante Faktoren raus, sondern alle Einheiten in der LOKALISIERUNG nach
4174 // der Monomordnung!!! Im Beispiel unten verschwindet der Faktor x+y+1, wenn
4175 // man ds statt dp als Ordnung nimmt!
4176   hilf_conj=C[i];
4177   for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4178   hilf[2]=hilf[2]*L[2][i];
4179   hil1=hilf[1];
4180   gross=size(hil1);
4181   if (gross>1) {
4182     v=hilf[2];
4183     faktoren=list(ideal(hil1[2..gross]),intvec(v[2..gross]));
4184     conjugates=intvec(hilf_conj[2..gross]);
4185   }
4186   else         { faktoren=hilf; conjugates=hilf_conj; }
4187 }
4188 else {
4189   faktoren=L;
4190   conjugates=C;
4191 }
4192
4193 for (i++; i<=size(L[2]); i++) {
4194 //------------------------- linearer Term -- irreduzibel ---------------------
4195   if (L[1][i] == jet(L[1][i],1)) {
4196     if (L[1][i] != jet(L[1][i],0)) {           // konst. Faktoren eliminieren
4197       hil1=faktoren[1];
4198       hil1[size(hil1)+1]=L[1][i];
4199       faktoren[1]=hil1;
4200       v=faktoren[2],L[2][i];
4201       conjugates=conjugates,C[i];
4202       faktoren[2]=v;
4203     }
4204   }
4205 //----------------------- nichtlinearer Term -- faktorisiere -----------------
4206   else {
4207     hilf=factorize(L[1][i]);
4208     hilf_conj=C[i];
4209     for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4210     hilf[2]=hilf[2]*L[2][i];
4211     hil1=faktoren[1];
4212     hil2=hilf[1];
4213     gross=size(hil2);
4214       // hil2[1] ist konstant, wird weggelassen:
4215     hil1[(size(hil1)+1)..(size(hil1)+gross-1)]=hil2[2..gross];
4216       // ideal+ideal does not work due to simplification;
4217       // ideal,ideal not allowed
4218     faktoren[1]=hil1;
4219     w=hilf[2];
4220     v=faktoren[2],w[2..gross];
4221     conjugates=conjugates,hilf_conj[2..gross];
4222     faktoren[2]=v;
4223   }
4224 }
4225 if (with_conj==0) { return(faktoren); }
4226 else { return(list(faktoren,conjugates)); }  // for essential development
4227}
4228example
4229{ "EXAMPLE:"; echo = 2;
4230 ring exring=0,(x,y),ds;
4231 list L=list(ideal(x,(x-y)^2*(x+y+1),x+y),intvec(2,2,1));
4232 L;
4233 factorlist(L);
4234}
4235
4236///////////////////////////////////////////////////////////////////////////////
4237
4238proc delta
4239"USAGE:  delta(INPUT);  INPUT a polynomial defining an isolated plane curve
4240         singularity at 0, or the Hamburger-Noether expansion thereof, i.e.
4241         the output of @code{develop(f)}, or the output of @code{hnexpansion(f)},
4242         or the list of HN data computed by @code{hnexpansion(f)}.
4243RETURN:  int, the delta invariant of the singularity at 0, that is, the vector
4244         space dimension of R~/R, (R~ the normalization of the local ring of
4245         the singularity).
4246NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
4247         for other purposes as well it is better to calculate this first
4248         with the aid of @code{hnexpansion} and use it as input instead of
4249         the polynomial itself.
4250SEE ALSO: deltaLoc, invariants
4251KEYWORDS: delta invariant
4252EXAMPLE: example delta;  shows an example
4253"
4254{
4255  if (typeof(#[1])=="poly") { // INPUT = polynomial defining the singularity
4256    list L=hnexpansion(#[1]);
4257    if (typeof(L[1])=="ring") {
4258      def altring = basering;
4259      def HNring = L[1]; setring HNring;
4260      return(delta(hne));
4261    }
4262    else {
4263      return(delta(L));
4264    }
4265  }
4266  if (typeof(#[1])=="ring") { // INPUT = HNEring of curve
4267    def HNring = #[1]; setring HNring;
4268    return(delta(hne));
4269  }
4270  if (typeof(#[1])=="matrix")
4271  { // INPUT = hne of an irreducible curve
4272    return(invariants(#)[5]/2);
4273  }
4274  else
4275  { // INPUT = hne of a reducible curve
4276    list INV=invariants(#);
4277    return(INV[size(INV)][3]);
4278  }
4279}
4280example
4281{ "EXAMPLE:"; echo = 2;
4282  ring r = 32003,(x,y),ds;
4283  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
4284           +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
4285           -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
4286           +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
4287  delta(f);
4288}
4289
4290///////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.