source: git/Singular/LIB/hnoether.lib @ 699fed

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