source: git/Singular/LIB/hnoether.lib @ fd5013

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