source: git/Singular/LIB/hnoether.lib @ 5dace4

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