source: git/Singular/LIB/hnoether.lib @ 4defacf

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