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

spielwiese
Last change on this file since bc80a9 was bc80a9, checked in by Hans Schönemann <hannes@…>, 19 years ago
*hannes: help references git-svn-id: file:///usr/local/Singular/svn/trunk@7906 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 152.1 KB
Line 
1-       version="$Id: hnoether.lib,v 1.47 2005-04-26 17:19:14 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 paramametrize;   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 x 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 transformed,
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 transformed 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 in 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   if(system("with","Namespaces")) { kill Top::extdguenstig; }
2536   else { kill extdguenstig; }
2537 }
2538
2539 return(list(mneu,v,switch,f));
2540}
2541example
2542{
2543  "EXAMPLE:"; echo = 2;
2544  ring exring=0,(x,y),dp;
2545  list hne=hnexpansion(x14-3y2x11-y3x10-y2x9+3y4x8+y5x7+3y4x6+x5*(-y6+y5)
2546                      -3y6x3-y7x2+y8);
2547  displayHNE(hne);    // HNE of 1st,3rd branch is finite
2548  print(extdevelop(hne[1],5)[1]);
2549  list ehne=extdevelop(hne[2],5);
2550  displayHNE(ehne);
2551  param(hne[2]);
2552  param(ehne);
2553
2554}
2555///////////////////////////////////////////////////////////////////////////////
2556
2557proc stripHNE (list l)
2558"USAGE:   stripHNE(L);  L list
2559ASSUME:  L is the output of @code{develop(f)}, or of
2560         @code{extdevelop(develop(f),n)}, or (one entry of) the list
2561         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2562RETURN:  list in the same format as L, but all polynomials L[4], resp.
2563         L[i][4], are set to zero.
2564NOTE:    The purpose of this procedure is to remove huge amounts of data
2565         no longer needed. It is useful, if one or more of the polynomials
2566         in L consume much memory. It is still possible to compute invariants,
2567         parametrizations etc. with the stripped HNE(s), but it is not possible
2568         to use @code{extdevelop} with them.
2569SEE ALSO: develop, hnexpansion, extdevelop
2570EXAMPLE: example stripHNE;  shows an example
2571"
2572{
2573 list h;
2574 if (typeof(l[1])=="matrix") { l[4]=poly(0); }
2575 else {
2576  for (int i=1; i<=size(l); i++) {
2577    h=l[i];
2578    h[4]=poly(0);
2579    l[i]=h;
2580  }
2581 }
2582 return(l);
2583}
2584example
2585{
2586  "EXAMPLE:"; echo = 2;
2587  ring r=0,(x,y),dp;
2588  list hne=develop(x2+y3+y4);
2589  hne;
2590  stripHNE(hne);
2591}
2592///////////////////////////////////////////////////////////////////////////////
2593static proc extractHNEs(list HNEs, int transvers)
2594"USAGE:  extractHNEs(HNEs,transvers);  list HNEs (output from HN),
2595        int transvers: 1 if x,y were exchanged, 0 else
2596RETURN: list of Hamburger-Noether-Extensions in the form of hne in hnexpansion
2597NOTE:   This procedure is only for internal purpose; examples don't make sense
2598"
2599{
2600 int i,maxspalte,hspalte,hnezaehler;
2601 list HNEaktu,Ergebnis;
2602 for (hnezaehler=1; hnezaehler<=size(HNEs); hnezaehler++) {
2603  maxspalte=0;
2604  HNEaktu=HNEs[hnezaehler];
2605  if (defined(HNDebugOn)) {"To process:";HNEaktu;}
2606  if (size(HNEaktu)!=size(HNEaktu[1])+2) {
2607     "The ideals and the hqs in HNEs[",hnezaehler,"] don't match!!";
2608     HNEs[hnezaehler];
2609  }
2610 //------------ ermittle  maximale Anzahl benoetigter Spalten: ----------------
2611  for (i=2; i<size(HNEaktu); i++) {
2612    hspalte=ncols(HNEaktu[i]);
2613    maxspalte=maxspalte*(hspalte < maxspalte)+hspalte*(hspalte >= maxspalte);
2614  }
2615 //------------- schreibe Ausgabe fuer hnezaehler-ten Zweig: ------------------
2616  matrix ma[size(HNEaktu)-2][maxspalte];
2617  for (i=1; i<=(size(HNEaktu)-2); i++) {
2618    if (ncols(HNEaktu[i+1]) > 1) {
2619      ma[i,1..ncols(HNEaktu[i+1])]=HNEaktu[i+1]; }
2620    else { ma[i,1]=HNEaktu[i+1][1];}
2621  }
2622  Ergebnis[hnezaehler]=list(ma,HNEaktu[1],transvers,HNEaktu[size(HNEaktu)]);
2623  kill ma;
2624 }
2625 return(Ergebnis);
2626}
2627///////////////////////////////////////////////////////////////////////////////
2628
2629proc factorfirst(poly f, int M, int N)
2630"USAGE : factorfirst(f,M,N); f poly, M,N int
2631RETURN: number d such that f=const*(y^(N/e) - d*x^(M/e))^e, where e=gcd(M,N),
2632        0 if such a d does not exist
2633EXAMPLE: example factorfirst;  shows an example
2634"
2635{
2636 number c = koeff(f,0,N);
2637 number delt;
2638 int eps,l;
2639 int p=char(basering);
2640 string ringchar=charstr(basering);
2641
2642 if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
2643 int e = gcd(M,N);
2644
2645 if (p==0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2646 else {
2647   if (e%p != 0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2648   else {
2649     eps = e;
2650     for (l = 0; eps%p == 0; l=l+1) { eps=eps/ p;}
2651     if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
2652     delt = koeff(f,(M/ e)*p^l,(N/ e)*p^l*(eps-1)) / (-1*eps*c);
2653
2654     if ((charstr(basering) != string(p)) and (delt != 0)) {
2655 //------ coefficient field is not Z/pZ => (p^l)th root is not identity -------
2656       delt=0;
2657       if (defined(HNDebugOn)) {
2658         "trivial factorization not implemented for",
2659         "parameters---I've to use 'factorize'";
2660       }
2661     }
2662   }
2663 }
2664 if (defined(HNDebugOn)) {"quasihomogeneous leading form:",f," = ",c,
2665        "* (y^"+string(N/ e),"-",delt,"* x^"+string(M/ e)+")^",e," ?";}
2666 if (f != c*(var(2)^(N/ e) - delt*var(1)^(M/ e))^e) {return(0);}
2667 else {return(delt);}
2668}
2669example
2670{ "EXAMPLE:"; echo = 2;
2671  ring exring=7,(x,y),dp;
2672  factorfirst(2*(y3-3x4)^5,20,15);
2673  factorfirst(x14+y7,14,7);
2674  factorfirst(x14+x8y3+y7,14,7);
2675}
2676
2677///////////////////////////////////////////////////////////////////////////
2678
2679proc hnexpansion(poly f,list #)
2680"USAGE:   hnexpansion(f[,\"ess\"]);   f poly
2681ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2682RETURN:  list @code{L}, containing Hamburger-Noether data of @code{f}:
2683         If the computation of the HNE required no field extension, @code{L}
2684         is a list of lists @code{L[i]} (corresponding to the output of
2685         @code{develop}, applied to a branch of @code{f}, but the last entry
2686         being omitted):
2687@texinfo
2688@table @asis
2689@item @code{L[i][1]}; matrix:
2690         Each row contains the coefficients of the corresponding line of the
2691         Hamburger-Noether expansion (HNE) for the i-th branch. The end of
2692         the line is marked in the matrix by the first ring variable
2693         (usually x).
2694@item @code{L[i][2]}; intvec:
2695         indicating the length of lines of the HNE
2696@item @code{L[i][3]}; int:
2697         0  if the 1st ring variable was transversal (with respect to the
2698            i-th branch), @*
2699         1  if the variables were changed at the beginning of the
2700            computation, @*
2701        -1  if an error has occurred.
2702@item @code{L[i][4]}; poly:
2703         the transformed equation of the i-th branch to make it possible
2704         to extend the Hamburger-Noether data a posteriori without having
2705         to do all the previous calculation once again (0 if not needed).
2706@end table
2707@end texinfo
2708         If the computation of the HNE required a field extension, the first
2709         entry @code{L[1]} of the list is a ring, in which a list @code{hne}
2710         of lists (the HN data, as above) and a poly @code{f} (image of
2711         @code{f} over the new field) are stored.
2712         @*
2713         If called with an additional input parameter, @code{hnexpansion}
2714         computes only one representative for each class of conjugate
2715         branches (over the ground field active when calling the procedure).
2716         In this case, the returned list @code{L} always has only two
2717         entries: @code{L[1]} is either a list of lists (the HN data) or a
2718         ring (as above), and @code{L[2]} is an integer vector (the number
2719         of branches in the respective conjugacy classes).
2720
2721NOTE:    If f is known to be irreducible as a power series, @code{develop(f)}
2722         could be chosen instead to avoid a change of basering during the
2723         computations. @*
2724         Increasing  @code{printlevel} leads to more and more comments. @*
2725         Having defined a variable @code{HNDebugOn} leads to a maximum
2726         number of comments.
2727
2728SEE ALSO: develop, extdevelop, param, displayHNE
2729EXAMPLE: example hnexpansion;  shows an example
2730"
2731{
2732 int essential;
2733 if (size(#)==1) { essential=1; }
2734 int field_ext;
2735 def altring=basering;
2736
2737 //--------- Falls Ring (p^k,a),...: Wechsel in (p,a),... + minpoly -----------
2738 if ( (find(charstr(basering),string(char(basering)))!=1) &&
2739      (charstr(basering)<>"real")&&
2740      (charstr(basering)<>"complex") ) {
2741   string strmip=string(minpoly);
2742   string strf=string(f);
2743   execute("ring tempr=("+string(char(basering))+","+parstr(basering)+"),("
2744           +varstr(basering)+"),dp;");
2745   execute("minpoly="+strmip+";");
2746   execute("poly f="+strf+";");
2747   field_ext=1;
2748   def L=pre_HN(f,essential);
2749   if (size(L)==0) { return(list()); }
2750   def HNEring=L[1];
2751   setring HNEring;
2752   if ((typeof(hne[1])=="ideal")) { return(list()); }
2753   if ((voice==2) && (printlevel > -1)) {
2754     "// Attention: The parameter",par(1),"may have changed its meaning!";
2755     "// It needs no longer be a generator of the cyclic group of unities!";
2756   }
2757   dbprint(printlevel-voice+2,
2758     "// result: "+string(size(hne))+" branch(es) successfully computed.");
2759 }
2760 else {
2761   def L=pre_HN(f,essential);
2762   if (size(L)==0) { return(list()); }
2763   if (L[2]==1) { field_ext=1; }
2764   intvec hne_conj=L[3];
2765   def HNEring=L[1];
2766   setring HNEring;
2767   if ((typeof(hne[1])=="ideal")) { return(list()); }
2768   dbprint(printlevel-voice+2,
2769      "// result: "+string(size(hne))+" branch(es) successfully computed.");
2770 }
2771
2772 // ----- Lossen 10/02 : the branches have to be resorted to be able to
2773 // -----                display the multsequence in a nice way
2774 if (size(hne)>2)
2775 { 
2776   int i,j,k,m;
2777   list dummy;
2778   int nbsave;
2779   int no_br = size(hne);
2780   intmat nbhd[no_br][no_br];
2781   for (i=1;i<no_br;i++)
2782   {
2783     for (j=i+1;j<=no_br;j++) 
2784     {
2785       nbhd[i,j]=separateHNE(hne[i],hne[j]);
2786       k=i+1;
2787       while ( (nbhd[i,k] >= nbhd[i,j]) and (k<j) )
2788       {
2789         k++;
2790       }
2791       if (k<j)  // branches have to be resorted
2792       {
2793         dummy=hne[j];
2794         nbsave=nbhd[i,j];
2795         for (m=k; m<j; m++)
2796         {
2797           hne[m+1]=hne[m];
2798           nbhd[i,m+1]=nbhd[i,m];
2799         }
2800         hne[k]=dummy;
2801         nbhd[i,k]=nbsave;
2802       }
2803     }
2804   }
2805 }
2806 // -----
2807 
2808 if (field_ext==1) {
2809   dbprint(printlevel-voice+3,"
2810// 'hnexpansion' created a list of one ring.
2811// To see the ring and the data stored in the ring, type (if you assigned
2812// the name L to the list):
2813     show(L);
2814// To display the computed HN expansion, type
2815     def HNring = L[1]; setring HNring;  displayHNE(hne); ");
2816   if (essential==1) {
2817     dbprint(printlevel-voice+3,""+
2818"// As second entry of the returned list L, you obtain an integer vector,
2819// indicating the number of conjugates for each of the computed branches.");
2820     return(list(HNEring,hne_conj));
2821   }   
2822   return(list(HNEring));
2823 }
2824 else { // no change of basering necessary --> map data to original ring
2825   setring altring;
2826   if ((npars(altring)==1) and (minpoly!=0)) {
2827     ring HNhelpring=char(altring),(a,x,y),ls;
2828     list hne=imap(HNEring,hne);
2829     setring altring;
2830     map mmm=HNhelpring,par(1),var(1),var(2);
2831     list hne=mmm(hne);
2832     kill mmm,HNhelpring;
2833   }
2834   else {   
2835     list hne=fetch(HNEring,hne);
2836   }
2837   kill HNEring;
2838   if (essential==1) {
2839     dbprint(printlevel-voice+3,""+
2840"// No change of ring necessary, return value is a list:
2841//   first entry  =  list :  HN expansion of essential branches.
2842//   second entry =  intvec: numbers of conjugated branches ");
2843     return(list(hne,hne_conj));
2844   }
2845   else {
2846     dbprint(printlevel-voice+3,""+
2847"// No change of ring necessary, return value is HN expansion.");
2848     return(hne);
2849   }
2850 }
2851}
2852example
2853{
2854  "EXAMPLE:"; echo = 2;
2855  ring r=0,(x,y),dp;
2856  // First, an example which requires no field extension:
2857  list hne=hnexpansion(x4-y6);
2858  size(hne);           // number of branches
2859  displayHNE(hne);     // HN expansion of branches
2860  param(hne[1]);       // parametrization of 1st branch
2861  param(hne[2]);       // parametrization of 2nd branch
2862
2863  // An example which requires a field extension:
2864  list L=hnexpansion((x4-y6)*(y2+x4));
2865  def R=L[1]; setring R; displayHNE(hne);
2866  basering;
2867  setring r; kill R;
2868 
2869  // Computing only one representative per conjugacy class:
2870  L=hnexpansion((x4-y6)*(y2+x4),"ess");
2871  def R=L[1]; setring R; displayHNE(hne);
2872  L[2];     // number of branches in respective conjugacy classes
2873}
2874
2875///////////////////////////////////////////////////////////////////////////////
2876
2877static proc pre_HN (poly f, int essential)
2878"NOTE: This procedure is only for internal use, it is called via
2879       hnexpansion
2880RETURN: list:  first entry = HNEring  (containing list hne, poly f)
2881               second entry = 0  if no change of base ring necessary
2882                              1  if change of base ring necessary
2883               third entry = numbers of conjugates ( if essential = 1 )
2884        if some error has occured, the empty list is returned
2885"
2886{
2887 def altring = basering;
2888 int p = char(basering);
2889 int field_ext;
2890 intvec hne_conj;
2891
2892 //-------------------- Tests auf Zulaessigkeit von basering ------------------
2893 if (charstr(basering)=="real") {
2894   " Singular cannot factorize over 'real' as ground field";
2895   return(list());
2896 }
2897 if (size(maxideal(1))<2) {
2898   " A univariate polynomial ring makes no sense !";
2899   return(list());
2900 }
2901 if (size(maxideal(1))>2) {
2902   dbprint(printlevel-voice+2,
2903   " Warning: all variables except the first two will be ignored!");
2904 }
2905 if (find(charstr(basering),string(char(basering)))!=1) {
2906   " ring of type (p^k,a) not implemented";
2907 //----------------------------------------------------------------------------
2908 // weder primitives Element noch factorize noch map "char p^k" -> "char -p"
2909 // [(p^k,a)->(p,a) ground field] noch fetch
2910 //----------------------------------------------------------------------------
2911   return(list());
2912 }
2913 //----------------- Definition eines neuen Ringes: HNEring -------------------
2914 string namex=varstr(1); string namey=varstr(2);
2915 if (string(char(altring))==charstr(altring)) { // kein Parameter, nicht 'real'
2916   ring HNEring = char(altring),(x,y),ls;
2917   map m=altring,x,y;
2918   poly f=m(f);
2919   export f;
2920   kill m;
2921 }
2922 else {
2923   string mipl=string(minpoly);
2924   if (mipl=="0") {
2925     "// ** WARNING: Algebraic extension of given ground field not possible!";
2926     "// ** We try to develop this polynomial, but if the need for a field";
2927     "// ** extension occurs during the calculation, we cannot proceed with";
2928     "// ** the corresponding branches.";
2929     execute("ring HNEring=("+charstr(basering)+"),(x,y),ls;");
2930   }
2931   else {
2932    string pa=parstr(altring);
2933    ring HNhelpring=p,`pa`,dp;
2934    execute("poly mipo="+mipl+";");  // Minimalpolynom in Polynom umgewandelt
2935    ring HNEring=(p,a),(x,y),ls;
2936    map getminpol=HNhelpring,a;
2937    mipl=string(getminpol(mipo));    // String umgewandelt mit 'a' als Param.
2938    execute("minpoly="+mipl+";");    // "minpoly=poly is not supported"
2939    kill HNhelpring, getminpol;
2940   }
2941   if (nvars(altring)==2) {
2942     poly f=fetch(altring,f);
2943     export f;
2944   }
2945   else {
2946     if (defined(pa)) { // Parameter hatte vorher anderen Namen als 'a'
2947       ring HNhelpring=p,(`pa`,x,y),ls;
2948       poly f=imap(altring,f);
2949       setring HNEring;
2950       map m=HNhelpring,a,x,y;
2951       poly f=m(f);
2952       kill HNhelpring;
2953     }
2954     else {
2955       map m=altring,x,y;
2956       poly f=m(f);
2957     }
2958     export f;
2959     kill m;
2960   }
2961 }
2962 
2963 if (defined(HNDebugOn))
2964 {"received polynomial: ",f,", with x =",namex,", y =",namey;}
2965
2966 //----------------------- Variablendefinitionen ------------------------------
2967 int Abbruch,i,NullHNEx,NullHNEy;
2968 string str;
2969 list Newton,hne;
2970
2971 // --- changed for SINGULAR 3: ---
2972 hne=ideal(0);
2973 export hne;
2974
2975 //====================== Tests auf Zulaessigkeit des Polynoms ================
2976
2977 //-------------------------- Test, ob Einheit oder Null ----------------------
2978 if (subst(subst(f,x,0),y,0)!=0) {
2979   dbprint(printlevel+1,
2980           "The given polynomial is a unit in the power series ring!");
2981   setring altring; kill HNEring;
2982   return(list());                   // there are no HNEs
2983 }
2984 if (f==0) {
2985   dbprint(printlevel+1,"The given polynomial is zero!");
2986   setring altring; kill HNEring;
2987   return(list());                   // there are no HNEs
2988 }
2989
2990 //-----------------------  Test auf Quadratfreiheit --------------------------
2991
2992 if ((p==0) and (size(charstr(basering))==1)) {
2993
2994 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
2995 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
2996 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring HNEring
2997 //----------------------------------------------------------------------------
2998  int testerg=(polytest(f)==0);
2999  ring zweitring = 32003,(x,y),dp;
3000
3001  map polyhinueber=HNEring,x,y;         // fetch geht nicht
3002  poly f=polyhinueber(f);
3003  poly test_sqr=squarefree(f);
3004  if (test_sqr != f) {
3005   if (printlevel>0) {
3006     "Most probably the given polynomial is not squarefree. But the test was";
3007     "made in characteristic 32003 and not 0 to improve speed. You can";
3008     "(r) redo the test in char 0 (but this may take some time)";
3009     "(c) continue the development, if you're sure that the polynomial IS",
3010     "squarefree";
3011     if (testerg==1) {
3012       "(s) continue the development with a squarefree factor (*)";}
3013     "(q) or just quit the algorithm (default action)";
3014     "";"Please enter the letter of your choice:";
3015     str=read("")[1];             // reads one character
3016   }
3017   else { str="r"; }              // printlevel <= 0: non-interactive behaviour
3018   setring HNEring;
3019   map polyhinueber=zweitring,x,y;
3020   if (str=="r") {
3021     poly test_sqr=squarefree(f);
3022     if (test_sqr != f) {
3023      if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
3024      else              { "The given polynomial is not squarefree!"; }
3025      "I'll continue with the radical.";
3026      f=test_sqr;
3027     }
3028     else {
3029      dbprint(printlevel,
3030       "everything is ok -- the polynomial is squarefree in characteristic 0");
3031     }
3032   }
3033   else {
3034     if ((str=="s") and (testerg==1)) {
3035       "(*)attention: it could be that the factor is only one in char 32003!";
3036       f=polyhinueber(test_sqr);
3037     }
3038     else {
3039       if (str<>"c") {
3040         setring altring;
3041         kill HNEring;kill zweitring;
3042         return(list());}
3043       else { "if the algorithm doesn't terminate, you were wrong...";}
3044   }}
3045   kill zweitring;
3046   if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3047  }
3048  else {
3049    setring HNEring;
3050    kill zweitring;
3051  }
3052 }
3053 //------------------ Fall Char > 0 oder Ring hat Parameter -------------------
3054 else {
3055  poly test_sqr=squarefree(f);
3056  if (test_sqr != f) {
3057   if (printlevel>0) {
3058    if (test_sqr == 1) {
3059     "The given polynomial is of the form g^"+string(p)+",";
3060     "therefore not squarefree.  You can:";
3061     " (q) quit the algorithm (recommended) or";
3062     " (f) continue with the full radical (using a factorization of the";
3063     "     pure power part; this could take much time)";
3064     "";"Please enter the letter of your choice:";
3065     str=read("")[1];
3066     if (str<>"f") { str="q"; }
3067    }
3068    else {
3069     "The given polynomial is not squarefree.";
3070     if (p != 0)
3071      {
3072       " You can:";
3073       " (c) continue with a squarefree divisor (but factors of the form g^"
3074       +string(p);
3075       "     are lost; this is recommended, takes no extra time)";
3076       " (f) continue with the full radical (using a factorization of the";
3077       "     pure power part; this could take some time)";
3078       " (q) quit the algorithm";
3079       "";"Please enter the letter of your choice:";
3080       str=read("")[1];
3081       if ((str<>"f") && (str<>"q")) { str="c"; }
3082      }
3083     else { "I'll continue with the radical."; str="c"; }
3084    }                                // endelse (test_sqr!=1)
3085   }
3086   else {
3087     "//** Error: The given polynomial is not squarefree!";
3088     "//** Since the global variable `printlevel' has the value",printlevel,
3089       "we stop here.";
3090     "//   Either call me again with a squarefree polynomial f or assign";
3091     "            printlevel=1;";
3092     "//   before calling me with a non-squarefree f.";
3093     "//   If printlevel > 0, I present some possibilities how to proceed.";
3094     str="q";
3095   }
3096   if (str=="q") {
3097    setring altring;kill HNEring;
3098    return(list());
3099   }
3100   if (str=="c") { f=test_sqr; }
3101   if (str=="f") { f=allsquarefree(f,test_sqr); }
3102  }
3103  if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3104
3105 }
3106 //====================== Ende Test auf Quadratfreiheit =======================
3107 if (subst(subst(f,x,0),y,0)!=0) {
3108   "The polynomial is a unit in the power series ring. No HNE computed.";
3109   setring altring;kill HNEring;
3110   return(list());
3111 }
3112 //---------------------- Test, ob f teilbar durch x oder y -------------------
3113 if (subst(f,y,0)==0) {
3114   f=f/y; NullHNEy=1; }             // y=0 is a solution
3115 if (subst(f,x,0)==0) {
3116   f=f/x; NullHNEx=1; }             // x=0 is a solution
3117
3118 Newton=newtonpoly(f,1);
3119 i=1; Abbruch=0;
3120 //----------------------------------------------------------------------------
3121 // finde Eckpkt. des Newtonpolys, der den Teil abgrenzt, fuer den x transvers:
3122 // Annahme: Newton ist sortiert, s.d. Newton[1]=Punkt auf der y-Achse,
3123 // Newton[letzt]=Punkt auf der x-Achse
3124 //----------------------------------------------------------------------------
3125 while ((i<size(Newton)) and (Abbruch==0)) {
3126  if ((Newton[i+1][1]-Newton[i][1])>=(Newton[i][2]-Newton[i+1][2]))
3127   {Abbruch=1;}
3128  else {i=i+1;}
3129 }
3130 int grenze1=Newton[i][2];
3131 int grenze2=Newton[i][1];
3132 //----------------------------------------------------------------------------
3133 // Stelle Ring bereit zur Uebertragung der Daten im Fall einer Koerperer-
3134 // weiterung. Definiere Objekte, die spaeter uebertragen werden.
3135 // Binde die Listen (azeilen,...) an den Ring (um sie nicht zu ueberschreiben
3136 // bei Def. in einem anderen Ring).
3137 //----------------------------------------------------------------------------
3138 ring HNE_noparam = char(altring),(a,x,y),ls;
3139 poly f;
3140 list azeilen=ideal(0);
3141 list HNEs=ideal(0);
3142 list aneu=ideal(0);
3143 list faktoren=ideal(0);
3144
3145 ideal deltais;
3146 poly delt;
3147
3148 //----- hier steht die Anzahl bisher benoetigter Ringerweiterungen drin: -----
3149 int EXTHNEnumber=0;
3150
3151 list EXTHNEring;
3152 list HNE_RingDATA;
3153 int number_of_letztring;
3154 setring HNEring;
3155 number_of_letztring=0;
3156
3157 // ================= Die eigentliche Berechnung der HNE: =====================
3158
3159 // ------- Berechne HNE von allen Zweigen, fuer die x transversal ist: -------
3160 if (defined(HNDebugOn))
3161   {"1st step: Treat Newton polygon until height",grenze1;}
3162 if (grenze1>0) {
3163  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3164  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3165                      number_of_letztring);
3166
3167  list hilflist=HN(HNE_RingDATA,f,grenze1,1,essential,0,hne_conj,1);
3168  kill HNEring, HNE_noparam;
3169  if (EXTHNEnumber>0) { kill EXTHNEring(1..EXTHNEnumber);}
3170  def HNEring = hilflist[1][1];
3171  def HNE_noparam = hilflist[1][2];
3172  EXTHNEnumber = hilflist[1][3];
3173  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3174  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3175  else                { setring EXTHNEring(hilflist[2]);}
3176  if (hilflist[3]==1){field_ext=1;}
3177  hne_conj=hilflist[5];
3178
3179  if (number_of_letztring != hilflist[2])
3180  {  // Ringwechsel in Prozedur HN
3181     map hole=HNE_noparam,transfproc,x,y;
3182     setring HNE_noparam;
3183     if (not(defined(f))) {poly f;}
3184     f=imap(HNEring,f);
3185     setring EXTHNEring(EXTHNEnumber);
3186     if (not(defined(f))) {poly f; f=hole(f); export f;}
3187     else                 {f=hole(f);}
3188  }
3189  number_of_letztring = hilflist[2];
3190  kill hilflist;
3191 }
3192
3193 if (NullHNEy==1) {
3194  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3195  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(0),poly(0)));
3196  if (hne_conj==0) { hne_conj=1; }
3197  else { hne_conj = hne_conj, 1; }
3198 }
3199 // --------------- Berechne HNE von allen verbliebenen Zweigen: --------------
3200 if (defined(HNDebugOn))
3201    {"2nd step: Treat Newton polygon until height",grenze2;}
3202 if (grenze2>0) {
3203
3204  if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3205
3206  if (essential==1) { number_of_letztring=0; }
3207  if (number_of_letztring==0) { setring HNEring; }
3208  else                        { setring EXTHNEring(number_of_letztring); }
3209  map xytausch=basering,y,x;
3210
3211  HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3212                      number_of_letztring);
3213  list hilflist=HN(HNE_RingDATA,xytausch(f),grenze2,1,essential,1,hne_conj,1);
3214  kill HNEring, HNE_noparam;
3215  if (EXTHNEnumber>0){ kill EXTHNEring(1..EXTHNEnumber); }
3216  def HNEring = hilflist[1][1];
3217  def HNE_noparam = hilflist[1][2];
3218  EXTHNEnumber = hilflist[1][3];
3219  for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=hilflist[1][4][i]; }
3220  if (hilflist[2]==0) { setring HNEring; number_of_letztring=0; }
3221  else                { setring EXTHNEring(hilflist[2]);
3222                        number_of_letztring=hilflist[2]; }
3223  if (hilflist[3]==1){field_ext=1;}
3224  hne_conj=hilflist[5];
3225  kill hilflist;
3226 }
3227 if (NullHNEx==1) {
3228  if ((typeof(hne[1])=="ideal")) { hne=list(); }
3229  hne=hne+list(list(matrix(ideal(0,x)),intvec(1),int(1),poly(0)));
3230  if (hne_conj==0) { hne_conj=1; }
3231  else { hne_conj = hne_conj, 1; }
3232 }
3233
3234
3235 // --- aufraeumen ---
3236 if (defined(HNEakut)){
3237   kill HNEakut,faktoren,deltais,transformiert,teiler,leitf;
3238 }
3239 if (defined(hilflist)) {kill hilflist;}
3240 if (defined(erg)) {kill erg;}
3241 if (defined(delt)) {kill delt;}
3242 if (defined(azeilen)) { kill azeilen;}
3243 if (defined(aneu)) { kill aneu;}
3244 if (defined(transfproc)) { kill transfproc;}
3245 if (defined(transf)) { kill transf;}
3246 if (not(defined(f))) { poly f = imap(HNEring,f); export f; }
3247
3248 return(list(basering,field_ext,hne_conj));
3249}
3250
3251//////////////////////////////////////////////////////////////////////////////
3252proc essdevelop (poly f)
3253"USAGE:   essdevelop(f); f poly
3254NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.
3255SEE ALSO: hnexpansion, develop, extdevelop, param
3256"
3257{
3258 printlevel=printlevel+1;
3259 list Ergebnis=hnexpansion(f,1);
3260 printlevel=printlevel-1;
3261 return(Ergebnis);
3262}
3263
3264///////////////////////////////////////////////////////////////////////////////
3265static proc HN (list HNE_RingDATA,poly fneu,int grenze,Aufruf_Ebene,
3266                     essential,getauscht,intvec hne_conj,int conj_factor) 
3267"NOTE: This procedure is only for internal use, it is called via pre_HN
3268RETURN: list: first entry = list of HNErings,
3269              second entry = number of new base ring (0 for HNEring,
3270                                                      -1 for HNE_noparam,
3271                                                      i for EXTHNEring(i))
3272              third entry = 0 if no field extension necessary
3273                            1 if field extension necessary
3274              forth entry = HNEs (only if no change of basering)
3275"
3276{
3277 //---------- Variablendefinitionen fuer den unverzweigten Teil: --------------
3278 if (defined(HNDebugOn)) {"procedure HN",Aufruf_Ebene;}
3279 int Abbruch,ende,i,j,k,e,M,N,Q,R,zeiger,zeile,zeilevorher,dd;
3280 intvec hqs;
3281 int field_ext;
3282 int ring_changed, hneshift;
3283 intvec conjugates,conj2,conj1;
3284
3285 list EXTHNEring;
3286 def HNEring = HNE_RingDATA[1];
3287 def HNE_noparam = HNE_RingDATA[2];
3288 int EXTHNEnumber = HNE_RingDATA[3];
3289 for (i=1; i<=EXTHNEnumber; i++) { def EXTHNEring(i)=HNE_RingDATA[4][i]; }
3290 int number_of_letztring = HNE_RingDATA[5];
3291 if (defined(basering))
3292 {
3293   if (number_of_letztring==0) { kill HNEring; def HNEring=basering; }
3294   else                 { kill EXTHNEring(number_of_letztring);
3295                          def EXTHNEring(number_of_letztring)=basering; }
3296 }
3297 else
3298 {
3299   if ( number_of_letztring==0) { setring HNEring; }
3300   else                         { setring EXTHNEring(number_of_letztring); }
3301 }
3302 if (not(defined(hne))) {list hne;}
3303 poly fvorher;
3304 list erg=ideal(0); list HNEs=ideal(0); // um die Listen an den Ring zu binden
3305
3306 //-------------------- Bedeutung von Abbruch: --------------------------------
3307 //------- 0:keine Verzweigung | 1:Verzweigung,nicht fertig | 2:fertig --------
3308 //
3309 // Struktur von HNEs : Liste von Listen L (fuer jeden Zweig) der Form
3310 // L[1]=intvec (hqs), L[2],L[3],... ideal (die Zeilen (0,1,...) der HNE)
3311 // L[letztes]=poly (transformiertes f)
3312 //----------------------------------------------------------------------------
3313 list Newton;
3314 number delt;
3315 int p = char(basering);                // Ringcharakteristik
3316 list azeilen=ideal(0);
3317
3318 ideal hilfid; intvec hilfvec;
3319
3320 // ======================= der unverzweigte Teil: ============================
3321 while (Abbruch==0) {
3322  Newton=newtonpoly(fneu,1);
3323  zeiger=find_in_list(Newton,grenze);
3324  if (Newton[zeiger][2] != grenze)
3325    {"Didn't find an edge in the Newton polygon!";}
3326  if (zeiger==size(Newton)-1) {
3327    if (defined(HNDebugOn)) {"only one relevant side in Newton polygon";}
3328    M=Newton[zeiger+1][1]-Newton[zeiger][1];
3329    N=Newton[zeiger][2]-Newton[zeiger+1][2];
3330    R = M%N;
3331    Q = M / N;
3332
3333    //-------- 1. Versuch: ist der quasihomogene Leitterm reine Potenz ? ------
3334    //              (dann geht alles wie im irreduziblen Fall)
3335    //-------------------------------------------------------------------------
3336    e = gcd(M,N);
3337    delt=factorfirst(redleit(fneu,Newton[zeiger],Newton[zeiger+1])
3338                      /x^Newton[zeiger][1],M,N);
3339    if (delt==0) {
3340      if (defined(HNDebugOn)) {" The given polynomial is reducible !";}
3341      Abbruch=1;
3342    }
3343    if (Abbruch==0) {
3344      //----------- fneu,zeile retten fuer den Spezialfall (###): -------------
3345      fvorher=fneu;zeilevorher=zeile;
3346      if (R==0) {
3347        //-------- transformiere fneu mit T1, wenn kein Abbruch nachher: ------
3348        if (N>1) { fneu = T1_Transform(fneu,delt,M/ e); }
3349        else     { ende=1; }
3350        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3351        azeilen[zeile+1][Q]=delt;
3352      }
3353      else {
3354        //------------- R > 0 : transformiere fneu mit T2 ---------------------
3355        erg=T2_Transform(fneu,delt,M,N,referencepoly(Newton));
3356        fneu=erg[1];delt=erg[2];
3357        //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ----
3358        while (R!=0) {
3359         if (defined(HNDebugOn)) { "h("+string(zeile)+") =",Q; }
3360         hqs[zeile+1]=Q;         // denn zeile beginnt mit dem Wert 0
3361         //--------------- markiere das Zeilenende der HNE: -------------------
3362         azeilen[zeile+1][Q+1]=x;
3363         zeile=zeile+1;
3364         //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ----
3365         azeilen[zeile+1]=ideal(0);
3366         M=N; N=R; R=M%N; Q=M / N;
3367        }
3368        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3369        azeilen[zeile+1][Q]=delt;
3370      }
3371      if (defined(HNDebugOn)) {"transformed polynomial: ",fneu;}
3372      grenze=e;
3373      //----------------------- teste Abbruchbedingungen: ---------------------
3374      if (subst(fneu,y,0)==0) {              // <==> y|fneu
3375        dbprint(printlevel-voice+3,"finite HNE of one branch found");
3376           // voice abzufragen macht bei rekursiven procs keinen Sinn
3377        azeilen[zeile+1][Q+1]=x;
3378        //----- Q wird nur in hqs eingetragen, wenn der Spezialfall nicht
3379        //      eintritt (siehe unten) -----
3380        Abbruch=2;
3381        if (grenze>1) {
3382         if (jet(fneu,1,intvec(0,1))==0) {
3383           //- jet(...)=alle Monome von fneu, die nicht durch y2 teilbar sind -
3384           "THE TEST FOR SQUAREFREENESS WAS BAD!!";
3385           " The polynomial was NOT squarefree!!!";}
3386         else {
3387           //----------------------- Spezialfall (###): -----------------------
3388           // Wir haben das Problem, dass die HNE eines Zweiges hier abbricht,
3389           // aber ein anderer Zweig bis hierher genau die gleiche HNE hat, die
3390           // noch weiter geht
3391           // Loesung: mache Transform. rueckgaengig und behandle fneu im
3392           // Verzweigungsteil
3393           //------------------------------------------------------------------
3394          Abbruch=1;
3395          fneu=fvorher;zeile=zeilevorher;grenze=Newton[zeiger][2];
3396        }}
3397        else {fneu=0;}     // fneu nicht mehr gebraucht - spare Speicher
3398        if (Abbruch==2) { hqs[zeile+1]=Q; }
3399      }                 // Spezialfall nicht eingetreten
3400      else {
3401        if (ende==1) {
3402          dbprint(printlevel-voice+2,"HNE of one branch found");
3403          Abbruch=2; hqs[zeile+1]=-Q-1;}
3404      }
3405    }                   // end(if Abbruch==0)
3406  }                     // end(if zeiger...)
3407  else { Abbruch=1;}
3408 }                      // end(while Abbruch==0)
3409
3410 // ===================== der Teil bei Verzweigung: ===========================
3411 if (Abbruch==1) {
3412  //---------- Variablendefinitionen fuer den verzweigten Teil: ---------------
3413  poly leitf,teiler,transformiert;
3414  list aneu=ideal(0);
3415  list faktoren;
3416  ideal deltais;
3417  list HNEakut=ideal(0); 
3418  intvec eis;
3419  int zaehler,hnezaehler,zl,zl1,M1,N1,R1,Q1,needext;
3420  int numberofRingchanges,lastRingnumber,ringischanged,flag;
3421  string letztringname;
3422
3423  zeiger=find_in_list(Newton,grenze);
3424  if (defined(HNDebugOn)) {
3425    "Branching part reached---Newton polygon :",Newton;
3426    "relevant part until height",grenze,", from",Newton[zeiger],"on";
3427  }
3428  azeilen=list(hqs)+azeilen; // hat jetzt Struktur von HNEs: hqs in der 1.Zeile
3429
3430  //======= Schleife fuer jede zu betrachtende Seite des Newtonpolygons: ======
3431  for(i=zeiger; i<size(Newton); i++) {
3432   if ((essential==1) and (EXTHNEnumber>number_of_letztring)) {
3433     // ----- setze ring zurueck fuer neue Kante  -----
3434     // ---- (damit konjugierte Zweige erkennbar) -----
3435     hneshift=hneshift+hnezaehler;
3436     hnezaehler=0;
3437     ring_changed=0;
3438     def SaveRing = EXTHNEring(EXTHNEnumber);
3439     setring SaveRing;
3440     if (not(defined(HNEs))) { // HN wurde zum 2.Mal von pre_HN aufgerufen
3441       list HNEs=ideal(0);
3442     }
3443     for (k=number_of_letztring+1; k<=EXTHNEnumber; k++) { kill EXTHNEring(k);}
3444     EXTHNEnumber=number_of_letztring;   
3445     if (EXTHNEnumber==0) { setring HNEring; }
3446     else                 { setring EXTHNEring(EXTHNEnumber); }
3447     if (not(defined(HNEs))) { list HNEs; }
3448     HNEs=ideal(0);
3449     deltais=0;
3450     delt=0;
3451     if (defined(zerlege)) { kill zerlege; }
3452   }
3453
3454   if (defined(HNDebugOn)) { "we consider side",Newton[i],Newton[i+1]; }
3455   M=Newton[i+1][1]-Newton[i][1];
3456   N=Newton[i][2]-Newton[i+1][2];
3457   R = M%N;
3458   Q = M / N;
3459   e=gcd(M,N);
3460   needext=1;
3461   letztringname=nameof(basering);
3462   lastRingnumber=EXTHNEnumber;
3463   faktoren=list(ideal(charPoly(redleit(fneu,Newton[i],Newton[i+1])
3464                       /(x^Newton[i][1]*y^Newton[i+1][2]),M,N)  ),
3465                 intvec(1));                  // = (zu faktoriserendes Poly, 1)
3466   conjugates=1;
3467
3468   //-- wechsle so lange in Ringerweiterungen, bis Leitform vollstaendig
3469   //   in Linearfaktoren zerfaellt -----
3470   for (numberofRingchanges=1; needext==1; numberofRingchanges++) {
3471    leitf=redleit(fneu,Newton[i],Newton[i+1])/
3472                     (x^Newton[i][1]*y^Newton[i+1][2]);
3473    delt=factorfirst(leitf,M,N);
3474    needext=0;
3475    if (delt==0) {
3476     //---------- Sonderbehandlung: faktorisiere einige Polynome ueber Q(a): --
3477     if ((charstr(basering)=="0,a") and (essential==0)) {
3478        faktoren=factorize(charPoly(leitf,M,N)); 
3479        conjugates=1;
3480        for (k=2;k<=size(faktoren[2]);k++) {conjugates=conjugates,1;}
3481     }
3482     else {
3483       //------------------ faktorisiere das charakt. Polynom: ----------------
3484       if ((numberofRingchanges==1) or (essential==0)) {
3485         def L_help=factorlist(faktoren,conjugates);
3486         faktoren=L_help[1];
3487         conjugates=L_help[2]*conj_factor;
3488         kill L_help;
3489       }
3490       else {     // eliminiere alle konjugierten Nullstellen bis auf eine:
3491         ideal hilf_id;
3492         for (zaehler=1; zaehler<=size(faktoren[1]); zaehler++) {
3493           hilf_id=factorize(faktoren[1][zaehler],1);  // war vorher ...)[1];
3494           if (size(hilf_id)>1) {
3495             poly fac=hilf_id[1];
3496             dd=deg(fac);
3497             // Zur Sicherheit:
3498             if (deg(fac)==0) { fac=hilf_id[2]; }
3499             for (k=2;k<=size(hilf_id);k++) {
3500               dd=dd+deg(hilf_id[k]);
3501               if (deg(hilf_id[k])<deg(fac)) { fac=hilf_id[k]; }
3502             }
3503             faktoren[1][zaehler]=fac;
3504             kill fac;
3505             conjugates[zaehler]=conj_factor*dd;
3506           }
3507           else {
3508             faktoren[1][zaehler]=hilf_id[1];
3509             conjugates[zaehler]=conj_factor;
3510           }
3511         }
3512       }
3513     }
3514
3515     zaehler=1; eis=0;
3516     for (j=1; j<=size(faktoren[2]); j++) {
3517      teiler=faktoren[1][j];
3518      if (teiler/y != 0) {         // sonst war's eine Konstante --> wegwerfen!
3519        if (defined(HNDebugOn)) {"factor of leading form found:",teiler;}
3520        if (teiler/y2 == 0) {      // --> Faktor hat die Form cy+d
3521          deltais[zaehler]=-subst(teiler,y,0)/koeff(teiler,0,1); //=-d/c
3522          eis[zaehler]=faktoren[2][j];
3523          conj2[zaehler]=conjugates[j];
3524          zaehler++;
3525        }
3526        else {
3527          dbprint(printlevel-voice+2,
3528             " Change of basering (field extension) necessary!");
3529          if (defined(HNDebugOn)) { teiler,"is not yet properly factorized!"; }
3530          if (needext==0) { poly zerlege=teiler; }
3531          needext=1;
3532          field_ext=1;
3533        }
3534      }
3535     }  // end(for j)
3536    }
3537    else { deltais=ideal(delt); eis=e; conj2=conj_factor; }
3538    if (defined(HNDebugOn)) {"roots of char. poly:";deltais;
3539                             "with multiplicities:",eis;}
3540    if (needext==1) {
3541      //--------------------- fuehre den Ringwechsel aus: ---------------------
3542      ringischanged=1;
3543      if ((size(parstr(basering))>0) && string(minpoly)=="0") {
3544        " ** We've had bad luck! The HNE cannot be calculated completely!";
3545        // HNE in transzendenter Erweiterung fehlgeschlagen
3546        kill zerlege;
3547        ringischanged=0; break;    // weiter mit gefundenen Faktoren
3548      }
3549      if (parstr(basering)=="") {
3550        EXTHNEnumber++;
3551        def EXTHNEring(EXTHNEnumber) = splitring(zerlege);
3552        setring EXTHNEring(EXTHNEnumber);
3553
3554        poly transf=0;
3555        poly transfproc=0;
3556        ring_changed=1;
3557        export transfproc;
3558      }
3559      else {
3560        if (numberofRingchanges>1) {  // ein Ringwechsel hat nicht gereicht
3561         def helpring = splitring(zerlege,list(transf,transfproc,faktoren));
3562         kill EXTHNEring(EXTHNEnumber);
3563         def EXTHNEring(EXTHNEnumber)=helpring;
3564         setring EXTHNEring(EXTHNEnumber);
3565         kill helpring;
3566
3567         poly transf=erg[1];
3568         poly transfproc=erg[2];
3569         ring_changed=1;
3570         list faktoren=erg[3];
3571         export transfproc;
3572         kill erg;
3573        }
3574        else {
3575         if (ring_changed==1) { // in dieser proc geschah schon Ringwechsel
3576          EXTHNEnumber++;
3577          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,list(a,transfproc));
3578          setring EXTHNEring(EXTHNEnumber);
3579          poly transf=erg[1];
3580          poly transfproc=erg[2];
3581          export transfproc;
3582          kill erg;
3583         }
3584         else { // parameter war vorher da
3585          EXTHNEnumber++;
3586          def EXTHNEring(EXTHNEnumber) = splitring(zerlege,a);
3587          setring EXTHNEring(EXTHNEnumber);
3588          poly transf=erg[1];
3589          poly transfproc=transf;
3590          ring_changed=1;
3591          export transfproc;
3592          kill erg;
3593        }}
3594      }
3595      //-----------------------------------------------------------------------
3596      // transf enthaelt jetzt den alten Parameter des Ringes, der aktiv war
3597      // vor Beginn der Schleife (evtl. also ueber mehrere Ringwechsel
3598      // weitergereicht),
3599      // transfproc enthaelt den alten Parameter des Ringes, der aktiv war zu
3600      // Beginn der Prozedur, und der an die aufrufende Prozedur zurueckgegeben
3601      // werden muss
3602      // transf ist Null, falls der alte Ring keinen Parameter hatte,
3603      // das gleiche gilt fuer transfproc
3604      //-----------------------------------------------------------------------
3605
3606      //---- Neudef. von Variablen, Uebertragung bisher errechneter Daten: ----
3607      poly leitf,teiler,transformiert;
3608      list aneu=ideal(0);
3609      ideal deltais;
3610      number delt;
3611      setring HNE_noparam;
3612      if (defined(letztring)) { kill letztring; }
3613      if (EXTHNEnumber>1) { def letztring=EXTHNEring(EXTHNEnumber-1); }
3614      else                { def letztring=HNEring; }
3615      if (not defined(fneu)) {poly fneu;}
3616      fneu=imap(letztring,fneu);
3617      if (not defined(f)) {poly f;}
3618      f=imap(letztring,f);
3619      if (not defined(hne)) {list hne;}
3620      hne=imap(letztring,hne);
3621
3622      if (not defined(faktoren)) {list faktoren; }
3623      faktoren=imap(letztring,faktoren);
3624       
3625      if (not(defined(azeilen))){list azeilen,HNEs;}
3626      azeilen=imap(letztring,azeilen);
3627      HNEs=imap(letztring,HNEs);
3628
3629      setring EXTHNEring(EXTHNEnumber);
3630      if (not(defined(hole))) { map hole; }
3631      hole=HNE_noparam,transf,x,y;
3632      poly fneu=hole(fneu);
3633      if (not defined(faktoren)) {list faktoren;}
3634      faktoren=hole(faktoren);
3635
3636      if (not(defined(f)))
3637      {
3638        poly f=hole(f);
3639        list hne=hole(hne);
3640        export f,hne;     
3641      }
3642    }
3643   }    // end (while needext==1) bzw. for (numberofRingchanges)
3644
3645   if (eis==0) { i++; continue; }
3646   if (ringischanged==1) {
3647    list erg,HNEakut;            // dienen nur zum Sp. von Zwi.erg.
3648
3649    ideal hilfid;
3650    erg=ideal(0); HNEakut=erg;
3651
3652    hole=HNE_noparam,transf,x,y;
3653    setring HNE_noparam;
3654    if (not(defined(azeilen))){list azeilen,HNEs;}
3655    azeilen=imap(letztring,azeilen);
3656    HNEs=imap(letztring,HNEs);
3657
3658    setring EXTHNEring(EXTHNEnumber);
3659    list azeilen=hole(azeilen);
3660    list HNEs=hole(HNEs);
3661    kill letztring;
3662    ringischanged=0;
3663   }
3664
3665   //============ Schleife fuer jeden gefundenen Faktor der Leitform: =========
3666   for (j=1; j<=size(eis); j++) {
3667     //---- Mache Transformation T1 oder T2, trage Daten in HNEs ein,
3668     //     falls HNE abbricht: ----
3669
3670    //------------------------ Fall R==0: -------------------------------------
3671    if (R==0) {
3672      transformiert = T1_Transform(fneu,number(deltais[j]),M/ e);
3673      if (defined(HNDebugOn)) {
3674        "a("+string(zeile)+","+string(Q)+") =",deltais[j];
3675        "transformed polynomial: ",transformiert;
3676      }
3677      if (subst(transformiert,y,0)==0) {
3678       dbprint(printlevel-voice+3,"finite HNE found");
3679       hnezaehler++;
3680       //-------- trage deltais[j],x ein in letzte Zeile, fertig: -------------
3681       HNEakut=azeilen+list(poly(0));        // =HNEs[hnezaehler];
3682       hilfid=HNEakut[zeile+2]; hilfid[Q]=deltais[j]; hilfid[Q+1]=x;
3683       HNEakut[zeile+2]=hilfid;
3684       HNEakut[1][zeile+1]=Q;                // aktualisiere Vektor mit den hqs
3685       HNEs[hnezaehler]=HNEakut;
3686       conj1[hneshift+hnezaehler]=conj2[j];
3687       if (eis[j]>1) {
3688        transformiert=transformiert/y;
3689        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3690                                  +"! The polynomial was NOT squarefree!!!";}
3691        else {
3692          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3693          eis[j]=eis[j]-1;
3694        }
3695       }
3696      }
3697    }
3698    else {
3699      //------------------------ Fall R <> 0: ---------------------------------
3700      erg=T2_Transform(fneu,number(deltais[j]),M,N,referencepoly(Newton));
3701      transformiert=erg[1];delt=erg[2];
3702      if (defined(HNDebugOn)) {"transformed polynomial: ",transformiert;}
3703      if (subst(transformiert,y,0)==0) {
3704       dbprint(printlevel-voice+3,"finite HNE found");
3705       hnezaehler++;
3706       //---------------- trage endliche HNE in HNEs ein: ---------------------
3707       HNEakut=azeilen;           // dupliziere den gemeins. Anfang der HNE's
3708       zl=2;                      // (kommt schliesslich nach HNEs[hnezaehler])
3709       //----------------------------------------------------------------------
3710       // Werte von:  zeile: aktuelle Zeilennummer der HNE (gemeinsamer Teil)
3711       //             zl : die HNE spaltet auf; zeile+zl ist der Index fuer die
3712       //                  Zeile des aktuellen Zweigs; (zeile+zl-2) ist die
3713       //                  tatsaechl. Zeilennr. (bei 0 angefangen) der HNE 
3714       //                  ([1] <- intvec(hqs), [2] <- 0. Zeile usw.)
3715       //----------------------------------------------------------------------
3716
3717       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3718       M1=M;N1=N;R1=R;Q1=M1/ N1;
3719       while (R1!=0) {
3720        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3721        HNEakut[1][zeile+zl-1]=Q1;
3722        HNEakut[zeile+zl][Q1+1]=x;
3723                                  // markiere das Zeilenende der HNE
3724        zl=zl+1;
3725        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3726        HNEakut[zeile+zl]=ideal(0);
3727
3728        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3729       }
3730       if (defined(HNDebugOn)) {
3731         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3732       }
3733       HNEakut[zeile+zl][Q1]  =delt;
3734       HNEakut[zeile+zl][Q1+1]=x;
3735       HNEakut[1][zeile+zl-1] =Q1;     // aktualisiere Vektor mit hqs
3736       HNEakut[zeile+zl+1]=poly(0);
3737       HNEs[hnezaehler]=HNEakut;
3738       conj1[hneshift+hnezaehler]=conj2[j];
3739
3740       //-------------------- Ende der Eintragungen in HNEs -------------------
3741
3742       if (eis[j]>1) {
3743        transformiert=transformiert/y;
3744        if (subst(transformiert,y,0)==0){"THE TEST FOR SQUAREFREENESS WAS BAD!"
3745                               +" The polynomial was NOT squarefree!!!";}
3746         else {
3747          //--- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --
3748          eis[j]=eis[j]-1;
3749       }}
3750      }                           // endif (subst()==0)
3751    }                             // endelse (R<>0)
3752
3753    //========== Falls HNE nicht abbricht: Rekursiver Aufruf von HN: ==========
3754    //------------------- Berechne HNE von transformiert ----------------------
3755    if (subst(transformiert,y,0)!=0) {
3756     lastRingnumber=EXTHNEnumber;
3757
3758     if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
3759     HNE_RingDATA = list( HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring,
3760                          lastRingnumber);
3761     if (defined(HNerg)) {kill HNerg;}
3762     list HNerg=HN(HNE_RingDATA,transformiert,eis[j],Aufruf_Ebene+1,
3763                                essential,getauscht,hne_conj,conj2[j]);   
3764     HNE_RingDATA = HNerg[1];
3765     if (conj1==0) { conj1=HNerg[5]; }
3766     else  { conj1 = conj1,HNerg[5]; }
3767
3768     if (HNerg[3]==1) { field_ext=1; }
3769     if (HNerg[2]==lastRingnumber) { // kein Ringwechsel in HN aufgetreten
3770       if (not(defined(aneu))) { list aneu; }
3771       aneu = HNerg[4];
3772     }
3773     else { // Ringwechsel aufgetreten
3774       if (defined(HNDebugOn))
3775          {" ring change in HN(",Aufruf_Ebene+1,") detected";}
3776       EXTHNEnumber = HNerg[1][3];
3777       for (i=lastRingnumber+1; i<=EXTHNEnumber; i++) {
3778         def EXTHNEring(i)=HNerg[1][4][i];
3779       }
3780       if (HNerg[2]==0) { setring HNEring; }
3781       else             { setring EXTHNEring(HNerg[2]); }
3782       def tempRing=HNerg[4];
3783       def aneu=imap(tempRing,HNEs);
3784       kill tempRing;
3785
3786       //--- stelle lokale Variablen im neuen Ring wieder her, und rette
3787       //    gegebenenfalls ihren Inhalt: ----
3788       list erg,faktoren,HNEakut;
3789       ideal hilfid;     
3790       erg=ideal(0); faktoren=erg; HNEakut=erg;
3791       poly leitf,teiler,transformiert;
3792       map hole=HNE_noparam,transfproc,x,y;
3793       setring HNE_noparam;
3794       if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3795       else                  { def letztring=HNEring; }
3796       if (not defined(HNEs)) {list HNEs;}
3797       HNEs=imap(letztring,HNEs);
3798       if (not defined(azeilen)) {list azeilen;}
3799       azeilen=imap(letztring,azeilen);
3800       if (not defined(deltais)) {ideal deltais;}
3801       deltais=imap(letztring,deltais);
3802       if (not defined(delt)) {poly delt;}
3803       delt=imap(letztring,delt);
3804       if (not defined(fneu)) {poly fneu;}
3805       fneu=imap(letztring,fneu);
3806       if (not defined(f)) {poly f;}
3807       f=imap(letztring,f);
3808       if (not defined(hne)) {list hne;}
3809       hne=imap(letztring,hne);
3810
3811       setring EXTHNEring(EXTHNEnumber);
3812       list HNEs=hole(HNEs);
3813       list azeilen=hole(azeilen);
3814       ideal deltais=hole(deltais);
3815       number delt=number(hole(delt));
3816       poly fneu=hole(fneu);
3817       if (not(defined(f)))
3818       {
3819         poly f=hole(f);
3820         list hne=hole(hne);
3821         export f,hne;
3822       }
3823     }
3824
3825     //========== Verknuepfe bisherige HNE mit von HN gelieferten HNEs: ======
3826     if (R==0) {
3827       HNEs,hnezaehler=constructHNEs(HNEs,hnezaehler,aneu,azeilen,zeile,
3828                       deltais,Q,j);
3829       kill aneu;
3830     }
3831     else {
3832      for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3833       hnezaehler++;
3834       HNEakut=azeilen;          // dupliziere den gemeinsamen Anfang der HNE's
3835       zl=2;                     // (kommt schliesslich nach HNEs[hnezaehler])
3836       //------------ Trage Beitrag dieser Transformation T2 ein: -------------
3837       //------ Zur Bedeutung von zeile, zl: siehe Kommentar weiter oben ------
3838
3839       //----- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -----
3840       M1=M;N1=N;R1=R;Q1=M1/ N1;
3841       while (R1!=0) {
3842        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3843        HNEakut[1][zeile+zl-1]=Q1;
3844        HNEakut[zeile+zl][Q1+1]=x;    // Markierung des Zeilenendes der HNE
3845        zl=zl+1;
3846        //----- Bereitstellung von Speicherplatz fuer eine neue Zeile: --------
3847        HNEakut[zeile+zl]=ideal(0);
3848        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3849       }
3850       if (defined(HNDebugOn)) {
3851         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3852       }
3853       HNEakut[zeile+zl][Q1]=delt;
3854
3855       //-- Daten aus T2_Transform sind eingetragen; haenge Daten von HN an: --
3856       hilfid=HNEakut[zeile+zl];
3857       for (zl1=Q1+1; zl1<=ncols(aneu[zaehler][2]); zl1++) {
3858        hilfid[zl1]=aneu[zaehler][2][zl1];
3859       }
3860       HNEakut[zeile+zl]=hilfid;
3861       // ------ vorher HNEs[.][zeile+zl]<-aneu[.][2],
3862       //        jetzt [zeile+zl+1] <- [3] usw.: --------
3863       for (zl1=3; zl1<=size(aneu[zaehler]); zl1++) {
3864         HNEakut[zeile+zl+zl1-2]=aneu[zaehler][zl1];
3865       }
3866       //--- setze hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] --
3867       hilfvec=HNEakut[1],aneu[zaehler][1];
3868       HNEakut[1]=hilfvec;
3869       //-------- weil nicht geht: liste[1]=liste[1],aneu[zaehler][1] ---------
3870       HNEs[hnezaehler]=HNEakut;
3871      }                     // end(for zaehler)
3872     kill aneu;
3873     }                      // endelse (R<>0)
3874    }                       // endif (subst()!=0)  (weiteres Aufblasen mit HN)
3875
3876   }                        // end(for j) (Behandlung der einzelnen delta_i)
3877
3878
3879   // ------------------------- new for essdevelop ----------------------------
3880   if ((essential==1) and (defined(SaveRing))) {
3881     // ----- uebertrage Daten in gemeinsame Koerpererweiterung ---------------
3882     if (EXTHNEnumber>number_of_letztring) {
3883       // ----- fuer aktuelle Kante war Koerpererweiterung erforderlich -------
3884       EXTHNEnumber++;
3885       if (not(defined(minPol))) { poly miniPol; }
3886       miniPol=minpoly;
3887       setring SaveRing;
3888       if (not(defined(miniPol))) { poly miniPol; }
3889       miniPol=minpoly;
3890       setring HNE_noparam;
3891       if (not(defined(a_x))){ map a_x,a_y; poly mp_save, mp_new; }
3892       mp_save=imap(SaveRing,miniPol);
3893       mp_new=imap(EXTHNEring(EXTHNEnumber-1),miniPol);
3894       if (mp_save==mp_new) { // Sonderfall: wieder gleicher Ring
3895         def EXTHNEring(EXTHNEnumber)=SaveRing;
3896         setring EXTHNEring(EXTHNEnumber);
3897         if (not(defined(f))) {poly f; f=hole(f); export f;}
3898         list dummyL=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3899         if (not(defined(HNEs))) { def HNEs=list(); }
3900         if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3901         HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3902         kill dummyL,SaveRing;
3903       }
3904       else { // verschiedene Ringe
3905         a_x=HNE_noparam,x,0,0;
3906         a_y=HNE_noparam,y,0,0;
3907         mp_save=a_x(mp_save); // minpoly aus SaveRing mit a --> x
3908         mp_new=a_y(mp_new);   // minpoly aus SaveRing mit a --> y
3909         setring SaveRing;
3910         poly mp_new=imap(HNE_noparam,mp_new);
3911         list Lfac=factorize(mp_new,1);
3912         poly fac=Lfac[1][1];
3913         for (k=2;k<=size(Lfac[1]);k++) {
3914           if (deg(Lfac[1][k])<deg(fac)) { fac=Lfac[1][k]; }
3915         }
3916
3917         if (deg(fac)==1) { // keine Erweiterung noetig
3918           def EXTHNEring(EXTHNEnumber)=SaveRing;
3919           setring HNE_noparam;
3920           HNEs=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3921           setring EXTHNEring(EXTHNEnumber);
3922           if (not(defined(f))) {poly f; f=hole(f); export f;}
3923           map phi=HNE_noparam,-subst(fac,y,0)/koeff(fac,0,1),x,y;
3924           list dummyL=phi(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,phi,SaveRing;
3929         }
3930         else { // Koerpererweiterung noetig
3931           def EXTHNEring(EXTHNEnumber) = splitring(fac,list(a,transfproc));
3932           setring EXTHNEring(EXTHNEnumber);
3933           poly transf=erg[1];  // image of parameter from SaveRing
3934           poly transfproc=erg[2];
3935           poly transb=erg[3];  // image of parameter from EXTHNEring(..)
3936           export transfproc;
3937           kill erg;
3938           setring HNE_noparam;
3939           if (not(defined(HNEs1))) { list HNEs1=ideal(0); }
3940           HNEs1=imap(EXTHNEring(EXTHNEnumber-1),HNEs);
3941           if (not(defined(hne))) { list hne=ideal(0); }
3942           hne=imap(SaveRing,hne);
3943           HNEs=imap(SaveRing,HNEs);
3944           setring EXTHNEring(EXTHNEnumber);
3945           map hole=HNE_noparam,transf,x,y;
3946           poly fneu=hole(fneu);
3947           poly f=hole(f);
3948           map phi=HNE_noparam,transb,x,y;
3949           list HNEs=hole(HNEs);
3950           list hne=hole(hne);
3951           export f,hne;
3952           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3953           list dummyL=phi(HNEs1);
3954           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3955           kill dummyL,phi,SaveRing;
3956         }
3957       }
3958     }
3959     else { // nur bei letzter Kante muss was getan werden
3960       if (i==size(Newton)-1) {
3961         EXTHNEnumber++;
3962         if (number_of_letztring==0) { def letztring=HNEring; }
3963         else       { def letztring=EXTHNEring(EXTHNEnumber); }
3964         if (minpoly==0) {
3965           def EXTHNEring(EXTHNEnumber)=SaveRing;
3966           setring EXTHNEring(EXTHNEnumber);
3967           if (not(defined(f))) {poly f; f=hole(f); export f;}
3968           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3969           list dummyL=imap(letztring,HNEs);
3970           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3971           kill dummyL,letztring,SaveRing;
3972         }
3973         else { // muessen Daten nach SaveRing uebertragen;
3974           setring HNE_noparam;
3975           if (not(defined(HNEs))) { list HNEs; }
3976           HNEs=imap(letztring,HNEs);
3977           def EXTHNEring(EXTHNEnumber)=SaveRing;
3978           setring EXTHNEring(EXTHNEnumber);
3979           if (not(defined(hole))) { map hole; }
3980           hole=HNE_noparam,transfproc,x,y;
3981           list dummyL=hole(HNEs);
3982           if (not(defined(HNEs))) { def HNEs=list(); }
3983           if ((size(HNEs)==1) and (typeof(HNEs[1])=="ideal")) {HNEs=list();}
3984           HNEs[size(HNEs)+1..size(HNEs)+size(dummyL)]=dummyL[1..size(dummyL)];
3985           kill dummyL, letztring,SaveRing;
3986         }
3987       }
3988     }
3989   }
3990   // -----------------end of new part (loop for essential=1) ----------------
3991  } // end (Loop uber Kanten)
3992  if (defined(SaveRing)) { kill SaveRing; }
3993 }
3994 else {
3995  HNEs[1]=list(hqs)+azeilen+list(fneu); // fneu ist transform. Poly oder Null
3996  conj1[1]=conj_factor;
3997 }
3998
3999 if (Aufruf_Ebene == 1)
4000 {
4001   if ((number_of_letztring!=EXTHNEnumber) and (not(defined(hne))))
4002   {
4003     //----- falls Zweige in transz. Erw. berechnet werden konnten ---------
4004     if (defined(transfproc))
4005     { // --- Ringwechsel hat stattgefunden ---
4006       if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
4007       if (not(defined(hole))) { map hole; }
4008       hole=HNE_noparam,transfproc,x,y;
4009       setring HNE_noparam;
4010       f=imap(HNEring,f);
4011       if (number_of_letztring==0) { def letztring=HNEring; }
4012       else                        { def letztring=EXTHNEring(EXTHNEnumber); }
4013       if (not(defined(hne))) { list hne; }
4014       hne=imap(letztring,hne);
4015       setring EXTHNEring(EXTHNEnumber);
4016       if (not(defined(f))) { poly f=hole(f); export f; }
4017       list hne=hole(hne);
4018       export hne;
4019     }
4020   }
4021   if (size(HNEs)>0) {
4022     if ((size(HNEs)>1) or (typeof(HNEs[1])!="ideal") or (size(HNEs[1])>0)) {
4023       if ((typeof(hne[1])=="ideal")) { hne=list(); }
4024       hne=hne+extractHNEs(HNEs,getauscht);
4025       if (hne_conj==0) { hne_conj=conj1; }
4026       else { hne_conj = hne_conj, conj1; }
4027     }
4028   }
4029 }
4030 else
4031 { // HN wurde rekursiv aufgerufen
4032   if (number_of_letztring!=EXTHNEnumber)
4033   { // Ringwechsel hatte stattgefunden
4034     string mipl_alt = string(minpoly);
4035     execute("ring tempRing = ("+charstr(basering)+"),("+varstr(basering)+
4036                              "),("+ordstr(basering)+");");
4037     execute("minpoly="+ mipl_alt +";");
4038     list HNEs=imap(EXTHNEring(EXTHNEnumber),HNEs);
4039     export HNEs;
4040     if (defined(HNDebugOn)) {" ! tempRing defined ! ";}
4041   }
4042   if (conj1!=0) { hne_conj=conj1; }
4043   else          { hne_conj=conj_factor; }
4044 }
4045 if (EXTHNEnumber>0){ EXTHNEring = EXTHNEring(1..EXTHNEnumber); }
4046 HNE_RingDATA = list(HNEring, HNE_noparam, EXTHNEnumber, EXTHNEring);
4047 if (number_of_letztring==EXTHNEnumber) {
4048   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,HNEs,hne_conj));
4049 }
4050 else {
4051   if (defined(tempRing)) {
4052     return(list(HNE_RingDATA,EXTHNEnumber,field_ext,tempRing,hne_conj));
4053   }
4054   return(list(HNE_RingDATA,EXTHNEnumber,field_ext,0,hne_conj));
4055 }
4056}
4057
4058///////////////////////////////////////////////////////////////////////////////
4059
4060static proc constructHNEs (list HNEs,int hnezaehler,list aneu,list azeilen,
4061                    int zeile,ideal deltais,int Q,int j)
4062"NOTE: This procedure is only for internal use, it is called via HN"
4063{
4064  int zaehler,zl;
4065  ideal hilfid;
4066  list hilflist;
4067  intvec hilfvec;
4068  for (zaehler=1; zaehler<=size(aneu); zaehler++) {
4069     hnezaehler++;
4070     // HNEs[hnezaehler]=azeilen;            // dupliziere gemeins. Anfang
4071 //----------------------- trage neu berechnete Daten ein ---------------------
4072     hilfid=azeilen[zeile+2];
4073     hilfid[Q]=deltais[j];
4074     for (zl=Q+1; zl<=ncols(aneu[zaehler][2]); zl++) {
4075      hilfid[zl]=aneu[zaehler][2][zl];
4076     }
4077     hilflist=azeilen; hilflist[zeile+2]=hilfid;
4078 //------------------ haenge uebrige Zeilen von aneu[] an: --------------------
4079     for (zl=3; zl<=size(aneu[zaehler]); zl++) {
4080      hilflist[zeile+zl]=aneu[zaehler][zl];
4081     }
4082 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
4083     if (hilflist[1]==0) { hilflist[1]=aneu[zaehler][1]; }
4084     else { hilfvec=hilflist[1],aneu[zaehler][1]; hilflist[1]=hilfvec; }
4085     HNEs[hnezaehler]=hilflist;
4086  }
4087  return(HNEs,hnezaehler);
4088}
4089///////////////////////////////////////////////////////////////////////////////
4090
4091proc referencepoly (list newton)
4092"USAGE:   referencepoly(newton);
4093         newton is list of intvec(x,y) which represents points in the Newton
4094         diagram (e.g. output of the proc newtonpoly)
4095RETURN:  a polynomial which has newton as Newton diagram
4096SEE ALSO: newtonpoly
4097EXAMPLE: example referencepoly;  shows an example
4098"
4099{
4100 poly f;
4101 for (int i=1; i<=size(newton); i++) {
4102   f=f+var(1)^newton[i][1]*var(2)^newton[i][2];
4103 }
4104 return(f);
4105}
4106example
4107{ "EXAMPLE:"; echo = 2;
4108 ring exring=0,(x,y),ds;
4109 referencepoly(list(intvec(0,4),intvec(2,3),intvec(5,1),intvec(7,0)));
4110}
4111///////////////////////////////////////////////////////////////////////////////
4112
4113proc factorlist (list L, list #)
4114"USAGE:   factorlist(L);   L a list in the format of `factorize'
4115RETURN:  the nonconstant irreducible factors of
4116         L[1][1]^L[2][1] * L[1][2]^L[2][2] *...* L[1][size(L[1])]^...
4117         with multiplicities (same format as factorize)
4118SEE ALSO: factorize
4119EXAMPLE: example factorlist;  shows an example
4120"
4121{
4122 int k;
4123 if ((size(#)>=1) and ((typeof(#[1])=="intvec") or (typeof(#[1])=="int"))) {
4124   int with_conj = 1; intvec C = #[1];
4125 }
4126 else {
4127   int with_conj = 0; intvec C = L[2];
4128 }
4129 // eine Sortierung der Faktoren eruebrigt sich, weil keine zwei versch.
4130 // red.Fakt. einen gleichen irred. Fakt. haben koennen (I.3.27 Diplarb.)
4131 int i,gross;
4132 list faktoren,hilf;
4133 intvec conjugates;
4134 ideal hil1,hil2;
4135 intvec v,w,hilf_conj;
4136 for (i=1; (L[1][i] == jet(L[1][i],0)) && (i<size(L[1])); i++) {;}
4137 if (L[1][i] != jet(L[1][i],0)) {
4138   hilf=factorize(L[1][i]);
4139 // Achtung!!! factorize(..,2) wirft entgegen der Beschreibung nicht nur
4140 // konstante Faktoren raus, sondern alle Einheiten in der LOKALISIERUNG nach
4141 // der Monomordnung!!! Im Beispiel unten verschwindet der Faktor x+y+1, wenn
4142 // man ds statt dp als Ordnung nimmt!
4143   hilf_conj=C[i];
4144   for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4145   hilf[2]=hilf[2]*L[2][i];
4146   hil1=hilf[1];
4147   gross=size(hil1);
4148   if (gross>1) {
4149     v=hilf[2];
4150     faktoren=list(ideal(hil1[2..gross]),intvec(v[2..gross]));
4151     conjugates=intvec(hilf_conj[2..gross]);
4152   }
4153   else         { faktoren=hilf; conjugates=hilf_conj; }
4154 }
4155 else {
4156   faktoren=L;
4157   conjugates=C;
4158 }
4159
4160 for (i++; i<=size(L[2]); i++) {
4161 //------------------------- linearer Term -- irreduzibel ---------------------
4162   if (L[1][i] == jet(L[1][i],1)) {
4163     if (L[1][i] != jet(L[1][i],0)) {           // konst. Faktoren eliminieren
4164       hil1=faktoren[1];
4165       hil1[size(hil1)+1]=L[1][i];
4166       faktoren[1]=hil1;
4167       v=faktoren[2],L[2][i];
4168       conjugates=conjugates,C[i];
4169       faktoren[2]=v;
4170     }
4171   }
4172 //----------------------- nichtlinearer Term -- faktorisiere -----------------
4173   else {
4174     hilf=factorize(L[1][i]);
4175     hilf_conj=C[i];
4176     for (k=2;k<=size(hilf[2]);k++){ hilf_conj=hilf_conj,C[i]; }
4177     hilf[2]=hilf[2]*L[2][i];
4178     hil1=faktoren[1];
4179     hil2=hilf[1];
4180     gross=size(hil2);
4181       // hil2[1] ist konstant, wird weggelassen:
4182     hil1[(size(hil1)+1)..(size(hil1)+gross-1)]=hil2[2..gross];
4183       // ideal+ideal does not work due to simplification;
4184       // ideal,ideal not allowed
4185     faktoren[1]=hil1;
4186     w=hilf[2];
4187     v=faktoren[2],w[2..gross];
4188     conjugates=conjugates,hilf_conj[2..gross];
4189     faktoren[2]=v;
4190   }
4191 }
4192 if (with_conj==0) { return(faktoren); }
4193 else { return(list(faktoren,conjugates)); }  // for essential development
4194}
4195example
4196{ "EXAMPLE:"; echo = 2;
4197 ring exring=0,(x,y),ds;
4198 list L=list(ideal(x,(x-y)^2*(x+y+1),x+y),intvec(2,2,1));
4199 L;
4200 factorlist(L);
4201}
4202
4203///////////////////////////////////////////////////////////////////////////////
4204
4205proc delta
4206"USAGE:  delta(INPUT);  INPUT a polynomial defining an isolated plane curve
4207         singularity at 0, or the Hamburger-Noether expansion thereof, i.e.
4208         the output of @code{develop(f)}, or the output of @code{hnexpansion(f)},
4209         or the list of HN data computed by @code{hnexpansion(f)}.
4210RETURN:  int, the delta invariant of the singularity at 0, that is, the vector
4211         space dimension of R~/R, (R~ the normalization of the local ring of
4212         the singularity.
4213NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
4214         for other purposes as well it is better to calculate this first
4215         with the aid of @code{hnexpansion} and use it as input instead of
4216         the polynomial itself.
4217SEE ALSO: deltaLoc, invariants
4218KEYWORDS: delta invariant
4219EXAMPLE: example delta;  shows an example
4220"
4221{
4222  if (typeof(#[1])=="poly") { // INPUT = polynomial defining the singularity
4223    list L=hnexpansion(#[1]);
4224    if (typeof(L[1])=="ring") {
4225      def altring = basering;
4226      def HNring = L[1]; setring HNring;
4227      return(delta(hne));
4228    }
4229    else {
4230      return(delta(L));
4231    } 
4232  }
4233  if (typeof(#[1])=="ring") { // INPUT = HNEring of curve
4234    def HNring = #[1]; setring HNring;
4235    return(delta(hne));
4236  }
4237  if (typeof(#[1])=="matrix") 
4238  { // INPUT = hne of an irreducible curve 
4239    return(invariants(#)[5]/2);
4240  }
4241  else
4242  { // INPUT = hne of a reducible curve
4243    list INV=invariants(#);
4244    return(INV[size(INV)][3]);
4245  }
4246}
4247example
4248{ "EXAMPLE:"; echo = 2;
4249  ring r = 32003,(x,y),ds;
4250  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
4251           +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
4252           -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
4253           +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
4254  delta(f);
4255}
4256
4257///////////////////////////////////////////////////////////////////////////////
Note: See TracBrowser for help on using the repository browser.