source: git/Singular/LIB/hnoether.lib @ 93332c

spielwiese
Last change on this file since 93332c was 93332c, checked in by Hans Schönemann <hannes@…>, 20 years ago
*hannes: lib changes git-svn-id: file:///usr/local/Singular/svn/trunk@7331 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 154.1 KB
Line 
1version="$Id: hnoether.lib,v 1.39 2004-08-05 15:59:21 Singular Exp $";
2category="Singularities";
3info="
4LIBRARY:  hnoether.lib   Hamburger-Noether (Puiseux) Development
5AUTHOR:   Martin Lamm,   lamm@mathematik.uni-kl.de
6
7OVERVIEW:
8 A library for computing the Hamburger-Noether, resp. Puiseux, development
9 of a plane curve singularity following [Campillo, A.: Algebroid curves
10 in positive characteristic, Springer LNM 813 (1980)]. @*
11 The library contains also procedures for computing the (topological)
12 numerical invariants of plane curve singularities.
13
14MAIN PROCEDURES:
15 hnexpansion(f);            Hamburger-Noether (H-N) development of f
16 sethnering(hn);            changes to the hnering created by hnexpansion
17 develop(f [,n]);           H-N development of irreducible curves
18 extdevelop(hne,n);         extension of the H-N development hne of f
19 parametrisation(f [,x]);   a parametrization of f
20 displayHNE(hne);           display H-N development as an ideal
21 invariants(f);             invariants of f, e.g. the characteristic exponents
22 displayInvariants(f);      display invariants of f
23 multsequence(f);           sequence of multiplicities
24 displayMultsequence(f);    display sequence of multiplicities
25 intersection(hne1,hne2);   intersection multiplicity of two curves
26 stripHNE(hne);             reduce amount of memory consumed by hne
27 is_irred(f);               test if f is irreducible
28 delta(f);                  delta invariant of f
29 newtonpoly(f);             (local) Newton polygon of f
30 is_NND(f);                 test if f is Newton non-degenerate
31
32
33AUXILIARY PROCEDURES:
34 puiseux2generators(m,n);   convert Puiseux pairs to generators of semigroup
35 separateHNE(hne1,hne2);    number of quadratic transf. needed for separation
36 squarefree(f);             a squarefree divisor of the poly f
37 allsquarefree(f,l);        the maximal squarefree divisor of the poly f
38 further_hn_proc();         show further procedures useful for interactive use
39
40KEYWORDS: Hamburger-Noether expansion; Puiseux expansion; curve singularities
41";
42
43// HNdevelop(f);              Hamburger-Noether (H-N) development of f
44// reddevelop(f);             H-N development of reducible curves
45// essdevelop(f);             H-N development of essential branches
46// multiplicities(hne);       multiplicities of blowed up curves
47
48
49///////////////////////////////////////////////////////////////////////////////
50LIB "primitiv.lib";
51LIB "inout.lib";
52LIB "sing.lib";
53
54///////////////////////////////////////////////////////////////////////////////
55
56proc further_hn_proc()
57"USAGE: further_hn_proc();
58NOTE:  The library @code{hnoether.lib} contains some more procedures which
59       are not shown when typing @code{help hnoether.lib;}. They may be useful
60       for interactive use (e.g. if you want to do the calculation of an HN
61       development \"by hand\" to see the intermediate results), and they
62       can be enumerated by calling @code{further_hn_proc()}. @*
63       Use @code{help <procedure>;} for detailed information about each of
64       them.
65"
66{
67 "
68 The following procedures are also part of `hnoether.lib':
69
70 getnm(f);           intersection pts. of Newton polygon with axes
71 T_Transform(f,Q,N); returns f(y,xy^Q)/y^NQ (f: poly, Q,N: int)
72 T1_Transform(f,d,M); returns f(x,y+d*x^M)  (f: poly,d:number,M:int)
73 T2_Transform(f,d,M,N,ref);   a composition of T1 & T
74 koeff(f,I,J);       gets coefficient of indicated monomial of poly f
75 redleit(f,S,E);     restriction of monomials of f to line (S-E)
76 leit(f,n,m);        special case of redleit (for irred. polynomials)
77 testreducible(f,n,m); tests whether f is reducible
78 charPoly(f,M,N);    characteristic polynomial of f
79 find_in_list(L,p);  find int p in list L
80 get_last_divisor(M,N); last divisor in Euclid's algorithm
81 factorfirst(f,M,N); try to factor f without `factorize'
82 factorlist(L);      factorize a list L of polynomials
83 referencepoly(D);   a polynomial f s.t. D is the Newton diagram of f";
84
85//       static procedures not useful for interactive use:
86// polytest(f);        tests coefficients and exponents of poly f
87// extractHNEs(H,t);   extracts output H of HN to output of reddevelop
88// HN(f,grenze);       recursive subroutine for reddevelop
89// constructHNEs(...); subroutine for HN
90}
91example
92{ echo=2;
93  further_hn_proc();
94}
95///////////////////////////////////////////////////////////////////////////////
96
97proc getnm (poly f)
98"USAGE:   getnm(f); f bivariate polynomial
99RETURN:  intvec(n,m) : (0,n) is the intersection point of the Newton
100         polygon of f with the y-axis, n=-1 if it doesn't exist
101         (m,0) is its intersection point with the x-axis,
102         m=-1 if this point doesn't exist
103ASSUME:  ring has ordering `ls' or `ds'
104EXAMPLE: example getnm; shows an example
105"
106{
107 // assume being called by develop ==> ring ordering is ls (ds would also work)
108 return(ord(subst(f,var(1),0)),ord(subst(f,var(2),0)));
109}
110example
111{ "EXAMPLE:"; echo = 2;
112   ring r = 0,(x,y),ds;
113   poly f = x5+x4y3-y2+y4;
114   getnm(f);
115}
116///////////////////////////////////////////////////////////////////////////////
117
118proc leit (poly f, int n, int m)
119"USAGE:   leit(f,n,m);  poly f, int n,m
120RETURN:  all monomials on the line from (0,n) to (m,0) in the Newton diagram
121EXAMPLE: example leit;  shows an example
122"
123{
124 return(jet(f,m*n,intvec(n,m))-jet(f,m*n-1,intvec(n,m)))
125}
126example
127{ "EXAMPLE:"; echo = 2;
128   ring r = 0,(x,y),ds;
129   poly f = x5+x4y3-y2+y4;
130   leit(f,2,5);
131}
132///////////////////////////////////////////////////////////////////////////////
133proc testreducible (poly f, int n, int m)
134"USAGE:   testreducible(f,n,m);  f poly, n,m int
135RETURN:  1 if there are points in the Newton diagram below the line (0,n)-(m,0)
136         0 else
137EXAMPLE: example testreducible;  shows an example
138"
139{
140 return(size(jet(f,m*n-1,intvec(n,m))) != 0)
141}
142example
143{ "EXAMPLE:"; echo = 2;
144  ring rg=0,(x,y),ls;
145  testreducible(x2+y3-xy4,3,2);
146}
147///////////////////////////////////////////////////////////////////////////////
148proc T_Transform (poly f, int Q, int N)
149"USAGE:   T_Transform(f,Q,N);  f poly, Q,N int
150RETURN:  f(y,xy^Q)/y^NQ   if x,y are the ring variables
151NOTE:    this is intended for irreducible power series f
152EXAMPLE: example T_Transform;  shows an example
153"
154{
155 map T = basering,var(2),var(1)*var(2)^Q;
156 return(T(f)/var(2)^(N*Q));
157}
158example
159{ "EXAMPLE:"; echo = 2;
160  ring exrg=0,(x,y),ls;
161  export exrg;
162  T_Transform(x3+y2-xy3,1,2);
163  kill exrg;
164}
165///////////////////////////////////////////////////////////////////////////////
166proc T1_Transform (poly f, number d, int Q)
167"USAGE:   T1_Transform(f,d,Q);  f poly, d number, Q int
168RETURN:  f(x,y+d*x^Q)   if x,y are the ring variables
169EXAMPLE: example T1_Transform;  shows an example
170"
171{
172 map T1 = basering,var(1),var(2)+d*var(1)^Q;
173 return(T1(f));
174}
175example
176{ "EXAMPLE:"; echo = 2;
177  ring exrg=0,(x,y),ls;
178  export exrg;
179  T1_Transform(y2-2xy+x2+x2y,1,1);
180  kill exrg;
181}
182///////////////////////////////////////////////////////////////////////////////
183
184proc T2_Transform (poly f, number d, int M, int N, poly refpoly)
185"USAGE:   T2_Transform(f,d,M,N,ref); f poly, d number; M,N int; ref poly
186RETURN:  list: poly T2(f,d',M,N), number d' in \{ d, 1/d \}
187ASSUME:  ref has the same Newton polygon as f (but can be simpler)
188         for this you can e.g. use the proc `referencepoly' or simply f again
189COMMENT: T2 is a composition of T_Transform and T1_Transform; the exact
190         definition can be found in  Rybowicz: `Sur le calcul des places ...'
191         or in  Lamm: `Hamburger-Noether-Entwicklung von Kurvensingularitaeten'
192SEE ALSO: T_Transform, T1_Transform, referencepoly
193EXAMPLE: example T2_Transform;  shows an example
194"
195{
196 //---------------------- compute gcd and extgcd of N,M -----------------------
197  int ggt=gcd(M,N);
198  M=M/ggt; N=N/ggt;
199  list ts=extgcd(M,N);
200  int tau,sigma=ts[2],-ts[3];
201  int s,t;
202  poly xp=var(1);
203  poly yp=var(2);
204  poly hilf;
205  if (sigma<0) { tau=-tau; sigma=-sigma;}
206 // es gilt: 0<=tau<=N, 0<=sigma<=M, |N*sigma-M*tau| = 1 = ggT(M,N)
207  if (N*sigma < M*tau) { d = 1/d; }
208 //--------------------------- euklid. Algorithmus ----------------------------
209  int R;
210  int M1,N1=M,N;
211  for ( R=M1%N1; R!=0; ) { M1=N1; N1=R; R=M1%N1;}
212  int Q=M1 / N1;
213  map T1 = basering,xp,yp+d*xp^Q;
214  map Tstar=basering,xp^(N-Q*tau)*yp^tau,xp^(M-sigma*Q)*yp^sigma;
215  if (defined(HNDebugOn)) {
216   "Trafo. T2: x->x^"+string(N-Q*tau)+"*y^"+string(tau)+", y->x^"
217    +string(M-sigma*Q)+"*y^"+string(sigma);
218   "delt =",d,"Q =",Q,"tau,sigma =",tau,sigma;
219  }
220 //------------------- Durchfuehrung der Transformation T2 --------------------
221  f=Tstar(f);
222  refpoly=Tstar(refpoly);
223 //--- dividiere f so lange durch x & y, wie die Div. aufgeht, benutze ein  ---
224 //--- Referenzpolynom mit gleichem Newtonpolynom wie f zur Beschleunigung: ---
225  for (hilf=refpoly/xp; hilf*xp==refpoly; hilf=refpoly/xp) {refpoly=hilf; s++;}
226  for (hilf=refpoly/yp; hilf*yp==refpoly; hilf=refpoly/yp) {refpoly=hilf; t++;}
227  f=f/(xp^s*yp^t);
228  return(list(T1(f),d));
229}
230example
231{ "EXAMPLE:"; echo = 2;
232  ring exrg=0,(x,y),ds;
233  export exrg;
234  poly f=y2-2x2y+x6-x5y+x4y2;
235  T2_Transform(f,1/2,4,1,f);
236  T2_Transform(f,1/2,4,1,referencepoly(newtonpoly(f,1)));
237  // if  size(referencepoly) << size(f)  the 2nd example would be faster
238  referencepoly(newtonpoly(f,1));
239  kill exrg;
240}
241///////////////////////////////////////////////////////////////////////////////
242
243proc koeff (poly f, int I, int J)
244"USAGE:   koeff(f,I,J); f bivariate polynomial, I,J integers
245RETURN:  if f = sum(a(i,j)*x^i*y^j), then koeff(f,I,J)= a(I,J) (of type number)
246NOTE:    J must be in the range of the exponents of the 2nd ring variable
247EXAMPLE: example koeff;  shows an example
248"
249{
250  matrix mat = coeffs(coeffs(f,var(2))[J+1,1],var(1));
251  if (size(mat) <= I) { return(0);}
252  else { return(leadcoef(mat[I+1,1]));}
253}
254example
255{ "EXAMPLE:"; echo = 2;
256  ring r=0,(x,y),dp;
257  koeff(x2+2xy+3xy2-x2y-2y3,1,2);
258}
259///////////////////////////////////////////////////////////////////////////////
260
261proc squarefree (poly f)
262"USAGE:  squarefree(f);  f poly
263ASSUME:  f is a bivariate polynomial (in the first 2 ring variables).
264RETURN:  poly, a squarefree divisor of f.
265NOTE:    Usually, the return value is the greatest squarefree divisor, but
266         there is one exception: factors with a p-th root, p the
267         characteristic of the basering, are lost.
268SEE ALSO: allsquarefree
269EXAMPLE: example squarefree; shows some examples.
270"
271{
272 //----------------- Wechsel in geeigneten Ring & Variablendefinition ---------
273  def altring = basering;
274  int e;
275  int gcd_ok=1;
276  string mipl="0";
277  if (size(parstr(altring))==1) { mipl=string(minpoly); }
278 //---- test: char = (p^k,a) (-> gcd not implemented) or (p,a) (gcd works) ----
279  if ((char(basering)!=0) and (charstr(basering)!=string(char(basering)))) {
280    string tststr=charstr(basering);
281    tststr=tststr[1..find(tststr,",")-1];           //-> "p^k" bzw. "p"
282    gcd_ok=(tststr==string(char(basering)));
283  }
284  execute("ring rsqrf = ("+charstr(altring)+"),(x,y),dp;");
285  if ((gcd_ok!=0) && (mipl!="0")) { execute("minpoly="+mipl+";"); }
286  poly f=fetch(altring,f);
287  poly dif,g,l;
288  if ((char(basering)==0) and (charstr(basering)!=string(char(basering)))
289      and (mipl!="0")) {
290    gcd_ok=0;                   // since Singular 1.2 gcd no longer implemented
291  }
292  if (gcd_ok!=0) {
293 //--------------------- Berechne f/ggT(f,df/dx,df/dy) ------------------------
294    dif=diff(f,x);
295    if (dif==0) { g=f; }        // zur Beschleunigung
296    else { g=gcd(f,dif); }
297    if (g!=1) {                 // sonst schon sicher, dass f quadratfrei
298     dif=diff(f,y);
299     if (dif!=0) { g=gcd(g,dif); }
300    }
301    if (g!=1) {
302     e=0;
303     if (g==f) { l=1; }         // zur Beschleunigung
304     else {
305       module m=syz(ideal(g,f));
306       if (deg(m[2,1])>0) {
307         "!! The Singular command 'syz' has returned a wrong result !!";
308         l=1;                   // Division f/g muss aufgehen
309       }
310       else { l=m[1,1]; }
311     }
312    }
313    else { e=1; }
314  }
315  else {
316 //------------------- Berechne syz(f,df/dx) oder syz(f,df/dy) ----------------
317 //-- Achtung: Ist f reduzibel, koennen Faktoren mit Ableitung Null verloren --
318 //-- gehen! Ist aber nicht weiter schlimm, weil char (p^k,a) nur im irred.  --
319 //-- Fall vorkommen kann. Wenn f nicht g^p ist, wird auf jeden Fall         --
320 //------------------------ ein Faktor gefunden. ------------------------------
321    dif=diff(f,x);
322    if (dif == 0) {
323     dif=diff(f,y);
324     if (dif==0) { e=2; l=1; } // f is of power divisible by char of basefield
325     else { l=syz(ideal(dif,f))[1,1];  // x^p+y^(p-1) abgedeckt
326            if (subst(f,x,0)==0) { l=l*x; }
327            if (deg(l)==deg(f))  { e=1;}
328            else {e=0;}
329     }
330    }
331    else { l=syz(ideal(dif,f))[1,1];
332           if (subst(f,y,0)==0) { l=l*y; }
333           if (deg(l)==deg(f))  { e=1;}
334           else {e=0;}
335    }
336  }
337 //--------------- Wechsel in alten Ring und Rueckgabe des Ergebnisses --------
338  setring altring;
339  if (e==1) { return(f); }    // zur Beschleunigung
340  else {
341   poly l=fetch(rsqrf,l);
342   return(l);
343  }
344}
345example
346{ "EXAMPLE:"; echo = 2;
347 ring exring=3,(x,y),dp;
348 squarefree((x3+y)^2);
349 squarefree((x+y)^3*(x-y)^2); // Warning: (x+y)^3 is lost
350 squarefree((x+y)^4*(x-y)^2); // result is (x+y)*(x-y)
351}
352///////////////////////////////////////////////////////////////////////////////
353
354proc allsquarefree (poly f, poly l)
355"USAGE : allsquarefree(f,g);  f,g poly
356ASSUME: g is the output of @code{squarefree(f)}.
357RETURN: the greatest squarefree divisor of f.
358NOTE  : This proc uses factorize to get the missing factors of f not in g and,
359        therefore, may be slow.
360SEE ALSO: squarefree
361EXAMPLE: example allsquarefree;  shows an example
362"
363{
364 //------------------------ Wechsel in geeigneten Ring ------------------------
365 def altring = basering;
366 string mipl="0";
367 if (size(parstr(altring))==1) { mipl=string(minpoly); }
368 if ((char(basering)!=0) and (charstr(basering)!=string(char(basering)))) {
369   string tststr=charstr(basering);
370   tststr=tststr[1..find(tststr,",")-1];           //-> "p^k" bzw. "p"
371   if (tststr!=string(char(basering))) {
372     " Sorry -- not implemented for this ring (gcd doesn't work)";
373     return(l);
374   }
375 }
376 execute("ring rsqrf = ("+charstr(altring)+"),(x,y),dp;");
377 if (mipl!="0") { execute("minpoly="+mipl+";"); }
378 poly f=fetch(altring,f);
379 poly l=fetch(altring,l);
380 //---------- eliminiere bereits mit squarefree gefundene Faktoren ------------
381 poly g=l;
382 while (deg(g)!=0) {
383   f=syz(ideal(g,f))[1,1];                         // f=f/g;
384   g=gcd(f,l);
385 }                                                 // jetzt f=h^p
386 //--------------- Berechne uebrige Faktoren mit factorize --------------------
387 if (deg(f)>0) {
388  g=1;
389//*CL old:  ideal factf=factorize(f,1);
390//*         for (int i=1; i<=size(factf); i++) { g=g*factf[i]; }
391  ideal factf=factorize(f)[1];
392  for (int i=2; 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 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
929        with two entries indicating the highest degree up to which the
930        coefficients of the monomials in L[i][1] are exact (entry -1 means that
931        the corresponding 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: parametrization, 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
1233         entry 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: multsequence, 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)}.
1755RETURN:  intvec corresponding to the multiplicity sequence of (a branch)
1756         of the curve (the same as @code{invariants(INPUT)[6]}).
1757
1758ASSUME:  INPUT is a bivariate polynomial, or the output of @code{hnexpansion(f)},
1759         or the list @code{hne} in the ring created by @code{hnexpansion(f)}.
1760RETURN:  list of two integer matrices:
1761@texinfo
1762@table @asis
1763@item  @code{multsequence(INPUT)[1][i,*]}
1764   contains the multiplicities of the branches at their infinitely near point
1765   of 0 in its (i-1) order neighbourhood (i.e., i=1: multiplicity of the
1766   branches themselves, i=2: multiplicity of their 1st quadratic transformed,
1767   etc., @*
1768   Hence, @code{multsequence(INPUT)[1][*,j]} is the multiplicity sequence
1769   of branch j.
1770@item  @code{multsequence(INPUT)[2][i,*]}:
1771   contains the information which of these infinitely near points coincide.
1772@end table
1773@end texinfo
1774NOTE:  The order of elements of the list @code{hne} obtained from @code{hnexpansion(f[,\"ess\")}
1775       must not be changed (because then the coincident infinitely near points
1776       couldn't be grouped together, cf. meaning of 2nd intmat in example).
1777       Hence, it is not wise to compute the HNE of several polynomials
1778       separately, put them into a list INPUT and call @code{multsequence(INPUT)}. @*
1779       Use @code{displayMultsequence} to produce a better readable output for
1780       reducible curves on the screen. @*
1781       In case the Hamburger-Noether expansion of the curve f is needed
1782       for other purposes as well it is better to calculate this first
1783       with the aid of @code{hnexpansion} and use it as input instead of
1784       the polynomial itself.
1785SEE ALSO: displayMultsequence, develop, hnexpansion, separateHNE
1786KEYWORDS: multiplicity sequence
1787EXAMPLE: example multsequence;  shows an example
1788"
1789{
1790 //---- INPUT = poly, or HNEring --------------------
1791  if (typeof(#[1])=="poly")
1792  {
1793    list HNEXPANSION=hnexpansion(#[1]);
1794    return(multsequence(HNEXPANSION));
1795  }
1796  if (typeof(#[1])=="ring")
1797  {
1798    def H_N_ER_I_N_G=#[1];
1799    def ret_te_ring=basering;
1800    setring H_N_ER_I_N_G;
1801    list ErGeBnIs=multsequence(hne);
1802    setring ret_te_ring;
1803    kill H_N_ER_I_N_G;
1804    return(ErGeBnIs);
1805  }
1806 //-- entferne ueberfluessige Daten zur Erhoehung der Rechengeschwindigkeit: --
1807 #=stripHNE(#);
1808 int k,i,j;
1809 //----------------- Multiplizitaetensequenz eines Zweiges --------------------
1810 if (typeof(#[1])=="matrix") {
1811  intvec v=#[2];
1812  list ergebnis;
1813  if (#[3]==-1) {
1814    "An error has occurred in develop, so there is no HNE.";
1815   return(intvec(0));
1816  }
1817  intvec multips,multseq;
1818  multips=multiplicities(#);
1819  k=1;
1820  for (i=1; i<size(v); i++) {
1821    for (j=1; j<=v[i]; j++) {
1822      multseq[k]=multips[i];
1823      k++;
1824  }}
1825  multseq[k]=1;
1826  //--- fuelle die Multipl.seq. mit den notwendigen Einsen auf -- T.Keilen ----
1827  int tester=k;
1828  while((multseq[tester]==1) and (tester>1))
1829  {
1830    tester=tester-1;
1831  }
1832  if((multseq[tester]!=1) and (multseq[tester]!=k-tester))
1833  {
1834    for (i=k+1; i<=tester+multseq[tester]; i++)
1835    {
1836      multseq[i]=1;
1837    }
1838  }
1839  //--- Ende T.Keilen --- 06.05.02 
1840  return(multseq);
1841 }
1842 //---------------------------- mehrere Zweige --------------------------------
1843 else {
1844   list HNEs=#;
1845   int anzahl=size(HNEs);
1846   int maxlength=0;
1847   int bisher;
1848   intvec schnitt,ones;
1849   ones[anzahl]=0;
1850   ones=ones+1;                  // = 1,1,...,1
1851   for (i=1; i<anzahl; i++) {
1852     schnitt[i]=separateHNE(HNEs[i],HNEs[i+1]);
1853     j=size(multsequence(HNEs[i]));
1854     maxlength=maxlength*(j < maxlength) + j*(j >= maxlength);
1855     maxlength=maxlength*(schnitt[i]+1 < maxlength)
1856               + (schnitt[i]+1)*(schnitt[i]+1 >= maxlength);
1857   }
1858   j=size(multsequence(HNEs[anzahl]));
1859   maxlength=maxlength*(j < maxlength) + j*(j >= maxlength);
1860
1861//-------------- Konstruktion der ersten zu berechnenden Matrix ---------------
1862   intmat allmults[maxlength][anzahl];
1863   for (i=1; i<=maxlength; i++)  { allmults[i,1..anzahl]=ones[1..anzahl]; }
1864   for (i=1; i<=anzahl; i++) {
1865     ones=multsequence(HNEs[i]);
1866     allmults[1..size(ones),i]=ones[1..size(ones)];
1867   }
1868//---------------------- Konstruktion der zweiten Matrix ----------------------
1869   intmat separate[maxlength][anzahl];
1870   for (i=1; i<=maxlength; i++) {
1871     k=1;
1872     bisher=0;
1873     if (anzahl==1) { separate[i,1]=1; }
1874     for (j=1; j<anzahl; j++)   {
1875       if (schnitt[j]<i) {
1876         separate[i,k]=j-bisher;
1877         bisher=j;
1878         k++;
1879       }
1880       separate[i,k]=anzahl-bisher;
1881     }
1882   }
1883  return(list(allmults,separate));
1884 }
1885}
1886example
1887{
1888  // -------- prepare for example ---------
1889  if (nameof(basering)=="HNEring") {
1890   def rettering=HNEring;
1891   kill HNEring;
1892  }
1893  // ------ the example starts here -------
1894  "EXAMPLE:"; echo = 2;
1895  ring r=0,(x,y),dp;
1896  list hn=hnexpansion((x6-y10)*(x+y2-y3)*(x+y2+y3));   // 4 branches
1897  def HNEring=hn[1];
1898  setring HNEring;
1899  multsequence(hne[1]),"  |  ",multsequence(hne[2]),"  |  ",
1900  multsequence(hne[3]),"  |  ",multsequence(hne[4]);
1901  multsequence(hne);
1902  // The meaning of the entries of the 2nd matrix is as follows:
1903  displayMultsequence(hne);
1904  echo = 0;
1905  // --- restore HNEring if previously defined ---
1906  kill HNEring,r;
1907  if (defined(rettering)) {
1908   setring rettering;
1909   def HNEring=rettering;
1910   export HNEring;
1911  }
1912}
1913///////////////////////////////////////////////////////////////////////////////
1914
1915proc displayMultsequence
1916"USAGE:   displayMultsequence(INPUT); INPUT list or poly
1917ASSUME:  INPUT is a bivariate polynomial, or the output of @code{develop(f)},
1918         or of @code{extdevelop(develop(f),n)}, or of of @code{hnexpansion(f[,\"ess\"])},
1919         or (one entry in) the list @code{hne} of the ring created by @code{hnexpansion(f[,\"ess \"])}.
1920RETURN:  nothing
1921DISPLAY: the sequence of multiplicities:
1922@format
1923 - if @code{INPUT=develop(f)} or @code{INPUT=extdevelop(develop(f),n)} or @code{INPUT=hne[i]}:
1924                      @code{a , b , c , ....... , 1}
1925 - if @code{INPUT=f} or @code{INPUT=hnexpansion(f[,\"ess\"])} or @code{INPUT=hne}:
1926                      @code{[(a_1, .... , b_1 , .... , c_1)],}
1927                      @code{[(a_2, ... ), ... , (... , c_2)],}
1928                      @code{ ........................................ ,}
1929                      @code{[(a_n),(b_n), ....., (c_n)]}
1930     with:
1931       @code{a_1 , ... , a_n} the sequence of multiplicities of the 1st branch,
1932       @code{[...]} the multiplicities of the j-th transformed of all branches,
1933       @code{(...)} indicating branches meeting in an infinitely near point.
1934@end format
1935NOTE:  The same restrictions for INPUT as in @code{multsequence} apply.@*
1936       In case the Hamburger-Noether expansion of the curve f is needed
1937       for other purposes as well it is better to calculate this first
1938       with the aid of @code{hnexpansion} and use it as input instead of
1939       the polynomial itself.
1940SEE ALSO: multsequence, develop, hnexpansion, separateHNE
1941EXAMPLE: example displayMultsequence;  shows an example
1942"
1943{
1944 //---- INPUT = poly, or HNEring --------------------
1945  if (typeof(#[1])=="poly")
1946  {
1947    list HNEXPANSION=hnexpansion(#[1]);
1948    displayMultsequence(HNEXPANSION);
1949    return();
1950  }
1951  if (typeof(#[1])=="ring")
1952  {
1953    def H_N_ER_I_N_G=#[1];
1954    def ret_te_ring=basering;
1955    setring H_N_ER_I_N_G;
1956    displayMultsequence(hne);
1957    setring ret_te_ring;
1958    kill H_N_ER_I_N_G;
1959    return();
1960  }
1961 //-- entferne ueberfluessige Daten zur Erhoehung der Rechengeschwindigkeit: --
1962 #=stripHNE(#);
1963 //----------------- Multiplizitaetensequenz eines Zweiges --------------------
1964 if (typeof(#[1])=="matrix") {
1965   if (#[3]==-1) {
1966     "An error has occurred in develop, so there is no HNE.";
1967   }
1968   else {
1969     "The sequence of multiplicities is  ",multsequence(#);
1970 }}
1971 //---------------------------- mehrere Zweige --------------------------------
1972 else {
1973   list multips=multsequence(#);
1974   int i,j,k,l;
1975   string output;
1976   for (i=1; i<=nrows(multips[1]); i++) {
1977     output="[";
1978     k=1;
1979     for (l=1; k<=ncols(multips[1]); l++) {
1980       output=output+"(";
1981       for (j=1; j<=multips[2][i,l]; j++) {
1982         output=output+string(multips[1][i,k]);
1983         k++;
1984         if (j<multips[2][i,l]) { output=output+","; }
1985       }
1986       output=output+")";
1987       if ((k-1) < ncols(multips[1])) { output=output+","; }
1988      }
1989     output=output+"]";
1990     if (i<nrows(multips[1])) { output=output+","; }
1991     output;
1992   }
1993 }
1994} // example multsequence; geht wegen echo nicht (muesste auf 3 gesetzt werden)
1995example
1996{
1997  // ------ the example starts here -------
1998  "EXAMPLE:"; echo = 2;
1999  ring r=0,(x,y),dp;
2000  //// Example 1: Input = output of develop
2001  displayMultsequence(develop(x3-y5));
2002  //// Example 2: Input = bivariate polynomial
2003  displayMultsequence((x6-y10)*(x+y2-y3)*(x+y2+y3));
2004}
2005///////////////////////////////////////////////////////////////////////////////
2006
2007proc separateHNE (list hn1,list hn2)
2008"USAGE:    separateHNE(hne1,hne2);  hne1, hne2 lists
2009ASSUME:   hne1, hne2 are HNEs (=output of
2010          @code{develop(f)}, @code{extdevelop(develop(f),n)}, or
2011          one entry in the list @code{hne} in the ring created by
2012          @code{hnexpansion(f[,\"ess\"])}.
2013RETURN:   number of quadratic transformations needed to separate both curves
2014          (branches).
2015SEE ALSO: develop, hnexpansion, multsequence, displayMultsequence
2016EXAMPLE:  example separateHNE;  shows an example
2017"
2018{
2019 int i,j,s,unterschied,separated;
2020 matrix a1=hn1[1];
2021 matrix a2=hn2[1];
2022 intvec h1=hn1[2];
2023 intvec h2=hn2[2];
2024 if (hn1[3]!=hn2[3]) {
2025 //-- die jeweils erste Zeile von hn1,hn2 gehoert zu verschiedenen Parametern -
2026 //---------------- d.h. beide Kurven schneiden sich transversal --------------
2027   separated=1;
2028 }
2029 else {
2030 //--------- die jeweils erste Zeile gehoert zum gleichen Parameter -----------
2031   unterschied=0;
2032   for (s=1; (h1[s]==h2[s]) && (s<size(h1)) && (s<size(h2))
2033              && (unterschied==0); s++) {
2034     for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]); i++) {;}
2035     if (i<=h1[s]) {
2036       unterschied=1;
2037       s--;                    // um s++ am Schleifenende wieder auszugleichen
2038     }
2039   }
2040   if (unterschied==0) {
2041     if ((s<size(h1)) && (s<size(h2))) {
2042       for (i=1; (a1[s,i]==a2[s,i]) && (i<=h1[s]) && (i<=h2[s]); i++) {;}
2043     }
2044     else {
2045 //-------------- Sonderfall: Unterschied in letzter Zeile suchen -------------
2046 // Beachte: Es koennen undefinierte Stellen auftreten, bei abbrechender HNE
2047 // muss die Ende-Markierung weg, h_[r] ist unendlich, die Matrix muss mit
2048 // Nullen fortgesetzt gedacht werden
2049 //----------------------------------------------------------------------------
2050       if (ncols(a1)>ncols(a2)) { j=ncols(a1); }
2051       else                     { j=ncols(a2); }
2052       unterschied=0;
2053       if ((h1[s]>0) && (s==size(h1))) {
2054         a1[s,h1[s]+1]=0;
2055         if (ncols(a1)<=ncols(a2)) { unterschied=1; }
2056       }
2057       if ((h2[s]>0) && (s==size(h2))) {
2058         a2[s,h2[s]+1]=0;
2059         if (ncols(a2)<=ncols(a1)) { unterschied=1; }
2060       }
2061       if (unterschied==1) {                   // mind. eine HNE war endlich
2062         matrix ma1[1][j]=a1[s,1..ncols(a1)];  // und bedarf der Fortsetzung
2063         matrix ma2[1][j]=a2[s,1..ncols(a2)];  // mit Nullen
2064       }
2065       else {
2066         if (ncols(a1)>ncols(a2)) { j=ncols(a2); }
2067         else                     { j=ncols(a1); }
2068         matrix ma1[1][j]=a1[s,1..j];          // Beschr. auf vergleichbaren
2069         matrix ma2[1][j]=a2[s,1..j];          // Teil (der evtl. y's enth.)
2070       }
2071       for (i=1; (ma1[1,i]==ma2[1,i]) && (i<j) && (ma1[1,i]!=var(2)); i++) {;}
2072       if (ma1[1,i]==ma2[1,i]) {
2073         "//** The two HNE's are identical!";
2074         "//** You have either tried to compare a branch with itself,";
2075         "//** or the two branches have been developed separately.";
2076         "//   In the latter case use `extdevelop' to extend the HNE's until",
2077         "they differ.";
2078         return(-1);
2079       }
2080       if ((ma1[1,i]==var(2)) || (ma2[1,i]==var(2))) {
2081         "//** The two HNE's are (so far) identical. This is because they",
2082         "have been";
2083         "//** computed separately. I need more data; use `extdevelop' to",
2084         "extend them,";
2085         if (ma1[1,i]==var(2)) {"//** at least the first one.";}
2086         else                  {"//** at least the second one.";}
2087         return(-1);
2088       }
2089     }
2090   }
2091   separated=i;
2092   for (j=1; j<s; j++) { separated=separated+h1[j]; }
2093 }
2094 return(separated);
2095}
2096example
2097{ "EXAMPLE:"; echo = 2;
2098  int p=printlevel; printlevel=-1;
2099  ring r=0,(x,y),dp;
2100  list hne1=develop(x);
2101  list hne2=develop(x+y);
2102  list hne3=develop(x+y2);
2103  separateHNE(hne1,hne2);  // two transversal lines
2104  separateHNE(hne1,hne3);  // one quadratic transform. gives 1st example
2105  printlevel=p;
2106}
2107///////////////////////////////////////////////////////////////////////////////
2108
2109proc displayHNE(list ldev,list #)
2110"USAGE:   displayHNE(L[,n]); L list, n int
2111ASSUME:  L is the output of @code{develop(f)}, or of @code{exdevelop(f,n)},
2112         or of @code{hnexpansion(f[,\"ess\"])}, or (one entry in) the list
2113         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2114RETURN:  - if only one argument is given, no return value, but
2115         display an ideal HNE of the following form:
2116     @example
2117     HNE[1]=-y+[]*z(0)^1+[]*z(0)^2+...+z(0)^<>*z(1)
2118     HNE[2]=-x+          []*z(1)^2+...+z(1)^<>*z(2)
2119     HNE[3]=             []*z(2)^2+...+z(2)^<>*z(3)
2120     .......             ..........................
2121     HNE[r+1]=           []*z(r)^2+[]*z(r)^3+......
2122     @end example
2123     where @code{x},@code{y} are the first 2 variables of the basering.
2124     The values of @code{[]} are the coefficients of the Hamburger-Noether
2125     matrix, the values of @code{<>} are represented by @code{x} in the
2126     HN-matrix.@*
2127     - if a second argument is given, create and export a new ring with
2128     name @code{displayring} containing an ideal @code{HNE} as described
2129     above.@*
2130     - if L corresponds to the output of @code{hnexpansion(f[,\"ess\"])}
2131     or to the list @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])},
2132     @code{displayHNE(L[,n])} shows the HNE's of all branches of f in the form
2133     described above. The optional parameter is then ignored.
2134NOTE:  The 1st line of the above ideal (i.e., @code{HNE[1]}) means that
2135     @code{y=[]*z(0)^1+...}, the 2nd line (@code{HNE[2]}) means that
2136     @code{x=[]*z(1)^2+...}, so you can see which indeterminate
2137     corresponds to which line (it's also possible that @code{x} corresponds
2138     to the 1st line and @code{y} to the 2nd).
2139
2140SEE ALSO: develop, hnexpansion
2141EXAMPLE: example displayHNE; shows an example
2142"
2143{
2144 if ((typeof(ldev[1])=="list") || (typeof(ldev[1])=="none")) {
2145   for (int i=1; i<=size(ldev); i++) {
2146     "// Hamburger-Noether development of branch nr."+string(i)+":";
2147     displayHNE(ldev[i]);"";
2148   }
2149   return();
2150 }
2151 //--------------------- Initialisierungen und Ringwechsel --------------------
2152 matrix m=ldev[1];
2153 intvec v=ldev[2];
2154 int switch=ldev[3];
2155 if (switch==-1) {
2156   "An error has occurred throughout the expansion, so there is no HNE.";
2157   return(ideal(0));
2158 }
2159 def altring=basering;
2160 /////////////////////////////////////////////////////////
2161 //  Change by T. Keilen 08.06.2002
2162 //  ring + ring does not work if one ring is an algebraic extension
2163/*
2164 if (parstr(basering)!="") {
2165   if (charstr(basering)!=string(char(basering))+","+parstr(basering)) {
2166     execute
2167      ("ring dazu=("+charstr(basering)+"),z(0.."+string(size(v)-1)+"),ls;");
2168   }
2169   else { ring dazu=char(altring),z(0..size(v)-1),ls; }
2170 }
2171 else   { ring dazu=char(altring),z(0..size(v)-1),ls; }
2172 def displayring=dazu+altring;
2173*/
2174 execute("ring displayring=("+charstr(basering)+"),(z(0.."+string(size(v)-1)+"),"+varstr(basering)+"),(ls("+string(size(v))+"),"+ordstr(basering)+");");
2175 // End change by T. Keilen
2176 //////////////////////////////////////////////////////////////
2177 setring displayring;
2178 if (size(#) != 0) {
2179    export displayring;
2180  }
2181 map holematrix=altring,0;        // mappt nur die Monome vom Grad Null
2182 matrix m=holematrix(m);
2183 //--------------------- Erzeuge Matrix n mit n[i,j]=z(j-1)^i -----------------
2184 int i;
2185 matrix n[ncols(m)][nrows(m)];
2186 for (int j=1; j<=nrows(m); j++) {
2187    for (i=1; i<=ncols(m); i++) { n[i,j]=z(j-1)^i; }
2188 }
2189 matrix displaymat=m*n;
2190 ideal HNE;
2191 for (i=1; i<nrows(m); i++) { HNE[i]=displaymat[i,i]+z(i)*z(i-1)^v[i]; }
2192 HNE[nrows(m)]=displaymat[nrows(m),nrows(m)];
2193 if (nrows(m)<2) { HNE[2]=z(0); }
2194 if (switch==0) {
2195    HNE[1] = HNE[1]-var(size(v)+2);
2196    HNE[2] = HNE[2]-var(size(v)+1);
2197 }
2198 else {
2199    HNE[1] = HNE[1]-var(size(v)+1);
2200    HNE[2] = HNE[2]-var(size(v)+2);
2201 }
2202if (size(#) == 0) {
2203   HNE;
2204   return();
2205 }
2206if (size(#) != 0) {
2207   "// basering is now 'displayring' containing ideal 'HNE'";
2208   keepring(displayring);
2209   export(HNE);
2210   return(HNE);
2211 }
2212}
2213example
2214{ "EXAMPLE:"; echo = 2;
2215  ring r=0,(x,y),dp;
2216  poly f=x3+2xy2+y2;
2217  list hn=develop(f);
2218  displayHNE(hn);
2219}
2220///////////////////////////////////////////////////////////////////////////////
2221//                      procedures for reducible curves                      //
2222///////////////////////////////////////////////////////////////////////////////
2223
2224// proc newtonhoehne (poly f)
2225// USAGE:   newtonhoehne(f);   f poly
2226// ASSUME:  basering = ...,(x,y),ds  or ls
2227// RETURN:  list of intvec(x,y) of coordinates of the newtonpolygon of f
2228// NOTE:    This proc is only available in versions of Singular that know the
2229//         command  system("newton",f);  f poly
2230// {
2231// intvec nm = getnm(f);
2232//  if ((nm[1]>0) && (nm[2]>0)) { f=jet(f,nm[1]*nm[2],nm); }
2233//  list erg=system("newton",f);
2234//  int i; list Ausgabe;
2235//  for (i=1; i<=size(erg); i++) { Ausgabe[i]=leadexp(erg[i]); }
2236// return(Ausgabe);
2237// }
2238///////////////////////////////////////////////////////////////////////////////
2239
2240proc newtonpoly (poly f, int #)
2241"USAGE:   newtonpoly(f);   f poly
2242ASSUME:  basering has exactly two variables; @*
2243         f is convenient, that is, f(x,0) != 0 != f(0,y).
2244RETURN:  list of intvecs (= coordinates x,y of the Newton polygon of f).
2245NOTE:    Procedure uses @code{execute}; this can be avoided by calling
2246         @code{newtonpoly(f,1)} if the ordering of the basering is @code{ls}.
2247KEYWORDS: Newton polygon
2248EXAMPLE: example newtonpoly;  shows an example
2249"
2250{
2251  if (size(#)>=1)
2252  {
2253    if (typeof(#[1])=="int")
2254    {
2255      // this is done to avoid the "execute" command for procedures in
2256      //  hnoether.lib
2257      def is_ls=#[1];
2258    }
2259  }
2260  if (defined(is_ls)<=0)
2261  {
2262    def @Rold=basering;
2263    execute("ring @RR=("+charstr(basering)+"),("+varstr(basering)+"),ls;");
2264    poly f=imap(@Rold,f);
2265  }
2266  intvec A=(0,ord(subst(f,var(1),0)));
2267  intvec B=(ord(subst(f,var(2),0)),0);
2268  intvec C,H; list L;
2269  int abbruch,i;
2270  poly hilf;
2271  L[1]=A;
2272  f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]));
2273  if (defined(is_ls))
2274  {
2275    map xytausch=basering,var(2),var(1);
2276  }
2277  else
2278  {
2279    map xytausch=@RR,var(2),var(1);
2280  }
2281  for (i=2; f!=0; i++)
2282  {
2283     abbruch=0;
2284     while (abbruch==0)
2285     {
2286        C=leadexp(f);         
2287        if(jet(f,A[2]*C[1]-A[1]*C[2]-1,intvec(A[2]-C[2],C[1]-A[1]))==0)
2288        {
2289           abbruch=1;
2290        }       
2291        else
2292        {
2293           f=jet(f,-C[1]-1,intvec(-1,0));
2294        }
2295    }
2296    hilf=jet(f,A[2]*C[1]-A[1]*C[2],intvec(A[2]-C[2],C[1]-A[1]));
2297    H=leadexp(xytausch(hilf));
2298    A=H[2],H[1];
2299    L[i]=A;
2300    f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]-A[1]));
2301  }
2302  L[i]=B;
2303  if (defined(is_ls))
2304  {
2305    return(L);
2306  }
2307  else
2308  {
2309    setring @Rold;
2310    return(L);
2311  }
2312}
2313example
2314{
2315 "EXAMPLE:"; echo = 2;
2316  ring r=0,(x,y),ls;
2317  poly f=x5+2x3y-x2y2+3xy5+y6-y7;
2318  newtonpoly(f);
2319}
2320///////////////////////////////////////////////////////////////////////////////
2321
2322proc is_NND (poly f, list #)
2323"USAGE:   is_NND(f[,mu,NP]);   f poly, mu int, NP list of intvecs
2324ASSUME:  f is convenient, that is, f(x,0) != 0 != f(0,y);@*
2325         mu (optional) is Milnor number of f.@*
2326         NP (optional) is output of @code{newtonpoly(f)}.
2327RETURN:  int: 1 if f in Newton non-degenerate, 0 otherwise.
2328SEE ALSO: newtonpoly
2329KEYWORDS: Newton non-degenerate; Newton polygon
2330EXAMPLE: example is_NND;  shows examples
2331"
2332{
2333  int i;
2334  int i_print=printlevel-voice+2;
2335
2336  if (size(#)==0)
2337  {
2338    int mu=milnor(f);
2339    list NP=newtonpoly(f);
2340  }
2341  else
2342  {
2343    if (typeof(#[1])=="int")
2344    {
2345      def mu=#[1];
2346      def NP=#[2];
2347      for (i=1;i<=size(NP);i++)
2348      {
2349        if (typeof(NP[i])!="intvec")
2350        {
2351          print("third input cannot be Newton polygon ==> ignored ")
2352          NP=newtonpoly(f);
2353          i=size(NP)+1;
2354        } 
2355      }
2356    }
2357    else
2358    {
2359      print("second input cannot be Milnor number ==> ignored ")
2360      int mu=milnor(f);
2361      NP=newtonpoly(f);
2362    }
2363  }
2364
2365  // computation of the Newton number:
2366  int s=size(NP);
2367  int nN=-NP[1][2]-NP[s][1]+1;
2368  intmat m[2][2];
2369  for(i=1;i<=s-1;i++)
2370  {
2371    m=NP[i+1],NP[i];
2372    nN=nN+det(m);
2373  }
2374
2375  if(mu==nN)                   
2376  { // the Newton-polygon is non-degenerate
2377    return(1);
2378  }
2379  else
2380  {
2381    return(0);
2382  }
2383}
2384example
2385{
2386 "EXAMPLE:"; echo = 2;
2387  ring r=0,(x,y),ls;
2388  poly f=x5+y3;
2389  is_NND(f);
2390  poly g=(x-y)^5+3xy5+y6-y7;
2391  is_NND(g);
2392
2393  // if already computed, one should give the Minor number and Newton polygon
2394  // as second and third input:
2395  int mu=milnor(g);
2396  list NP=newtonpoly(g);
2397  is_NND(g,mu,NP);
2398}
2399
2400
2401///////////////////////////////////////////////////////////////////////////////
2402
2403proc charPoly(poly f, int M, int N)
2404"USAGE:  charPoly(f,M,N);  f bivariate poly,  M,N int: length and height
2405                          of Newton polygon of f, which has to be only one line
2406RETURN:  the characteristic polynomial of f
2407EXAMPLE: example charPoly;  shows an example
2408"
2409{
2410 poly charp;
2411 int Np=N/ gcd(M,N);
2412 f=subst(f,var(1),1);
2413 for(charp=0; f<>0; f=f-lead(f))
2414  { charp=charp+leadcoef(f)*var(2)^(leadexp(f)[2]/ Np);}
2415 return(charp);
2416}
2417example
2418{ "EXAMPLE:"; echo = 2;
2419  ring exring=0,(x,y),dp;
2420  charPoly(y4+2y3x2-yx6+x8,8,4);
2421  charPoly(y6+3y3x2-x4,4,6);
2422}
2423///////////////////////////////////////////////////////////////////////////////
2424
2425proc find_in_list(list L,int p)
2426"USAGE:   find_in_list(L,p); L: list of intvec(x,y)
2427         (sorted in y: L[1][2]>=L[2][2]), int p >= 0
2428RETURN:  int i: L[i][2]=p if existent; otherwise i with L[i][2]<p if existent;
2429         otherwise i = size(L)+1;
2430EXAMPLE: example find_in_list;  shows an example
2431"
2432{
2433 int i;
2434 L[size(L)+1]=intvec(0,-1);          // falls p nicht in L[.][2] vorkommt
2435 for (i=1; L[i][2]>p; i++) {;}
2436 return(i);
2437}
2438example
2439{ "EXAMPLE:"; echo = 2;
2440  list L = intvec(0,4), intvec(1,2), intvec(2,1), intvec(4,0);
2441  find_in_list(L,1);
2442  L[find_in_list(L,2)];
2443}
2444///////////////////////////////////////////////////////////////////////////////
2445
2446proc get_last_divisor(int M, int N)
2447"USAGE:   get_last_divisor(M,N); int M,N
2448RETURN:  int Q: M=q1*N+r1, N=q2*r1+r2, ..., ri=Q*r(i+1) (Euclidean alg.)
2449EXAMPLE: example get_last_divisor; shows an example
2450"
2451{
2452 int R=M%N; int Q=M / N;
2453 while (R!=0) {M=N; N=R; R=M%N; Q=M / N;}
2454 return(Q)
2455}
2456example
2457{ "EXAMPLE"; echo = 2;
2458  ring r=0,(x,y),dp;
2459  get_last_divisor(12,10);
2460}
2461///////////////////////////////////////////////////////////////////////////////
2462proc redleit (poly f,intvec S, intvec E)
2463"USAGE:   redleit(f,S,E);  f poly, S,E intvec(x,y)
2464         S,E are two different points on a line in the Newton diagram of f
2465RETURN:  poly g: all monomials of f which lie on or below that line
2466NOTE:    The main purpose is that if the line defined by S and E is part of the
2467         Newton polygon, the result is the quasihomogeneous leading form of f
2468         wrt. that line.
2469SEE ALSO: newtonpoly
2470EXAMPLE: example redleit;  shows an example
2471"
2472{
2473 if (E[1]<S[1]) { intvec H=E; E=S; S=H; } // S,E verkehrt herum eingegeben
2474 return(jet(f,E[1]*S[2]-E[2]*S[1],intvec(S[2]-E[2],E[1]-S[1])));
2475}
2476example
2477{ "EXAMPLE"; echo = 2;
2478  ring exring=0,(x,y),dp;
2479  redleit(y6+xy4-2x3y2+x4y+x6,intvec(3,2),intvec(4,1));
2480}
2481///////////////////////////////////////////////////////////////////////////////
2482
2483
2484proc extdevelop (list l, int Exaktheit)
2485"USAGE:   extdevelop(L,N); list L, int N
2486ASSUME:  L is the output of @code{develop(f)}, or of @code{extdevelop(l,n)},
2487         or one entry in the list @code{hne} in the ring created by
2488          @code{hnexpansion(f[,\"ess\"])}.
2489RETURN:  an extension of the Hamburger-Noether development of f as a list
2490         in the same format as L has (up to the last entry in the output
2491         of @code{develop(f)}).@*
2492         Type @code{help develop;}, resp. @code{help hnexpansion;} for more
2493         details.
2494NOTE:    The new HN-matrix will have at least N columns (if the HNE is not
2495         finite). In particular, if f is irreducible then (in most cases)
2496         @code{extdevelop(develop(f),N)} will produce the same result as
2497         @code{develop(f,N)}.@*
2498         If the matrix M of L has n columns then, compared with
2499         @code{parametrisation(L)}, @code{paramametrize(extdevelop(L,N))} will increase the
2500         exactness by at least (N-n) more significant monomials.
2501SEE ALSO: develop, hnexpansion, parametrisation
2502EXAMPLE: example extdevelop;  shows an example
2503"
2504{
2505 //------------ Initialisierungen und Abfangen unzulaessiger Aufrufe ----------
2506 matrix m=l[1];
2507 intvec v=l[2];
2508 int switch=l[3];
2509 if (nvars(basering) < 2) {
2510   " Sorry. I need two variables in the ring.";
2511   return(list(matrix(maxideal(1)[1]),intvec(0),-1,poly(0)));}
2512 if (switch==-1) {
2513   "An error has occurred in develop, so there is no HNE and no extension.";
2514   return(l);
2515 }
2516 poly f=l[4];
2517 if (f==0) {
2518   " No extension is possible";
2519   return(l);
2520 }
2521 int Q=v[size(v)];
2522 if (Q>0) {
2523   " The HNE was already exact";
2524   return(l);
2525 }
2526 else {
2527   if (Q==-1) { Q=ncols(m); }
2528   else { Q=-Q-1; }
2529 }
2530 int zeile=nrows(m);
2531 int spalten,i,M;
2532 ideal lastrow=m[zeile,1..Q];
2533 int ringwechsel=(varstr(basering)!="x,y") or (ordstr(basering)!="ls(2),C");
2534
2535 //------------------------- Ringwechsel, falls noetig ------------------------
2536 if (ringwechsel) {
2537  def altring = basering;
2538  int p = char(basering);
2539  if (charstr(basering)!=string(p)) {
2540     string tststr=charstr(basering);
2541     tststr=tststr[1..find(tststr,",")-1];     //-> "p^k" bzw. "p"
2542     if (tststr==string(p)) {
2543       if (size(parstr(basering))>1) {         // ring (p,a,..),...
2544        execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2545       }
2546       else {                                  // ring (p,a),...
2547        string mipl=string(minpoly);
2548        ring extdguenstig=(p,`parstr(basering)`),(x,y),ls;
2549        if (mipl!="0") { execute("minpoly="+mipl+";"); }
2550       }
2551     }
2552     else {
2553       execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2554     }
2555  }
2556  else {                               // charstr(basering)== p : no parameter
2557     ring extdguenstig=p,(x,y),ls;
2558  }
2559  export extdguenstig;
2560  map hole=altring,x,y;
2561 //----- map kann sehr zeitaufwendig sein, daher Vermeidung, wo moeglich: -----
2562  if (nvars(altring)==2) { poly f=fetch(altring,f); }
2563  else                   { poly f=hole(f);          }
2564  ideal a=hole(lastrow);
2565 }
2566 else { ideal a=lastrow; }
2567 list Newton=newtonpoly(f,1);
2568 int M1=Newton[size(Newton)-1][1];     // konstant
2569 number delt;
2570 if (Newton[size(Newton)-1][2]!=1) {
2571    " *** The transformed polynomial was not valid!!";}
2572 else {
2573 //--------------------- Fortsetzung der HNE ----------------------------------
2574  while (Q<Exaktheit) {
2575    M=ord(subst(f,y,0));
2576    Q=M-M1;
2577 //------ quasihomogene Leitform ist c*x^M1*y+d*x^(M1+Q) => delta=-d/c: -------
2578    delt=-koeff(f,M,0)/koeff(f,M1,1);
2579    a[Q]=delt;
2580    dbprint(printlevel-voice+2,"a("+string(zeile-1)+","+string(Q)+") = "+string(delt));
2581    if (Q<Exaktheit) {
2582     f=T1_Transform(f,delt,Q);
2583     if (defined(HNDebugOn)) { "transformed polynomial:",f; }
2584     if (subst(f,y,0)==0) {
2585       dbprint(printlevel-voice+2,"The HNE is finite!");
2586       a[Q+1]=x; Exaktheit=Q;
2587       f=0;                        // Speicherersparnis: f nicht mehr gebraucht
2588     }
2589    }
2590  }
2591 }
2592 //------- Wechsel in alten Ring, Zusammensetzung alte HNE + Erweiterung ------
2593 if (ringwechsel) {
2594  setring altring;
2595  map zurueck=extdguenstig,var(1),var(2);
2596  if (nvars(altring)==2) { f=fetch(extdguenstig,f); }
2597  else                   { f=zurueck(f);            }
2598  lastrow=zurueck(a);
2599 }
2600 else { lastrow=a; }
2601 if (ncols(lastrow)>ncols(m)) { spalten=ncols(lastrow); }
2602 else { spalten=ncols(m); }
2603 matrix mneu[zeile][spalten];
2604 for (i=1; i<nrows(m); i++) {
2605  mneu[i,1..ncols(m)]=m[i,1..ncols(m)];
2606 }
2607 mneu[zeile,1..ncols(lastrow)]=lastrow;
2608 if (lastrow[ncols(lastrow)]!=var(1)) {
2609  if (ncols(lastrow)==spalten) { v[zeile]=-1; }  // keine undefinierten Stellen
2610  else {
2611   v[zeile]=-Q-1;
2612   for (i=ncols(lastrow)+1; i<=spalten; i++) {
2613    mneu[zeile,i]=var(2);           // fuelle nicht def. Stellen der Matrix auf
2614 }}}
2615 else { v[zeile]=Q; }               // HNE war exakt
2616 if (ringwechsel)
2617 {
2618   if(system("with","Namespaces")) { kill Top::extdguenstig; }
2619   if (defined(extdguenstig)) {kill extdguenstig; }
2620 }
2621
2622 return(list(mneu,v,switch,f));
2623}
2624example
2625{
2626  if (defined(HNEring))
2627  {
2628    def save_r_i_n_g=HNEring;
2629    kill HNEring;
2630  }
2631  // ------ the example starts here -------
2632  "EXAMPLE:"; echo = 2;
2633  ring exring=0,(x,y),dp;
2634  list hn=hnexpansion(x14-3y2x11-y3x10-y2x9+3y4x8+y5x7+3y4x6+x5*(-y6+y5)
2635                      -3y6x3-y7x2+y8);
2636  def HNEring=hn[1];
2637  setring HNEring;  echo=0;
2638  export(HNEring);  echo=2;
2639  print(hne[1][1]);    // HNE of 1st branch is finite
2640  print(extdevelop(hne[1],5)[1]);
2641  print(hne[2][1]);    // HNE of 2nd branch can be extended
2642  list ehne=extdevelop(hne[2],5);
2643  print(ehne[1]);      // new HN-matrix has 5 columns
2644  parametrisation(hne[2]);
2645  parametrisation(ehne);
2646  echo=0;
2647  if (defined(save_r_i_n_g))
2648  {
2649    kill HNEring;
2650    def HNEring=save_r_i_n_g;
2651  }
2652}
2653///////////////////////////////////////////////////////////////////////////////
2654
2655proc stripHNE (list l)
2656"USAGE:   stripHNE(L);  L list
2657ASSUME:  L is the output of @code{develop(f)}, or of
2658         @code{extdevelop(develop(f),n)}, or (one entry of) the list
2659         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2660RETURN:  list in the same format as L, but all polynomials L[4], resp.
2661         L[i][4], are set to zero.
2662NOTE:    The purpose of this procedure is to remove huge amounts of data
2663         no longer needed. It is useful, if one or more of the polynomials
2664         in L consume much memory. It is still possible to compute invariants,
2665         parametrizations etc. with the stripped HNE(s), but it is not possible
2666         to use @code{extdevelop} with them.
2667SEE ALSO: develop, hnexpansion, extdevelop
2668EXAMPLE: example stripHNE;  shows an example
2669"
2670{
2671 list h;
2672 if (typeof(l[1])=="matrix") { l[4]=poly(0); }
2673 else {
2674  for (int i=1; i<=size(l); i++) {
2675    h=l[i];
2676    h[4]=poly(0);
2677    l[i]=h;
2678  }
2679 }
2680 return(l);
2681}
2682example
2683{
2684  "EXAMPLE:"; echo = 2;
2685  ring r=0,(x,y),dp;
2686  list hne=develop(x2+y3+y4);
2687  hne;
2688  stripHNE(hne);
2689}
2690///////////////////////////////////////////////////////////////////////////////
2691static proc extractHNEs(list HNEs, int transvers)
2692"USAGE:  extractHNEs(HNEs,transvers);  list HNEs (output from HN),
2693        int transvers: 1 if x,y were exchanged, 0 else
2694RETURN: list of Hamburger-Noether-Extensions in the form of hne in hnexpansion
2695NOTE:   This procedure is only for internal purpose; examples don't make sense
2696"
2697{
2698 int i,maxspalte,hspalte,hnezaehler;
2699 list HNEaktu,Ergebnis;
2700 for (hnezaehler=1; hnezaehler<=size(HNEs); hnezaehler++) {
2701  maxspalte=0;
2702  HNEaktu=HNEs[hnezaehler];
2703  if (defined(HNDebugOn)) {"To process:";HNEaktu;}
2704  if (size(HNEaktu)!=size(HNEaktu[1])+2) {
2705     "The ideals and the hqs in HNEs[",hnezaehler,"] don't match!!";
2706     HNEs[hnezaehler];
2707  }
2708 //------------ ermittle  maximale Anzahl benoetigter Spalten: ----------------
2709  for (i=2; i<size(HNEaktu); i++) {
2710    hspalte=ncols(HNEaktu[i]);
2711    maxspalte=maxspalte*(hspalte < maxspalte)+hspalte*(hspalte >= maxspalte);
2712  }
2713 //------------- schreibe Ausgabe fuer hnezaehler-ten Zweig: ------------------
2714  matrix ma[size(HNEaktu)-2][maxspalte];
2715  for (i=1; i<=(size(HNEaktu)-2); i++) {
2716    if (ncols(HNEaktu[i+1]) > 1) {
2717      ma[i,1..ncols(HNEaktu[i+1])]=HNEaktu[i+1]; }
2718    else { ma[i,1]=HNEaktu[i+1][1];}
2719  }
2720  Ergebnis[hnezaehler]=list(ma,HNEaktu[1],transvers,HNEaktu[size(HNEaktu)]);
2721  kill ma;
2722 }
2723 return(Ergebnis);
2724}
2725///////////////////////////////////////////////////////////////////////////////
2726
2727proc factorfirst(poly f, int M, int N)
2728"USAGE : factorfirst(f,M,N); f poly, M,N int
2729RETURN: number d: f=c*(y^(N/e) - d*x^(M/e))^e with e=gcd(M,N), number c fitting
2730        0 if d does not exist
2731EXAMPLE: example factorfirst;  shows an example
2732"
2733{
2734 number c = koeff(f,0,N);
2735 number delt;
2736 int eps,l;
2737 int p=char(basering);
2738 string ringchar=charstr(basering);
2739
2740 if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
2741 int e = gcd(M,N);
2742
2743 if (p==0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2744 else {
2745   if (e%p != 0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2746   else {
2747     eps = e;
2748     for (l = 0; eps%p == 0; l=l+1) { eps=eps/ p;}
2749     if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
2750     delt = koeff(f,(M/ e)*p^l,(N/ e)*p^l*(eps-1)) / (-1*eps*c);
2751
2752     if ((charstr(basering) != string(p)) and (delt != 0)) {
2753 //------ coefficient field is not Z/pZ => (p^l)th root is not identity -------
2754       delt=0;
2755       if (defined(HNDebugOn)) {
2756         "trivial factorization not implemented for",
2757         "parameters---I've to use 'factorize'";
2758       }
2759     }
2760   }
2761 }
2762 if (defined(HNDebugOn)) {"quasihomogeneous leading form:",f," = ",c,
2763        "* (y^"+string(N/ e),"-",delt,"* x^"+string(M/ e)+")^",e," ?";}
2764 if (f != c*(var(2)^(N/ e) - delt*var(1)^(M/ e))^e) {return(0);}
2765 else {return(delt);}
2766}
2767example
2768{ "EXAMPLE:"; echo = 2;
2769  ring exring=7,(x,y),dp;
2770  factorfirst(2*(y3-3x4)^5,20,15);
2771  factorfirst(x14+y7,14,7);
2772  factorfirst(x14+x8y3+y7,14,7);
2773}
2774
2775///////////////////////////////////////////////////////////////////////////////
2776//         
2777//  the command HNdevelop is obsolete  --> here is the former help string:
2778//
2779///////////////////////////////////////////////////////////////////////////////
2780//
2781//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2782//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
2783//         @code{ls} over a field extension of the current basering's ground
2784//         field. @*
2785//         Since the Hamburger-Noether development usually does not exist
2786//         in the originally given basering, @code{HNdevelop} always defines
2787//         @code{HNEring} and CHANGES to it. The field extension is chosen
2788//         minimally.
2789//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
2790//         @code{develop(f[i])}, f[i] a branch of f, but the last entry being
2791//         omitted).
2792//@texinfo
2793//@table @asis
2794//@item @code{L[i][1]}; matrix:
2795//         Each row contains the coefficients of the corresponding line of the
2796//         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
2797//         marked in the matrix by the first ring variable (usually x).
2798//@item @code{L[i][2]}; intvec:
2799//         indicating the length of lines of the HNE
2800//@item @code{L[i][3]}; int:
2801//         0  if the 1st ring variable was transversal (with respect to f[i]), @*
2802//         1  if the variables were changed at the beginning of the
2803//            computation, @*
2804//        -1  if an error has occurred.
2805//@item @code{L[i][4]}; poly:
2806//         the transformed polynomial of f[i] to make it possible to extend the
2807//         Hamburger-Noether development a posteriori without having to do
2808//         all the previous calculation once again (0 if not needed)
2809//@end table
2810//@end texinfo
2811//NOTE:    @code{HNdevelop} decides which procedure (@code{develop} or
2812//         @code{reddevelop}) applies best to the given problem and calls it. @*
2813//         If f is known to be irreducible as a power series, @code{develop(f)}
2814//         should be chosen instead to avoid the change of basering. @*
2815//         If @code{printlevel>=2} comments are displayed (default is
2816//         @code{printlevel=0}).
2817//
2818//EXAMPLE: example HNdevelop;  shows an example
2819//
2820proc HNdevelop (poly f)
2821"USAGE:   HNdevelop(f); f poly
2822NOTE:     command is obsolete, use hnexpansion(f) instead.
2823SEE ALSO: hnexpansion, develop, extdevelop, param, displayHNE
2824"
2825{
2826 int irred=0;
2827 //--------- Falls Ring (p^k,a),...: Wechsel in (p,a),... + minpoly -----------
2828 if ((find(charstr(basering),string(char(basering)))!=1) &&
2829     (charstr(basering)<>"real")) {
2830   string strmip=string(minpoly);
2831   string strf=string(f);
2832   execute("ring tempr=("+string(char(basering))+","+parstr(basering)+"),("
2833           +varstr(basering)+"),dp;");
2834   execute("minpoly="+strmip+";");
2835   execute("poly f="+strf+";");
2836   list hne=reddevelop(f);
2837   if ((voice==2) && (printlevel > -1)) {
2838     "// Attention: The parameter",par(1),"has changed its meaning!";
2839     "// It need no longer be a generator of the cyclic group of unities!";
2840   }
2841 }
2842 else {
2843 //--- Falls Ring (0,a),... + minpoly : solange factorize nicht in Singular ---
2844 //------- implementiert ist, develop aufrufen (kann spaeter entfallen) -------
2845   if ((char(basering)==0) && (npars(basering)==1)) {
2846     if (string(minpoly)<>"0") { irred=1; }
2847   }
2848 //------------------ Aufruf der geeigneten Prozedur --------------------------
2849   if (irred==0) {
2850     list hne=pre_HN(f,0);       // = reddevelop(f);
2851     dbprint(printlevel-voice+2,
2852        "// result: "+string(size(hne))+" branch(es) successfully computed,",
2853        "//         basering has changed to HNEring");
2854   }
2855   else {
2856     def altring=basering;
2857     string strmip=string(minpoly);
2858     ring HNEring=(char(altring),`parstr(altring)`),(x,y),ls;
2859     execute("minpoly="+strmip+";");
2860     export HNEring;
2861     poly f=fetch(altring,f);
2862     list hn=develop(f,-1);
2863     list hne;
2864     if (hn[3] <> -1) {
2865       hne[1]=list(hn[1],hn[2],hn[3],hn[4]);
2866       if (hn[5] <> 1) {
2867   " ** WARNING : The curve is reducible, but only one branch could be found!";
2868       }
2869     }
2870     else { " ** Sorry -- could not find a HNE."; }
2871     dbprint(printlevel-voice+2,"// note: basering has changed to HNEring");
2872   }
2873 }
2874 keepring basering;
2875 return(hne);
2876}
2877example
2878{
2879  // -------- prepare for example ---------
2880  if (nameof(basering)=="HNEring") {
2881   def rettering=HNEring;
2882   kill HNEring;
2883  }
2884  // ------ the example starts here -------
2885  "EXAMPLE:"; echo = 2;
2886  ring r=0,(x,y),dp;
2887  list hne=HNdevelop(x4-y6);
2888  nameof(basering);
2889  size(hne);           // number of branches
2890  print(hne[1][1]);    // HN-matrix of 1st branch
2891  param(hne[1]);       // parametrization of 1st branch
2892  param(hne[2]);       // parametrization of 2nd branch
2893  kill HNEring,r;
2894  echo = 0;
2895  // --- restore HNEring if previously defined ---
2896  if (defined(rettering)) {
2897   setring rettering;
2898   def HNEring=rettering;
2899   export HNEring;
2900  }
2901}
2902
2903///////////////////////////////////////////////////////////////////////////////
2904//         
2905//  the command reddevelop is obsolete  --> here is the former help string:
2906//
2907///////////////////////////////////////////////////////////////////////////////
2908//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2909//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
2910//         @code{ls} over a field extension of the current basering's ground
2911//         field. @*
2912//         Since the Hamburger-Noether development of a reducible curve
2913//         singularity usually does not exist in the originally given basering,
2914//         @code{reddevelop} always defines @code{HNEring} and CHANGES to it.
2915//         The field extension is chosen minimally.
2916//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
2917//         @code{develop(f[i])}, f[i] a branch of f, but the last entry being
2918//         omitted).
2919//@texinfo
2920//@table @asis
2921//@item @code{L[i][1]}; matrix:
2922//         Each row contains the coefficients of the corresponding line of the
2923//         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
2924//         marked in the matrix by the first ring variable (usually x).
2925//@item @code{L[i][2]}; intvec:
2926//         indicating the length of lines of the HNE
2927//@item @code{L[i][3]}; int:
2928//         0  if the 1st ring variable was transversal (with respect to f[i]), @*
2929//         1  if the variables were changed at the beginning of the
2930//            computation, @*
2931//        -1  if an error has occurred.
2932//@item @code{L[i][4]}; poly:
2933//         the transformed polynomial of f[i] to make it possible to extend the
2934//         Hamburger-Noether development a posteriori without having to do
2935//         all the previous calculation once again (0 if not needed)
2936//@end table
2937//@end texinfo
2938//NOTE:    If @code{printlevel>=0} comments are displayed (default is
2939//         @code{printlevel=0}).
2940//
2941//EXAMPLE: example reddevelop;  shows an example
2942//
2943proc reddevelop (poly f)
2944"USAGE:   reddevelop(f); f poly
2945NOTE:     command is obsolete, use hnexpansion(f) instead.   
2946SEE ALSO: hnexpansion, develop, extdevelop, param, displayHNE
2947"
2948{
2949 list Ergebnis=pre_HN(f,0);
2950 if (size(Ergebnis)>0) {     // otherwise an error may have occurred
2951  dbprint(printlevel-voice+2,
2952   "// result: "+string(size(Ergebnis))+" branch(es) successfully computed,",
2953   "//         basering has changed to HNEring");
2954 }
2955
2956 // ----- Lossen 10/02 : the branches have to be resorted to be able to
2957 // -----                display the multsequence in a nice way
2958 if (size(Ergebnis)>2)
2959 { 
2960   int i,j,k,m;
2961   list dummy;
2962   int nbsave;
2963   int no_br = size(Ergebnis);
2964   intmat nbhd[no_br][no_br];
2965   for (i=1;i<no_br;i++)
2966   {
2967     for (j=i+1;j<=no_br;j++) 
2968     {
2969       nbhd[i,j]=separateHNE(Ergebnis[i],Ergebnis[j]);
2970       k=i+1;
2971       while ( (nbhd[i,k] >= nbhd[i,j]) and (k<j) )
2972       {
2973         k++;
2974       }
2975       if (k<j)  // branches have to be resorted
2976       {
2977         dummy=Ergebnis[j];
2978         nbsave=nbhd[i,j];
2979         for (m=k; m<j; m++)
2980         {
2981           Ergebnis[m+1]=Ergebnis[m];
2982           nbhd[i,m+1]=nbhd[i,m];
2983         }
2984         Ergebnis[k]=dummy;
2985         nbhd[i,k]=nbsave;
2986       }
2987     }
2988   }
2989 }
2990 // -----
2991 
2992 keepring basering;
2993 return(Ergebnis);
2994}
2995example
2996{
2997  // -------- prepare for example ---------
2998  if (nameof(basering)=="HNEring")
2999  {
3000   def rettering=HNEring;
3001   kill HNEring;
3002  }
3003  // ------ the example starts here -------
3004  "EXAMPLE:"; echo = 2;
3005  ring r = 32003,(x,y),dp;
3006  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
3007          +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
3008          -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
3009          +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
3010  list hne=reddevelop(f);
3011  size(hne);            // number of branches
3012  print(hne[1][1]);     // HN-matrix of 1st branch
3013  print(hne[4][1]);     // HN-matrix of 4th branch
3014  // a ring change was necessary, a is a parameter
3015  HNEring;
3016  kill HNEring,r;
3017  echo = 0;
3018  // --- restore HNEring if previously defined ---
3019  if (defined(rettering)) {
3020   setring rettering;
3021   def HNEring=rettering;
3022   export HNEring;
3023  }
3024}
3025///////////////////////////////////////////////////////////////////////////////
3026
3027static proc pre_HN (poly f, int essential)
3028"NOTE: This procedure is only for internal use, it is called via
3029      reddevelop or essdevelop"
3030{
3031 def altring = basering;
3032 int p = char(basering);                 // Ringcharakteristik
3033
3034 //-------------------- Tests auf Zulaessigkeit von basering ------------------
3035 if (charstr(basering)=="real") {
3036   " Singular cannot factorize over 'real' as ground field";
3037   return(list());
3038 }
3039 if (size(maxideal(1))<2) {
3040   " A univariate polynomial ring makes no sense !";
3041   return(list());
3042 }
3043 if (size(maxideal(1))>2) {
3044   dbprint(printlevel-voice+2,
3045   " Warning: all variables except the first two will be ignored!");
3046 }
3047 if (find(charstr(basering),string(char(basering)))!=1) {
3048   " ring of type (p^k,a) not implemented";
3049 //----------------------------------------------------------------------------
3050 // weder primitives Element noch factorize noch map "char p^k" -> "char -p"
3051 // [(p^k,a)->(p,a) ground field] noch fetch
3052 //----------------------------------------------------------------------------
3053   return(list());
3054 }
3055 //----------------- Definition eines neuen Ringes: HNEring -------------------
3056 string namex=varstr(1); string namey=varstr(2);
3057 if (string(char(altring))==charstr(altring)) {       // kein Parameter
3058   ring HNEring = char(altring),(x,y),ls;
3059   map m=altring,x,y;
3060   poly f=m(f);
3061   kill m;
3062 }
3063 else {
3064   string mipl=string(minpoly);
3065   if (mipl=="0") {
3066     " ** WARNING: No algebraic extension of this ground field is possible!";
3067     " ** We try to develop this polynomial, but if the need for an extension";
3068     " ** occurs during the calculation, we cannot proceed with the";
3069     " ** corresponding branches ...";
3070     execute("ring HNEring=("+charstr(basering)+"),(x,y),ls;");
3071 //--- ring ...=(char(.),`parstr()`),... geht nicht, wenn mehr als 1 Param. ---
3072   }
3073   else {
3074    string pa=parstr(altring);
3075    ring HNhelpring=p,`pa`,dp;
3076    execute("poly mipo="+mipl+";");  // Minimalpolynom in Polynom umgewandelt
3077    ring HNEring=(p,a),(x,y),ls;
3078    map getminpol=HNhelpring,a;
3079    mipl=string(getminpol(mipo));    // String umgewandelt mit 'a' als Param.
3080    execute("minpoly="+mipl+";");     // "minpoly=poly is not supported"
3081    kill HNhelpring, getminpol;
3082   }
3083   if (nvars(altring)==2) { poly f=fetch(altring,f); }
3084   else {
3085     map m=altring,x,y;
3086     poly f=m(f);
3087     kill m;
3088   }
3089 }
3090 export HNEring;
3091
3092 if (defined(HNDebugOn))
3093 {"received polynomial: ",f,", with x =",namex,", y =",namey;}
3094
3095 //----------------------- Variablendefinitionen ------------------------------
3096 int Abbruch,i,NullHNEx,NullHNEy;
3097 string str;
3098 list Newton,Ergebnis,hilflist;
3099
3100 //====================== Tests auf Zulaessigkeit des Polynoms ================
3101
3102 //-------------------------- Test, ob Einheit oder Null ----------------------
3103 if (subst(subst(f,x,0),y,0)!=0) {
3104   dbprint(printlevel+1,
3105           "The given polynomial is a unit in the power series ring!");
3106   keepring HNEring;
3107   return(list());                   // there are no HNEs
3108 }
3109 if (f==0) {
3110   dbprint(printlevel+1,"The given polynomial is zero!");
3111   keepring HNEring;
3112   return(list());                   // there are no HNEs
3113 }
3114
3115 //-----------------------  Test auf Quadratfreiheit --------------------------
3116
3117 if ((p==0) and (size(charstr(basering))==1)) {
3118
3119 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
3120 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
3121 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring HNEring
3122 //----------------------------------------------------------------------------
3123  int testerg=(polytest(f)==0);
3124  ring zweitring = 32003,(x,y),dp;
3125
3126  map polyhinueber=HNEring,x,y;         // fetch geht nicht
3127  poly f=polyhinueber(f);
3128  poly test_sqr=squarefree(f);
3129  if (test_sqr != f) {
3130   if (printlevel>0) {
3131     "Most probably the given polynomial is not squarefree. But the test was";
3132     "made in characteristic 32003 and not 0 to improve speed. You can";
3133     "(r) redo the test in char 0 (but this may take some time)";
3134     "(c) continue the development, if you're sure that the polynomial IS",
3135     "squarefree";
3136     if (testerg==1) {
3137       "(s) continue the development with a squarefree factor (*)";}
3138     "(q) or just quit the algorithm (default action)";
3139     "";"Please enter the letter of your choice:";
3140     str=read("")[1];             // reads one character
3141   }
3142   else { str="r"; }              // printlevel <= 0: non-interactive behaviour
3143   setring HNEring;
3144   map polyhinueber=zweitring,x,y;
3145   if (str=="r") {
3146     poly test_sqr=squarefree(f);
3147     if (test_sqr != f) {
3148      if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
3149      else              { "The given polynomial is not squarefree!"; }
3150      "I'll continue with the radical.";
3151      f=test_sqr;
3152     }
3153     else {
3154      dbprint(printlevel,
3155       "everything is ok -- the polynomial is squarefree in characteristic 0");
3156     }
3157   }
3158   else {
3159     if ((str=="s") and (testerg==1)) {
3160       "(*)attention: it could be that the factor is only one in char 32003!";
3161       f=polyhinueber(test_sqr);
3162     }
3163     else {
3164       if (str<>"c") {
3165         setring altring;
3166         if(system("with","Namespaces")) { kill Top::HNEring; }
3167         kill HNEring;kill zweitring;
3168         return(list());}
3169       else { "if the algorithm doesn't terminate, you were wrong...";}
3170   }}
3171   kill zweitring;
3172   if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3173  }
3174  else {
3175    setring HNEring;
3176    kill zweitring;
3177  }
3178 }
3179 //------------------ Fall Char > 0 oder Ring hat Parameter -------------------
3180 else {
3181  poly test_sqr=squarefree(f);
3182  if (test_sqr != f) {
3183   if (printlevel>0) {
3184    if (test_sqr == 1) {
3185     "The given polynomial is of the form g^"+string(p)+",";
3186     "therefore not squarefree.  You can:";
3187     " (q) quit the algorithm (recommended) or";
3188     " (f) continue with the full radical (using a factorization of the";
3189     "     pure power part; this could take much time)";
3190     "";"Please enter the letter of your choice:";
3191     str=read("")[1];
3192     if (str<>"f") { str="q"; }
3193    }
3194    else {
3195     "The given polynomial is not squarefree.";
3196     if (p != 0)
3197      {
3198       " You can:";
3199       " (c) continue with a squarefree divisor (but factors of the form g^"
3200       +string(p);
3201       "     are lost; this is recommended, takes no more time)";
3202       " (f) continue with the full radical (using a factorization of the";
3203       "     pure power part; this could take much time)";
3204       " (q) quit the algorithm";
3205       "";"Please enter the letter of your choice:";
3206       str=read("")[1];
3207       if ((str<>"f") && (str<>"q")) { str="c"; }
3208      }
3209     else { "I'll continue with the radical."; str="c"; }
3210    }                                // endelse (test_sqr!=1)
3211   }
3212   else {
3213     "//** Error: The given polynomial is not squarefree!";
3214     "//** Since the global variable `printlevel' has the value",printlevel,
3215       "we stop here.";
3216     "//   Either call me again with a squarefree polynomial f or assign";
3217     "            printlevel=1;";
3218     "//   before calling me with a non-squarefree f.";
3219     "//   If printlevel > 0, I will present to you some possibilities how to",
3220       "proceed.";
3221     str="q";
3222   }
3223   if (str=="q") {
3224    if(system("with","Namespaces")) { kill Top::HNEring; }
3225    setring altring;kill HNEring;
3226    return(list());
3227   }
3228   if (str=="c") { f=test_sqr; }
3229   if (str=="f") { f=allsquarefree(f,test_sqr); }
3230  }
3231  if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3232
3233 }
3234 //====================== Ende Test auf Quadratfreiheit =======================
3235 if (subst(subst(f,x,0),y,0)!=0) {
3236   "Sorry. The remaining polynomial is a unit in the power series ring...";
3237   keepring HNEring;
3238   return(list());
3239 }
3240 //---------------------- Test, ob f teilbar durch x oder y -------------------
3241 if (subst(f,y,0)==0) {
3242   f=f/y; NullHNEy=1; }             // y=0 is a solution
3243 if (subst(f,x,0)==0) {
3244   f=f/x; NullHNEx=1; }             // x=0 is a solution
3245
3246 Newton=newtonpoly(f,1);
3247 i=1; Abbruch=0;
3248 //----------------------------------------------------------------------------
3249 // finde Eckpkt. des Newtonpolys, der den Teil abgrenzt, fuer den x transvers:
3250 // Annahme: Newton ist sortiert, s.d. Newton[1]=Punkt auf der y-Achse,
3251 // Newton[letzt]=Punkt auf der x-Achse
3252 //----------------------------------------------------------------------------
3253 while ((i<size(Newton)) and (Abbruch==0)) {
3254  if ((Newton[i+1][1]-Newton[i][1])>=(Newton[i][2]-Newton[i+1][2]))
3255   {Abbruch=1;}
3256  else {i=i+1;}
3257 }
3258 int grenze1=Newton[i][2];
3259 int grenze2=Newton[i][1];
3260 //----------------------------------------------------------------------------
3261 // Stelle Ring bereit zur Uebertragung der Daten im Fall einer Koerperer-
3262 // weiterung. Definiere Objekte, die spaeter uebertragen werden.
3263 // Binde die Listen (azeilen,...) an den Ring (um sie nicht zu ueberschreiben
3264 // bei Def. in einem anderen Ring).
3265 // Exportiere Objekte, damit sie auch in der proc HN noch da sind
3266 //----------------------------------------------------------------------------
3267 ring HNE_noparam = char(altring),(a,x,y),ls;
3268 export HNE_noparam;
3269 poly f;
3270 list azeilen=ideal(0);
3271 list HNEs=ideal(0);
3272 list aneu=ideal(0);
3273 list faktoren=ideal(0);
3274 ideal deltais;
3275 poly delt;                   // nicht number, weil delta von a abhaengen kann
3276 export f,azeilen,HNEs,aneu,faktoren,deltais,delt;
3277 //----- hier steht die Anzahl bisher benoetigter Ringerweiterungen drin: -----
3278 int EXTHNEnumber=0; export EXTHNEnumber;
3279 setring HNEring;
3280
3281 // ================= Die eigentliche Berechnung der HNE: =====================
3282
3283 // ------- Berechne HNE von allen Zweigen, fuer die x transversal ist: -------
3284 if (defined(HNDebugOn))
3285   {"1st step: Treat Newton polygon until height",grenze1;}
3286 if (grenze1>0) {
3287  hilflist=HN(f,grenze1,1,essential);
3288  if (typeof(hilflist[1][1])=="ideal") { hilflist[1]=list(); }
3289 //- fuer den Fall, dass keine Zweige in transz. Erw. berechnet werden konnten-
3290  Ergebnis=extractHNEs(hilflist[1],0);
3291  if (hilflist[2]!=-1) {
3292    if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
3293    poly transfproc=hilflist[2];
3294    map hole=HNE_noparam,transfproc,x,y;
3295    setring HNE_noparam;
3296    f=imap(HNEring,f);
3297    setring EXTHNEring(EXTHNEnumber);
3298    poly f=hole(f);
3299  }
3300 }
3301 if (NullHNEy==1) {
3302  Ergebnis=Ergebnis+list(list(matrix(ideal(0,x)),intvec(1),int(0),poly(0)));
3303 }
3304 // --------------- Berechne HNE von allen verbliebenen Zweigen: --------------
3305 if (defined(HNDebugOn))
3306    {"2nd step: Treat Newton polygon until height",grenze2;}
3307 if (grenze2>0) {
3308  map xytausch=basering,y,x;
3309  kill hilflist;
3310  def letztring=basering;
3311  if (EXTHNEnumber==0) { setring HNEring; }
3312  else                 { setring EXTHNEring(EXTHNEnumber); }
3313  list hilflist=HN(xytausch(f),grenze2,1,essential);
3314  if (typeof(hilflist[1][1])=="ideal") { hilflist[1]=list(); }
3315  if (not defined(Ergebnis)) {
3316 //-- HN wurde schon mal ausgefuehrt; Ringwechsel beim zweiten Aufruf von HN --
3317    if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
3318    poly transfproc=hilflist[2];
3319    map hole=HNE_noparam,transfproc,x,y;
3320    setring HNE_noparam;
3321    list Ergebnis=imap(letztring,Ergebnis);
3322    setring EXTHNEring(EXTHNEnumber);
3323    list Ergebnis=hole(Ergebnis);
3324  }
3325  Ergebnis=Ergebnis+extractHNEs(hilflist[1],1);
3326 }
3327 if (NullHNEx==1) {
3328  Ergebnis=Ergebnis+list(list(matrix(ideal(0,x)),intvec(1),int(1),poly(0)));
3329 }
3330 //------------------- Loesche globale, nicht mehr benoetigte Objekte: --------
3331 if (EXTHNEnumber>0) {
3332  if(system("with","Namespaces")) { kill Top::HNEring; }
3333  kill HNEring;
3334  def HNEring=EXTHNEring(EXTHNEnumber);
3335  setring HNEring;
3336  export HNEring;
3337  kill EXTHNEring(1..EXTHNEnumber);
3338 }
3339 kill HNE_noparam;
3340 kill EXTHNEnumber;
3341 keepring basering;
3342
3343 return(Ergebnis);
3344}
3345
3346///////////////////////////////////////////////////////////////////////////////
3347//         
3348//  the command essdevelop is obsolete  --> here is the former help string:
3349//
3350///////////////////////////////////////////////////////////////////////////////
3351//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
3352//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
3353//         @code{ls} over a field extension of the current basering's ground
3354//         field. @*
3355//         Since the Hamburger-Noether development of a reducible curve
3356//         singularity usually does not exist in the originally given basering,
3357//         @code{essdevelop} always defines @code{HNEring} and CHANGES to it.
3358//         The field extension is chosen minimally.
3359//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
3360//         @code{develop(f[i])}, f[i] an \"essential\" branch of f, but the
3361//         last entry being omitted).@*
3362//         For more details type @code{help reddevelop;}.
3363//NOTE:    If the HNE needs a field extension, some of the branches will be
3364//         conjugate. In this case @code{essdevelop} reduces the computation to
3365//         one representative for each group of conjugate branches.@*
3366//         Note that the degree of each branch is in general less than the
3367//         degree of the field extension in which all HNEs can be put.@*
3368//         Use @code{reddevelop} or @code{HNdevelop} to compute a complete HNE,
3369//         i.e., a HNE for all branches.@*
3370//         If @code{printlevel>=0} comments are displayed (default is
3371//         @code{printlevel=0}).
3372//SEE ALSO: hnexpansion, develop, reddevelop, HNdevelop, extdevelop
3373//EXAMPLE: example essdevelop;  shows an example
3374proc essdevelop (poly f)
3375"USAGE:   essdevelop(f); f poly
3376NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.
3377SEE ALSO: hnexpansion, develop, extdevelop, param
3378"
3379{
3380 list Ergebnis=pre_HN(f,1);
3381 dbprint(printlevel-voice+2,
3382    "// result: "+string(size(Ergebnis))+" branch(es) successfully computed;");
3383 if (string(minpoly) <> "0") {
3384   dbprint(printlevel-voice+2,
3385    "// note that conjugate branches are omitted and that the number",
3386    "// of branches represented by each remaining one may vary!");
3387 }
3388 dbprint(printlevel-voice+2,
3389    "// basering has changed to HNEring");
3390 keepring basering;
3391 return(Ergebnis);
3392}
3393example
3394{
3395  // -------- prepare for example ---------
3396  if (nameof(basering)=="HNEring") {
3397   def rettering=HNEring;
3398   kill HNEring;
3399  }
3400  // ------ the example starts here -------
3401  "EXAMPLE:"; echo = 2;
3402  ring r=2,(x,y),dp;
3403  poly f=(x4+x2y+y2)*(x3+xy2+y3);
3404  // --------- compute all branches: ---------
3405  list hne=reddevelop(f);
3406  displayHNE(hne[1]);   // HN-matrix of 1st branch
3407  displayHNE(hne[4]);   // HN-matrix of 4th branch
3408  setring r;
3409  kill HNEring;
3410  // --- compute only one of conjugate branches: ---
3411  list hne=essdevelop(f);
3412  displayHNE(hne);
3413  // no. 1 of essdevelop represents no. 1 - 3 of reddevelop and
3414  // no. 2 of essdevelop represents no. 4 + 5 of reddevelop
3415  kill HNEring,r;
3416  echo = 0;
3417  // --- restore HNEring if previously defined ---
3418  if (defined(rettering)) {
3419   setring rettering;
3420   def HNEring=rettering;
3421   export HNEring;
3422  }
3423}
3424
3425///////////////////////////////////////////////////////////////////////////////
3426static proc HN (poly f,int grenze, int Aufruf_Ebene, int essential)
3427"NOTE: This procedure is only for internal use, it is called via pre_HN"
3428{
3429 //---------- Variablendefinitionen fuer den unverzweigten Teil: --------------
3430 if (defined(HNDebugOn)) {"procedure HN",Aufruf_Ebene;}
3431 int Abbruch,ende,i,j,e,M,N,Q,R,zeiger,zeile,zeilevorher;
3432 intvec hqs;
3433 poly fvorher;
3434 list erg=ideal(0); list HNEs=ideal(0); // um die Listen an den Ring zu binden
3435
3436 //-------------------- Bedeutung von Abbruch: --------------------------------
3437 //------- 0:keine Verzweigung | 1:Verzweigung,nicht fertig | 2:fertig --------
3438 //
3439 // Struktur von HNEs : Liste von Listen L (fuer jeden Zweig) der Form
3440 // L[1]=intvec (hqs), L[2],L[3],... ideal (die Zeilen (0,1,...) der HNE)
3441 // L[letztes]=poly (transformiertes f)
3442 //----------------------------------------------------------------------------
3443 list Newton;
3444 number delt;
3445 int p = char(basering);                // Ringcharakteristik
3446 list azeilen=ideal(0);
3447 ideal hilfid; list hilflist=ideal(0); intvec hilfvec;
3448
3449 // ======================= der unverzweigte Teil: ============================
3450 while (Abbruch==0) {
3451  Newton=newtonpoly(f,1);
3452  zeiger=find_in_list(Newton,grenze);
3453  if (Newton[zeiger][2] != grenze)
3454    {"Didn't find an edge in the Newton polygon!";}
3455  if (zeiger==size(Newton)-1) {
3456    if (defined(HNDebugOn)) {"only one relevant side in Newton polygon";}
3457    M=Newton[zeiger+1][1]-Newton[zeiger][1];
3458    N=Newton[zeiger][2]-Newton[zeiger+1][2];
3459    R = M%N;
3460    Q = M / N;
3461
3462 //-------- 1. Versuch: ist der quasihomogene Leitterm reine Potenz ? ---------
3463 //              (dann geht alles wie im irreduziblen Fall)
3464 //----------------------------------------------------------------------------
3465    e = gcd(M,N);
3466    delt=factorfirst(redleit(f,Newton[zeiger],Newton[zeiger+1])
3467                      /x^Newton[zeiger][1],M,N);
3468    if (delt==0) {
3469      if (defined(HNDebugOn)) {" The given polynomial is reducible !";}
3470      Abbruch=1;
3471    }
3472    if (Abbruch==0) {
3473 //-------------- f,zeile retten fuer den Spezialfall (###): ------------------
3474      fvorher=f;zeilevorher=zeile;
3475      if (R==0) {
3476 //------------- transformiere f mit T1, wenn kein Abbruch nachher: -----------
3477        if (N>1) { f = T1_Transform(f,delt,M/ e); }
3478        else     { ende=1; }
3479        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3480        azeilen[zeile+1][Q]=delt;
3481      }
3482      else {
3483 //------------- R > 0 : transformiere f mit T2 -------------------------------
3484        erg=T2_Transform(f,delt,M,N,referencepoly(Newton));
3485        f=erg[1];delt=erg[2];
3486 //------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ---------
3487        while (R!=0) {
3488         if (defined(HNDebugOn)) { "h("+string(zeile)+") =",Q; }
3489         hqs[zeile+1]=Q;         // denn zeile beginnt mit dem Wert 0
3490 //------------------ markiere das Zeilenende der HNE: ------------------------
3491         azeilen[zeile+1][Q+1]=x;
3492         zeile=zeile+1;
3493 //----------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ---------
3494         azeilen[zeile+1]=ideal(0);
3495         M=N; N=R; R=M%N; Q=M / N;
3496        }
3497        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3498        azeilen[zeile+1][Q]=delt;
3499      }
3500      if (defined(HNDebugOn)) {"transformed polynomial: ",f;}
3501      grenze=e;
3502 //----------------------- teste Abbruchbedingungen: --------------------------
3503      if (subst(f,y,0)==0) {              // <==> y|f
3504        dbprint(printlevel-voice+3,"finite HNE of one branch found");
3505           // voice abzufragen macht bei rekursiven procs keinen Sinn
3506        azeilen[zeile+1][Q+1]=x;
3507 //- Q wird nur in hqs eingetragen, wenn der Spezialfall nicht eintritt (s.u.)-
3508        Abbruch=2;
3509        if (grenze>1) {
3510         if (jet(f,1,intvec(0,1))==0) {
3511 //------ jet(...)=alle Monome von f, die nicht durch y2 teilbar sind ---------
3512 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3513         else {
3514 //-------------------------- Spezialfall (###): ------------------------------
3515 // Wir haben das Problem, dass die HNE eines Zweiges hier abbricht, aber ein
3516 // anderer Zweig bis hierher genau die gleiche HNE hat, die noch weiter geht
3517 // Loesung: mache Transform. rueckgaengig und behandle f im Verzweigungsteil
3518 //----------------------------------------------------------------------------
3519          Abbruch=1;
3520          f=fvorher;zeile=zeilevorher;grenze=Newton[zeiger][2];
3521        }}
3522        else {f=0;}     // f nicht mehr gebraucht - spare Speicher
3523        if (Abbruch==2) { hqs[zeile+1]=Q; }
3524      }                 // Spezialfall nicht eingetreten
3525      else {
3526        if (ende==1) {
3527          dbprint(printlevel-voice+2,"HNE of one branch found");
3528          Abbruch=2; hqs[zeile+1]=-Q-1;}
3529      }
3530    }                   // end(if Abbruch==0)
3531  }                     // end(if zeiger...)
3532  else { Abbruch=1;}
3533 }                      // end(while Abbruch==0)
3534
3535 // ===================== der Teil bei Verzweigung: ===========================
3536
3537 if (Abbruch==1) {
3538 //---------- Variablendefinitionen fuer den verzweigten Teil: ----------------
3539  poly leitf,teiler,transformiert;
3540  list aneu=ideal(0);
3541  list faktoren;
3542  list HNEakut=ideal(0);
3543  ideal deltais;
3544  intvec eis;
3545  int zaehler,hnezaehler,zl,zl1,M1,N1,R1,Q1,needext;
3546  int numberofRingchanges,lastRingnumber,ringischanged,flag;
3547  string letztringname;
3548
3549  zeiger=find_in_list(Newton,grenze);
3550  if (defined(HNDebugOn)) {
3551    "Branching part reached---Newton polygon :",Newton;
3552    "relevant part until height",grenze,", from",Newton[zeiger],"on";
3553  }
3554  azeilen=list(hqs)+azeilen; // hat jetzt Struktur von HNEs: hqs in der 1.Zeile
3555
3556 //======= Schleife fuer jede zu betrachtende Seite des Newtonpolygons: =======
3557  for(i=zeiger; i<size(Newton); i++) {
3558   if (defined(HNDebugOn)) { "we consider side",Newton[i],Newton[i+1]; }
3559   M=Newton[i+1][1]-Newton[i][1];
3560   N=Newton[i][2]-Newton[i+1][2];
3561   R = M%N;
3562   Q = M / N;
3563   e=gcd(M,N);
3564   needext=1;
3565   letztringname=nameof(basering);
3566   lastRingnumber=EXTHNEnumber;
3567   faktoren=list(ideal(charPoly(redleit(f,Newton[i],Newton[i+1])
3568                       /(x^Newton[i][1]*y^Newton[i+1][2]),M,N)  ),
3569                 intvec(1));                  // = (zu faktoriserendes Poly, 1)
3570
3571 //-- wechsle so lange in Ringerw., bis Leitform vollst. in Linearfakt. zerf.:-
3572   for (numberofRingchanges=1; needext==1; numberofRingchanges++) {
3573    leitf=redleit(f,Newton[i],Newton[i+1])/(x^Newton[i][1]*y^Newton[i+1][2]);
3574    delt=factorfirst(leitf,M,N);
3575    needext=0;
3576    if (delt==0) {
3577
3578 //---------- Sonderbehandlung: faktorisiere einige Polynome ueber Q(a): -------
3579     if (charstr(basering)=="0,a") {
3580//*CL old: faktoren=factorize(charPoly(leitf,M,N),2);  // damit funktion. Bsp. Baladi 5
3581         faktoren=factorize(charPoly(leitf,M,N)); 
3582     }
3583     else {
3584 //------------------ faktorisiere das charakt. Polynom: ----------------------
3585       if ((numberofRingchanges==1) or (essential==0)) {
3586         faktoren=factorlist(faktoren);
3587       }
3588       else {     // eliminiere alle konjugierten Nullstellen bis auf eine:
3589         ideal hilf_id;
3590         for (zaehler=1; zaehler<=size(faktoren[1]); zaehler++) {
3591           hilf_id=factorize(faktoren[1][zaehler])[1];
3592           if (size(hilf_id)>1) { faktoren[1][zaehler]=hilf_id[2]; }
3593           else                 { faktoren[1][zaehler]=hilf_id[1]; }
3594         }
3595       }
3596     }
3597
3598     zaehler=1; eis=0;
3599     for (j=1; j<=size(faktoren[2]); j++) {
3600      teiler=faktoren[1][j];
3601      if (teiler/y != 0) {         // sonst war's eine Einheit --> wegwerfen!
3602        if (defined(HNDebugOn)) {"factor of leading form found:",teiler;}
3603        if (teiler/y2 == 0) {      // --> Faktor hat die Form cy+d
3604          deltais[zaehler]=-subst(teiler,y,0)/koeff(teiler,0,1); //=-d/c
3605          eis[zaehler]=faktoren[2][j];
3606          zaehler++;
3607        }
3608        else {
3609          dbprint(printlevel-voice+2,
3610             " Change of basering (field extension) necessary!");
3611          if (defined(HNDebugOn)) { teiler,"is not properly factored!"; }
3612          if (needext==0) { poly zerlege=teiler; }
3613          needext=1;
3614        }
3615      }
3616     }                             // end(for j)
3617    }
3618    else { deltais=ideal(delt); eis=e;}
3619    if (defined(HNDebugOn)) {"roots of char. poly:";deltais;
3620                             "with multiplicities:",eis;}
3621    if (needext==1) {
3622 //--------------------- fuehre den Ringwechsel aus: --------------------------
3623      ringischanged=1;
3624      if ((size(parstr(basering))>0) && string(minpoly)=="0") {
3625        " ** We've had bad luck! The HNE cannot completely be calculated!";
3626                                   // HNE in transzendenter Erw. fehlgeschlagen
3627        kill zerlege;
3628        ringischanged=0; break;    // weiter mit gefundenen Faktoren
3629      }
3630      if (parstr(basering)=="") {
3631        EXTHNEnumber++;
3632        splitring(zerlege,"EXTHNEring("+string(EXTHNEnumber)+")");
3633        poly transf=0;
3634        poly transfproc=0;
3635      }
3636      else {
3637        if (defined(translist)) { kill translist; } // Vermeidung einer Warnung
3638        if (numberofRingchanges>1) {  // ein Ringwechsel hat nicht gereicht
3639         list translist=splitring(zerlege,"",list(transf,transfproc,faktoren));
3640         poly transf=translist[1];
3641         poly transfproc=translist[2];
3642         list faktoren=translist[3];
3643        }
3644        else {
3645         if (defined(transfproc)) { // in dieser proc geschah schon Ringwechsel
3646          EXTHNEnumber++;
3647          list translist=splitring(zerlege,"EXTHNEring("
3648               +string(EXTHNEnumber)+")",list(a,transfproc));
3649          poly transf=translist[1];
3650          poly transfproc=translist[2];
3651         }
3652         else {
3653          EXTHNEnumber++;
3654          list translist=splitring(zerlege,"EXTHNEring("
3655               +string(EXTHNEnumber)+")",a);
3656          poly transf=translist[1];
3657          poly transfproc=transf;
3658        }}
3659      }
3660 //----------------------------------------------------------------------------
3661 // transf enthaelt jetzt den alten Parameter des Ringes, der aktiv war vor
3662 // Beginn der Schleife (evtl. also ueber mehrere Ringwechsel weitergereicht),
3663 // transfproc enthaelt den alten Parm. des R., der aktiv war zu Beginn der
3664 // Prozedur, und der an die aufrufende Prozedur zurueckgegeben werden muss
3665 // transf ist Null, falls der alte Ring keinen Parameter hatte,
3666 // das gleiche gilt fuer transfproc
3667 //----------------------------------------------------------------------------
3668
3669 //------ Neudef. von Variablen, Uebertragung bisher errechneter Daten: -------
3670      poly leitf,teiler,transformiert;
3671      list aneu=ideal(0);
3672      ideal deltais;
3673      number delt;
3674      setring HNE_noparam;
3675      if (defined(letztring)) { kill letztring; }
3676      if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3677      else                  { def letztring=HNEring; }
3678      f=imap(letztring,f);
3679      faktoren=imap(letztring,faktoren);
3680      setring EXTHNEring(EXTHNEnumber);
3681      map hole=HNE_noparam,transf,x,y;
3682      poly f=hole(f);
3683      if (not defined(faktoren)) {
3684        list faktoren=hole(faktoren);
3685      }
3686    }
3687   }    // end (while needext==1) bzw. for (numberofRingchanges)
3688
3689   if (eis==0) { i++; continue; }
3690   if (ringischanged==1) {
3691    list erg,hilflist,HNEakut;            // dienen nur zum Sp. von Zwi.erg.
3692    ideal hilfid;
3693    erg=ideal(0); hilflist=erg; HNEakut=erg;
3694
3695    hole=HNE_noparam,transf,x,y;
3696    setring HNE_noparam;
3697    azeilen=imap(letztring,azeilen);
3698    HNEs=imap(letztring,HNEs);
3699
3700    setring EXTHNEring(EXTHNEnumber);
3701    list azeilen=hole(azeilen);
3702    list HNEs=hole(HNEs);
3703    kill letztring;
3704    ringischanged=0;
3705   }
3706
3707 //============ Schleife fuer jeden gefundenen Faktor der Leitform: ===========
3708   for (j=1; j<=size(eis); j++) {
3709 //-- Mache Transf. T1 oder T2, trage Daten in HNEs ein, falls HNE abbricht: --
3710
3711 //------------------------ Fall R==0: ----------------------------------------
3712    if (R==0) {
3713      transformiert = T1_Transform(f,number(deltais[j]),M/ e);
3714      if (defined(HNDebugOn)) {
3715        "a("+string(zeile)+","+string(Q)+") =",deltais[j];
3716        "transformed polynomial: ",transformiert;
3717      }
3718      if (subst(transformiert,y,0)==0) {
3719       dbprint(printlevel-voice+3,"finite HNE found");
3720       hnezaehler++;
3721 //------------ trage deltais[j],x ein in letzte Zeile, fertig: ---------------
3722       HNEakut=azeilen+list(poly(0));        // =HNEs[hnezaehler];
3723       hilfid=HNEakut[zeile+2]; hilfid[Q]=deltais[j]; hilfid[Q+1]=x;
3724       HNEakut[zeile+2]=hilfid;
3725       HNEakut[1][zeile+1]=Q;                // aktualisiere Vektor mit den hqs
3726       HNEs[hnezaehler]=HNEakut;
3727       if (eis[j]>1) {
3728        transformiert=transformiert/y;
3729        if (subst(transformiert,y,0)==0) {
3730 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3731        else {
3732 //------ Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --------
3733          eis[j]=eis[j]-1;
3734        }
3735       }
3736      }
3737    }
3738    else {
3739 //------------------------ Fall R <> 0: --------------------------------------
3740      erg=T2_Transform(f,number(deltais[j]),M,N,referencepoly(Newton));
3741      transformiert=erg[1];delt=erg[2];
3742      if (defined(HNDebugOn)) {"transformed polynomial: ",transformiert;}
3743      if (subst(transformiert,y,0)==0) {
3744       dbprint(printlevel-voice+3,"finite HNE found");
3745       hnezaehler++;
3746 //---------------- trage endliche HNE in HNEs ein: ---------------------------
3747       HNEakut=azeilen;           // dupliziere den gemeins. Anfang der HNE's
3748       zl=2;                      // (kommt schliesslich nach HNEs[hnezaehler])
3749 //----------------------------------------------------------------------------
3750 // Werte von:  zeile: aktuelle Zeilennummer der HNE (gemeinsamer Teil)
3751 //             zl   : die HNE spaltet auf; zeile+zl ist der Index fuer die
3752 // Zeile des aktuellen Zweigs; (zeile+zl-2) ist die tatsaechl. Zeilennr.
3753 // (bei 0 angefangen) der HNE  ([1] <- intvec(hqs), [2] <- 0. Zeile usw.)
3754 //----------------------------------------------------------------------------
3755
3756 //---------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ------
3757       M1=M;N1=N;R1=R;Q1=M1/ N1;
3758       while (R1!=0) {
3759        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3760        HNEakut[1][zeile+zl-1]=Q1;
3761        HNEakut[zeile+zl][Q1+1]=x;
3762                                  // markiere das Zeilenende der HNE
3763        zl=zl+1;
3764 //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ------------
3765        HNEakut[zeile+zl]=ideal(0);
3766
3767        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3768       }
3769       if (defined(HNDebugOn)) {
3770         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3771       }
3772       HNEakut[zeile+zl][Q1]  =delt;
3773       HNEakut[zeile+zl][Q1+1]=x;
3774       HNEakut[1][zeile+zl-1] =Q1;     // aktualisiere Vektor mit hqs
3775       HNEakut[zeile+zl+1]=poly(0);
3776       HNEs[hnezaehler]=HNEakut;
3777 //-------------------- Ende der Eintragungen in HNEs -------------------------
3778
3779       if (eis[j]>1) {
3780        transformiert=transformiert/y;
3781        if (subst(transformiert,y,0)==0) {
3782 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3783         else {
3784 //--------- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden -----
3785          eis[j]=eis[j]-1;
3786       }}
3787      }                           // endif (subst()==0)
3788    }                             // endelse (R<>0)
3789
3790 //========== Falls HNE nicht abbricht: Rekursiver Aufruf von HN: =============
3791 //------------------- Berechne HNE von transformiert -------------------------
3792    if (subst(transformiert,y,0)!=0) {
3793     lastRingnumber=EXTHNEnumber;
3794     list HNerg=HN(transformiert,eis[j],Aufruf_Ebene+1,essential);
3795     if (HNerg[2]==-1) {          // kein Ringwechsel in HN aufgetreten
3796       aneu=HNerg[1];  }
3797     else {
3798       if (defined(HNDebugOn))
3799          {" ring change in HN(",Aufruf_Ebene+1,") detected";}
3800       list aneu=HNerg[1];
3801       poly transfproc=HNerg[2];
3802
3803 //- stelle lokale Var. im neuen Ring wieder her und rette ggf. ihren Inhalt: -
3804       list erg,hilflist,faktoren,HNEakut;
3805       ideal hilfid;
3806       erg=ideal(0); hilflist=erg; faktoren=erg; HNEakut=erg;
3807       poly leitf,teiler,transformiert;
3808
3809       map hole=HNE_noparam,transfproc,x,y;
3810       setring HNE_noparam;
3811       if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3812       else                  { def letztring=HNEring; }
3813       HNEs=imap(letztring,HNEs);
3814       azeilen=imap(letztring,azeilen);
3815       deltais=imap(letztring,deltais);
3816       delt=imap(letztring,delt);
3817       f=imap(letztring,f);
3818
3819       setring EXTHNEring(EXTHNEnumber);
3820       list HNEs=hole(HNEs);
3821       list azeilen=hole(azeilen);
3822       ideal deltais=hole(deltais);
3823       number delt=number(hole(delt));
3824       poly f=hole(f);
3825     }
3826     kill HNerg;
3827 //----------------------------------------------------------------------------
3828 // HNerg muss jedesmal mit "list" neu definiert werden, weil vorher noch nicht
3829 // ------- klar ist, ob der Ring nach Aufruf von HN noch derselbe ist --------
3830
3831 //============= Verknuepfe bisherige HNE mit von HN gelieferten HNEs: ========
3832     if (R==0) {
3833       HNEs,hnezaehler=constructHNEs(HNEs,hnezaehler,aneu,azeilen,zeile,
3834                       deltais,Q,j);
3835     }
3836     else {
3837      for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3838       hnezaehler++;
3839       HNEakut=azeilen;          // dupliziere den gemeinsamen Anfang der HNE's
3840       zl=2;                     // (kommt schliesslich nach HNEs[hnezaehler])
3841 //---------------- Trage Beitrag dieser Transformation T2 ein: ---------------
3842 //--------- Zur Bedeutung von zeile, zl: siehe Kommentar weiter oben ---------
3843
3844 //--------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -------
3845       M1=M;N1=N;R1=R;Q1=M1/ N1;
3846       while (R1!=0) {
3847        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3848        HNEakut[1][zeile+zl-1]=Q1;
3849        HNEakut[zeile+zl][Q1+1]=x;    // Markierung des Zeilenendes der HNE
3850        zl=zl+1;
3851 //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ------------
3852        HNEakut[zeile+zl]=ideal(0);
3853        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3854       }
3855       if (defined(HNDebugOn)) {
3856         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3857       }
3858       HNEakut[zeile+zl][Q1]=delt;
3859
3860 //--- Daten aus T2_Transform sind eingetragen; haenge Daten von HN an: -------
3861       hilfid=HNEakut[zeile+zl];
3862       for (zl1=Q1+1; zl1<=ncols(aneu[zaehler][2]); zl1++) {
3863        hilfid[zl1]=aneu[zaehler][2][zl1];
3864       }
3865       HNEakut[zeile+zl]=hilfid;
3866 //--- vorher HNEs[.][zeile+zl]<-aneu[.][2], jetzt [zeile+zl+1] <- [3] usw.: --
3867       for (zl1=3; zl1<=size(aneu[zaehler]); zl1++) {
3868         HNEakut[zeile+zl+zl1-2]=aneu[zaehler][zl1];
3869       }
3870 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
3871       hilfvec=HNEakut[1],aneu[zaehler][1];
3872       HNEakut[1]=hilfvec;
3873 //----------- weil nicht geht: liste[1]=liste[1],aneu[zaehler][1] ------------
3874       HNEs[hnezaehler]=HNEakut;
3875      }                     // end(for zaehler)
3876     }                      // endelse (R<>0)
3877    }                       // endif (subst()!=0)  (weiteres Aufblasen mit HN)
3878
3879   }                        // end(for j) (Behandlung der einzelnen delta_i)
3880
3881  }
3882  keepring basering;
3883  if (system("with","Namespaces"))
3884  {
3885    if (defined(transfproc)) { return(list(HNEs,transfproc)); }
3886    else                     { return(list(HNEs,poly(-1))); }
3887  }
3888  else
3889  {
3890    if (defined(transfproc)) { return(list(HNEs,transfproc)); }
3891    else                     { return(list(HNEs,poly(-1))); }
3892  }
3893 // -1 als 2. Rueckgabewert zeigt an, dass kein Ringwechsel stattgefunden hat -
3894 }
3895 else {
3896  HNEs[1]=list(hqs)+azeilen+list(f); // f ist das transform. Poly oder Null
3897  keepring basering;
3898  return(list(HNEs,poly(-1)));
3899 //-- in dieser proc trat keine Verzweigung auf, also auch kein Ringwechsel ---
3900 }
3901}
3902///////////////////////////////////////////////////////////////////////////////
3903
3904static proc constructHNEs (list HNEs,int hnezaehler,list aneu,list azeilen,
3905                    int zeile,ideal deltais,int Q,int j)
3906"NOTE: This procedure is only for internal use, it is called via HN"
3907{
3908  int zaehler,zl;
3909  ideal hilfid;
3910  list hilflist;
3911  intvec hilfvec;
3912  for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3913     hnezaehler++;
3914     // HNEs[hnezaehler]=azeilen;            // dupliziere gemeins. Anfang
3915 //----------------------- trage neu berechnete Daten ein ---------------------
3916     hilfid=azeilen[zeile+2];
3917     hilfid[Q]=deltais[j];
3918     for (zl=Q+1; zl<=ncols(aneu[zaehler][2]); zl++) {
3919      hilfid[zl]=aneu[zaehler][2][zl];
3920     }
3921     hilflist=azeilen; hilflist[zeile+2]=hilfid;
3922 //------------------ haenge uebrige Zeilen von aneu[] an: --------------------
3923     for (zl=3; zl<=size(aneu[zaehler]); zl++) {
3924      hilflist[zeile+zl]=aneu[zaehler][zl];
3925     }
3926 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
3927     if (hilflist[1]==0) { hilflist[1]=aneu[zaehler][1]; }
3928     else { hilfvec=hilflist[1],aneu[zaehler][1]; hilflist[1]=hilfvec; }
3929     HNEs[hnezaehler]=hilflist;
3930  }
3931  return(HNEs,hnezaehler);
3932}
3933///////////////////////////////////////////////////////////////////////////////
3934
3935proc referencepoly (list newton)
3936"USAGE:   referencepoly(newton);
3937         newton is list of intvec(x,y) which represents points in the Newton
3938         diagram (e.g. output of the proc newtonpoly)
3939RETURN:  a polynomial which has newton as Newton diagram
3940SEE ALSO: newtonpoly
3941EXAMPLE: example referencepoly;  shows an example
3942"
3943{
3944 poly f;
3945 for (int i=1; i<=size(newton); i++) {
3946   f=f+var(1)^newton[i][1]*var(2)^newton[i][2];
3947 }
3948 return(f);
3949}
3950example
3951{ "EXAMPLE:"; echo = 2;
3952 ring exring=0,(x,y),ds;
3953 referencepoly(list(intvec(0,4),intvec(2,3),intvec(5,1),intvec(7,0)));
3954}
3955///////////////////////////////////////////////////////////////////////////////
3956
3957proc factorlist (list L)
3958"USAGE:   factorlist(L);   L a list in the format of `factorize'
3959RETURN:  the nonconstant irreducible factors of
3960         L[1][1]^L[2][1] * L[1][2]^L[2][2] *...* L[1][size(L[1])]^...
3961         with multiplicities (same format as factorize)
3962SEE ALSO: factorize
3963EXAMPLE: example factorlist;  shows an example
3964"
3965{
3966 // eine Sortierung der Faktoren eruebrigt sich, weil keine zwei versch.
3967 // red.Fakt. einen gleichen irred. Fakt. haben koennen (I.3.27 Diplarb.)
3968 int i,gross;
3969 list faktoren,hilf;
3970 ideal hil1,hil2;
3971 intvec v,w;
3972 for (i=1; (L[1][i] == jet(L[1][i],0)) && (i<size(L[1])); i++) {;}
3973 if (L[1][i] != jet(L[1][i],0)) {
3974   hilf=factorize(L[1][i]);
3975 // Achtung!!! factorize(..,2) wirft entgegen der Beschreibung nicht nur
3976 // konstante Faktoren raus, sondern alle Einheiten in der LOKALISIERUNG nach
3977 // der Monomordnung!!! Im Beispiel unten verschwindet der Faktor x+y+1, wenn
3978 // man ds statt dp als Ordnung nimmt!
3979   hilf[2]=hilf[2]*L[2][i];
3980   hil1=hilf[1];
3981   gross=size(hil1);
3982   if (gross>1) {
3983       // faktoren=list(hilf[1][2..gross],hilf[2][2..gross]);
3984       // -->  `? indexed object must have a name'
3985     v=hilf[2];
3986     faktoren=list(ideal(hil1[2..gross]),intvec(v[2..gross]));
3987   }
3988   else         { faktoren=hilf; }
3989 }
3990 else {
3991   faktoren=L;
3992 }
3993
3994 for (i++; i<=size(L[2]); i++) {
3995 //------------------------- linearer Term -- irreduzibel ---------------------
3996   if (L[1][i] == jet(L[1][i],1)) {
3997     if (L[1][i] != jet(L[1][i],0)) {           // konst. Faktoren eliminieren
3998       hil1=faktoren[1];
3999       hil1[size(hil1)+1]=L[1][i];
4000       faktoren[1]=hil1;
4001       v=faktoren[2],L[2][i];
4002       faktoren[2]=v;
4003     }
4004   }
4005 //----------------------- nichtlinearer Term -- faktorisiere -----------------
4006   else {
4007     hilf=factorize(L[1][i]);
4008     hilf[2]=hilf[2]*L[2][i];
4009     hil1=faktoren[1];
4010     hil2=hilf[1];
4011     gross=size(hil2);
4012       // hil2[1] ist konstant, wird weggelassen:
4013     hil1[(size(hil1)+1)..(size(hil1)+gross-1)]=hil2[2..gross];
4014       // ideal+ideal does not work due to simplification;
4015       // ideal,ideal not allowed
4016     faktoren[1]=hil1;
4017     w=hilf[2];
4018     v=faktoren[2],w[2..gross];
4019     faktoren[2]=v;
4020   }
4021 }
4022 return(faktoren);
4023}
4024example
4025{ "EXAMPLE:"; echo = 2;
4026 ring exring=0,(x,y),ds;
4027 list L=ideal(x,(x-y)^2*(x+y+1),x+y),intvec(2,2,1);
4028 L;
4029 factorlist(L);
4030}
4031///////////////////////////////////////////////////////////////////////////////
4032
4033proc deltaHNE(list hne)
4034"USAGE:   deltaHNE(L);  L list
4035NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.   
4036SEE ALSO: delta, deltaLoc
4037"
4038{
4039   int i,j,inters;
4040   int n=size(hne);
4041   list INV;
4042   for (i=1;i<=n;i++)
4043   {
4044     INV[i]=invariants(hne[i]);
4045   }
4046   int del=INV[n][5]/2;
4047   for(i=1;i<=n-1;i++)
4048   {
4049      del=del+INV[i][5]/2;
4050      for(j=i+1;j<=n;j++)
4051      {
4052         inters=inters+intersection(hne[i],hne[j]);
4053      }
4054   }   
4055   return(del+inters);
4056}
4057
4058///////////////////////////////////////////////////////////////////////////////
4059
4060proc delta
4061"USAGE:  delta(INPUT);  INPUT a polynomial defining an isolated  plane curve
4062         singularity at 0, or the Hamburger-Noether expansion thereof, i.e.
4063         the output of @code{develop(f)}, or the output of @code{hnexpansion(f[,\"ess\"])},
4064         or (one of the entries of) the list @code{hne} in the ring created
4065         by @code{hnexpansion(f[,\"ess\"])}.
4066RETURN:  the delta invariant of the singularity at 0, the vector space
4067         dimension of R~/R, where R~ is the normalization of the
4068         singularity R=basering/f
4069NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
4070         for other purposes as well it is better to calculate this first
4071         with the aid of @code{hnexpansion} and use it as input instead of
4072         the polynomial itself.
4073SEE ALSO: deltaLoc, invariants
4074KEYWORDS: delta invariant
4075EXAMPLE: example delta;  shows an example
4076"
4077{
4078  if (typeof(#[1])=="poly")
4079  { // INPUT = polynomial defining the curve
4080    list HNEXPANSION=hnexpansion(#[1]);
4081    return(delta(HNEXPANSION));
4082  }
4083  if (typeof(#[1])=="ring")
4084  { // INPUT = HNEring of curve
4085    def r_e_t_t_e_r_i_n_g=basering;
4086    def H_N_E_RING=#[1];
4087    setring H_N_E_RING;
4088    int del=delta(hne);
4089    setring r_e_t_t_e_r_i_n_g;
4090    kill H_N_E_RING;   
4091    return(del);
4092  }
4093  if (typeof(#[1])=="matrix") 
4094  { // INPUT = hne of an irreducible curve 
4095    return(invariants(#)[5]/2);
4096  }
4097  else
4098  { // INPUT = hne of a reducible curve
4099    list INV=invariants(#);
4100    return(INV[size(INV)][3]);
4101  }
4102}
4103example
4104{ "EXAMPLE:"; echo = 2;
4105  ring r = 32003,(x,y),ds;
4106  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
4107           +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
4108           -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
4109           +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
4110  delta(f);
4111}
4112
4113///////////////////////////////////////////////////////////////////////////////
4114
4115
4116proc hnexpansion(poly f,list #)
4117"USAGE:   hnexpansion(f); or hnexpansion(f,\"ess\");  f poly
4118
4119USAGE:   hnexpansion(f); f poly
4120ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
4121CREATE:  ring with variables @code{x,y} and ordering @code{ls} over a
4122         field extension of the current basering's ground field,         
4123         since the Hamburger-Noether development usually does not exist
4124         in the originally given basering. The field extension is chosen
4125         minimally.@*
4126         Moreover, in the ring a list @code{hne} of lists @code{hne[i]} is
4127         created (corresponding to the output of @code{develop(f[i])},
4128         f[i] a branch of f, but the last entry being omitted).
4129@texinfo
4130@table @asis
4131@item @code{hne[i][1]}; matrix:
4132         Each row contains the coefficients of the corresponding line of the
4133         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
4134         marked in the matrix by the first ring variable (usually x).
4135@item @code{hne[i][2]}; intvec:
4136         indicating the length of lines of the HNE
4137@item @code{hne[i][3]}; int:
4138         0  if the 1st ring variable was transversal (with respect to f[i]), @*
4139         1  if the variables were changed at the beginning of the
4140            computation, @*
4141        -1  if an error has occurred.
4142@item @code{hne[i][4]}; poly:
4143         the transformed polynomial of f[i] to make it possible to extend the
4144         Hamburger-Noether development a posteriori without having to do
4145         all the previous calculation once again (0 if not needed)
4146@end table
4147@end texinfo
4148RETURN:  a list, say @code{hn}, containing the created ring
4149NOTE:    to use the ring type: @code{def HNEring=hn[i]; setring HNEring;}.
4150         @*
4151         If f is known to be irreducible as a power series, @code{develop(f)}
4152         could be chosen instead to avoid the change of basering. @*
4153         Increasing  @code{printlevel} leads to more and more comments.
4154
4155USAGE:   hnexpansion(f,\"ess\"); f poly
4156ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
4157CREATE:  ring with variables @code{x,y} and ordering @code{ls} over a
4158         field extension of the current basering's ground field,         
4159         since the Hamburger-Noether development usually does not exist
4160         in the originally given basering. The field extension is chosen
4161         minimally.
4162         @*
4163         Moreover, in the ring a list @code{hne} of lists @code{hne[i]} is
4164         created (corresponding to the output of @code{develop(f[i])}, f[i] an
4165         \"essential\" branch of f, but the last entry being omitted). See
4166         @code{hnexpansion} above for more details.
4167RETURN:  a list, say @code{hn}, containing the created ring
4168NOTE:    to use the ring type: @code{def hnering=hn[i]; setring hnering;}.
4169         @*
4170         Alternatively you may use the procedure sethnering and type:
4171         @code{sethnering(hn);}
4172         @*
4173         If the HNE needs a field extension, some of the branches will be
4174         conjugate. In this case @code{hnexpansion(f,\"ess\")} reduces the
4175         computation to one representative for each group of conjugate
4176         branches.@*
4177         Note that the degree of each branch is in general less than the degree
4178         of the field extension in which all HNEs can be put.@*
4179         Use @code{hnexpansion(f)} to compute a complete HNE, i.e., a HNE for
4180         all branches.@*
4181         Increasing  @code{printlevel} leads to more and more comments.       
4182SEE ALSO: develop, extdevelop, parametrisation, displayHNE
4183EXAMPLE: example hnexpansion;  shows an example
4184"
4185{
4186  def rettering=basering;
4187  if (defined(HNEring))
4188  {
4189    def @HNEring = HNEring; 
4190    kill HNEring;
4191  }
4192  if (size(#)==1)
4193  {
4194    list hne=essdevelop(f);
4195  }
4196  else
4197  {
4198    list hne=HNdevelop(f);
4199  }
4200  export hne;
4201  list hnereturn=HNEring;
4202  setring rettering;
4203  kill HNEring;
4204  if (defined(@HNEring))
4205  {
4206    def HNEring=@HNEring; 
4207    export(HNEring);
4208  }
4209  dbprint(printlevel-voice+2,"
4210// 'hnexpansion' created a list containing a ring, which
4211// contains the Hamburger-Noether expansion as a list hne.
4212// To see the ring, type (if the name of your list is hn):
4213     show(hn);
4214// To access the ring and list, type:
4215     def hnering = hn[1];
4216     setring hnering;
4217     hne;
4218////////////////////////////////////////////////");
4219
4220  return(hnereturn);
4221}
4222example
4223{
4224  "EXAMPLE:"; echo = 2;
4225  ring r=0,(x,y),ls;
4226  list hn=hnexpansion(x4-y6);
4227  show(hn);
4228 
4229  def hnering=hn[1];
4230  setring hnering;
4231  size(hne);           // number of branches
4232  print(hne[1][1]);    // HN-matrix of 1st branch
4233  parametrisation(hne);    // parametrization of the two branches
4234  /////////////////////////////////////////////////////////
4235  ring s=2,(x,y),ls;
4236  poly f=(x4+x2y+y2)*(x3+xy2+y3);
4237  // --------- compute all branches: ---------
4238  hn=hnexpansion(f);
4239  hnering=hn[1];
4240  setring hnering;
4241  displayHNE(hne[1]);   // HN-matrix of 1st branch
4242  displayHNE(hne[4]);   // HN-matrix of 4th branch
4243  setring s;
4244  // --- compute only one of conjugate branches: ---
4245  hn=hnexpansion(f,"ess");
4246  hnering=hn[1];
4247  setring hnering;
4248  displayHNE(hne);
4249  // no. 1 of hnexpansion(f,"ess") represents no. 1 - 3 of hnexpansion(f) and
4250  // no. 2 of hnexpansion(f,"ess") represents no. 4 + 5 of hnexpansion(f)
4251}
4252///////////////////////////////////////////////////////////////////////////////
4253
4254proc sethnering (list L,list #)
4255"USAGE:  sethnering(L[,s]); L list, s string (optional)
4256ASSUME:  L is a list containing a ring (e.g. the output of @code{hnexpansion}).
4257CREATE:  The procedure creates a ring with name given by the optional parameter
4258         s resp. with name hnering, if no optional parameter is given, and
4259         changes your ring to this ring. The new ring will be the ring given
4260         as the first entry in the list L.         
4261RETURN:  nothing.
4262SEE ALSO: hnexpansion
4263EXAMPLE: example sethnering; shows some examples.
4264"
4265 
4266{
4267  if (typeof(L[1])=="ring")
4268  {
4269    if (size(#)>0)
4270    {
4271      if (typeof(#[1])=="string")
4272      {       
4273        execute("def "+#[1]+"=L[1];");
4274        execute("export "+#[1]+";");
4275        execute("setring "+#[1]+";");
4276        execute("keepring "+#[1]+";");
4277      }
4278      else
4279      {
4280        ERROR("Optional Input was no string.");
4281        return();
4282      }
4283    }
4284    else
4285    {
4286      def hnering=L[1];
4287      export hnering;
4288      setring hnering;
4289      keepring hnering;
4290    }
4291    return();
4292  }
4293  else
4294  {
4295    ERROR("Input was no hnering.");
4296    return();
4297  }
4298}
4299example
4300{
4301  // -------- prepare for example ---------
4302  if (defined(hnering))
4303  {
4304   def rette@ring=hnering;
4305   if (nameof(basering)=="hnering")
4306   {
4307     int wechsel=1;
4308   }
4309   else
4310   {
4311     int wechsel;
4312   }
4313   kill hnering;
4314  }
4315  // ------ the example starts here -------
4316  "EXAMPLE:"; echo = 2;
4317  ring r=0,(x,y),ls;
4318  nameof(basering);
4319  sethnering(hnexpansion(x4-y6)); // Creates hnering and changes to it!
4320  nameof(basering);
4321  echo = 0;
4322  // --- restore HNEring if previously defined ---
4323  kill hnering;
4324  if (defined(rette@ring)) {
4325   def hnering=rette@ring;
4326   export hnering;
4327   if (wechsel==1)
4328   {
4329     setring hnering;
4330   }
4331  }
4332}
Note: See TracBrowser for help on using the repository browser.