source: git/Singular/LIB/hnoether.lib

spielwiese
Last change on this file was e78236, checked in by Hans Schoenemann <hannes@…>, 11 months ago
format
  • Property mode set to 100644
File size: 153.0 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     list l2;
2019     for (int zz = 0; zz <= size(v)-1; zz++)
2020     {
2021       l2[size(l2)+1] = "z("+string(zz)+")";
2022     }
2023     ring dazu = create_ring(ringlist(basering)[1], l2, "ls", "no_minpoly");
2024   }
2025   else { ring dazu=char(altring),z(0..size(v)-1),ls; }
2026 }
2027 else   { ring dazu=char(altring),z(0..size(v)-1),ls; }
2028 def displayring=dazu+altring;
2029*/
2030 list l1;
2031 for (int zz = 0; zz <= size(v)-1; zz++)
2032 {
2033   l1[size(l1)+1] = "z("+string(zz)+")";
2034 }
2035 list l2=ringlist(basering)[2];
2036 l1 = l1 + l2;
2037 ring displayring = create_ring(ringlist(basering)[1], l1, "(ls("+string(size(v))+"),"+ordstr(basering)+")", "no_minpoly");
2038 // End change by T. Keilen
2039 //////////////////////////////////////////////////////////////
2040 setring displayring;
2041 map holematrix=altring,0;        // mappt nur die Monome vom Grad Null
2042 matrix m=holematrix(m);
2043 int i,j;
2044
2045 // lossen: check the last row for finiteness (06/2004)
2046 int rowM=nrows(m);
2047 int colM=ncols(m);
2048 int undef_bd=v[size(v)];
2049 if ( undef_bd<-1 ){
2050   for (j=-undef_bd; j<=colM; j++) { m[rowM,j]=0; }
2051 }
2052
2053 //--------------------- Erzeuge Matrix n mit n[i,j]=z(j-1)^i -----------------
2054 matrix n[colM][rowM];
2055 for (j=1; j<=rowM; j++) {
2056    for (i=1; i<=colM; i++) { n[i,j]=z(j-1)^i; }
2057 }
2058 matrix displaymat=m*n;
2059 ideal HNE;
2060 for (i=1; i<rowM; i++) { HNE[i]=displaymat[i,i]+z(i)*z(i-1)^v[i]; }
2061 HNE[rowM]=displaymat[rowM,rowM];
2062
2063 // lossen: output modified (06/2004)
2064 if (size(#) == 0)
2065 {
2066   if (switch==0) {
2067     HNE=subst(HNE,z(0),var(size(v)+1));
2068   }
2069   else  {
2070     HNE=subst(HNE,z(0),var(size(v)+2));
2071   }
2072
2073   for (j=1; j<=ncols(HNE); j++){
2074     string stHNE(j)=string(HNE[j]);
2075   }
2076   if (undef_bd<-1)
2077   {
2078     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2079                                 +string(-undef_bd)+")";
2080   }
2081   if (undef_bd==-1)
2082   {
2083     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2084                                 +string(colM+1)+")";
2085   }
2086
2087   if (switch==0) {
2088     stHNE(1) = "  "+string(var(size(v)+2))+" = "+stHNE(1);
2089   }
2090   else {
2091     stHNE(1) = "  "+string(var(size(v)+1))+" = "+stHNE(1);
2092   }
2093   stHNE(1);
2094   if (ncols(HNE)==1) {return();}
2095
2096   if (switch==0) {
2097     stHNE(2) = "  "+string(var(size(v)+1))+" = "+stHNE(2);
2098   }
2099   else {
2100     stHNE(2) = "  "+string(var(size(v)+2))+" = "+stHNE(2);
2101   }
2102   stHNE(2);
2103
2104   for (j=3; j<=ncols(HNE); j++){
2105     stHNE(j)= "  "+"z(" +string(j-2)+ ") = "+stHNE(j);
2106     stHNE(j);
2107   }
2108   return();
2109 }
2110
2111 if (rowM<2) { HNE[2]=z(0); }
2112
2113 if (switch==0) {
2114    HNE[1] = HNE[1]-var(size(v)+2);
2115    HNE[2] = HNE[2]-var(size(v)+1);
2116 }
2117 else {
2118    HNE[1] = HNE[1]-var(size(v)+1);
2119    HNE[2] = HNE[2]-var(size(v)+2);
2120 }
2121if (size(#) == 0) {
2122   HNE;
2123   return();
2124 }
2125if (size(#) != 0) {
2126   HNE;
2127   export(HNE);
2128   return(displayring);
2129 }
2130}
2131example
2132{ "EXAMPLE:"; echo = 2;
2133  ring r=0,(x,y),dp;
2134  poly f=x3+2xy2+y2;
2135  list hn=develop(f);
2136  displayHNE(hn);
2137}
2138///////////////////////////////////////////////////////////////////////////////
2139//                      procedures for reducible curves                      //
2140///////////////////////////////////////////////////////////////////////////////
2141
2142// proc newtonhoehne (poly f)
2143// USAGE:   newtonhoehne(f);   f poly
2144// ASSUME:  basering = ...,(x,y),ds  or ls
2145// RETURN:  list of intvec(x,y) of coordinates of the newtonpolygon of f
2146// NOTE:    This proc is only available in versions of Singular that know the
2147//         command  system("newton",f);  f poly
2148// {
2149// intvec nm = getnm(f);
2150//  if ((nm[1]>0) && (nm[2]>0)) { f=jet(f,nm[1]*nm[2],nm); }
2151//  list erg=system("newton",f);
2152//  int i; list Ausgabe;
2153//  for (i=1; i<=size(erg); i++) { Ausgabe[i]=leadexp(erg[i]); }
2154// return(Ausgabe);
2155// }
2156///////////////////////////////////////////////////////////////////////////////
2157
2158proc newtonpoly (poly f, int #)
2159"USAGE:   newtonpoly(f);   f poly
2160ASSUME:  basering has exactly two variables; @*
2161         f is convenient, that is, f(x,0) != 0 != f(0,y).
2162RETURN:  list of intvecs (= coordinates x,y of the Newton polygon of f).
2163NOTE:    Procedure uses @code{execute}; this can be avoided by calling
2164         @code{newtonpoly(f,1)} if the ordering of the basering is @code{ls}.
2165KEYWORDS: Newton polygon
2166EXAMPLE: example newtonpoly;  shows an example
2167"
2168{
2169  if (size(#)>=1)
2170  {
2171    if (typeof(#[1])=="int")
2172    {
2173      // this is done to avoid the "execute" command for procedures in
2174      //  hnoether.lib
2175      def is_ls=#[1];
2176    }
2177  }
2178  if (defined(is_ls)<=0)
2179  {
2180    def @Rold=basering;
2181    ring @RR = create_ring(ringlist(basering)[1],"("+varstr(basering)+")","ls","no_minpoly");
2182    poly f=imap(@Rold,f);
2183  }
2184  intvec A=(0,ord(subst(f,var(1),0)));
2185  intvec B=(ord(subst(f,var(2),0)),0);
2186  intvec C,H; list L;
2187  int abbruch,i;
2188  poly hilf;
2189  L[1]=A;
2190  f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]));
2191  if (defined(is_ls))
2192  {
2193    map xytausch=basering,var(2),var(1);
2194  }
2195  else
2196  {
2197    map xytausch=@RR,var(2),var(1);
2198  }
2199  for (i=2; f!=0; i++)
2200  {
2201     abbruch=0;
2202     while (abbruch==0)
2203     {
2204        C=leadexp(f);
2205        if(jet(f,A[2]*C[1]-A[1]*C[2]-1,intvec(A[2]-C[2],C[1]-A[1]))==0)
2206        {
2207           abbruch=1;
2208        }
2209        else
2210        {
2211           f=jet(f,-C[1]-1,intvec(-1,0));
2212        }
2213    }
2214    hilf=jet(f,A[2]*C[1]-A[1]*C[2],intvec(A[2]-C[2],C[1]-A[1]));
2215    H=leadexp(xytausch(hilf));
2216    A=H[2],H[1];
2217    L[i]=A;
2218    f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]-A[1]));
2219  }
2220  L[i]=B;
2221  if (defined(is_ls))
2222  {
2223    return(L);
2224  }
2225  else
2226  {
2227    setring @Rold;
2228    return(L);
2229  }
2230}
2231example
2232{
2233 "EXAMPLE:"; echo = 2;
2234  ring r=0,(x,y),ls;
2235  poly f=x5+2x3y-x2y2+3xy5+y6-y7;
2236  newtonpoly(f);
2237}
2238///////////////////////////////////////////////////////////////////////////////
2239
2240proc is_NND (poly f, list #)
2241"USAGE:   is_NND(f[,mu,NP]);   f poly, mu int, NP list of intvecs
2242ASSUME:  f is convenient, that is, f(x,0) != 0 != f(0,y);@*
2243         mu (optional) is Milnor number of f.@*
2244         NP (optional) is output of @code{newtonpoly(f)}.
2245RETURN:  int: 1 if f is Newton non-degenerate, 0 otherwise.
2246SEE ALSO: newtonpoly
2247KEYWORDS: Newton non-degenerate; Newton polygon
2248EXAMPLE: example is_NND;  shows examples
2249"
2250{
2251  int i;
2252  int i_print=printlevel-voice+2;
2253
2254  if (size(#)==0)
2255  {
2256    int mu=milnor(f);
2257    list NP=newtonpoly(f);
2258  }
2259  else
2260  {
2261    if (typeof(#[1])=="int")
2262    {
2263      def mu=#[1];
2264      def NP=#[2];
2265      for (i=1;i<=size(NP);i++)
2266      {
2267        if (typeof(NP[i])!="intvec")
2268        {
2269          print("third input cannot be Newton polygon ==> ignored ")
2270          NP=newtonpoly(f);
2271          i=size(NP)+1;
2272        }
2273      }
2274    }
2275    else
2276    {
2277      print("second input cannot be Milnor number ==> ignored ")
2278      int mu=milnor(f);
2279      NP=newtonpoly(f);
2280    }
2281  }
2282
2283  // computation of the Newton number:
2284  int s=size(NP);
2285  int nN=-NP[1][2]-NP[s][1]+1;
2286  intmat m[2][2];
2287  for(i=1;i<=s-1;i++)
2288  {
2289    m=NP[i+1],NP[i];
2290    nN=nN+det(m);
2291  }
2292
2293  if(mu==nN)
2294  { // the Newton-polygon is non-degenerate
2295    // REFERENCE? (tfuer mehr als 2 Variable gilt nicht, dass mu=nu impliziert,
2296    // dass NP nicht ausgeartet ist!, Siehe KOMMENTAR in equising.lib in esIdeal)
2297    return(1);
2298  }
2299  else
2300  {
2301    return(0);
2302  }
2303}
2304example
2305{
2306 "EXAMPLE:"; echo = 2;
2307  ring r=0,(x,y),ls;
2308  poly f=x5+y3;
2309  is_NND(f);
2310  poly g=(x-y)^5+3xy5+y6-y7;
2311  is_NND(g);
2312
2313  // if already computed, one should give the Minor number and Newton polygon
2314  // as second and third input:
2315  int mu=milnor(g);
2316  list NP=newtonpoly(g);
2317  is_NND(g,mu,NP);
2318}
2319
2320
2321///////////////////////////////////////////////////////////////////////////////
2322
2323proc charPoly(poly f, int M, int N)
2324"USAGE:  charPoly(f,M,N);  f bivariate poly,  M,N int: length and height
2325                          of Newton polygon of f, which has to be only one line
2326RETURN:  the characteristic polynomial of f
2327EXAMPLE: example charPoly;  shows an example
2328"
2329{
2330 poly charp;
2331 int Np=N div gcd(M,N);
2332 f=subst(f,var(1),1);
2333 for(charp=0; f<>0; f=f-lead(f))
2334  { charp=charp+leadcoef(f)*var(2)^(leadexp(f)[2] div Np);}
2335 return(charp);
2336}
2337example
2338{ "EXAMPLE:"; echo = 2;
2339  ring exring=0,(x,y),dp;
2340  charPoly(y4+2y3x2-yx6+x8,8,4);
2341  charPoly(y6+3y3x2-x4,4,6);
2342}
2343///////////////////////////////////////////////////////////////////////////////
2344
2345proc find_in_list(list L,int p)
2346"USAGE:   find_in_list(L,p); L: list of intvec(x,y)
2347         (sorted in y: L[1][2]>=L[2][2]), int p >= 0
2348RETURN:  int i: L[i][2]=p if existent; otherwise i with L[i][2]<p if existent;
2349         otherwise i = size(L)+1;
2350EXAMPLE: example find_in_list;  shows an example
2351"
2352{
2353 int i;
2354 L[size(L)+1]=intvec(0,-1);          // falls p nicht in L[.][2] vorkommt
2355 for (i=1; L[i][2]>p; i++) {;}
2356 return(i);
2357}
2358example
2359{ "EXAMPLE:"; echo = 2;
2360  list L = intvec(0,4), intvec(1,2), intvec(2,1), intvec(4,0);
2361  find_in_list(L,1);
2362  L[find_in_list(L,2)];
2363}
2364///////////////////////////////////////////////////////////////////////////////
2365
2366proc get_last_divisor(int M, int N)
2367"USAGE:   get_last_divisor(M,N); int M,N
2368RETURN:  int Q: M=q1*N+r1, N=q2*r1+r2, ..., ri=Q*r(i+1) (Euclidean alg.)
2369EXAMPLE: example get_last_divisor; shows an example
2370"
2371{
2372 int R=M%N; int Q=M div N;
2373 while (R!=0) {M=N; N=R; R=M%N; Q=M div N;}
2374 return(Q)
2375}
2376example
2377{ "EXAMPLE"; echo = 2;
2378  ring r=0,(x,y),dp;
2379  get_last_divisor(12,10);
2380}
2381///////////////////////////////////////////////////////////////////////////////
2382proc redleit (poly f,intvec S, intvec E)
2383"USAGE:   redleit(f,S,E);  f poly, S,E intvec(x,y)
2384         S,E are two different points on a line in the Newton diagram of f
2385RETURN:  poly g: all monomials of f which lie on or below that line
2386NOTE:    The main purpose is that if the line defined by S and E is part of the
2387         Newton polygon, the result is the quasihomogeneous leading form of f
2388         w.r.t. that line.
2389SEE ALSO: newtonpoly
2390EXAMPLE: example redleit;  shows an example
2391"
2392{
2393 if (E[1]<S[1]) { intvec H=E; E=S; S=H; } // S,E verkehrt herum eingegeben
2394 return(jet(f,E[1]*S[2]-E[2]*S[1],intvec(S[2]-E[2],E[1]-S[1])));
2395}
2396example
2397{ "EXAMPLE"; echo = 2;
2398  ring exring=0,(x,y),dp;
2399  redleit(y6+xy4-2x3y2+x4y+x6,intvec(3,2),intvec(4,1));
2400}
2401///////////////////////////////////////////////////////////////////////////////
2402
2403
2404proc extdevelop (list l, int Exaktheit)
2405"USAGE:   extdevelop(L,N); list L, int N
2406ASSUME:  L is the output of @code{develop(f)}, or of @code{extdevelop(l,n)},
2407         or one entry in the list @code{hne} in the ring created by
2408          @code{hnexpansion(f[,\"ess\"])}.
2409RETURN:  an extension of the Hamburger-Noether development of f as a list
2410         in the same format as L has (up to the last entry in the output
2411         of @code{develop(f)}).@*
2412         Type @code{help develop;}, resp. @code{help hnexpansion;} for more
2413         details.
2414NOTE:    The new HN-matrix will have at least N columns (if the HNE is not
2415         finite). In particular, if f is irreducible then (in most cases)
2416         @code{extdevelop(develop(f),N)} will produce the same result as
2417         @code{develop(f,N)}.@*
2418         If the matrix M of L has n columns then, compared with
2419         @code{parametrization(L)}, @code{paramametrize(extdevelop(L,N))} will increase the
2420         exactness by at least (N-n) more significant monomials.
2421SEE ALSO: develop, hnexpansion, param
2422EXAMPLE: example extdevelop;  shows an example
2423"
2424{
2425 //------------ Initialisierungen und Abfangen unzulaessiger Aufrufe ----------
2426 matrix m=l[1];
2427 intvec v=l[2];
2428 int switch=l[3];
2429 if (nvars(basering) < 2) {
2430   " Sorry. I need two variables in the ring.";
2431   return(list(matrix(maxideal(1)[1]),intvec(0),-1,poly(0)));}
2432 if (switch==-1) {
2433   "An error has occurred in develop, so there is no HNE and no extension.";
2434   return(l);
2435 }
2436 poly f=l[4];
2437 if (f==0) {
2438   " No extension is possible";
2439   return(l);
2440 }
2441 int Q=v[size(v)];
2442 if (Q>0) {
2443   " The HNE was already exact";
2444   return(l);
2445 }
2446 else {
2447   if (Q==-1) { Q=ncols(m); }
2448   else { Q=-Q-1; }
2449 }
2450 int zeile=nrows(m);
2451 int spalten,i,M;
2452 ideal lastrow=m[zeile,1..Q];
2453 int ringwechsel=(varstr(basering)!="x,y") or (ordstr(basering)!="ls(2),C");
2454
2455 //------------------------- Ringwechsel, falls noetig ------------------------
2456 if (ringwechsel) {
2457  def altring = basering;
2458  int p = char(basering);
2459  //if (charstr(basering)!=string(p))
2460  if(hasAlgExtensionCoefficient(basering)
2461  or hasTransExtensionCoefficient(basering)
2462  or hasGFCoefficient(basering))
2463  {
2464     string tststr=charstr(basering);
2465     tststr=tststr[1..find(tststr,",")-1];     //-> "p^k" bzw. "p"
2466     //if (tststr==string(p))
2467     if (!hasGFCoefficient(basering))
2468     {
2469       if (npars(basering)>1) {         // ring (p,a,..),...
2470        ring extdguenstig = create_ring(ringlist(basering)[1],"(x,y)","ls","no_minpoly");
2471       }
2472       else {                                  // ring (p,a),...
2473        list rl=ringlist(basering);
2474        rl[1][1]=p;
2475        ring extdguenstig=ring(rl);
2476       }
2477     }
2478     else {
2479       ring extdguenstig = create_ring(ringlist(basering)[1],"(x,y)","ls","no_minpoly");
2480     }
2481  }
2482  else {                               // charstr(basering)== p : no parameter
2483     ring extdguenstig=p,(x,y),ls;
2484  }
2485  export extdguenstig;
2486  map hole=altring,x,y;
2487 //----- map kann sehr zeitaufwendig sein, daher Vermeidung, wo moeglich: -----
2488  if (nvars(altring)==2) { poly f=fetch(altring,f); }
2489  else                   { poly f=hole(f);          }
2490  ideal a=hole(lastrow);
2491 }
2492 else { ideal a=lastrow; }
2493 list Newton=newtonpoly(f,1);
2494 int M1=Newton[size(Newton)-1][1];     // konstant
2495 number delt;
2496 if (Newton[size(Newton)-1][2]!=1) {
2497    " *** The transformed polynomial was not valid!!";}
2498 else {
2499 //--------------------- Fortsetzung der HNE ----------------------------------
2500  while (Q<Exaktheit) {
2501    M=ord(subst(f,y,0));
2502    Q=M-M1;
2503 //------ quasihomogene Leitform ist c*x^M1*y+d*x^(M1+Q) => delta=-d/c: -------
2504    delt=-koeff(f,M,0)/koeff(f,M1,1);
2505    a[Q]=delt;
2506    dbprint(printlevel-voice+2,"a("+string(zeile-1)+","+string(Q)+") = "+string(delt));
2507    if (Q<Exaktheit) {
2508     f=T1_Transform(f,delt,Q);
2509     if (defined(HNDebugOn)) { "transformed polynomial:",f; }
2510     if (subst(f,y,0)==0) {
2511       dbprint(printlevel-voice+2,"The HNE is finite!");
2512       a[Q+1]=x; Exaktheit=Q;
2513       f=0;                        // Speicherersparnis: f nicht mehr gebraucht
2514     }
2515    }
2516  }
2517 }
2518 //------- Wechsel in alten Ring, Zusammensetzung alte HNE + Erweiterung ------
2519 if (ringwechsel) {
2520  setring altring;
2521  map zurueck=extdguenstig,var(1),var(2);
2522  if (nvars(altring)==2) { f=fetch(extdguenstig,f); }
2523  else                   { f=zurueck(f);            }
2524  lastrow=zurueck(a);
2525 }
2526 else { lastrow=a; }
2527 if (ncols(lastrow)>ncols(m)) { spalten=ncols(lastrow); }
2528 else { spalten=ncols(m); }
2529 matrix mneu[zeile][spalten];
2530 for (i=1; i<nrows(m); i++) {
2531  mneu[i,1..ncols(m)]=m[i,1..ncols(m)];
2532 }
2533 mneu[zeile,1..ncols(lastrow)]=lastrow;
2534 if (lastrow[ncols(lastrow)]!=var(1)) {
2535  if (ncols(lastrow)==spalten) { v[zeile]=-1; }  // keine undefinierten Stellen
2536  else {
2537   v[zeile]=-Q-1;
2538   for (i=ncols(lastrow)+1; i<=spalten; i++) {
2539    mneu[zeile,i]=var(2);           // fuelle nicht def. Stellen der Matrix auf
2540 }}}
2541 else { v[zeile]=Q; }               // HNE war exakt
2542 if (ringwechsel)
2543 {
2544   kill extdguenstig;
2545 }
2546
2547 return(list(mneu,v,switch,f));
2548}
2549example
2550{
2551  "EXAMPLE:"; echo = 2;
2552  ring exring=0,(x,y),dp;
2553  list Hne=hnexpansion(x14-3y2x11-y3x10-y2x9+3y4x8+y5x7+3y4x6+x5*(-y6+y5)
2554                      -3y6x3-y7x2+y8);
2555  displayHNE(Hne);    // HNE of 1st,3rd branch is finite
2556  print(extdevelop(Hne[1],5)[1]);
2557  list ehne=extdevelop(Hne[2],5);
2558  displayHNE(ehne);
2559  param(Hne[2]);
2560  param(ehne);
2561
2562}
2563///////////////////////////////////////////////////////////////////////////////
2564
2565proc stripHNE (list l)
2566"USAGE:   stripHNE(L);  L list
2567ASSUME:  L is the output of @code{develop(f)}, or of
2568         @code{extdevelop(develop(f),n)}, or (one entry of) the list
2569         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2570RETURN:  list in the same format as L, but all polynomials L[4], resp.
2571         L[i][4], are set to zero.
2572NOTE:    The purpose of this procedure is to remove huge amounts of data
2573         no longer needed. It is useful, if one or more of the polynomials
2574         in L consume much memory. It is still possible to compute invariants,
2575         parametrizations etc. with the stripped HNE(s), but it is not possible
2576         to use @code{extdevelop} with them.
2577SEE ALSO: develop, hnexpansion, extdevelop
2578EXAMPLE: example stripHNE;  shows an example
2579"
2580{
2581 list h;
2582 if (typeof(l[1])=="matrix") { l[4]=poly(0); }
2583 else {
2584  for (int i=1; i<=size(l); i++) {
2585    h=l[i];
2586    h[4]=poly(0);
2587    l[i]=h;
2588  }
2589 }
2590 return(l);
2591}
2592example
2593{
2594  "EXAMPLE:"; echo = 2;
2595  ring r=0,(x,y),dp;
2596  list Hne=develop(x2+y3+y4);
2597  Hne;
2598  stripHNE(Hne);
2599}
2600///////////////////////////////////////////////////////////////////////////////
2601static proc extractHNEs(list HNEs, int transvers)
2602"USAGE:  extractHNEs(HNEs,transvers);  list HNEs (output from HN),
2603        int transvers: 1 if x,y were exchanged, 0 else
2604RETURN: list of Hamburger-Noether-Extensions in the form of hne in hnexpansion
2605NOTE:   This procedure is only for internal purpose; examples don't make sense
2606"
2607{
2608 int i,maxspalte,hspalte,hnezaehler;
2609 list HNEaktu,Ergebnis;
2610 for (hnezaehler=1; hnezaehler<=size(HNEs); hnezaehler++) {
2611  maxspalte=0;
2612  HNEaktu=HNEs[hnezaehler];
2613  if (defined(HNDebugOn)) {"To process:";HNEaktu;}
2614  if (size(HNEaktu)!=size(HNEaktu[1])+2) {
2615     "The ideals and the hqs in HNEs[",hnezaehler,"] don't match!!";
2616     HNEs[hnezaehler];
2617  }
2618 //------------ ermittle  maximale Anzahl benoetigter Spalten: ----------------
2619  for (i=2; i<size(HNEaktu); i++) {
2620    hspalte=ncols(HNEaktu[i]);
2621    maxspalte=maxspalte*(hspalte < maxspalte)+hspalte*(hspalte >= maxspalte);
2622  }
2623 //------------- schreibe Ausgabe fuer hnezaehler-ten Zweig: ------------------
2624  matrix ma[size(HNEaktu)-2][maxspalte];
2625  for (i=1; i<=(size(HNEaktu)-2); i++) {
2626    if (ncols(HNEaktu[i+1]) > 1) {
2627      ma[i,1..ncols(HNEaktu[i+1])]=HNEaktu[i+1]; }
2628    else { ma[i,1]=HNEaktu[i+1][1];}
2629  }
2630  Ergebnis[hnezaehler]=list(ma,HNEaktu[1],transvers,HNEaktu[size(HNEaktu)]);
2631  kill ma;
2632 }
2633 return(Ergebnis);
2634}
2635///////////////////////////////////////////////////////////////////////////////
2636
2637proc factorfirst(poly f, int M, int N)
2638"USAGE : factorfirst(f,M,N); f poly, M,N int
2639RETURN: number d such that f=const*(y^(N/e) - d*x^(M/e))^e, where e=gcd(M,N),
2640        0 if such a d does not exist
2641EXAMPLE: example factorfirst;  shows an example
2642"
2643{
2644 number c = koeff(f,0,N);
2645 number delt;
2646 int eps,l;
2647 int p=char(basering);
2648
2649 if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
2650 int e = gcd(M,N);
2651
2652 if (p==0) { delt = koeff(f,M div e,N - N div e) / (-1*e*c); }
2653 else {
2654   if (e%p != 0) { delt = koeff(f,M div e,N - N div e) / (-1*e*c); }
2655   else {
2656     eps = e;
2657     for (l = 0; eps%p == 0; l=l+1) { eps=eps div p;}
2658     if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
2659     delt = koeff(f,(M div e)*p^l,(N div e)*p^l*(eps-1)) / (-1*eps*c);
2660
2661     if ((!hasZpCoefficient(basering)) and (delt != 0)) {
2662 //------ coefficient field is not Z/pZ => (p^l)th root is not identity -------
2663       delt=0;
2664       if (defined(HNDebugOn)) {
2665         "trivial factorization not implemented for",
2666         "parameters---I've to use 'factorize'";
2667       }
2668     }
2669   }
2670 }
2671 if (defined(HNDebugOn)) {"quasihomogeneous leading form:",f," = ",c,
2672        "* (y^"+string(N div e),"-",delt,"* x^"+string(M div e)+")^",e," ?";}
2673 if (f != c*(var(2)^(N div e) - delt*var(1)^(M div e))^e) {return(0);}
2674 else {return(delt);}
2675}
2676example
2677{ "EXAMPLE:"; echo = 2;
2678  ring exring=7,(x,y),dp;
2679  factorfirst(2*(y3-3x4)^5,20,15);
2680  factorfirst(x14+y7,14,7);
2681  factorfirst(x14+x8y3+y7,14,7);
2682}
2683
2684///////////////////////////////////////////////////////////////////////////
2685
2686proc hnexpansion(poly f,list #)
2687"USAGE:   hnexpansion(f[,\"ess\"]);   f poly
2688ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2689RETURN:  list @code{L}, containing Hamburger-Noether data of @code{f}:
2690         If the computation of the HNE required no field extension, @code{L}
2691         is a list of lists @code{L[i]} (corresponding to the output of
2692         @code{develop}, applied to a branch of @code{f}, but the last entry
2693         being omitted):
2694@texinfo
2695@table @asis
2696@item @code{L[i][1]}; matrix:
2697         Each row contains the coefficients of the corresponding line of the
2698         Hamburger-Noether expansion (HNE) for the i-th branch. The end of
2699         the line is marked in the matrix by the first ring variable
2700         (usually x).
2701@item @code{L[i][2]}; intvec:
2702         indicating the length of lines of the HNE
2703@item @code{L[i][3]}; int:
2704         0  if the 1st ring variable was transversal (with respect to the
2705            i-th branch), @*
2706         1  if the variables were changed at the beginning of the
2707            computation, @*
2708        -1  if an error has occurred.
2709@item @code{L[i][4]}; poly:
2710         the transformed equation of the i-th branch to make it possible
2711         to extend the Hamburger-Noether data a posteriori without having
2712         to do all the previous calculation once again (0 if not needed).
2713@end table
2714@end texinfo
2715         If the computation of the HNE required a field extension, the first
2716         entry @code{L[1]} of the list is a ring, in which a list @code{hne}
2717         of lists (the HN data, as above) and a polynomial @code{f} (image of
2718         @code{f} over the new field) are stored.
2719         @*
2720         If called with an additional input parameter, @code{hnexpansion}
2721         computes only one representative for each class of conjugate
2722         branches (over the ground field active when calling the procedure).
2723         In this case, the returned list @code{L} always has only two
2724         entries: @code{L[1]} is either a list of lists (the HN data) or a
2725         ring (as above), and @code{L[2]} is an integer vector (the number
2726         of branches in the respective conjugacy classes).
2727
2728NOTE:    If f is known to be irreducible as a power series, @code{develop(f)}
2729         could be chosen instead to avoid a change of basering during the
2730         computations. @*
2731         Increasing  @code{printlevel} leads to more and more comments. @*
2732         Having defined a variable @code{HNDebugOn} leads to a maximum
2733         number of comments.
2734
2735SEE ALSO: develop, extdevelop, param, displayHNE
2736EXAMPLE: example hnexpansion;  shows an example
2737"
2738{
2739 int essential;
2740 if (size(#)==1) { essential=1; }
2741 int field_ext;
2742 def altring=basering;
2743
2744 //--------- Falls Ring (p^k,a),...: Wechsel in (p,a),... + minpoly -----------
2745 if ( hasGFCoefficient(basering) )
2746 {
2747   string strmip=string(minpoly);
2748   string strf=string(f);
2749   ring tempr = create_ring("("+string(char(basering))+","+parstr(basering)+")", "("+varstr(basering)+")", "dp");
2750   execute("minpoly="+strmip+";");
2751   execute("poly f="+strf+";");
2752   field_ext=1;
2753   def L=pre_HN(f,essential);
2754   if (size(L)==0) { return(list()); }
2755   def HNEring=L[1];
2756   setring HNEring;
2757   if ((typeof(hne[1])=="ideal")) { return(list()); }
2758   if ((voice==2) && (printlevel > -1)) {
2759     "// Attention: The parameter",par(1),"may have changed its meaning!";
2760     "// It needs no longer be a generator of the cyclic group of unities!";
2761   }
2762   dbprint(printlevel-voice+2,
2763     "// result: "+string(size(hne))+" branch(es) successfully computed.");
2764 }
2765 else {
2766   def L=pre_HN(f,essential);
2767   if (size(L)==0) { return(list()); }
2768   if (L[2]==1) { field_ext=1; }
2769   intvec hne_conj=L[3];
2770   def HNEring=L[1];
2771   setring HNEring;
2772   if ((typeof(hne[1])=="ideal")) { return(list()); }
2773   dbprint(printlevel-voice+2,
2774      "// result: "+string(size(hne))+" branch(es) successfully computed.");
2775 }
2776
2777 // ----- Lossen 10/02 : the branches have to be resorted to be able to
2778 // -----                display the multsequence in a nice way
2779 if (size(hne)>2)
2780 {
2781   int i,j,k,m;
2782   list dummy;
2783   int nbsave;
2784   int no_br = size(hne);
2785   intmat nbhd[no_br][no_br];
2786   for (i=1;i<no_br;i++)
2787   {
2788     for (j=i+1;j<=no_br;j++)
2789     {
2790       nbhd[i,j]=separateHNE(hne[i],hne[j]);
2791       k=i+1;
2792       while ( (nbhd[i,k] >= nbhd[i,j]) and (k<j) )
2793       {
2794         k++;
2795       }
2796       if (k<j)  // branches have to be resorted
2797       {
2798         dummy=hne[j];
2799         nbsave=nbhd[i,j];
2800         for (m=k; m<j; m++)
2801         {
2802           hne[m+1]=hne[m];
2803           nbhd[i,m+1]=nbhd[i,m];
2804         }
2805         hne[k]=dummy;
2806         nbhd[i,k]=nbsave;
2807       }
2808     }
2809   }
2810 }
2811 // -----
2812
2813 if (field_ext==1) {
2814   dbprint(printlevel-voice+3,"
2815// 'hnexpansion' created a list of one ring.
2816// To see the ring and the data stored in the ring, type (if you assigned
2817// the name L to the list):
2818     show(L);
2819// To display the computed HN expansion, type
2820     def HNring = L[1]; setring HNring;  displayHNE(hne); ");
2821   if (essential==1) {
2822     dbprint(printlevel-voice+3,""+
2823"// As second entry of the returned list L, you obtain an integer vector,
2824// indicating the number of conjugates for each of the computed branches.");
2825     return(list(HNEring,hne_conj));
2826   }
2827   return(list(HNEring));
2828 }
2829 else { // no change of basering necessary --> map data to original ring
2830   setring altring;
2831   if ((npars(altring)==1) and (minpoly!=0)) {
2832     ring HNhelpring=char(altring),(a,x,y),ls;
2833     list hne=imap(HNEring,hne);
2834     setring altring;
2835     map mmm=HNhelpring,par(1),var(1),var(2);
2836     list hne=mmm(hne);
2837     kill mmm,HNhelpring;
2838   }
2839   else {
2840     list hne=fetch(HNEring,hne);
2841   }
2842   kill HNEring;
2843   if (essential==1) {
2844     dbprint(printlevel-voice+3,""+
2845"// No change of ring necessary, return value is a list:
2846//   first entry  =  list :  HN expansion of essential branches.
2847//   second entry =  intvec: numbers of conjugated branches ");
2848     return(list(hne,hne_conj));
2849   }
2850   else {
2851     dbprint(printlevel-voice+3,""+
2852"// No change of ring necessary, return value is HN expansion.");
2853     return(hne);
2854   }
2855 }
2856}
2857example
2858{
2859  "EXAMPLE:"; echo = 2;
2860  ring r=0,(x,y),dp;
2861  // First, an example which requires no field extension:
2862  list Hne=hnexpansion(x4-y6);
2863  size(Hne);           // number of branches
2864  displayHNE(Hne);     // HN expansion of branches
2865  param(Hne[1]);       // parametrization of 1st branch
2866  param(Hne[2]);       // parametrization of 2nd branch
2867
2868  // An example which requires a field extension:
2869  list L=hnexpansion((x4-y6)*(y2+x4));
2870  def R=L[1]; setring R; displayHNE(hne);
2871  basering;
2872  setring r; kill R;
2873
2874  // Computing only one representative per conjugacy class:
2875  L=hnexpansion((x4-y6)*(y2+x4),"ess");
2876  def R=L[1]; setring R; displayHNE(hne);
2877  L[2];     // number of branches in respective conjugacy classes
2878}
2879
2880///////////////////////////////////////////////////////////////////////////////
2881
2882static proc pre_HN (poly f, int essential)
2883"NOTE: This procedure is only for internal use, it is called via
2884       hnexpansion
2885RETURN: list:  first entry = HNEring  (containing list hne, poly f)
2886               second entry = 0  if no change of base ring necessary
2887                              1  if change of base ring necessary
2888               third entry = numbers of conjugates ( if essential = 1 )
2889        if some error has occurred, the empty list is returned
2890"
2891{
2892 def altring = basering;
2893 int p = char(basering);
2894 int field_ext;
2895 intvec hne_conj;
2896
2897 //-------------------- Tests auf Zulaessigkeit von basering ------------------
2898 if (hasNumericCoeffs(basering)) {
2899   " Singular cannot factorize over 'real' as ground field";
2900   return(list());
2901 }
2902 if (nvars(basering)<2) {
2903   " A univariate polynomial ring makes no sense !";
2904   return(list());
2905 }
2906 if (nvars(basering)>2) {
2907   dbprint(printlevel-voice+2,
2908   " Warning: all variables except the first two will be ignored!");
2909 }
2910 if (hasGFCoefficient(basering))
2911 {
2912   ERROR(" ring of type (p^k,a) not implemented");
2913 //----------------------------------------------------------------------------
2914 // weder primitives Element noch factorize noch map "char p^k" -> "char -p"
2915 // [(p^k,a)->(p,a) ground field] noch fetch
2916 //----------------------------------------------------------------------------
2917 }
2918 //----------------- Definition eines neuen Ringes: HNEring -------------------
2919 string namex=varstr(1); string namey=varstr(2);
2920 if ((npars(altring)==0)&&(!hasNumericCoeffs(basering))) { // kein Parameter, nicht 'real'
2921   ring HNEring = char(altring),(x,y),ls;
2922   map m=altring,x,y;
2923   poly f=m(f);
2924   export f;
2925   kill m;
2926 }
2927 else {
2928   string mipl=string(minpoly);
2929   if (mipl=="0") {
2930     "// ** WARNING: Algebraic extension of given ground field not possible!";
2931     "// ** We try to develop this polynomial, but if the need for a field";
2932     "// ** extension occurs during the calculation, we cannot proceed with";
2933     "// ** the corresponding branches.";
2934     ring HNEring = create_ring(ringlist(basering)[1],"(x,y)","ls","no_minpoly");
2935   }
2936   else {
2937    string pa=parstr(altring);
2938    list rl=ringlist(altring);
2939    rl=rl[1]; rl[1]=p;
2940    ring HNhelpring=ring(rl);
2941    execute("poly mipo="+mipl+";");  // Minimalpolynom in Polynom umgewandelt
2942    ring HNEring=(p,a),(x,y),ls;
2943    map getminpol=HNhelpring,a;
2944    mipl=string(getminpol(mipo));    // String umgewandelt mit 'a' als Param.
2945    execute("minpoly="+mipl+";");    // "minpoly=poly is not supported"
2946    kill HNhelpring; if(defined(getminpol)){ kill getminpol; }
2947   }
2948   if (nvars(altring)==2) {
2949     poly f=fetch(altring,f);
2950     export f;
2951   }
2952   else {
2953     if (defined(pa)) { // Parameter hatte vorher anderen Namen als 'a'
2954       list rl=ringlist(altring);
2955       rl=rl[1]; rl[1]=p;
2956       rl[2]=rl[2]+list("x","y");
2957       rl[3]=list(list("ls",1:3),list("C",0));
2958       ring HNhelpring=ring(rl);
2959       poly f=imap(altring,f);
2960       setring HNEring;
2961       map m=HNhelpring,a,x,y;
2962       poly f=m(f);
2963       kill HNhelpring;
2964     }
2965     else {
2966       map m=altring,x,y;
2967       poly f=m(f);
2968     }
2969     export f;
2970     kill m;
2971   }
2972 }
2973
2974 if (defined(HNDebugOn))
2975 {"received polynomial: ",f,", with x =",namex,", y =",namey;}
2976
2977 //----------------------- Variablendefinitionen ------------------------------
2978 int Abbruch,i,NullHNEx,NullHNEy;
2979 string str;
2980 list Newton,hne;
2981
2982 // --- changed for SINGULAR 3: ---
2983 hne=ideal(0);
2984 export hne;
2985
2986 //====================== Tests auf Zulaessigkeit des Polynoms ================
2987
2988 //-------------------------- Test, ob Einheit oder Null ----------------------
2989 if (subst(subst(f,x,0),y,0)!=0) {
2990   dbprint(printlevel+1,
2991           "The given polynomial is a unit in the power series ring!");
2992   setring altring; kill HNEring;
2993   return(list());                   // there are no HNEs
2994 }
2995 if (f==0) {
2996   dbprint(printlevel+1,"The given polynomial is zero!");
2997   setring altring; kill HNEring;
2998   return(list());                   // there are no HNEs
2999 }
3000
3001 //-----------------------  Test auf Quadratfreiheit --------------------------
3002
3003 if (hasQQCoefficient(basering)) {
3004
3005 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
3006 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
3007 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring HNEring
3008 //----------------------------------------------------------------------------
3009  int testerg=(polytest(f)==0);
3010  ring zweitring = 32003,(x,y),dp;
3011
3012  map polyhinueber=HNEring,x,y;         // fetch geht nicht
3013  poly f=polyhinueber(f);
3014  poly test_sqr=squarefree(f);
3015  if (test_sqr != f) {
3016   if (printlevel>0) {
3017     "Most probably the given polynomial is not squarefree. But the test was";
3018     "made in characteristic 32003 and not 0 to improve speed. You can";
3019     "(r) redo the test in char 0 (but this may take some time)";
3020     "(c) continue the development, if you're sure that the polynomial IS",
3021     "squarefree";
3022     if (testerg==1) {
3023       "(s) continue the development with a squarefree factor (*)";}
3024     "(q) or just quit the algorithm (default action)";
3025     "";"Please enter the letter of your choice:";
3026     str=read("")[1];             // reads one character
3027   }
3028   else { str="r"; }              // printlevel <= 0: non-interactive behaviour
3029   setring HNEring;
3030   map polyhinueber=zweitring,x,y;
3031   if (str=="r") {
3032     poly test_sqr=squarefree(f);
3033     if (test_sqr != f) {
3034      if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
3035      else              { "The given polynomial is not squarefree!"; }
3036      "I'll continue with the radical.";
3037      f=test_sqr;
3038     }
3039     else {
3040      dbprint(printlevel,
3041       "everything is ok -- the polynomial is squarefree in characteristic 0");
3042     }
3043   }
3044   else {
3045     if ((str=="s") and (testerg==1)) {
3046       "(*)attention: it could be that the factor is only one in char 32003!";
3047       f=polyhinueber(test_sqr);
3048     }
3049     else {
3050       if (str<>"c") {
3051         setring altring;
3052         kill HNEring;kill zweitring;
3053         return(list());}
3054       else { "if the algorithm doesn't terminate, you were wrong...";}
3055   }}
3056   kill zweitring;
3057   if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3058  }
3059  else {
3060    setring HNEring;
3061    kill zweitring;
3062  }
3063 }
3064 //------------------ Fall Char > 0 oder Ring hat Parameter -------------------
3065 else {
3066  poly test_sqr=squarefree(f);
3067  if (test_sqr != f) {
3068   if (printlevel>0) {
3069    if (test_sqr == 1) {
3070     "The given polynomial is of the form g^"+string(p)+",";
3071     "therefore not squarefree.  You can:";
3072     " (q) quit the algorithm (recommended) or";
3073     " (f) continue with the full radical (using a factorization of the";
3074     "     pure power part; this could take much time)";
3075     "";"Please enter the letter of your choice:";
3076     str=read("")[1];
3077     if (str<>"f") { str="q"; }
3078    }
3079    else {
3080     "The given polynomial is not squarefree.";
3081     if (p != 0)
3082      {
3083       " You can:";
3084       " (c) continue with a squarefree divisor (but factors of the form g^"
3085       +string(p);
3086       "     are lost; this is recommended, takes no extra time)";
3087       " (f) continue with the full radical (using a factorization of the";
3088       "     pure power part; this could take some time)";
3089       " (q) quit the algorithm";
3090       "";"Please enter the letter of your choice:";
3091       str=read("")[1];
3092       if ((str<>"f") && (str<>"q")) { str="c"; }
3093      }
3094     else { "I'll continue with the radical."; str="c"; }
3095    }                                // endelse (test_sqr!=1)
3096   }
3097   else {
3098     "//** Error: The given polynomial is not squarefree!";
3099     "//** Since the global variable 'printlevel' has the value",printlevel,
3100       "we stop here.";
3101     "//   Either call me again with a squarefree polynomial f or assign";
3102     "            printlevel=1;";
3103     "//   before calling me with a non-squarefree f.";
3104     "//   If printlevel > 0, I present some possibilities how to proceed.";
3105     str="q";
3106   }
3107   if (str=="q") {
3108    setring altring;kill HNEring;
3109    return(list());
3110   }
3111   if (str=="c") { f=test_sqr; }
3112   if (str=="f") { f=allsquarefree(f,test_sqr); }
3113  }
3114  if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3115
3116 }
3117 //====================== Ende Test auf Quadratfreiheit =======================
3118 if (subst(subst(f,x,0),y,0)!=0) {
3119   "The polynomial is a unit in the power series ring. No HNE computed.";
3120   setring altring;kill HNEring;
3121   return(list());
3122 }
3123 //---------------------- Test, ob f teilbar durch x oder y -------------------
3124 if (subst(f,y,0)==0) {
3125   f=f/y; NullHNEy=1; }             // y=0 is a solution
3126 if (subst(f,x,0)==0) {
3127   f=f/x; NullHNEx=1; }             // x=0 is a solution
3128
3129 Newton=newtonpoly(f,1);
3130 i=1; Abbruch=0;
3131 //----------------------------------------------------------------------------
3132 // finde Eckpkt. des Newtonpolys, der den Teil abgrenzt, fuer den x transvers:
3133 // Annahme: Newton ist sortiert, s.d. Newton[1]=Punkt auf der y-Achse,
3134 // Newton[letzt]=Punkt auf der x-Achse
3135 //----------------------------------------------------------------------------
3136 while ((i<size(Newton)) and (Abbruch==0)) {
3137  if ((Newton[i+1][1]-Newton[i][1])>=(Newton[i][2]-Newton[i+1][2]))
3138   {Abbruch=1;}
3139  else {i=i+1;}
3140 }
3141 int grenze1=Newton[i][2];
3142 int grenze2=Newton[i][1];
3143 //----------------------------------------------------------------------------
3144 // Stelle Ring bereit zur Uebertragung der Daten im Fall einer Koerperer-
3145 // weiterung. Definiere Objekte, die spaeter uebertragen werden.
3146 // Binde die Listen (azeilen,...) an den Ring (um sie nicht zu ueberschreiben
3147 // bei Def. in einem anderen Ring).
3148 //----------------------------------------------------------------------------
3149 ring HNE_noparam = char(altring),(a,x,y),ls;
3150 poly f;
3151 list azeilen=ideal(0);
3152 list HNEs=ideal(0);
3153 list aneu=ideal(0);
3154 list faktoren=ideal(0);
3155
3156 ideal deltais;
3157 poly delt;
3158
3159 //----- hier steht die Anzahl bisher benoetigter Ringerweiterungen drin: -----
3160 int EXTHNEnumber=0;
3161
3162 list EXTHNEring;
3163 list HNE_RingDATA;
3164 int number_of_letztring;
3165 setring HNEring;
3166 number_of_letztring=0;
3167
3168 // ================= Die eigentliche Berechnung der HNE: =====================
3169
3170 // ------- Berechne HNE von allen Zweigen, fuer die x transversal ist: -------
3171 if (defined(HNDebugOn))
3172   {"1st step: Treat Newton polygon until height",grenze1;}
3173 if (grenze1>0) {
3174  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3175  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3176                      number_of_letztring);
3177
3178  list hilflist=HN(HNE_RingDATA,f,grenze1,1,essential,0,hne_conj,1);
3179  kill HNEring, HNE_noparam;
3180  if (EXTHNEnumber>0) { kill EXTHNEring(1..EXTHNEnumber);}
3181  def HNEring = hilflist[1][1];
3182  def HNE_noparam = hilflist[1][2];
3183  EXTHNEnumber = hilflist[1][3];
3184  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3185  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3186  else                { setring EXTHNEring(hilflist[2]);}
3187  if (hilflist[3]==1){field_ext=1;}
3188  hne_conj=hilflist[5];
3189
3190  if (number_of_letztring != hilflist[2])
3191  {  // Ringwechsel in Prozedur HN
3192     map hole=HNE_noparam,transfproc,x,y;
3193     setring HNE_noparam;
3194     if (not(defined(f))) {poly f;}
3195     f=imap(HNEring,f);
3196     setring EXTHNEring(EXTHNEnumber);
3197     if (not(defined(f))) {poly f; f=hole(f); export f;}
3198     else                 {f=hole(f);}
3199  }
3200  number_of_letztring = hilflist[2];
3201  kill hilflist;
3202 }
3203
3204 if (NullHNEy==1) {
3205  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3206  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(0),poly(0)));
3207  if (hne_conj==0) { hne_conj=1; }
3208  else { hne_conj = hne_conj, 1; }
3209 }
3210 // --------------- Berechne HNE von allen verbliebenen Zweigen: --------------
3211 if (defined(HNDebugOn))
3212    {"2nd step: Treat Newton polygon until height",grenze2;}
3213 if (grenze2>0) {
3214
3215  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3216
3217  if (essential==1) { number_of_letztring=0; }
3218  if (number_of_letztring==0) { setring HNEring; }
3219  else                        { setring EXTHNEring(number_of_letztring); }
3220  map xytausch=basering,y,x;
3221
3222  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3223                      number_of_letztring);
3224  list hilflist=HN(HNE_RingDATA,xytausch(f),grenze2,1,essential,1,hne_conj,1);
3225  kill HNEring, HNE_noparam;
3226  if (EXTHNEnumber>0){ kill EXTHNEring(1..EXTHNEnumber); }
3227  def HNEring = hilflist[1][1];
3228  def HNE_noparam = hilflist[1][2];
3229  EXTHNEnumber = hilflist[1][3];
3230  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3231  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3232  else                { setring EXTHNEring(hilflist[2]);
3233                        number_of_letztring=hilflist[2]; }
3234  if (hilflist[3]==1){field_ext=1;}
3235  hne_conj=hilflist[5];
3236  kill hilflist;
3237 }
3238 if (NullHNEx==1) {
3239  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3240  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(1),poly(0)));
3241  if (hne_conj==0) { hne_conj=1; }
3242  else { hne_conj = hne_conj, 1; }
3243 }
3244
3245
3246 // --- aufraeumen ---
3247 if (defined(HNEakut)){
3248   kill HNEakut,faktoren,deltais,transformiert,teiler,leitf;
3249 }
3250 if (defined(hilflist)) {kill hilflist;}
3251 if (defined(erg)) {kill erg;}
3252 if (defined(delt)) {kill delt;}
3253 if (defined(azeilen)) { kill azeilen;}
3254 if (defined(aneu)) { kill aneu;}
3255 if (defined(transfproc)) { kill transfproc;}
3256 if (defined(transf)) { kill transf;}
3257 if (not(defined(f))) { poly f = imap(HNEring,f); export f; }
3258
3259 return(list(basering,field_ext,hne_conj));
3260}
3261
3262//////////////////////////////////////////////////////////////////////////////
3263proc essdevelop (poly f)
3264"USAGE:   essdevelop(f); f poly
3265NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.
3266SEE ALSO: hnexpansion, develop, extdevelop, param
3267"
3268{
3269 printlevel=printlevel+1;
3270 list Ergebnis=hnexpansion(f,1);
3271 printlevel=printlevel-1;
3272 return(Ergebnis);
3273}
3274
3275///////////////////////////////////////////////////////////////////////////////
3276static proc HN (list HNE_RingDATA,poly fneu,int grenze,def Aufruf_Ebene,
3277                def essential,def getauscht,intvec hne_conj,int conj_factor)
3278"NOTE: This procedure is only for internal use, it is called via pre_HN
3279RETURN: list: first entry = list of HNErings,
3280              second entry = number of new base ring (0 for HNEring,
3281                                                      -1 for HNE_noparam,
3282                                                      i for EXTHNEring(i))
3283              third entry = 0 if no field extension necessary
3284                            1 if field extension necessary
3285              forth entry = HNEs (only if no change of basering)
3286"
3287{
3288 //---------- Variablendefinitionen fuer den unverzweigten Teil: --------------
3289 if (defined(HNDebugOn)) {"procedure HN",Aufruf_Ebene;}
3290 int Abbruch,ende,i,j,k,e,M,N,Q,R,zeiger,zeile,zeilevorher,dd,ii;
3291 intvec hqs;
3292 int field_ext;
3293 int ring_changed, hneshift;
3294 intvec conjugates,conj2,conj1;
3295
3296 list EXTHNEring;
3297 def HNEring = HNE_RingDATA[1];
3298 def HNE_noparam = HNE_RingDATA[2];
3299 int EXTHNEnumber = HNE_RingDATA[3];
3300 for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=HNE_RingDATA[4][i]; }
3301 int number_of_letztring = HNE_RingDATA[5];
3302 if (defined(basering))
3303 {
3304   if (number_of_letztring==0) { kill HNEring; def HNEring=basering; }
3305   else                 { kill EXTHNEring(number_of_letztring);
3306                          def EXTHNEring(number_of_letztring)=basering; }
3307 }
3308 else
3309 {
3310   if ( number_of_letztring==0) { setring HNEring; }
3311   else                         { setring EXTHNEring(number_of_letztring); }
3312 }
3313 if (not(defined(hne))) {list hne;}
3314 poly fvorher;
3315 list erg=ideal(0); list HNEs=ideal(0); // um die Listen an den Ring zu binden
3316
3317 //-------------------- Bedeutung von Abbruch: --------------------------------
3318 //------- 0:keine Verzweigung | 1:Verzweigung,nicht fertig | 2:fertig --------
3319 //
3320 // Struktur von HNEs : Liste von Listen L (fuer jeden Zweig) der Form
3321 // L[1]=intvec (hqs), L[2],L[3],... ideal (die Zeilen (0,1,...) der HNE)
3322 // L[letztes]=poly (transformiertes f)
3323 //----------------------------------------------------------------------------
3324 list Newton;
3325 number delt;
3326 int p = char(basering);                // Ringcharakteristik
3327 list azeilen=ideal(0);
3328
3329 ideal hilfid; intvec hilfvec;
3330
3331 // ======================= der unverzweigte Teil: ============================
3332 while (Abbruch==0) {
3333  Newton=newtonpoly(fneu,1);
3334  zeiger=find_in_list(Newton,grenze);
3335  if (Newton[zeiger][2] != grenze)
3336    {"Didn't find an edge in the Newton polygon!";}
3337  if (zeiger==size(Newton)-1) {
3338    if (defined(HNDebugOn)) {"only one relevant side in Newton polygon";}
3339    M=Newton[zeiger+1][1]-Newton[zeiger][1];
3340    N=Newton[zeiger][2]-Newton[zeiger+1][2];
3341    R = M%N;
3342    Q = M div N;
3343
3344    //-------- 1. Versuch: ist der quasihomogene Leitterm reine Potenz ? ------
3345    //              (dann geht alles wie im irreduziblen Fall)
3346    //-------------------------------------------------------------------------
3347    e = gcd(M,N);
3348    delt=factorfirst(redleit(fneu,Newton[zeiger],Newton[zeiger+1])
3349                      /x^Newton[zeiger][1],M,N);
3350    if (delt==0) {
3351      if (defined(HNDebugOn)) {" The given polynomial is reducible !";}
3352      Abbruch=1;
3353    }
3354    if (Abbruch==0) {
3355      //----------- fneu,zeile retten fuer den Spezialfall (###): -------------
3356      fvorher=fneu;zeilevorher=zeile;
3357      if (R==0) {
3358        //-------- transformiere fneu mit T1, wenn kein Abbruch nachher: ------
3359        if (N>1) { fneu = T1_Transform(fneu,delt,M div e); }
3360        else     { ende=1; }
3361        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3362        azeilen[zeile+1][Q]=delt;
3363      }
3364      else {
3365        //------------- R > 0 : transformiere fneu mit T2 ---------------------
3366        erg=T2_Transform(fneu,delt,M,N,referencepoly(Newton));
3367        fneu=erg[1];delt=erg[2];
3368        //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ----
3369        while (R!=0) {
3370         if (defined(HNDebugOn)) { "h("+string(zeile)+") =",Q; }
3371         hqs[zeile+1]=Q;         // denn zeile beginnt mit dem Wert 0
3372         //--------------- markiere das Zeilenende der HNE: -------------------
3373         azeilen[zeile+1][Q+1]=x;
3374         zeile=zeile+1;
3375         //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ----
3376         azeilen[zeile+1]=ideal(0);
3377         M=N; N=R; R=M%N; Q=M div N;
3378        }
3379        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3380        azeilen[zeile+1][Q]=delt;
3381      }
3382      if (defined(HNDebugOn)) {"transformed polynomial: ",fneu;}
3383      grenze=e;
3384      //----------------------- teste Abbruchbedingungen: ---------------------
3385      if (subst(fneu,y,0)==0) {              // <==> y|fneu
3386        dbprint(printlevel-voice+3,"finite HNE of one branch found");
3387           // voice abzufragen macht bei rekursiven procs keinen Sinn
3388        azeilen[zeile+1][Q+1]=x;
3389        //----- Q wird nur in hqs eingetragen, wenn der Spezialfall nicht
3390        //      eintritt (siehe unten) -----
3391        Abbruch=2;
3392        if (grenze>1) {
3393         if (jet(fneu,1,intvec(0,1))==0) {
3394           //- jet(...)=alle Monome von fneu, die nicht durch y2 teilbar sind -
3395           "THE TEST FOR SQUAREFREENESS WAS BAD!!";
3396           " The polynomial was NOT squarefree!!!";}
3397         else {
3398           //----------------------- Spezialfall (###): -----------------------
3399           // Wir haben das Problem, dass die HNE eines Zweiges hier abbricht,
3400           // aber ein anderer Zweig bis hierher genau die gleiche HNE hat, die
3401           // noch weiter geht
3402           // Loesung: mache Transform. rueckgaengig und behandle fneu im
3403           // Verzweigungsteil
3404           //------------------------------------------------------------------
3405          Abbruch=1;
3406          fneu=fvorher;zeile=zeilevorher;grenze=Newton[zeiger][2];
3407        }}
3408        else {fneu=0;}     // fneu nicht mehr gebraucht - spare Speicher
3409        if (Abbruch==2) { hqs[zeile+1]=Q; }
3410      }                 // Spezialfall nicht eingetreten
3411      else {
3412        if (ende==1) {
3413          dbprint(printlevel-voice+2,"HNE of one branch found");
3414          Abbruch=2; hqs[zeile+1]=-Q-1;}
3415      }
3416    }                   // end(if Abbruch==0)
3417  }                     // end(if zeiger...)
3418  else { Abbruch=1;}
3419 }                      // end(while Abbruch==0)
3420
3421 // ===================== der Teil bei Verzweigung: ===========================
3422 if (Abbruch==1) {
3423  //---------- Variablendefinitionen fuer den verzweigten Teil: ---------------
3424  poly leitf,teiler,transformiert;
3425  list aneu=ideal(0);
3426  list faktoren;
3427  ideal deltais;
3428  list HNEakut=ideal(0);
3429  intvec eis;
3430  int zaehler,hnezaehler,zl,zl1,M1,N1,R1,Q1,needext;
3431  int numberofRingchanges,lastRingnumber,ringischanged,flag;
3432  string letztringname;
3433
3434  zeiger=find_in_list(Newton,grenze);
3435  if (defined(HNDebugOn)) {
3436    "Branching part reached---Newton polygon :",Newton;
3437    "relevant part until height",grenze,", from",Newton[zeiger],"on";
3438  }
3439  azeilen=list(hqs)+azeilen; // hat jetzt Struktur von HNEs: hqs in der 1.Zeile
3440
3441  //======= Schleife fuer jede zu betrachtende Seite des Newtonpolygons: ======
3442  for(i=zeiger; i<size(Newton); i++) {
3443   if ((essential==1) and (EXTHNEnumber>number_of_letztring)) {
3444     // ----- setze ring zurueck fuer neue Kante  -----
3445     // ---- (damit konjugierte Zweige erkennbar) -----
3446     hneshift=hneshift+hnezaehler;
3447     hnezaehler=0;
3448     ring_changed=0;
3449     def SaveRing = EXTHNEring(EXTHNEnumber);
3450     setring SaveRing;
3451     if (not(defined(HNEs))) { // HN wurde zum 2.Mal von pre_HN aufgerufen
3452       list HNEs=ideal(0);
3453     }
3454     for (k=number_of_letztring+1; k<=EXTHNEnumber; k++) { kill EXTHNEring(k);}
3455     EXTHNEnumber=number_of_letztring;
3456     if (EXTHNEnumber==0) { setring HNEring; }
3457     else                 { setring EXTHNEring(EXTHNEnumber); }
3458     if (not(defined(HNEs))) { list HNEs; }
3459     HNEs=ideal(0);
3460     deltais=0;
3461     delt=0;
3462     if (defined(zerlege)) { kill zerlege; }
3463   }
3464
3465   if (defined(HNDebugOn)) { "we consider side",Newton[i],Newton[i+1]; }
3466   M=Newton[i+1][1]-Newton[i][1];
3467   N=Newton[i][2]-Newton[i+1][2];
3468   R = M%N;
3469   Q = M div N;
3470   e=gcd(M,N);
3471   needext=1;
3472   letztringname=nameof(basering);
3473   lastRingnumber=EXTHNEnumber;
3474   faktoren=list(ideal(charPoly(redleit(fneu,Newton[i],Newton[i+1])
3475                       /(x^Newton[i][1]*y^Newton[i+1][2]),M,N)  ),
3476                 intvec(1));                  // = (zu faktoriserendes Poly, 1)
3477   conjugates=conj_factor;
3478
3479   //-- wechsle so lange in Ringerweiterungen, bis Leitform vollstaendig
3480   //   in Linearfaktoren zerfaellt -----
3481   for (numberofRingchanges=1; needext==1; numberofRingchanges++) {
3482    leitf=redleit(fneu,Newton[i],Newton[i+1])/
3483                     (x^Newton[i][1]*y^Newton[i+1][2]);
3484    delt=factorfirst(leitf,M,N);
3485    needext=0;
3486    if (delt==0) {
3487     //---------- Sonderbehandlung: faktorisiere einige Polynome ueber Q(a): --
3488     if ((char(basering)==0) and (hasAlgExtensionCoefficient(basering)) and (essential==0)) {
3489        // ====================================================
3490        // neu CL:  06.10.05
3491        poly CHPOLY=charPoly(leitf,M,N);
3492        poly tstpoly;
3493        if (defined(faktoren)!=0) {
3494          // Test, damit kein Fehler eingebaut (vermutlich nicht notwendig)
3495          tstpoly = faktoren[1][1]^faktoren[2][1];
3496          for (k=2; k<=size(faktoren[1]); k++) {
3497            tstpoly = tstpoly * faktoren[1][k]^faktoren[2][k];
3498          }
3499          tstpoly = CHPOLY-tstpoly*(CHPOLY/tstpoly);
3500          kill CHPOLY;
3501        }
3502        if ((numberofRingchanges>1) and (defined(faktoren)!=0) and (tstpoly==0)) {
3503          def L_help=factorlist(faktoren,conjugates);
3504          faktoren=L_help[1];
3505          conjugates=L_help[2];
3506          kill L_help;
3507        }
3508        else {
3509          faktoren=factorize(charPoly(leitf,M,N));
3510          conjugates=conj_factor;
3511          for (k=2;k<=size(faktoren[2]);k++) {conjugates=conjugates,conj_factor;}
3512        }
3513        kill tstpoly;
3514        // Ende neu (vorher nur else Fall)
3515        // ====================================================
3516     }
3517     else {
3518       //------------------ faktorisiere das charakt. Polynom: ----------------
3519       if ((numberofRingchanges==1) or (essential==0)) {
3520         def L_help=factorlist(faktoren,conjugates);
3521         faktoren=L_help[1];
3522         conjugates=L_help[2];
3523         kill L_help;
3524       }
3525       else {     // eliminiere alle konjugierten Nullstellen bis auf eine:
3526         ideal hilf_id;
3527         for (zaehler=1; zaehler<=size(faktoren[1]); zaehler++) {
3528           hilf_id=factorize(faktoren[1][zaehler],1);
3529           if (size(hilf_id)>1) {
3530             poly fac=hilf_id[1];
3531             dd=deg(fac);
3532             // Zur Sicherheit:
3533             if (deg(fac)==0) { fac=hilf_id[2]; }
3534             for (k=2;k<=size(hilf_id);k++) {
3535               dd=dd+deg(hilf_id[k]);
3536               if (deg(hilf_id[k])<deg(fac)) { fac=hilf_id[k]; }
3537             }
3538             faktoren[1][zaehler]=fac;
3539             kill fac;
3540             if (conjugates[zaehler]==conj_factor) {
3541               // number of conjugates not yet determined for this factor
3542               conjugates[zaehler]=conjugates[zaehler]*dd;
3543             }
3544           }
3545           else {
3546             faktoren[1][zaehler]=hilf_id[1];
3547           }
3548         }
3549       }
3550     }
3551
3552     zaehler=1; eis=0;
3553     for (j=1; j<=size(faktoren[2]); j++) {
3554      teiler=faktoren[1][j];
3555      if (teiler/y != 0) {         // sonst war's eine Konstante --> wegwerfen!
3556        if (defined(HNDebugOn)) {"factor of leading form found:",teiler;}
3557        if (teiler/y2 == 0) {      // --> Faktor hat die Form cy+d
3558          deltais[zaehler]=-subst(teiler,y,0)/koeff(teiler,0,1); //=-d/c
3559          eis[zaehler]=faktoren[2][j];
3560          conj2[zaehler]=conjugates[j];
3561          zaehler++;
3562        }
3563        else {
3564          dbprint(printlevel-voice+2,
3565             " Change of basering (field extension) necessary!");
3566          if (defined(HNDebugOn)) { teiler,"is not yet properly factorized!"; }
3567          if (needext==0) { poly zerlege=teiler; }
3568          needext=1;
3569          field_ext=1;
3570        }
3571      }
3572     }  // end(for j)
3573    }
3574    else { deltais=ideal(delt); eis=e; conj2=conj_factor; }
3575    if (defined(HNDebugOn)) {"roots of char. poly:";deltais;
3576                             "with multiplicities:",eis;}
3577    if (needext==1) {
3578      //--------------------- fuehre den Ringwechsel aus: ---------------------
3579      ringischanged=1;
3580      if ((size(parstr(basering))>0) && string(minpoly)=="0") {
3581        " ** We've had bad luck! The HNE cannot be calculated completely!";
3582        // HNE in transzendenter Erweiterung fehlgeschlagen
3583        kill zerlege;
3584        ringischanged=0; break;    // weiter mit gefundenen Faktoren
3585      }
3586      if (parstr(basering)=="") {
3587        EXTHNEnumber++;
3588        def EXTHNEring(EXTHNEnumber) = splitring(zerlege);
3589        setring EXTHNEring(EXTHNEnumber);
3590
3591        poly transf=0;
3592        poly transfproc=0;
3593        ring_changed=1;
3594        export transfproc;
3595      }
3596      else {
3597        if (numberofRingchanges>1) {  // ein Ringwechsel hat nicht gereicht
3598         def helpring = splitring(zerlege,list(transf,transfproc,faktoren));
3599         kill EXTHNEring(EXTHNEnumber);
3600         def EXTHNEring(EXTHNEnumber)=helpring;
3601         setring EXTHNEring(EXTHNEnumber);
3602         kill helpring;
3603
3604         poly transf=erg[1];
3605         poly transfproc=erg[2];
3606         ring_changed=1;
3607         list faktoren=erg[3];
3608         export transfproc;
3609         kill erg;
3610        }
3611        else {
3612         if (ring_changed==1) { // in dieser proc geschah schon Ringwechsel
3613          EXTHNEnumber++;
3614          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,list(a,transfproc));
3615          setring EXTHNEring(EXTHNEnumber);
3616          poly transf=erg[1];
3617          poly transfproc=erg[2];
3618          export transfproc;
3619          kill erg;
3620         }
3621         else { // parameter war vorher da
3622          EXTHNEnumber++;
3623          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,a);
3624          setring EXTHNEring(EXTHNEnumber);
3625          poly transf=erg[1];
3626          poly transfproc=transf;
3627          ring_changed=1;
3628          export transfproc;
3629          kill erg;
3630        }}
3631      }
3632      //-----------------------------------------------------------------------
3633      // transf enthaelt jetzt den alten Parameter des Ringes, der aktiv war
3634      // vor Beginn der Schleife (evtl. also ueber mehrere Ringwechsel
3635      // weitergereicht),
3636      // transfproc enthaelt den alten Parameter des Ringes, der aktiv war zu
3637      // Beginn der Prozedur, und der an die aufrufende Prozedur zurueckgegeben
3638      // werden muss
3639      // transf ist Null, falls der alte Ring keinen Parameter hatte,
3640      // das gleiche gilt fuer transfproc
3641      //-----------------------------------------------------------------------
3642
3643      //---- Neudef. von Variablen, Uebertragung bisher errechneter Daten: ----
3644      poly leitf,teiler,transformiert;
3645      list aneu=ideal(0);
3646      ideal deltais;
3647      number delt;
3648      setring HNE_noparam;
3649      if (defined(letztring)) { kill letztring; }
3650      if (EXTHNEnumber>1) { def letztring=EXTHNEring(EXTHNEnumber-1); }
3651      else                { def letztring=HNEring; }
3652      if (not defined(fneu)) {poly fneu;}
3653      fneu=imap(letztring,fneu);
3654      if (not defined(f)) {poly f;}
3655      f=imap(letztring,f);
3656      if (not defined(hne)) {list hne;}
3657      hne=imap(letztring,hne);
3658
3659      if (not defined(faktoren)) {list faktoren; }
3660      faktoren=imap(letztring,faktoren);
3661
3662      if (not(defined(azeilen))){list azeilen,HNEs;}
3663      azeilen=imap(letztring,azeilen);
3664      HNEs=imap(letztring,HNEs);
3665
3666      setring EXTHNEring(EXTHNEnumber);
3667      if (not(defined(hole))) { map hole; }
3668      hole=HNE_noparam,transf,x,y;
3669      poly fneu=hole(fneu);
3670      if (not defined(faktoren)) {
3671        list faktoren;
3672        faktoren=hole(faktoren);
3673      }
3674      if (not(defined(f)))
3675      {
3676        poly f=hole(f);
3677        list hne=hole(hne);
3678        export f,hne;
3679      }
3680    }
3681   }    // end (while needext==1) bzw. for (numberofRingchanges)
3682
3683   if (eis==0) { i++; continue; }
3684   if (ringischanged==1) {
3685    list erg,HNEakut;            // dienen nur zum Sp. von Zwi.erg.
3686
3687    ideal hilfid;
3688    erg=ideal(0); HNEakut=erg;
3689
3690    hole=HNE_noparam,transf,x,y;
3691    setring HNE_noparam;
3692    if (not(defined(azeilen))){list azeilen,HNEs;}
3693    azeilen=imap(letztring,azeilen);
3694    HNEs=imap(letztring,HNEs);
3695
3696    setring EXTHNEring(EXTHNEnumber);
3697    list azeilen=hole(azeilen);
3698    list HNEs=hole(HNEs);
3699    kill letztring;
3700    ringischanged=0;
3701   }
3702
3703   //============ Schleife fuer jeden gefundenen Faktor der Leitform: =========
3704   for (j=1; j<=size(eis); j++) {
3705     //---- Mache Transformation T1 oder T2, trage Daten in HNEs ein,
3706     //     falls HNE abbricht: ----
3707
3708    //------------------------ Fall R==0: -------------------------------------
3709    if (R==0) {
3710      transformiert = T1_Transform(fneu,number(deltais[j]),M div e);
3711      if (defined(HNDebugOn)) {
3712        "a("+string(zeile)+","+string(Q)+") =",deltais[j];
3713        "transformed polynomial: ",transformiert;
3714      }
3715      if (subst(transformiert,y,0)==0) {
3716       dbprint(printlevel-voice+3,"finite HNE found");
3717       hnezaehler++;
3718       //-------- trage deltais[j],x ein in letzte Zeile, fertig: -------------
3719       HNEakut=azeilen+list(poly(0));        // =HNEs[hnezaehler];
3720       hilfid=HNEakut[zeile+2]; hilfid[Q]=deltais[j]; hilfid[Q+1]=x;
3721       HNEakut[zeile+2]=hilfid;
3722       HNEakut[1][zeile+1]=Q;                // aktualisiere Vektor mit den hqs
3723       HNEs[hnezaehler]=HNEakut;
3724       conj1[hneshift+hnezaehler]=conj2[j];
3725       if (eis[j]>1) {
3726        transformiert=transformiert/y;
3727        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3728                                  +"! The polynomial was NOT squarefree!!!";}
3729        else {
3730          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3731          eis[j]=eis[j]-1;
3732        }
3733       }
3734      }
3735    }
3736    else {
3737      //------------------------ Fall R <> 0: ---------------------------------
3738      erg=T2_Transform(fneu,number(deltais[j]),M,N,referencepoly(Newton));
3739      transformiert=erg[1];delt=erg[2];
3740      if (defined(HNDebugOn)) {"transformed polynomial: ",transformiert;}
3741      if (subst(transformiert,y,0)==0) {
3742       dbprint(printlevel-voice+3,"finite HNE found");
3743       hnezaehler++;
3744       //---------------- trage endliche HNE in HNEs ein: ---------------------
3745       HNEakut=azeilen;           // dupliziere den gemeins. Anfang der HNE's
3746       zl=2;                      // (kommt schliesslich nach HNEs[hnezaehler])
3747       //----------------------------------------------------------------------
3748       // Werte von:  zeile: aktuelle Zeilennummer der HNE (gemeinsamer Teil)
3749       //             zl : die HNE spaltet auf; zeile+zl ist der Index fuer die
3750       //                  Zeile des aktuellen Zweigs; (zeile+zl-2) ist die
3751       //                  tatsaechl. Zeilennr. (bei 0 angefangen) der HNE
3752       //                  ([1] <- intvec(hqs), [2] <- 0. Zeile usw.)
3753       //----------------------------------------------------------------------
3754
3755       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3756       M1=M;N1=N;R1=R;Q1=M1 div N1;
3757       while (R1!=0) {
3758        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3759        HNEakut[1][zeile+zl-1]=Q1;
3760        HNEakut[zeile+zl][Q1+1]=x;
3761                                  // markiere das Zeilenende der HNE
3762        zl=zl+1;
3763        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3764        HNEakut[zeile+zl]=ideal(0);
3765
3766        M1=N1; N1=R1; R1=M1%N1; Q1=M1 div N1;
3767       }
3768       if (defined(HNDebugOn)) {
3769         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3770       }
3771       HNEakut[zeile+zl][Q1]  =delt;
3772       HNEakut[zeile+zl][Q1+1]=x;
3773       HNEakut[1][zeile+zl-1] =Q1;     // aktualisiere Vektor mit hqs
3774       HNEakut[zeile+zl+1]=poly(0);
3775       HNEs[hnezaehler]=HNEakut;
3776       conj1[hneshift+hnezaehler]=conj2[j];
3777
3778       //-------------------- Ende der Eintragungen in HNEs -------------------
3779
3780       if (eis[j]>1) {
3781        transformiert=transformiert/y;
3782        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3783                               +" The polynomial was NOT squarefree!!!";}
3784         else {
3785          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3786          eis[j]=eis[j]-1;
3787       }}
3788      }                           // endif (subst()==0)
3789    }                             // endelse (R<>0)
3790
3791    //========== Falls HNE nicht abbricht: Rekursiver Aufruf von HN: ==========
3792    //------------------- Berechne HNE von transformiert ----------------------
3793    if (subst(transformiert,y,0)!=0) {
3794     lastRingnumber=EXTHNEnumber;
3795
3796     if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3797     HNE_RingDATA = list( HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3798                          lastRingnumber);
3799     if (defined(HNerg)) {kill HNerg;}
3800     list HNerg=HN(HNE_RingDATA,transformiert,eis[j],Aufruf_Ebene+1,
3801                                essential,getauscht,hne_conj,conj2[j]);
3802     HNE_RingDATA = HNerg[1];
3803     if (conj1==0) { conj1=HNerg[5]; }
3804     else  { conj1 = conj1,HNerg[5]; }
3805
3806     if (HNerg[3]==1) { field_ext=1; }
3807     if (HNerg[2]==lastRingnumber) { // kein Ringwechsel in HN aufgetreten
3808       if (not(defined(aneu))) { list aneu; }
3809       aneu = HNerg[4];
3810     }
3811     else { // Ringwechsel aufgetreten
3812       if (defined(HNDebugOn))
3813          {" ring change in HN(",Aufruf_Ebene+1,") detected";}
3814       EXTHNEnumber = HNerg[1][3];
3815       for (ii=lastRingnumber+1; ii<=EXTHNEnumber; ii++) {
3816         def EXTHNEring(ii)=HNerg[1][4][ii];
3817       }
3818       if (HNerg[2]==0) { setring HNEring; }
3819       else             { setring EXTHNEring(HNerg[2]); }
3820       def tempRing=HNerg[4];
3821       def aneu=imap(tempRing,HNEs);
3822       kill tempRing;
3823
3824       //--- stelle lokale Variablen im neuen Ring wieder her, und rette
3825       //    gegebenenfalls ihren Inhalt: ----
3826       list erg,faktoren,HNEakut;
3827       ideal hilfid;
3828       erg=ideal(0); faktoren=erg; HNEakut=erg;
3829       poly leitf,teiler,transformiert;
3830       map hole=HNE_noparam,transfproc,x,y;
3831       setring HNE_noparam;
3832       if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3833       else                  { def letztring=HNEring; }
3834       if (not defined(HNEs)) {list HNEs;}
3835       HNEs=imap(letztring,HNEs);
3836       if (not defined(azeilen)) {list azeilen;}
3837       azeilen=imap(letztring,azeilen);
3838       if (not defined(deltais)) {ideal deltais;}
3839       deltais=imap(letztring,deltais);
3840       if (not defined(delt)) {poly delt;}
3841       delt=imap(letztring,delt);
3842       if (not defined(fneu)) {poly fneu;}
3843       fneu=imap(letztring,fneu);
3844       if (not defined(f)) {poly f;}
3845       f=imap(letztring,f);
3846       if (not defined(hne)) {list hne;}
3847       hne=imap(letztring,hne);
3848
3849       setring EXTHNEring(EXTHNEnumber);
3850       list HNEs=hole(HNEs);
3851       list azeilen=hole(azeilen);
3852       ideal deltais=hole(deltais);
3853       number delt=number(hole(delt));
3854       poly fneu=hole(fneu);
3855       if (not(defined(f)))
3856       {
3857         poly f=hole(f);
3858         list hne=hole(hne);
3859         export f,hne;
3860       }
3861     }
3862
3863     //========== Verknuepfe bisherige HNE mit von HN gelieferten HNEs: ======
3864     if (R==0) {
3865       HNEs,hnezaehler=constructHNEs(HNEs,hnezaehler,aneu,azeilen,zeile,
3866                       deltais,Q,j);
3867       kill aneu;
3868     }
3869     else {
3870      for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3871       hnezaehler++;
3872       HNEakut=azeilen;          // dupliziere den gemeinsamen Anfang der HNE's
3873       zl=2;                     // (kommt schliesslich nach HNEs[hnezaehler])
3874       //------------ Trage Beitrag dieser Transformation T2 ein: -------------
3875       //------ Zur Bedeutung von zeile, zl: siehe Kommentar weiter oben ------
3876
3877       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3878       M1=M;N1=N;R1=R;Q1=M1 div N1;
3879       while (R1!=0) {
3880        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3881        HNEakut[1][zeile+zl-1]=Q1;
3882        HNEakut[zeile+zl][Q1+1]=x;    // Markierung des Zeilenendes der HNE
3883        zl=zl+1;
3884        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3885        HNEakut[zeile+zl]=ideal(0);
3886        M1=N1; N1=R1; R1=M1%N1; Q1=M1 div N1;
3887       }
3888       if (defined(HNDebugOn)) {
3889         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3890       }
3891       HNEakut[zeile+zl][Q1]=delt;
3892
3893       //-- Daten aus T2_Transform sind eingetragen; haenge Daten von HN an: --
3894       hilfid=HNEakut[zeile+zl];
3895       for (zl1=Q1+1; zl1<=ncols(aneu[zaehler][2]); zl1++) {
3896        hilfid[zl1]=aneu[zaehler][2][zl1];
3897       }
3898       HNEakut[zeile+zl]=hilfid;
3899       // ------ vorher HNEs[.][zeile+zl]<-aneu[.][2],
3900       //        jetzt [zeile+zl+1] <- [3] usw.: --------
3901       for (zl1=3; zl1<=size(aneu[zaehler]); zl1++) {
3902         HNEakut[zeile+zl+zl1-2]=aneu[zaehler][zl1];
3903       }
3904       //--- setze hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] --
3905       hilfvec=HNEakut[1],aneu[zaehler][1];
3906       HNEakut[1]=hilfvec;
3907       //-------- weil nicht geht: liste[1]=liste[1],aneu[zaehler][1] ---------
3908       HNEs[hnezaehler]=HNEakut;
3909      }                     // end(for zaehler)
3910     kill aneu;
3911     }                      // endelse (R<>0)
3912    }                       // endif (subst()!=0)  (weiteres Aufblasen mit HN)
3913
3914   }                        // end(for j) (Behandlung der einzelnen delta_i)
3915
3916
3917   // ------------------------- new for essdevelop ----------------------------
3918   if ((essential==1) and (defined(SaveRing))) {
3919     // ----- uebertrage Daten in gemeinsame Koerpererweiterung ---------------
3920     if (EXTHNEnumber>number_of_letztring) {
3921       // ----- fuer aktuelle Kante war Koerpererweiterung erforderlich -------
3922       EXTHNEnumber++;
3923       string @miniPol_EXTHNEring(EXTHNEnumber-1) = string(minpoly);
3924       setring SaveRing;
3925       string @miniPol_SaveRing = string(minpoly);
3926       setring HNE_noparam;
3927       if (not(defined(a_x))){ map a_x,a_y; poly mp_save, mp_new; }
3928       execute("mp_save= " + @miniPol_SaveRing + ";");
3929       execute("mp_new = " + @miniPol_EXTHNEring(EXTHNEnumber-1) + ";" );;
3930       if (mp_save==mp_new) { // Sonderfall: wieder gleicher Ring
3931         def EXTHNEring(EXTHNEnumber)=SaveRing;
3932         setring EXTHNEring(EXTHNEnumber);
3933         if (not(defined(f))) {poly f; f=hole(f); export f;}
3934         list dummyL=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3935         if (not(defined(HNEs))) { def HNEs=list(); }
3936         if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3937         HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3938         kill dummyL,SaveRing;
3939       }
3940       else { // verschiedene Ringe
3941         a_x=HNE_noparam,x,0,0;
3942         a_y=HNE_noparam,y,0,0;
3943         mp_save=a_x(mp_save); // minpoly aus SaveRing mit a --> x
3944         mp_new=a_y(mp_new);   // minpoly aus SaveRing mit a --> y
3945         setring SaveRing;
3946         poly mp_new=imap(HNE_noparam,mp_new);
3947         list Lfac=factorize(mp_new,1);
3948         poly fac=Lfac[1][1];
3949         for (k=2;k<=size(Lfac[1]);k++) {
3950           if (deg(Lfac[1][k])<deg(fac)) { fac=Lfac[1][k]; }
3951         }
3952
3953         if (deg(fac)==1) { // keine Erweiterung noetig
3954           def EXTHNEring(EXTHNEnumber)=SaveRing;
3955           setring HNE_noparam;
3956           HNEs=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3957           setring EXTHNEring(EXTHNEnumber);
3958           if (not(defined(f))) {poly f; f=hole(f); export f;}
3959           map phi=HNE_noparam,-subst(fac,y,0)/koeff(fac,0,1),x,y;
3960           list dummyL=phi(HNEs);
3961           if (not(defined(HNEs))) { def HNEs=list(); }
3962           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3963           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3964           kill dummyL,phi,SaveRing;
3965         }
3966         else { // Koerpererweiterung noetig
3967           def EXTHNEring(EXTHNEnumber) = splitring(fac,list(a,transfproc));
3968           setring EXTHNEring(EXTHNEnumber);
3969           poly transf=erg[1];  // image of parameter from SaveRing
3970           poly transfproc=erg[2];
3971           poly transb=erg[3];  // image of parameter from EXTHNEring(..)
3972           export transfproc;
3973           kill erg;
3974           setring HNE_noparam;
3975           if (not(defined(HNEs1))) { list HNEs1=ideal(0); }
3976           HNEs1=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3977           if (not(defined(hne))) { list hne=ideal(0); }
3978           hne=imap(SaveRing,hne);
3979           HNEs=imap(SaveRing,HNEs);
3980           setring EXTHNEring(EXTHNEnumber);
3981           map hole=HNE_noparam,transf,x,y;
3982           poly fneu=hole(fneu);
3983           poly f=hole(f);
3984           map phi=HNE_noparam,transb,x,y;
3985           list HNEs=hole(HNEs);
3986           list hne=hole(hne);
3987           export f,hne;
3988           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3989           list dummyL=phi(HNEs1);
3990           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3991           kill dummyL,phi,SaveRing;
3992         }
3993       }
3994     }
3995     else { // nur bei letzter Kante muss was getan werden
3996       if (i==size(Newton)-1) {
3997         EXTHNEnumber++;
3998         if (number_of_letztring==0) { def letztring=HNEring; }
3999         else       { def letztring=EXTHNEring(EXTHNEnumber); }
4000         if (minpoly==0) {
4001           def EXTHNEring(EXTHNEnumber)=SaveRing;
4002           setring EXTHNEring(EXTHNEnumber);
4003           if (not(defined(f))) {poly f; f=hole(f); export f;}
4004           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
4005           list dummyL=imap(letztring,HNEs);
4006           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
4007           kill dummyL,letztring,SaveRing;
4008         }
4009         else { // muessen Daten nach SaveRing uebertragen;
4010           setring HNE_noparam;
4011           if (not(defined(HNEs))) { list HNEs; }
4012           HNEs=imap(letztring,HNEs);
4013           def EXTHNEring(EXTHNEnumber)=SaveRing;
4014           setring EXTHNEring(EXTHNEnumber);
4015           if (not(defined(hole))) { map hole; }
4016           hole=HNE_noparam,transfproc,x,y;
4017           list dummyL=hole(HNEs);
4018           if (not(defined(HNEs))) { def HNEs=list(); }
4019           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
4020           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
4021           kill dummyL, letztring,SaveRing;
4022         }
4023       }
4024     }
4025   }
4026   // -----------------end of new part (loop for essential=1) ----------------
4027  } // end (Loop uber Kanten)
4028  if (defined(SaveRing)) { kill SaveRing; }
4029 }
4030 else {
4031  HNEs[1]=list(hqs)+azeilen+list(fneu); // fneu ist transform. Polynom oder Null
4032  conj1[1]=conj_factor;
4033 }
4034
4035 if (Aufruf_Ebene == 1)
4036 {
4037   if ((number_of_letztring!=EXTHNEnumber) and (not(defined(hne))))
4038   {
4039     //----- falls Zweige in transz. Erw. berechnet werden konnten ---------
4040     if (defined(transfproc))
4041     { // --- Ringwechsel hat stattgefunden ---
4042       if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
4043       if (not(defined(hole))) { map hole; }
4044       hole=HNE_noparam,transfproc,x,y;
4045       setring HNE_noparam;
4046       f=imap(HNEring,f);
4047       if (number_of_letztring==0) { def letztring=HNEring; }
4048       else                        { def letztring=EXTHNEring(EXTHNEnumber); }
4049       if (not(defined(hne))) { list hne; }
4050       hne=imap(letztring,hne);
4051       setring EXTHNEring(EXTHNEnumber);
4052       if (not(defined(f))) { poly f=hole(f); export f; }
4053       list hne=hole(hne);
4054       export hne;
4055     }
4056   }
4057   if (size(HNEs)>0) {
4058     if ((size(HNEs)>1) or (typeof(HNEs[1])!="ideal") or (size(HNEs[1])>0)) {
4059       if ((typeof(hne[1])=="ideal")) { hne=list(); }
4060       hne=hne+extractHNEs(HNEs,getauscht);
4061       if (hne_conj==0) { hne_conj=conj1; }
4062       else { hne_conj = hne_conj, conj1; }
4063     }
4064   }
4065 }
4066 else
4067 { // HN wurde rekursiv aufgerufen
4068   if (number_of_letztring!=EXTHNEnumber)
4069   { // Ringwechsel hatte stattgefunden
4070     string mipl_alt = string(minpoly);
4071     ring tempRing = create_ring(ringlist(basering)[1],"("+varstr(basering)+")","("+ordstr(basering)+")","no_minpoly");
4072     execute("minpoly="+ mipl_alt +";");
4073     list HNEs=imap(EXTHNEring(EXTHNEnumber),HNEs);
4074     export HNEs;
4075     if (defined(HNDebugOn)) {" ! tempRing defined ! ";}
4076   }
4077   if (conj1!=0) { hne_conj=conj1; }
4078   else          { hne_conj=conj_factor; }
4079 }
4080 if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
4081 HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring);
4082 if (number_of_letztring==EXTHNEnumber) {
4083   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,HNEs,hne_conj));
4084 }
4085 else {
4086   if (defined(tempRing)) {
4087     return(list(HNE_RingDATA,EXTHNEnumber,field_ext,tempRing,hne_conj));
4088   }
4089   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,0,hne_conj));
4090 }
4091}
4092
4093///////////////////////////////////////////////////////////////////////////////
4094
4095static proc constructHNEs (list HNEs,int hnezaehler,list aneu,list azeilen,
4096                    int zeile,ideal deltais,int Q,int j)
4097"NOTE: This procedure is only for internal use, it is called via HN"
4098{
4099  int zaehler,zl;
4100  ideal hilfid;
4101  list hilflist;
4102  intvec hilfvec;
4103  for (zaehler=1; zaehler<=size(aneu); zaehler++) {
4104     hnezaehler++;
4105     // HNEs[hnezaehler]=azeilen;            // dupliziere gemeins. Anfang
4106 //----------------------- trage neu berechnete Daten ein ---------------------
4107     hilfid=azeilen[zeile+2];
4108     hilfid[Q]=deltais[j];
4109     for (zl=Q+1; zl<=ncols(aneu[zaehler][2]); zl++) {
4110      hilfid[zl]=aneu[zaehler][2][zl];
4111     }
4112     hilflist=azeilen; hilflist[zeile+2]=hilfid;
4113 //------------------ haenge uebrige Zeilen von aneu[] an: --------------------
4114     for (zl=3; zl<=size(aneu[zaehler]); zl++) {
4115      hilflist[zeile+zl]=aneu[zaehler][zl];
4116     }
4117 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
4118     if (hilflist[1]==0) { hilflist[1]=aneu[zaehler][1]; }
4119     else { hilfvec=hilflist[1],aneu[zaehler][1]; hilflist[1]=hilfvec; }
4120     HNEs[hnezaehler]=hilflist;
4121  }
4122  return(HNEs,hnezaehler);
4123}
4124///////////////////////////////////////////////////////////////////////////////
4125
4126proc referencepoly (list newton)
4127"USAGE:   referencepoly(newton);
4128         newton is list of intvec(x,y) which represents points in the Newton
4129         diagram (e.g. output of the proc newtonpoly)
4130RETURN:  a polynomial which has newton as Newton diagram
4131SEE ALSO: newtonpoly
4132EXAMPLE: example referencepoly;  shows an example
4133"
4134{
4135 poly f;
4136 for (int i=1; i<=size(newton); i++) {
4137   f=f+var(1)^newton[i][1]*var(2)^newton[i][2];
4138 }
4139 return(f);
4140}
4141example
4142{ "EXAMPLE:"; echo = 2;
4143 ring exring=0,(x,y),ds;
4144 referencepoly(list(intvec(0,4),intvec(2,3),intvec(5,1),intvec(7,0)));
4145}
4146///////////////////////////////////////////////////////////////////////////////
4147
4148proc factorlist (list L, list #)
4149"USAGE:   factorlist(L);   L a list in the format of 'factorize'
4150RETURN:  the nonconstant irreducible factors of
4151         L[1][1]^L[2][1] * L[1][2]^L[2][2] *...* L[1][size(L[1])]^...
4152         with multiplicities (same format as factorize)
4153SEE ALSO: factorize
4154EXAMPLE: example factorlist;  shows an example
4155"
4156{
4157 int k;
4158 if ((size(#)>=1) and ((typeof(#[1])=="intvec") or (typeof(#[1])=="int"))) {
4159   int with_conj = 1; intvec C = #[1];
4160 }
4161 else {
4162   int with_conj = 0; intvec C = L[2];
4163 }
4164 // eine Sortierung der Faktoren eruebrigt sich, weil keine zwei versch.
4165 // red.Fakt. einen gleichen irred. Fakt. haben koennen (I.3.27 Diplarb.)
4166 int i,gross;
4167 list faktoren,hilf;
4168 intvec conjugates;
4169 ideal hil1,hil2;
4170 intvec v,w,hilf_conj;
4171 for (i=1; (L[1][i] == jet(L[1][i],0)) && (i<size(L[1])); i++) {;}
4172 if (L[1][i] != jet(L[1][i],0)) {
4173   hilf=factorize(L[1][i]);
4174 // Achtung!!! factorize(..,2) wirft entgegen der Beschreibung nicht nur
4175 // konstante Faktoren raus, sondern alle Einheiten in der LOKALISIERUNG nach
4176 // der Monomordnung!!! Im Beispiel unten verschwindet der Faktor x+y+1, wenn
4177 // man ds statt dp als Ordnung nimmt!
4178   hilf_conj=C[i];
4179   for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4180   hilf[2]=hilf[2]*L[2][i];
4181   hil1=hilf[1];
4182   gross=size(hil1);
4183   if (gross>1) {
4184     v=hilf[2];
4185     faktoren=list(ideal(hil1[2..gross]),intvec(v[2..gross]));
4186     conjugates=intvec(hilf_conj[2..gross]);
4187   }
4188   else         { faktoren=hilf; conjugates=hilf_conj; }
4189 }
4190 else {
4191   faktoren=L;
4192   conjugates=C;
4193 }
4194
4195 for (i++; i<=size(L[2]); i++) {
4196 //------------------------- linearer Term -- irreduzibel ---------------------
4197   if (L[1][i] == jet(L[1][i],1)) {
4198     if (L[1][i] != jet(L[1][i],0)) {           // konst. Faktoren eliminieren
4199       hil1=faktoren[1];
4200       hil1[size(hil1)+1]=L[1][i];
4201       faktoren[1]=hil1;
4202       v=faktoren[2],L[2][i];
4203       conjugates=conjugates,C[i];
4204       faktoren[2]=v;
4205     }
4206   }
4207 //----------------------- nichtlinearer Term -- faktorisiere -----------------
4208   else {
4209     hilf=factorize(L[1][i]);
4210     hilf_conj=C[i];
4211     for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4212     hilf[2]=hilf[2]*L[2][i];
4213     hil1=faktoren[1];
4214     hil2=hilf[1];
4215     gross=size(hil2);
4216       // hil2[1] ist konstant, wird weggelassen:
4217     hil1[(size(hil1)+1)..(size(hil1)+gross-1)]=hil2[2..gross];
4218       // ideal+ideal does not work due to simplification;
4219       // ideal,ideal not allowed
4220     faktoren[1]=hil1;
4221     w=hilf[2];
4222     v=faktoren[2],w[2..gross];
4223     conjugates=conjugates,hilf_conj[2..gross];
4224     faktoren[2]=v;
4225   }
4226 }
4227 if (with_conj==0) { return(faktoren); }
4228 else { return(list(faktoren,conjugates)); }  // for essential development
4229}
4230example
4231{ "EXAMPLE:"; echo = 2;
4232 ring exring=0,(x,y),ds;
4233 list L=list(ideal(x,(x-y)^2*(x+y+1),x+y),intvec(2,2,1));
4234 L;
4235 factorlist(L);
4236}
4237
4238///////////////////////////////////////////////////////////////////////////////
4239
4240proc delta
4241"USAGE:  delta(INPUT);  INPUT a polynomial defining an isolated plane curve
4242         singularity at 0, or the Hamburger-Noether expansion thereof, i.e.
4243         the output of @code{develop(f)}, or the output of @code{hnexpansion(f)},
4244         or the list of HN data computed by @code{hnexpansion(f)}.
4245RETURN:  int, the delta invariant of the singularity at 0, that is, the vector
4246         space dimension of R~/R, (R~ the normalization of the local ring of
4247         the singularity).
4248NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
4249         for other purposes as well it is better to calculate this first
4250         with the aid of @code{hnexpansion} and use it as input instead of
4251         the polynomial itself.
4252SEE ALSO: deltaLoc, invariants
4253KEYWORDS: delta invariant
4254EXAMPLE: example delta;  shows an example
4255"
4256{
4257  if (typeof(#[1])=="poly") { // INPUT = polynomial defining the singularity
4258    list L=hnexpansion(#[1]);
4259    if (typeof(L[1])=="ring") {
4260      def altring = basering;
4261      def HNring = L[1]; setring HNring;
4262      return(delta(hne));
4263    }
4264    else {
4265      return(delta(L));
4266    }
4267  }
4268  if (typeof(#[1])=="ring") { // INPUT = HNEring of curve
4269    def HNring = #[1]; setring HNring;
4270    return(delta(hne));
4271  }
4272  if (typeof(#[1])=="matrix")
4273  { // INPUT = hne of an irreducible curve
4274    return(invariants(#)[5] div 2);
4275  }
4276  else
4277  { // INPUT = hne of a reducible curve
4278    list INV=invariants(#);
4279    return(INV[size(INV)][3]);
4280  }
4281}
4282example
4283{ "EXAMPLE:"; echo = 2;
4284  ring r = 32003,(x,y),ds;
4285  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
4286           +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
4287           -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
4288           +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
4289  delta(f);
4290}
4291
4292///////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.