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

spielwiese
Last change on this file since cbcc6f6 was cbcc6f6, checked in by Hans Schönemann <hannes@…>, 20 years ago
*hannes: typo git-svn-id: file:///usr/local/Singular/svn/trunk@7396 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 155.1 KB
Line 
1version="$Id: hnoether.lib,v 1.42 2004-08-13 12:54:32 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       y = []*x^1+[]*x^2   +...+x^<>*z(1)
2118       x =        []*z(1)^2+...+z(1)^<>*z(2)
2119       z(1) =     []*z(2)^2+...+z(2)^<>*z(3)
2120       .......             ..........................
2121       z(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 int i,j;
2184
2185 // lossen: check the last row for finiteness (06/2004)
2186 int rowM=nrows(m);
2187 int colM=ncols(m);
2188 int undef_bd=v[size(v)];
2189 if ( undef_bd<-1 ){
2190   for (j=-undef_bd; j<=colM; j++) { m[rowM,j]=0; }
2191 }
2192
2193 //--------------------- Erzeuge Matrix n mit n[i,j]=z(j-1)^i -----------------
2194 matrix n[colM][rowM];
2195 for (j=1; j<=rowM; j++) {
2196    for (i=1; i<=colM; i++) { n[i,j]=z(j-1)^i; }
2197 }
2198 matrix displaymat=m*n;
2199 ideal HNE;
2200 for (i=1; i<rowM; i++) { HNE[i]=displaymat[i,i]+z(i)*z(i-1)^v[i]; }
2201 HNE[rowM]=displaymat[rowM,rowM];
2202
2203 // lossen: output modified (06/2004)
2204 if (size(#) == 0)
2205 {
2206   if (switch==0) {
2207     HNE=subst(HNE,z(0),var(size(v)+1));
2208   }
2209   else  {
2210     HNE=subst(HNE,z(0),var(size(v)+2));
2211   }
2212
2213   for (j=1; j<=ncols(HNE); j++){
2214     string stHNE(j)=string(HNE[j]);
2215   }
2216   if (undef_bd<-1)
2217   {   
2218     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2219                                 +string(-undef_bd)+")";
2220   }
2221   if (undef_bd==-1)
2222   {   
2223     stHNE(size(v))=stHNE(size(v))+" + ..... (terms of degree >="
2224                                 +string(colM+1)+")";
2225   }
2226
2227   if (switch==0) {
2228     stHNE(1) = "  "+string(var(size(v)+2))+" = "+stHNE(1);
2229   }
2230   else {
2231     stHNE(1) = "  "+string(var(size(v)+1))+" = "+stHNE(1);
2232   } 
2233   stHNE(1);
2234   if (ncols(HNE)==1) {return();}
2235
2236   if (switch==0) {
2237     stHNE(2) = "  "+string(var(size(v)+1))+" = "+stHNE(2);
2238   }
2239   else {
2240     stHNE(2) = "  "+string(var(size(v)+2))+" = "+stHNE(2);
2241   } 
2242   stHNE(2);
2243
2244   for (j=3; j<=ncols(HNE); j++){
2245     stHNE(j)= "  "+"z(" +string(j-2)+ ") = "+stHNE(j);
2246     stHNE(j);
2247   }
2248   return();
2249 }
2250
2251 if (rowM<2) { HNE[2]=z(0); }
2252
2253 if (switch==0) {
2254    HNE[1] = HNE[1]-var(size(v)+2);
2255    HNE[2] = HNE[2]-var(size(v)+1);
2256 }
2257 else {
2258    HNE[1] = HNE[1]-var(size(v)+1);
2259    HNE[2] = HNE[2]-var(size(v)+2);
2260 }
2261if (size(#) == 0) {
2262   HNE;
2263   return();
2264 }
2265if (size(#) != 0) {
2266   "// basering is now 'displayring' containing ideal 'HNE'";
2267   keepring(displayring);
2268   export(HNE);
2269   return(HNE);
2270 }
2271}
2272example
2273{ "EXAMPLE:"; echo = 2;
2274  ring r=0,(x,y),dp;
2275  poly f=x3+2xy2+y2;
2276  list hn=develop(f);
2277  displayHNE(hn);
2278}
2279///////////////////////////////////////////////////////////////////////////////
2280//                      procedures for reducible curves                      //
2281///////////////////////////////////////////////////////////////////////////////
2282
2283// proc newtonhoehne (poly f)
2284// USAGE:   newtonhoehne(f);   f poly
2285// ASSUME:  basering = ...,(x,y),ds  or ls
2286// RETURN:  list of intvec(x,y) of coordinates of the newtonpolygon of f
2287// NOTE:    This proc is only available in versions of Singular that know the
2288//         command  system("newton",f);  f poly
2289// {
2290// intvec nm = getnm(f);
2291//  if ((nm[1]>0) && (nm[2]>0)) { f=jet(f,nm[1]*nm[2],nm); }
2292//  list erg=system("newton",f);
2293//  int i; list Ausgabe;
2294//  for (i=1; i<=size(erg); i++) { Ausgabe[i]=leadexp(erg[i]); }
2295// return(Ausgabe);
2296// }
2297///////////////////////////////////////////////////////////////////////////////
2298
2299proc newtonpoly (poly f, int #)
2300"USAGE:   newtonpoly(f);   f poly
2301ASSUME:  basering has exactly two variables; @*
2302         f is convenient, that is, f(x,0) != 0 != f(0,y).
2303RETURN:  list of intvecs (= coordinates x,y of the Newton polygon of f).
2304NOTE:    Procedure uses @code{execute}; this can be avoided by calling
2305         @code{newtonpoly(f,1)} if the ordering of the basering is @code{ls}.
2306KEYWORDS: Newton polygon
2307EXAMPLE: example newtonpoly;  shows an example
2308"
2309{
2310  if (size(#)>=1)
2311  {
2312    if (typeof(#[1])=="int")
2313    {
2314      // this is done to avoid the "execute" command for procedures in
2315      //  hnoether.lib
2316      def is_ls=#[1];
2317    }
2318  }
2319  if (defined(is_ls)<=0)
2320  {
2321    def @Rold=basering;
2322    execute("ring @RR=("+charstr(basering)+"),("+varstr(basering)+"),ls;");
2323    poly f=imap(@Rold,f);
2324  }
2325  intvec A=(0,ord(subst(f,var(1),0)));
2326  intvec B=(ord(subst(f,var(2),0)),0);
2327  intvec C,H; list L;
2328  int abbruch,i;
2329  poly hilf;
2330  L[1]=A;
2331  f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]));
2332  if (defined(is_ls))
2333  {
2334    map xytausch=basering,var(2),var(1);
2335  }
2336  else
2337  {
2338    map xytausch=@RR,var(2),var(1);
2339  }
2340  for (i=2; f!=0; i++)
2341  {
2342     abbruch=0;
2343     while (abbruch==0)
2344     {
2345        C=leadexp(f);         
2346        if(jet(f,A[2]*C[1]-A[1]*C[2]-1,intvec(A[2]-C[2],C[1]-A[1]))==0)
2347        {
2348           abbruch=1;
2349        }       
2350        else
2351        {
2352           f=jet(f,-C[1]-1,intvec(-1,0));
2353        }
2354    }
2355    hilf=jet(f,A[2]*C[1]-A[1]*C[2],intvec(A[2]-C[2],C[1]-A[1]));
2356    H=leadexp(xytausch(hilf));
2357    A=H[2],H[1];
2358    L[i]=A;
2359    f=jet(f,A[2]*B[1]-1,intvec(A[2],B[1]-A[1]));
2360  }
2361  L[i]=B;
2362  if (defined(is_ls))
2363  {
2364    return(L);
2365  }
2366  else
2367  {
2368    setring @Rold;
2369    return(L);
2370  }
2371}
2372example
2373{
2374 "EXAMPLE:"; echo = 2;
2375  ring r=0,(x,y),ls;
2376  poly f=x5+2x3y-x2y2+3xy5+y6-y7;
2377  newtonpoly(f);
2378}
2379///////////////////////////////////////////////////////////////////////////////
2380
2381proc is_NND (poly f, list #)
2382"USAGE:   is_NND(f[,mu,NP]);   f poly, mu int, NP list of intvecs
2383ASSUME:  f is convenient, that is, f(x,0) != 0 != f(0,y);@*
2384         mu (optional) is Milnor number of f.@*
2385         NP (optional) is output of @code{newtonpoly(f)}.
2386RETURN:  int: 1 if f in Newton non-degenerate, 0 otherwise.
2387SEE ALSO: newtonpoly
2388KEYWORDS: Newton non-degenerate; Newton polygon
2389EXAMPLE: example is_NND;  shows examples
2390"
2391{
2392  int i;
2393  int i_print=printlevel-voice+2;
2394
2395  if (size(#)==0)
2396  {
2397    int mu=milnor(f);
2398    list NP=newtonpoly(f);
2399  }
2400  else
2401  {
2402    if (typeof(#[1])=="int")
2403    {
2404      def mu=#[1];
2405      def NP=#[2];
2406      for (i=1;i<=size(NP);i++)
2407      {
2408        if (typeof(NP[i])!="intvec")
2409        {
2410          print("third input cannot be Newton polygon ==> ignored ")
2411          NP=newtonpoly(f);
2412          i=size(NP)+1;
2413        } 
2414      }
2415    }
2416    else
2417    {
2418      print("second input cannot be Milnor number ==> ignored ")
2419      int mu=milnor(f);
2420      NP=newtonpoly(f);
2421    }
2422  }
2423
2424  // computation of the Newton number:
2425  int s=size(NP);
2426  int nN=-NP[1][2]-NP[s][1]+1;
2427  intmat m[2][2];
2428  for(i=1;i<=s-1;i++)
2429  {
2430    m=NP[i+1],NP[i];
2431    nN=nN+det(m);
2432  }
2433
2434  if(mu==nN)                   
2435  { // the Newton-polygon is non-degenerate
2436    return(1);
2437  }
2438  else
2439  {
2440    return(0);
2441  }
2442}
2443example
2444{
2445 "EXAMPLE:"; echo = 2;
2446  ring r=0,(x,y),ls;
2447  poly f=x5+y3;
2448  is_NND(f);
2449  poly g=(x-y)^5+3xy5+y6-y7;
2450  is_NND(g);
2451
2452  // if already computed, one should give the Minor number and Newton polygon
2453  // as second and third input:
2454  int mu=milnor(g);
2455  list NP=newtonpoly(g);
2456  is_NND(g,mu,NP);
2457}
2458
2459
2460///////////////////////////////////////////////////////////////////////////////
2461
2462proc charPoly(poly f, int M, int N)
2463"USAGE:  charPoly(f,M,N);  f bivariate poly,  M,N int: length and height
2464                          of Newton polygon of f, which has to be only one line
2465RETURN:  the characteristic polynomial of f
2466EXAMPLE: example charPoly;  shows an example
2467"
2468{
2469 poly charp;
2470 int Np=N/ gcd(M,N);
2471 f=subst(f,var(1),1);
2472 for(charp=0; f<>0; f=f-lead(f))
2473  { charp=charp+leadcoef(f)*var(2)^(leadexp(f)[2]/ Np);}
2474 return(charp);
2475}
2476example
2477{ "EXAMPLE:"; echo = 2;
2478  ring exring=0,(x,y),dp;
2479  charPoly(y4+2y3x2-yx6+x8,8,4);
2480  charPoly(y6+3y3x2-x4,4,6);
2481}
2482///////////////////////////////////////////////////////////////////////////////
2483
2484proc find_in_list(list L,int p)
2485"USAGE:   find_in_list(L,p); L: list of intvec(x,y)
2486         (sorted in y: L[1][2]>=L[2][2]), int p >= 0
2487RETURN:  int i: L[i][2]=p if existent; otherwise i with L[i][2]<p if existent;
2488         otherwise i = size(L)+1;
2489EXAMPLE: example find_in_list;  shows an example
2490"
2491{
2492 int i;
2493 L[size(L)+1]=intvec(0,-1);          // falls p nicht in L[.][2] vorkommt
2494 for (i=1; L[i][2]>p; i++) {;}
2495 return(i);
2496}
2497example
2498{ "EXAMPLE:"; echo = 2;
2499  list L = intvec(0,4), intvec(1,2), intvec(2,1), intvec(4,0);
2500  find_in_list(L,1);
2501  L[find_in_list(L,2)];
2502}
2503///////////////////////////////////////////////////////////////////////////////
2504
2505proc get_last_divisor(int M, int N)
2506"USAGE:   get_last_divisor(M,N); int M,N
2507RETURN:  int Q: M=q1*N+r1, N=q2*r1+r2, ..., ri=Q*r(i+1) (Euclidean alg.)
2508EXAMPLE: example get_last_divisor; shows an example
2509"
2510{
2511 int R=M%N; int Q=M / N;
2512 while (R!=0) {M=N; N=R; R=M%N; Q=M / N;}
2513 return(Q)
2514}
2515example
2516{ "EXAMPLE"; echo = 2;
2517  ring r=0,(x,y),dp;
2518  get_last_divisor(12,10);
2519}
2520///////////////////////////////////////////////////////////////////////////////
2521proc redleit (poly f,intvec S, intvec E)
2522"USAGE:   redleit(f,S,E);  f poly, S,E intvec(x,y)
2523         S,E are two different points on a line in the Newton diagram of f
2524RETURN:  poly g: all monomials of f which lie on or below that line
2525NOTE:    The main purpose is that if the line defined by S and E is part of the
2526         Newton polygon, the result is the quasihomogeneous leading form of f
2527         wrt. that line.
2528SEE ALSO: newtonpoly
2529EXAMPLE: example redleit;  shows an example
2530"
2531{
2532 if (E[1]<S[1]) { intvec H=E; E=S; S=H; } // S,E verkehrt herum eingegeben
2533 return(jet(f,E[1]*S[2]-E[2]*S[1],intvec(S[2]-E[2],E[1]-S[1])));
2534}
2535example
2536{ "EXAMPLE"; echo = 2;
2537  ring exring=0,(x,y),dp;
2538  redleit(y6+xy4-2x3y2+x4y+x6,intvec(3,2),intvec(4,1));
2539}
2540///////////////////////////////////////////////////////////////////////////////
2541
2542
2543proc extdevelop (list l, int Exaktheit)
2544"USAGE:   extdevelop(L,N); list L, int N
2545ASSUME:  L is the output of @code{develop(f)}, or of @code{extdevelop(l,n)},
2546         or one entry in the list @code{hne} in the ring created by
2547          @code{hnexpansion(f[,\"ess\"])}.
2548RETURN:  an extension of the Hamburger-Noether development of f as a list
2549         in the same format as L has (up to the last entry in the output
2550         of @code{develop(f)}).@*
2551         Type @code{help develop;}, resp. @code{help hnexpansion;} for more
2552         details.
2553NOTE:    The new HN-matrix will have at least N columns (if the HNE is not
2554         finite). In particular, if f is irreducible then (in most cases)
2555         @code{extdevelop(develop(f),N)} will produce the same result as
2556         @code{develop(f,N)}.@*
2557         If the matrix M of L has n columns then, compared with
2558         @code{parametrisation(L)}, @code{paramametrize(extdevelop(L,N))} will increase the
2559         exactness by at least (N-n) more significant monomials.
2560SEE ALSO: develop, hnexpansion, parametrisation
2561EXAMPLE: example extdevelop;  shows an example
2562"
2563{
2564 //------------ Initialisierungen und Abfangen unzulaessiger Aufrufe ----------
2565 matrix m=l[1];
2566 intvec v=l[2];
2567 int switch=l[3];
2568 if (nvars(basering) < 2) {
2569   " Sorry. I need two variables in the ring.";
2570   return(list(matrix(maxideal(1)[1]),intvec(0),-1,poly(0)));}
2571 if (switch==-1) {
2572   "An error has occurred in develop, so there is no HNE and no extension.";
2573   return(l);
2574 }
2575 poly f=l[4];
2576 if (f==0) {
2577   " No extension is possible";
2578   return(l);
2579 }
2580 int Q=v[size(v)];
2581 if (Q>0) {
2582   " The HNE was already exact";
2583   return(l);
2584 }
2585 else {
2586   if (Q==-1) { Q=ncols(m); }
2587   else { Q=-Q-1; }
2588 }
2589 int zeile=nrows(m);
2590 int spalten,i,M;
2591 ideal lastrow=m[zeile,1..Q];
2592 int ringwechsel=(varstr(basering)!="x,y") or (ordstr(basering)!="ls(2),C");
2593
2594 //------------------------- Ringwechsel, falls noetig ------------------------
2595 if (ringwechsel) {
2596  def altring = basering;
2597  int p = char(basering);
2598  if (charstr(basering)!=string(p)) {
2599     string tststr=charstr(basering);
2600     tststr=tststr[1..find(tststr,",")-1];     //-> "p^k" bzw. "p"
2601     if (tststr==string(p)) {
2602       if (size(parstr(basering))>1) {         // ring (p,a,..),...
2603        execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2604       }
2605       else {                                  // ring (p,a),...
2606        string mipl=string(minpoly);
2607        ring extdguenstig=(p,`parstr(basering)`),(x,y),ls;
2608        if (mipl!="0") { execute("minpoly="+mipl+";"); }
2609       }
2610     }
2611     else {
2612       execute("ring extdguenstig=("+charstr(basering)+"),(x,y),ls;");
2613     }
2614  }
2615  else {                               // charstr(basering)== p : no parameter
2616     ring extdguenstig=p,(x,y),ls;
2617  }
2618  export extdguenstig;
2619  map hole=altring,x,y;
2620 //----- map kann sehr zeitaufwendig sein, daher Vermeidung, wo moeglich: -----
2621  if (nvars(altring)==2) { poly f=fetch(altring,f); }
2622  else                   { poly f=hole(f);          }
2623  ideal a=hole(lastrow);
2624 }
2625 else { ideal a=lastrow; }
2626 list Newton=newtonpoly(f,1);
2627 int M1=Newton[size(Newton)-1][1];     // konstant
2628 number delt;
2629 if (Newton[size(Newton)-1][2]!=1) {
2630    " *** The transformed polynomial was not valid!!";}
2631 else {
2632 //--------------------- Fortsetzung der HNE ----------------------------------
2633  while (Q<Exaktheit) {
2634    M=ord(subst(f,y,0));
2635    Q=M-M1;
2636 //------ quasihomogene Leitform ist c*x^M1*y+d*x^(M1+Q) => delta=-d/c: -------
2637    delt=-koeff(f,M,0)/koeff(f,M1,1);
2638    a[Q]=delt;
2639    dbprint(printlevel-voice+2,"a("+string(zeile-1)+","+string(Q)+") = "+string(delt));
2640    if (Q<Exaktheit) {
2641     f=T1_Transform(f,delt,Q);
2642     if (defined(HNDebugOn)) { "transformed polynomial:",f; }
2643     if (subst(f,y,0)==0) {
2644       dbprint(printlevel-voice+2,"The HNE is finite!");
2645       a[Q+1]=x; Exaktheit=Q;
2646       f=0;                        // Speicherersparnis: f nicht mehr gebraucht
2647     }
2648    }
2649  }
2650 }
2651 //------- Wechsel in alten Ring, Zusammensetzung alte HNE + Erweiterung ------
2652 if (ringwechsel) {
2653  setring altring;
2654  map zurueck=extdguenstig,var(1),var(2);
2655  if (nvars(altring)==2) { f=fetch(extdguenstig,f); }
2656  else                   { f=zurueck(f);            }
2657  lastrow=zurueck(a);
2658 }
2659 else { lastrow=a; }
2660 if (ncols(lastrow)>ncols(m)) { spalten=ncols(lastrow); }
2661 else { spalten=ncols(m); }
2662 matrix mneu[zeile][spalten];
2663 for (i=1; i<nrows(m); i++) {
2664  mneu[i,1..ncols(m)]=m[i,1..ncols(m)];
2665 }
2666 mneu[zeile,1..ncols(lastrow)]=lastrow;
2667 if (lastrow[ncols(lastrow)]!=var(1)) {
2668  if (ncols(lastrow)==spalten) { v[zeile]=-1; }  // keine undefinierten Stellen
2669  else {
2670   v[zeile]=-Q-1;
2671   for (i=ncols(lastrow)+1; i<=spalten; i++) {
2672    mneu[zeile,i]=var(2);           // fuelle nicht def. Stellen der Matrix auf
2673 }}}
2674 else { v[zeile]=Q; }               // HNE war exakt
2675 if (ringwechsel)
2676 {
2677   if(system("with","Namespaces")) { kill Top::extdguenstig; }
2678   else { kill extdguenstig; }
2679 }
2680
2681 return(list(mneu,v,switch,f));
2682}
2683example
2684{
2685  if (defined(HNEring))
2686  {
2687    def save_r_i_n_g=HNEring;
2688    kill HNEring;
2689  }
2690  // ------ the example starts here -------
2691  "EXAMPLE:"; echo = 2;
2692  ring exring=0,(x,y),dp;
2693  list hn=hnexpansion(x14-3y2x11-y3x10-y2x9+3y4x8+y5x7+3y4x6+x5*(-y6+y5)
2694                      -3y6x3-y7x2+y8);
2695  def HNEring=hn[1];
2696  setring HNEring;  echo=0;
2697  export(HNEring);  echo=2;
2698  print(hne[1][1]);    // HNE of 1st branch is finite
2699  print(extdevelop(hne[1],5)[1]);
2700  print(hne[2][1]);    // HNE of 2nd branch can be extended
2701  list ehne=extdevelop(hne[2],5);
2702  print(ehne[1]);      // new HN-matrix has 5 columns
2703  parametrisation(hne[2]);
2704  parametrisation(ehne);
2705  echo=0;
2706  if (defined(save_r_i_n_g))
2707  {
2708    kill HNEring;
2709    def HNEring=save_r_i_n_g;
2710  }
2711}
2712///////////////////////////////////////////////////////////////////////////////
2713
2714proc stripHNE (list l)
2715"USAGE:   stripHNE(L);  L list
2716ASSUME:  L is the output of @code{develop(f)}, or of
2717         @code{extdevelop(develop(f),n)}, or (one entry of) the list
2718         @code{hne} in the ring created by @code{hnexpansion(f[,\"ess\"])}.
2719RETURN:  list in the same format as L, but all polynomials L[4], resp.
2720         L[i][4], are set to zero.
2721NOTE:    The purpose of this procedure is to remove huge amounts of data
2722         no longer needed. It is useful, if one or more of the polynomials
2723         in L consume much memory. It is still possible to compute invariants,
2724         parametrizations etc. with the stripped HNE(s), but it is not possible
2725         to use @code{extdevelop} with them.
2726SEE ALSO: develop, hnexpansion, extdevelop
2727EXAMPLE: example stripHNE;  shows an example
2728"
2729{
2730 list h;
2731 if (typeof(l[1])=="matrix") { l[4]=poly(0); }
2732 else {
2733  for (int i=1; i<=size(l); i++) {
2734    h=l[i];
2735    h[4]=poly(0);
2736    l[i]=h;
2737  }
2738 }
2739 return(l);
2740}
2741example
2742{
2743  "EXAMPLE:"; echo = 2;
2744  ring r=0,(x,y),dp;
2745  list hne=develop(x2+y3+y4);
2746  hne;
2747  stripHNE(hne);
2748}
2749///////////////////////////////////////////////////////////////////////////////
2750static proc extractHNEs(list HNEs, int transvers)
2751"USAGE:  extractHNEs(HNEs,transvers);  list HNEs (output from HN),
2752        int transvers: 1 if x,y were exchanged, 0 else
2753RETURN: list of Hamburger-Noether-Extensions in the form of hne in hnexpansion
2754NOTE:   This procedure is only for internal purpose; examples don't make sense
2755"
2756{
2757 int i,maxspalte,hspalte,hnezaehler;
2758 list HNEaktu,Ergebnis;
2759 for (hnezaehler=1; hnezaehler<=size(HNEs); hnezaehler++) {
2760  maxspalte=0;
2761  HNEaktu=HNEs[hnezaehler];
2762  if (defined(HNDebugOn)) {"To process:";HNEaktu;}
2763  if (size(HNEaktu)!=size(HNEaktu[1])+2) {
2764     "The ideals and the hqs in HNEs[",hnezaehler,"] don't match!!";
2765     HNEs[hnezaehler];
2766  }
2767 //------------ ermittle  maximale Anzahl benoetigter Spalten: ----------------
2768  for (i=2; i<size(HNEaktu); i++) {
2769    hspalte=ncols(HNEaktu[i]);
2770    maxspalte=maxspalte*(hspalte < maxspalte)+hspalte*(hspalte >= maxspalte);
2771  }
2772 //------------- schreibe Ausgabe fuer hnezaehler-ten Zweig: ------------------
2773  matrix ma[size(HNEaktu)-2][maxspalte];
2774  for (i=1; i<=(size(HNEaktu)-2); i++) {
2775    if (ncols(HNEaktu[i+1]) > 1) {
2776      ma[i,1..ncols(HNEaktu[i+1])]=HNEaktu[i+1]; }
2777    else { ma[i,1]=HNEaktu[i+1][1];}
2778  }
2779  Ergebnis[hnezaehler]=list(ma,HNEaktu[1],transvers,HNEaktu[size(HNEaktu)]);
2780  kill ma;
2781 }
2782 return(Ergebnis);
2783}
2784///////////////////////////////////////////////////////////////////////////////
2785
2786proc factorfirst(poly f, int M, int N)
2787"USAGE : factorfirst(f,M,N); f poly, M,N int
2788RETURN: number d: f=c*(y^(N/e) - d*x^(M/e))^e with e=gcd(M,N), number c fitting
2789        0 if d does not exist
2790EXAMPLE: example factorfirst;  shows an example
2791"
2792{
2793 number c = koeff(f,0,N);
2794 number delt;
2795 int eps,l;
2796 int p=char(basering);
2797 string ringchar=charstr(basering);
2798
2799 if (c == 0) {"Something has gone wrong! I didn't get N correctly!"; exit;}
2800 int e = gcd(M,N);
2801
2802 if (p==0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2803 else {
2804   if (e%p != 0) { delt = koeff(f,M/ e,N - N/ e) / (-1*e*c); }
2805   else {
2806     eps = e;
2807     for (l = 0; eps%p == 0; l=l+1) { eps=eps/ p;}
2808     if (defined(HNDebugOn)) {e," -> ",eps,"*",p,"^",l;}
2809     delt = koeff(f,(M/ e)*p^l,(N/ e)*p^l*(eps-1)) / (-1*eps*c);
2810
2811     if ((charstr(basering) != string(p)) and (delt != 0)) {
2812 //------ coefficient field is not Z/pZ => (p^l)th root is not identity -------
2813       delt=0;
2814       if (defined(HNDebugOn)) {
2815         "trivial factorization not implemented for",
2816         "parameters---I've to use 'factorize'";
2817       }
2818     }
2819   }
2820 }
2821 if (defined(HNDebugOn)) {"quasihomogeneous leading form:",f," = ",c,
2822        "* (y^"+string(N/ e),"-",delt,"* x^"+string(M/ e)+")^",e," ?";}
2823 if (f != c*(var(2)^(N/ e) - delt*var(1)^(M/ e))^e) {return(0);}
2824 else {return(delt);}
2825}
2826example
2827{ "EXAMPLE:"; echo = 2;
2828  ring exring=7,(x,y),dp;
2829  factorfirst(2*(y3-3x4)^5,20,15);
2830  factorfirst(x14+y7,14,7);
2831  factorfirst(x14+x8y3+y7,14,7);
2832}
2833
2834///////////////////////////////////////////////////////////////////////////////
2835//         
2836//  the command HNdevelop is obsolete  --> here is the former help string:
2837//
2838///////////////////////////////////////////////////////////////////////////////
2839//
2840//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2841//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
2842//         @code{ls} over a field extension of the current basering's ground
2843//         field. @*
2844//         Since the Hamburger-Noether development usually does not exist
2845//         in the originally given basering, @code{HNdevelop} always defines
2846//         @code{HNEring} and CHANGES to it. The field extension is chosen
2847//         minimally.
2848//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
2849//         @code{develop(f[i])}, f[i] a branch of f, but the last entry being
2850//         omitted).
2851//@texinfo
2852//@table @asis
2853//@item @code{L[i][1]}; matrix:
2854//         Each row contains the coefficients of the corresponding line of the
2855//         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
2856//         marked in the matrix by the first ring variable (usually x).
2857//@item @code{L[i][2]}; intvec:
2858//         indicating the length of lines of the HNE
2859//@item @code{L[i][3]}; int:
2860//         0  if the 1st ring variable was transversal (with respect to f[i]), @*
2861//         1  if the variables were changed at the beginning of the
2862//            computation, @*
2863//        -1  if an error has occurred.
2864//@item @code{L[i][4]}; poly:
2865//         the transformed polynomial of f[i] to make it possible to extend the
2866//         Hamburger-Noether development a posteriori without having to do
2867//         all the previous calculation once again (0 if not needed)
2868//@end table
2869//@end texinfo
2870//NOTE:    @code{HNdevelop} decides which procedure (@code{develop} or
2871//         @code{reddevelop}) applies best to the given problem and calls it. @*
2872//         If f is known to be irreducible as a power series, @code{develop(f)}
2873//         should be chosen instead to avoid the change of basering. @*
2874//         If @code{printlevel>=2} comments are displayed (default is
2875//         @code{printlevel=0}).
2876//
2877//EXAMPLE: example HNdevelop;  shows an example
2878//
2879proc HNdevelop (poly f)
2880"USAGE:   HNdevelop(f); f poly
2881NOTE:     command is obsolete, use hnexpansion(f) instead.
2882SEE ALSO: hnexpansion, develop, extdevelop, param, displayHNE
2883"
2884{
2885 int irred=0;
2886 //--------- Falls Ring (p^k,a),...: Wechsel in (p,a),... + minpoly -----------
2887 if ((find(charstr(basering),string(char(basering)))!=1) &&
2888     (charstr(basering)<>"real")) {
2889   string strmip=string(minpoly);
2890   string strf=string(f);
2891   execute("ring tempr=("+string(char(basering))+","+parstr(basering)+"),("
2892           +varstr(basering)+"),dp;");
2893   execute("minpoly="+strmip+";");
2894   execute("poly f="+strf+";");
2895   list hne=reddevelop(f);
2896   if ((voice==2) && (printlevel > -1)) {
2897     "// Attention: The parameter",par(1),"has changed its meaning!";
2898     "// It need no longer be a generator of the cyclic group of unities!";
2899   }
2900 }
2901 else {
2902 //--- Falls Ring (0,a),... + minpoly : solange factorize nicht in Singular ---
2903 //------- implementiert ist, develop aufrufen (kann spaeter entfallen) -------
2904 //
2905 // **** lossen: gestrichen 08/05  ****
2906 //   if ((char(basering)==0) && (npars(basering)==1)) {
2907 //     if (string(minpoly)<>"0") { irred=1; }
2908 //   }
2909 //
2910 //------------------ Aufruf der geeigneten Prozedur --------------------------
2911   if (irred==0) {
2912     list hne=pre_HN(f,0);       // = reddevelop(f);
2913     dbprint(printlevel-voice+2,
2914        "// result: "+string(size(hne))+" branch(es) successfully computed,",
2915        "//         basering has changed to HNEring");
2916   }
2917   else {
2918     def altring=basering;
2919     string strmip=string(minpoly);
2920     ring HNEring=(char(altring),`parstr(altring)`),(x,y),ls;
2921     execute("minpoly="+strmip+";");
2922     export HNEring;
2923     poly f=fetch(altring,f);
2924     list hn=develop(f,-1);
2925     list hne;
2926     if (hn[3] <> -1) {
2927       hne[1]=list(hn[1],hn[2],hn[3],hn[4]);
2928       if (hn[5] <> 1) {
2929   " ** WARNING : The curve is reducible, but only one branch could be found!";
2930       }
2931     }
2932     else { " ** Sorry -- could not find a HNE."; }
2933     dbprint(printlevel-voice+2,"// note: basering has changed to HNEring");
2934   }
2935 }
2936 keepring basering;
2937 return(hne);
2938}
2939example
2940{
2941  // -------- prepare for example ---------
2942  if (nameof(basering)=="HNEring") {
2943   def rettering=HNEring;
2944   kill HNEring;
2945  }
2946  // ------ the example starts here -------
2947  "EXAMPLE:"; echo = 2;
2948  ring r=0,(x,y),dp;
2949  list hne=HNdevelop(x4-y6);
2950  nameof(basering);
2951  size(hne);           // number of branches
2952  print(hne[1][1]);    // HN-matrix of 1st branch
2953  param(hne[1]);       // parametrization of 1st branch
2954  param(hne[2]);       // parametrization of 2nd branch
2955  kill HNEring,r;
2956  echo = 0;
2957  // --- restore HNEring if previously defined ---
2958  if (defined(rettering)) {
2959   setring rettering;
2960   def HNEring=rettering;
2961   export HNEring;
2962  }
2963}
2964
2965///////////////////////////////////////////////////////////////////////////////
2966//         
2967//  the command reddevelop is obsolete  --> here is the former help string:
2968//
2969///////////////////////////////////////////////////////////////////////////////
2970//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
2971//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
2972//         @code{ls} over a field extension of the current basering's ground
2973//         field. @*
2974//         Since the Hamburger-Noether development of a reducible curve
2975//         singularity usually does not exist in the originally given basering,
2976//         @code{reddevelop} always defines @code{HNEring} and CHANGES to it.
2977//         The field extension is chosen minimally.
2978//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
2979//         @code{develop(f[i])}, f[i] a branch of f, but the last entry being
2980//         omitted).
2981//@texinfo
2982//@table @asis
2983//@item @code{L[i][1]}; matrix:
2984//         Each row contains the coefficients of the corresponding line of the
2985//         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
2986//         marked in the matrix by the first ring variable (usually x).
2987//@item @code{L[i][2]}; intvec:
2988//         indicating the length of lines of the HNE
2989//@item @code{L[i][3]}; int:
2990//         0  if the 1st ring variable was transversal (with respect to f[i]), @*
2991//         1  if the variables were changed at the beginning of the
2992//            computation, @*
2993//        -1  if an error has occurred.
2994//@item @code{L[i][4]}; poly:
2995//         the transformed polynomial of f[i] to make it possible to extend the
2996//         Hamburger-Noether development a posteriori without having to do
2997//         all the previous calculation once again (0 if not needed)
2998//@end table
2999//@end texinfo
3000//NOTE:    If @code{printlevel>=0} comments are displayed (default is
3001//         @code{printlevel=0}).
3002//
3003//EXAMPLE: example reddevelop;  shows an example
3004//
3005proc reddevelop (poly f)
3006"USAGE:   reddevelop(f); f poly
3007NOTE:     command is obsolete, use hnexpansion(f) instead.   
3008SEE ALSO: hnexpansion, develop, extdevelop, param, displayHNE
3009"
3010{
3011 list Ergebnis=pre_HN(f,0);
3012 if (size(Ergebnis)>0) {     // otherwise an error may have occurred
3013  dbprint(printlevel-voice+2,
3014   "// result: "+string(size(Ergebnis))+" branch(es) successfully computed,",
3015   "//         basering has changed to HNEring");
3016 }
3017
3018 // ----- Lossen 10/02 : the branches have to be resorted to be able to
3019 // -----                display the multsequence in a nice way
3020 if (size(Ergebnis)>2)
3021 { 
3022   int i,j,k,m;
3023   list dummy;
3024   int nbsave;
3025   int no_br = size(Ergebnis);
3026   intmat nbhd[no_br][no_br];
3027   for (i=1;i<no_br;i++)
3028   {
3029     for (j=i+1;j<=no_br;j++) 
3030     {
3031       nbhd[i,j]=separateHNE(Ergebnis[i],Ergebnis[j]);
3032       k=i+1;
3033       while ( (nbhd[i,k] >= nbhd[i,j]) and (k<j) )
3034       {
3035         k++;
3036       }
3037       if (k<j)  // branches have to be resorted
3038       {
3039         dummy=Ergebnis[j];
3040         nbsave=nbhd[i,j];
3041         for (m=k; m<j; m++)
3042         {
3043           Ergebnis[m+1]=Ergebnis[m];
3044           nbhd[i,m+1]=nbhd[i,m];
3045         }
3046         Ergebnis[k]=dummy;
3047         nbhd[i,k]=nbsave;
3048       }
3049     }
3050   }
3051 }
3052 // -----
3053 
3054 keepring basering;
3055 return(Ergebnis);
3056}
3057example
3058{
3059  // -------- prepare for example ---------
3060  if (nameof(basering)=="HNEring")
3061  {
3062   def rettering=HNEring;
3063   kill HNEring;
3064  }
3065  // ------ the example starts here -------
3066  "EXAMPLE:"; echo = 2;
3067  ring r = 32003,(x,y),dp;
3068  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
3069          +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
3070          -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
3071          +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
3072  list hne=reddevelop(f);
3073  size(hne);            // number of branches
3074  print(hne[1][1]);     // HN-matrix of 1st branch
3075  print(hne[4][1]);     // HN-matrix of 4th branch
3076  // a ring change was necessary, a is a parameter
3077  HNEring;
3078  kill HNEring,r;
3079  echo = 0;
3080  // --- restore HNEring if previously defined ---
3081  if (defined(rettering)) {
3082   setring rettering;
3083   def HNEring=rettering;
3084   export HNEring;
3085  }
3086}
3087///////////////////////////////////////////////////////////////////////////////
3088
3089static proc pre_HN (poly f, int essential)
3090"NOTE: This procedure is only for internal use, it is called via
3091      reddevelop or essdevelop"
3092{
3093 def altring = basering;
3094 int p = char(basering);                 // Ringcharakteristik
3095
3096 //-------------------- Tests auf Zulaessigkeit von basering ------------------
3097 if (charstr(basering)=="real") {
3098   " Singular cannot factorize over 'real' as ground field";
3099   return(list());
3100 }
3101 if (size(maxideal(1))<2) {
3102   " A univariate polynomial ring makes no sense !";
3103   return(list());
3104 }
3105 if (size(maxideal(1))>2) {
3106   dbprint(printlevel-voice+2,
3107   " Warning: all variables except the first two will be ignored!");
3108 }
3109 if (find(charstr(basering),string(char(basering)))!=1) {
3110   " ring of type (p^k,a) not implemented";
3111 //----------------------------------------------------------------------------
3112 // weder primitives Element noch factorize noch map "char p^k" -> "char -p"
3113 // [(p^k,a)->(p,a) ground field] noch fetch
3114 //----------------------------------------------------------------------------
3115   return(list());
3116 }
3117 //----------------- Definition eines neuen Ringes: HNEring -------------------
3118 string namex=varstr(1); string namey=varstr(2);
3119 if (string(char(altring))==charstr(altring)) {       // kein Parameter
3120   ring HNEring = char(altring),(x,y),ls;
3121   map m=altring,x,y;
3122   poly f=m(f);
3123   kill m;
3124 }
3125 else {
3126   string mipl=string(minpoly);
3127   if (mipl=="0") {
3128     " ** WARNING: No algebraic extension of this ground field is possible!";
3129     " ** We try to develop this polynomial, but if the need for an extension";
3130     " ** occurs during the calculation, we cannot proceed with the";
3131     " ** corresponding branches ...";
3132     execute("ring HNEring=("+charstr(basering)+"),(x,y),ls;");
3133 //--- ring ...=(char(.),`parstr()`),... geht nicht, wenn mehr als 1 Param. ---
3134   }
3135   else {
3136    string pa=parstr(altring);
3137    ring HNhelpring=p,`pa`,dp;
3138    execute("poly mipo="+mipl+";");  // Minimalpolynom in Polynom umgewandelt
3139    ring HNEring=(p,a),(x,y),ls;
3140    map getminpol=HNhelpring,a;
3141    mipl=string(getminpol(mipo));    // String umgewandelt mit 'a' als Param.
3142    execute("minpoly="+mipl+";");     // "minpoly=poly is not supported"
3143    kill HNhelpring, getminpol;
3144   }
3145   if (nvars(altring)==2) { poly f=fetch(altring,f); }
3146   else {
3147     map m=altring,x,y;
3148     poly f=m(f);
3149     kill m;
3150   }
3151 }
3152 export HNEring;
3153
3154 if (defined(HNDebugOn))
3155 {"received polynomial: ",f,", with x =",namex,", y =",namey;}
3156
3157 //----------------------- Variablendefinitionen ------------------------------
3158 int Abbruch,i,NullHNEx,NullHNEy;
3159 string str;
3160 list Newton,Ergebnis,hilflist;
3161
3162 //====================== Tests auf Zulaessigkeit des Polynoms ================
3163
3164 //-------------------------- Test, ob Einheit oder Null ----------------------
3165 if (subst(subst(f,x,0),y,0)!=0) {
3166   dbprint(printlevel+1,
3167           "The given polynomial is a unit in the power series ring!");
3168   keepring HNEring;
3169   return(list());                   // there are no HNEs
3170 }
3171 if (f==0) {
3172   dbprint(printlevel+1,"The given polynomial is zero!");
3173   keepring HNEring;
3174   return(list());                   // there are no HNEs
3175 }
3176
3177 //-----------------------  Test auf Quadratfreiheit --------------------------
3178
3179 if ((p==0) and (size(charstr(basering))==1)) {
3180
3181 //-------- Fall basering==0,... : Wechsel in Ring mit char >0 ----------------
3182 // weil squarefree eine Standardbasis berechnen muss (verwendet Syzygien)
3183 // -- wenn f in diesem Ring quadratfrei ist, dann erst recht im Ring HNEring
3184 //----------------------------------------------------------------------------
3185  int testerg=(polytest(f)==0);
3186  ring zweitring = 32003,(x,y),dp;
3187
3188  map polyhinueber=HNEring,x,y;         // fetch geht nicht
3189  poly f=polyhinueber(f);
3190  poly test_sqr=squarefree(f);
3191  if (test_sqr != f) {
3192   if (printlevel>0) {
3193     "Most probably the given polynomial is not squarefree. But the test was";
3194     "made in characteristic 32003 and not 0 to improve speed. You can";
3195     "(r) redo the test in char 0 (but this may take some time)";
3196     "(c) continue the development, if you're sure that the polynomial IS",
3197     "squarefree";
3198     if (testerg==1) {
3199       "(s) continue the development with a squarefree factor (*)";}
3200     "(q) or just quit the algorithm (default action)";
3201     "";"Please enter the letter of your choice:";
3202     str=read("")[1];             // reads one character
3203   }
3204   else { str="r"; }              // printlevel <= 0: non-interactive behaviour
3205   setring HNEring;
3206   map polyhinueber=zweitring,x,y;
3207   if (str=="r") {
3208     poly test_sqr=squarefree(f);
3209     if (test_sqr != f) {
3210      if (printlevel>0) { "The given polynomial is in fact not squarefree."; }
3211      else              { "The given polynomial is not squarefree!"; }
3212      "I'll continue with the radical.";
3213      f=test_sqr;
3214     }
3215     else {
3216      dbprint(printlevel,
3217       "everything is ok -- the polynomial is squarefree in characteristic 0");
3218     }
3219   }
3220   else {
3221     if ((str=="s") and (testerg==1)) {
3222       "(*)attention: it could be that the factor is only one in char 32003!";
3223       f=polyhinueber(test_sqr);
3224     }
3225     else {
3226       if (str<>"c") {
3227         setring altring;
3228         if(system("with","Namespaces")) { kill Top::HNEring; }
3229         kill HNEring;kill zweitring;
3230         return(list());}
3231       else { "if the algorithm doesn't terminate, you were wrong...";}
3232   }}
3233   kill zweitring;
3234   if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3235  }
3236  else {
3237    setring HNEring;
3238    kill zweitring;
3239  }
3240 }
3241 //------------------ Fall Char > 0 oder Ring hat Parameter -------------------
3242 else {
3243  poly test_sqr=squarefree(f);
3244  if (test_sqr != f) {
3245   if (printlevel>0) {
3246    if (test_sqr == 1) {
3247     "The given polynomial is of the form g^"+string(p)+",";
3248     "therefore not squarefree.  You can:";
3249     " (q) quit the algorithm (recommended) or";
3250     " (f) continue with the full radical (using a factorization of the";
3251     "     pure power part; this could take much time)";
3252     "";"Please enter the letter of your choice:";
3253     str=read("")[1];
3254     if (str<>"f") { str="q"; }
3255    }
3256    else {
3257     "The given polynomial is not squarefree.";
3258     if (p != 0)
3259      {
3260       " You can:";
3261       " (c) continue with a squarefree divisor (but factors of the form g^"
3262       +string(p);
3263       "     are lost; this is recommended, takes no more time)";
3264       " (f) continue with the full radical (using a factorization of the";
3265       "     pure power part; this could take much time)";
3266       " (q) quit the algorithm";
3267       "";"Please enter the letter of your choice:";
3268       str=read("")[1];
3269       if ((str<>"f") && (str<>"q")) { str="c"; }
3270      }
3271     else { "I'll continue with the radical."; str="c"; }
3272    }                                // endelse (test_sqr!=1)
3273   }
3274   else {
3275     "//** Error: The given polynomial is not squarefree!";
3276     "//** Since the global variable `printlevel' has the value",printlevel,
3277       "we stop here.";
3278     "//   Either call me again with a squarefree polynomial f or assign";
3279     "            printlevel=1;";
3280     "//   before calling me with a non-squarefree f.";
3281     "//   If printlevel > 0, I will present to you some possibilities how to",
3282       "proceed.";
3283     str="q";
3284   }
3285   if (str=="q") {
3286    if(system("with","Namespaces")) { kill Top::HNEring; }
3287    setring altring;kill HNEring;
3288    return(list());
3289   }
3290   if (str=="c") { f=test_sqr; }
3291   if (str=="f") { f=allsquarefree(f,test_sqr); }
3292  }
3293  if (defined(HNDebugOn)) {"I continue with the polynomial",f; }
3294
3295 }
3296 //====================== Ende Test auf Quadratfreiheit =======================
3297 if (subst(subst(f,x,0),y,0)!=0) {
3298   "Sorry. The remaining polynomial is a unit in the power series ring...";
3299   keepring HNEring;
3300   return(list());
3301 }
3302 //---------------------- Test, ob f teilbar durch x oder y -------------------
3303 if (subst(f,y,0)==0) {
3304   f=f/y; NullHNEy=1; }             // y=0 is a solution
3305 if (subst(f,x,0)==0) {
3306   f=f/x; NullHNEx=1; }             // x=0 is a solution
3307
3308 Newton=newtonpoly(f,1);
3309 i=1; Abbruch=0;
3310 //----------------------------------------------------------------------------
3311 // finde Eckpkt. des Newtonpolys, der den Teil abgrenzt, fuer den x transvers:
3312 // Annahme: Newton ist sortiert, s.d. Newton[1]=Punkt auf der y-Achse,
3313 // Newton[letzt]=Punkt auf der x-Achse
3314 //----------------------------------------------------------------------------
3315 while ((i<size(Newton)) and (Abbruch==0)) {
3316  if ((Newton[i+1][1]-Newton[i][1])>=(Newton[i][2]-Newton[i+1][2]))
3317   {Abbruch=1;}
3318  else {i=i+1;}
3319 }
3320 int grenze1=Newton[i][2];
3321 int grenze2=Newton[i][1];
3322 //----------------------------------------------------------------------------
3323 // Stelle Ring bereit zur Uebertragung der Daten im Fall einer Koerperer-
3324 // weiterung. Definiere Objekte, die spaeter uebertragen werden.
3325 // Binde die Listen (azeilen,...) an den Ring (um sie nicht zu ueberschreiben
3326 // bei Def. in einem anderen Ring).
3327 // Exportiere Objekte, damit sie auch in der proc HN noch da sind
3328 //----------------------------------------------------------------------------
3329 ring HNE_noparam = char(altring),(a,x,y),ls;
3330 export HNE_noparam;
3331 poly f;
3332 list azeilen=ideal(0);
3333 list HNEs=ideal(0);
3334 list aneu=ideal(0);
3335 list faktoren=ideal(0);
3336 ideal deltais;
3337 poly delt;                   // nicht number, weil delta von a abhaengen kann
3338 export f,azeilen,HNEs,aneu,faktoren,deltais,delt;
3339 //----- hier steht die Anzahl bisher benoetigter Ringerweiterungen drin: -----
3340 int EXTHNEnumber=0; export EXTHNEnumber;
3341 setring HNEring;
3342
3343 // ================= Die eigentliche Berechnung der HNE: =====================
3344
3345 // ------- Berechne HNE von allen Zweigen, fuer die x transversal ist: -------
3346 if (defined(HNDebugOn))
3347   {"1st step: Treat Newton polygon until height",grenze1;}
3348 if (grenze1>0) {
3349  hilflist=HN(f,grenze1,1,essential);
3350  if (typeof(hilflist[1][1])=="ideal") { hilflist[1]=list(); }
3351 //- fuer den Fall, dass keine Zweige in transz. Erw. berechnet werden konnten-
3352  Ergebnis=extractHNEs(hilflist[1],0);
3353  if (hilflist[2]!=-1) {
3354    if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
3355    poly transfproc=hilflist[2];
3356    map hole=HNE_noparam,transfproc,x,y;
3357    setring HNE_noparam;
3358    f=imap(HNEring,f);
3359    setring EXTHNEring(EXTHNEnumber);
3360    poly f=hole(f);
3361  }
3362 }
3363 if (NullHNEy==1) {
3364  Ergebnis=Ergebnis+list(list(matrix(ideal(0,x)),intvec(1),int(0),poly(0)));
3365 }
3366 // --------------- Berechne HNE von allen verbliebenen Zweigen: --------------
3367 if (defined(HNDebugOn))
3368    {"2nd step: Treat Newton polygon until height",grenze2;}
3369 if (grenze2>0) {
3370  map xytausch=basering,y,x;
3371  kill hilflist;
3372  def letztring=basering;
3373  if (EXTHNEnumber==0) { setring HNEring; }
3374  else                 { setring EXTHNEring(EXTHNEnumber); }
3375  list hilflist=HN(xytausch(f),grenze2,1,essential);
3376  if (typeof(hilflist[1][1])=="ideal") { hilflist[1]=list(); }
3377  if (not defined(Ergebnis)) {
3378 //-- HN wurde schon mal ausgefuehrt; Ringwechsel beim zweiten Aufruf von HN --
3379    if (defined(HNDebugOn)) {" ring change in HN(",1,") detected";}
3380    poly transfproc=hilflist[2];
3381    map hole=HNE_noparam,transfproc,x,y;
3382    setring HNE_noparam;
3383    list Ergebnis=imap(letztring,Ergebnis);
3384    setring EXTHNEring(EXTHNEnumber);
3385    list Ergebnis=hole(Ergebnis);
3386  }
3387  Ergebnis=Ergebnis+extractHNEs(hilflist[1],1);
3388 }
3389 if (NullHNEx==1) {
3390  Ergebnis=Ergebnis+list(list(matrix(ideal(0,x)),intvec(1),int(1),poly(0)));
3391 }
3392 //------------------- Loesche globale, nicht mehr benoetigte Objekte: --------
3393 if (EXTHNEnumber>0) {
3394  if(system("with","Namespaces")) { kill Top::HNEring; }
3395  kill HNEring;
3396  def HNEring=EXTHNEring(EXTHNEnumber);
3397  setring HNEring;
3398  export HNEring;
3399  kill EXTHNEring(1..EXTHNEnumber);
3400 }
3401 kill HNE_noparam;
3402 kill EXTHNEnumber;
3403 keepring basering;
3404
3405 return(Ergebnis);
3406}
3407
3408///////////////////////////////////////////////////////////////////////////////
3409//         
3410//  the command essdevelop is obsolete  --> here is the former help string:
3411//
3412///////////////////////////////////////////////////////////////////////////////
3413//ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
3414//CREATE:  ring with name @code{HNEring}, variables @code{x,y} and ordering
3415//         @code{ls} over a field extension of the current basering's ground
3416//         field. @*
3417//         Since the Hamburger-Noether development of a reducible curve
3418//         singularity usually does not exist in the originally given basering,
3419//         @code{essdevelop} always defines @code{HNEring} and CHANGES to it.
3420//         The field extension is chosen minimally.
3421//RETURN:  list @code{L} of lists @code{L[i]} (corresponding to the output of
3422//         @code{develop(f[i])}, f[i] an \"essential\" branch of f, but the
3423//         last entry being omitted).@*
3424//         For more details type @code{help reddevelop;}.
3425//NOTE:    If the HNE needs a field extension, some of the branches will be
3426//         conjugate. In this case @code{essdevelop} reduces the computation to
3427//         one representative for each group of conjugate branches.@*
3428//         Note that the degree of each branch is in general less than the
3429//         degree of the field extension in which all HNEs can be put.@*
3430//         Use @code{reddevelop} or @code{HNdevelop} to compute a complete HNE,
3431//         i.e., a HNE for all branches.@*
3432//         If @code{printlevel>=0} comments are displayed (default is
3433//         @code{printlevel=0}).
3434//SEE ALSO: hnexpansion, develop, reddevelop, HNdevelop, extdevelop
3435//EXAMPLE: example essdevelop;  shows an example
3436proc essdevelop (poly f)
3437"USAGE:   essdevelop(f); f poly
3438NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.
3439SEE ALSO: hnexpansion, develop, extdevelop, param
3440"
3441{
3442 list Ergebnis=pre_HN(f,1);
3443 dbprint(printlevel-voice+2,
3444    "// result: "+string(size(Ergebnis))+" branch(es) successfully computed;");
3445 if (string(minpoly) <> "0") {
3446   dbprint(printlevel-voice+2,
3447    "// note that conjugate branches are omitted and that the number",
3448    "// of branches represented by each remaining one may vary!");
3449 }
3450 dbprint(printlevel-voice+2,
3451    "// basering has changed to HNEring");
3452 keepring basering;
3453 return(Ergebnis);
3454}
3455example
3456{
3457  // -------- prepare for example ---------
3458  if (nameof(basering)=="HNEring") {
3459   def rettering=HNEring;
3460   kill HNEring;
3461  }
3462  // ------ the example starts here -------
3463  "EXAMPLE:"; echo = 2;
3464  ring r=2,(x,y),dp;
3465  poly f=(x4+x2y+y2)*(x3+xy2+y3);
3466  // --------- compute all branches: ---------
3467  list hne=reddevelop(f);
3468  displayHNE(hne[1]);   // HN-matrix of 1st branch
3469  displayHNE(hne[4]);   // HN-matrix of 4th branch
3470  setring r;
3471  kill HNEring;
3472  // --- compute only one of conjugate branches: ---
3473  list hne=essdevelop(f);
3474  displayHNE(hne);
3475  // no. 1 of essdevelop represents no. 1 - 3 of reddevelop and
3476  // no. 2 of essdevelop represents no. 4 + 5 of reddevelop
3477  kill HNEring,r;
3478  echo = 0;
3479  // --- restore HNEring if previously defined ---
3480  if (defined(rettering)) {
3481   setring rettering;
3482   def HNEring=rettering;
3483   export HNEring;
3484  }
3485}
3486
3487///////////////////////////////////////////////////////////////////////////////
3488static proc HN (poly f,int grenze, int Aufruf_Ebene, int essential)
3489"NOTE: This procedure is only for internal use, it is called via pre_HN"
3490{
3491 //---------- Variablendefinitionen fuer den unverzweigten Teil: --------------
3492 if (defined(HNDebugOn)) {"procedure HN",Aufruf_Ebene;}
3493 int Abbruch,ende,i,j,e,M,N,Q,R,zeiger,zeile,zeilevorher;
3494 intvec hqs;
3495 poly fvorher;
3496 list erg=ideal(0); list HNEs=ideal(0); // um die Listen an den Ring zu binden
3497
3498 //-------------------- Bedeutung von Abbruch: --------------------------------
3499 //------- 0:keine Verzweigung | 1:Verzweigung,nicht fertig | 2:fertig --------
3500 //
3501 // Struktur von HNEs : Liste von Listen L (fuer jeden Zweig) der Form
3502 // L[1]=intvec (hqs), L[2],L[3],... ideal (die Zeilen (0,1,...) der HNE)
3503 // L[letztes]=poly (transformiertes f)
3504 //----------------------------------------------------------------------------
3505 list Newton;
3506 number delt;
3507 int p = char(basering);                // Ringcharakteristik
3508 list azeilen=ideal(0);
3509 ideal hilfid; list hilflist=ideal(0); intvec hilfvec;
3510
3511 // ======================= der unverzweigte Teil: ============================
3512 while (Abbruch==0) {
3513  Newton=newtonpoly(f,1);
3514  zeiger=find_in_list(Newton,grenze);
3515  if (Newton[zeiger][2] != grenze)
3516    {"Didn't find an edge in the Newton polygon!";}
3517  if (zeiger==size(Newton)-1) {
3518    if (defined(HNDebugOn)) {"only one relevant side in Newton polygon";}
3519    M=Newton[zeiger+1][1]-Newton[zeiger][1];
3520    N=Newton[zeiger][2]-Newton[zeiger+1][2];
3521    R = M%N;
3522    Q = M / N;
3523
3524 //-------- 1. Versuch: ist der quasihomogene Leitterm reine Potenz ? ---------
3525 //              (dann geht alles wie im irreduziblen Fall)
3526 //----------------------------------------------------------------------------
3527    e = gcd(M,N);
3528    delt=factorfirst(redleit(f,Newton[zeiger],Newton[zeiger+1])
3529                      /x^Newton[zeiger][1],M,N);
3530    if (delt==0) {
3531      if (defined(HNDebugOn)) {" The given polynomial is reducible !";}
3532      Abbruch=1;
3533    }
3534    if (Abbruch==0) {
3535 //-------------- f,zeile retten fuer den Spezialfall (###): ------------------
3536      fvorher=f;zeilevorher=zeile;
3537      if (R==0) {
3538 //------------- transformiere f mit T1, wenn kein Abbruch nachher: -----------
3539        if (N>1) { f = T1_Transform(f,delt,M/ e); }
3540        else     { ende=1; }
3541        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3542        azeilen[zeile+1][Q]=delt;
3543      }
3544      else {
3545 //------------- R > 0 : transformiere f mit T2 -------------------------------
3546        erg=T2_Transform(f,delt,M,N,referencepoly(Newton));
3547        f=erg[1];delt=erg[2];
3548 //------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ---------
3549        while (R!=0) {
3550         if (defined(HNDebugOn)) { "h("+string(zeile)+") =",Q; }
3551         hqs[zeile+1]=Q;         // denn zeile beginnt mit dem Wert 0
3552 //------------------ markiere das Zeilenende der HNE: ------------------------
3553         azeilen[zeile+1][Q+1]=x;
3554         zeile=zeile+1;
3555 //----------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ---------
3556         azeilen[zeile+1]=ideal(0);
3557         M=N; N=R; R=M%N; Q=M / N;
3558        }
3559        if (defined(HNDebugOn)) {"a("+string(zeile)+","+string(Q)+") =",delt;}
3560        azeilen[zeile+1][Q]=delt;
3561      }
3562      if (defined(HNDebugOn)) {"transformed polynomial: ",f;}
3563      grenze=e;
3564 //----------------------- teste Abbruchbedingungen: --------------------------
3565      if (subst(f,y,0)==0) {              // <==> y|f
3566        dbprint(printlevel-voice+3,"finite HNE of one branch found");
3567           // voice abzufragen macht bei rekursiven procs keinen Sinn
3568        azeilen[zeile+1][Q+1]=x;
3569 //- Q wird nur in hqs eingetragen, wenn der Spezialfall nicht eintritt (s.u.)-
3570        Abbruch=2;
3571        if (grenze>1) {
3572         if (jet(f,1,intvec(0,1))==0) {
3573 //------ jet(...)=alle Monome von f, die nicht durch y2 teilbar sind ---------
3574 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3575         else {
3576 //-------------------------- Spezialfall (###): ------------------------------
3577 // Wir haben das Problem, dass die HNE eines Zweiges hier abbricht, aber ein
3578 // anderer Zweig bis hierher genau die gleiche HNE hat, die noch weiter geht
3579 // Loesung: mache Transform. rueckgaengig und behandle f im Verzweigungsteil
3580 //----------------------------------------------------------------------------
3581          Abbruch=1;
3582          f=fvorher;zeile=zeilevorher;grenze=Newton[zeiger][2];
3583        }}
3584        else {f=0;}     // f nicht mehr gebraucht - spare Speicher
3585        if (Abbruch==2) { hqs[zeile+1]=Q; }
3586      }                 // Spezialfall nicht eingetreten
3587      else {
3588        if (ende==1) {
3589          dbprint(printlevel-voice+2,"HNE of one branch found");
3590          Abbruch=2; hqs[zeile+1]=-Q-1;}
3591      }
3592    }                   // end(if Abbruch==0)
3593  }                     // end(if zeiger...)
3594  else { Abbruch=1;}
3595 }                      // end(while Abbruch==0)
3596
3597 // ===================== der Teil bei Verzweigung: ===========================
3598
3599 if (Abbruch==1) {
3600 //---------- Variablendefinitionen fuer den verzweigten Teil: ----------------
3601  poly leitf,teiler,transformiert;
3602  list aneu=ideal(0);
3603  list faktoren;
3604  list HNEakut=ideal(0);
3605  ideal deltais;
3606  intvec eis;
3607  int zaehler,hnezaehler,zl,zl1,M1,N1,R1,Q1,needext;
3608  int numberofRingchanges,lastRingnumber,ringischanged,flag;
3609  string letztringname;
3610
3611  zeiger=find_in_list(Newton,grenze);
3612  if (defined(HNDebugOn)) {
3613    "Branching part reached---Newton polygon :",Newton;
3614    "relevant part until height",grenze,", from",Newton[zeiger],"on";
3615  }
3616  azeilen=list(hqs)+azeilen; // hat jetzt Struktur von HNEs: hqs in der 1.Zeile
3617
3618 //======= Schleife fuer jede zu betrachtende Seite des Newtonpolygons: =======
3619  for(i=zeiger; i<size(Newton); i++) {
3620   if (defined(HNDebugOn)) { "we consider side",Newton[i],Newton[i+1]; }
3621   M=Newton[i+1][1]-Newton[i][1];
3622   N=Newton[i][2]-Newton[i+1][2];
3623   R = M%N;
3624   Q = M / N;
3625   e=gcd(M,N);
3626   needext=1;
3627   letztringname=nameof(basering);
3628   lastRingnumber=EXTHNEnumber;
3629   faktoren=list(ideal(charPoly(redleit(f,Newton[i],Newton[i+1])
3630                       /(x^Newton[i][1]*y^Newton[i+1][2]),M,N)  ),
3631                 intvec(1));                  // = (zu faktoriserendes Poly, 1)
3632
3633 //-- wechsle so lange in Ringerw., bis Leitform vollst. in Linearfakt. zerf.:-
3634   for (numberofRingchanges=1; needext==1; numberofRingchanges++) {
3635    leitf=redleit(f,Newton[i],Newton[i+1])/(x^Newton[i][1]*y^Newton[i+1][2]);
3636    delt=factorfirst(leitf,M,N);
3637    needext=0;
3638    if (delt==0) {
3639
3640 //---------- Sonderbehandlung: faktorisiere einige Polynome ueber Q(a): -------
3641     if (charstr(basering)=="0,a") {
3642//*CL old: faktoren=factorize(charPoly(leitf,M,N),2);  // damit funktion. Bsp. Baladi 5
3643         faktoren=factorize(charPoly(leitf,M,N)); 
3644     }
3645     else {
3646 //------------------ faktorisiere das charakt. Polynom: ----------------------
3647       if ((numberofRingchanges==1) or (essential==0)) {
3648         faktoren=factorlist(faktoren);
3649       }
3650       else {     // eliminiere alle konjugierten Nullstellen bis auf eine:
3651         ideal hilf_id;
3652         for (zaehler=1; zaehler<=size(faktoren[1]); zaehler++) {
3653           hilf_id=factorize(faktoren[1][zaehler])[1];
3654           if (size(hilf_id)>1) { faktoren[1][zaehler]=hilf_id[2]; }
3655           else                 { faktoren[1][zaehler]=hilf_id[1]; }
3656         }
3657       }
3658     }
3659
3660     zaehler=1; eis=0;
3661     for (j=1; j<=size(faktoren[2]); j++) {
3662      teiler=faktoren[1][j];
3663      if (teiler/y != 0) {         // sonst war's eine Einheit --> wegwerfen!
3664        if (defined(HNDebugOn)) {"factor of leading form found:",teiler;}
3665        if (teiler/y2 == 0) {      // --> Faktor hat die Form cy+d
3666          deltais[zaehler]=-subst(teiler,y,0)/koeff(teiler,0,1); //=-d/c
3667          eis[zaehler]=faktoren[2][j];
3668          zaehler++;
3669        }
3670        else {
3671          dbprint(printlevel-voice+2,
3672             " Change of basering (field extension) necessary!");
3673          if (defined(HNDebugOn)) { teiler,"is not properly factored!"; }
3674          if (needext==0) { poly zerlege=teiler; }
3675          needext=1;
3676        }
3677      }
3678     }                             // end(for j)
3679    }
3680    else { deltais=ideal(delt); eis=e;}
3681    if (defined(HNDebugOn)) {"roots of char. poly:";deltais;
3682                             "with multiplicities:",eis;}
3683    if (needext==1) {
3684 //--------------------- fuehre den Ringwechsel aus: --------------------------
3685      ringischanged=1;
3686      if ((size(parstr(basering))>0) && string(minpoly)=="0") {
3687        " ** We've had bad luck! The HNE cannot completely be calculated!";
3688                                   // HNE in transzendenter Erw. fehlgeschlagen
3689        kill zerlege;
3690        ringischanged=0; break;    // weiter mit gefundenen Faktoren
3691      }
3692      if (parstr(basering)=="") {
3693        EXTHNEnumber++;
3694        splitring(zerlege,"EXTHNEring("+string(EXTHNEnumber)+")");
3695        poly transf=0;
3696        poly transfproc=0;
3697      }
3698      else {
3699        if (defined(translist)) { kill translist; } // Vermeidung einer Warnung
3700        if (numberofRingchanges>1) {  // ein Ringwechsel hat nicht gereicht
3701         list translist=splitring(zerlege,"",list(transf,transfproc,faktoren));
3702         poly transf=translist[1];
3703         poly transfproc=translist[2];
3704         list faktoren=translist[3];
3705        }
3706        else {
3707         if (defined(transfproc)) { // in dieser proc geschah schon Ringwechsel
3708          EXTHNEnumber++;
3709          list translist=splitring(zerlege,"EXTHNEring("
3710               +string(EXTHNEnumber)+")",list(a,transfproc));
3711          poly transf=translist[1];
3712          poly transfproc=translist[2];
3713         }
3714         else {
3715          EXTHNEnumber++;
3716          list translist=splitring(zerlege,"EXTHNEring("
3717               +string(EXTHNEnumber)+")",a);
3718          poly transf=translist[1];
3719          poly transfproc=transf;
3720        }}
3721      }
3722 //----------------------------------------------------------------------------
3723 // transf enthaelt jetzt den alten Parameter des Ringes, der aktiv war vor
3724 // Beginn der Schleife (evtl. also ueber mehrere Ringwechsel weitergereicht),
3725 // transfproc enthaelt den alten Parm. des R., der aktiv war zu Beginn der
3726 // Prozedur, und der an die aufrufende Prozedur zurueckgegeben werden muss
3727 // transf ist Null, falls der alte Ring keinen Parameter hatte,
3728 // das gleiche gilt fuer transfproc
3729 //----------------------------------------------------------------------------
3730
3731 //------ Neudef. von Variablen, Uebertragung bisher errechneter Daten: -------
3732      poly leitf,teiler,transformiert;
3733      list aneu=ideal(0);
3734      ideal deltais;
3735      number delt;
3736      setring HNE_noparam;
3737      if (defined(letztring)) { kill letztring; }
3738      if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3739      else                  { def letztring=HNEring; }
3740      f=imap(letztring,f);
3741      faktoren=imap(letztring,faktoren);
3742      setring EXTHNEring(EXTHNEnumber);
3743      map hole=HNE_noparam,transf,x,y;
3744      poly f=hole(f);
3745      if (not defined(faktoren)) {
3746        list faktoren=hole(faktoren);
3747      }
3748    }
3749   }    // end (while needext==1) bzw. for (numberofRingchanges)
3750
3751   if (eis==0) { i++; continue; }
3752   if (ringischanged==1) {
3753    list erg,hilflist,HNEakut;            // dienen nur zum Sp. von Zwi.erg.
3754    ideal hilfid;
3755    erg=ideal(0); hilflist=erg; HNEakut=erg;
3756
3757    hole=HNE_noparam,transf,x,y;
3758    setring HNE_noparam;
3759    azeilen=imap(letztring,azeilen);
3760    HNEs=imap(letztring,HNEs);
3761
3762    setring EXTHNEring(EXTHNEnumber);
3763    list azeilen=hole(azeilen);
3764    list HNEs=hole(HNEs);
3765    kill letztring;
3766    ringischanged=0;
3767   }
3768
3769 //============ Schleife fuer jeden gefundenen Faktor der Leitform: ===========
3770   for (j=1; j<=size(eis); j++) {
3771 //-- Mache Transf. T1 oder T2, trage Daten in HNEs ein, falls HNE abbricht: --
3772
3773 //------------------------ Fall R==0: ----------------------------------------
3774    if (R==0) {
3775      transformiert = T1_Transform(f,number(deltais[j]),M/ e);
3776      if (defined(HNDebugOn)) {
3777        "a("+string(zeile)+","+string(Q)+") =",deltais[j];
3778        "transformed polynomial: ",transformiert;
3779      }
3780      if (subst(transformiert,y,0)==0) {
3781       dbprint(printlevel-voice+3,"finite HNE found");
3782       hnezaehler++;
3783 //------------ trage deltais[j],x ein in letzte Zeile, fertig: ---------------
3784       HNEakut=azeilen+list(poly(0));        // =HNEs[hnezaehler];
3785       hilfid=HNEakut[zeile+2]; hilfid[Q]=deltais[j]; hilfid[Q+1]=x;
3786       HNEakut[zeile+2]=hilfid;
3787       HNEakut[1][zeile+1]=Q;                // aktualisiere Vektor mit den hqs
3788       HNEs[hnezaehler]=HNEakut;
3789       if (eis[j]>1) {
3790        transformiert=transformiert/y;
3791        if (subst(transformiert,y,0)==0) {
3792 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3793        else {
3794 //------ Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden --------
3795          eis[j]=eis[j]-1;
3796        }
3797       }
3798      }
3799    }
3800    else {
3801 //------------------------ Fall R <> 0: --------------------------------------
3802      erg=T2_Transform(f,number(deltais[j]),M,N,referencepoly(Newton));
3803      transformiert=erg[1];delt=erg[2];
3804      if (defined(HNDebugOn)) {"transformed polynomial: ",transformiert;}
3805      if (subst(transformiert,y,0)==0) {
3806       dbprint(printlevel-voice+3,"finite HNE found");
3807       hnezaehler++;
3808 //---------------- trage endliche HNE in HNEs ein: ---------------------------
3809       HNEakut=azeilen;           // dupliziere den gemeins. Anfang der HNE's
3810       zl=2;                      // (kommt schliesslich nach HNEs[hnezaehler])
3811 //----------------------------------------------------------------------------
3812 // Werte von:  zeile: aktuelle Zeilennummer der HNE (gemeinsamer Teil)
3813 //             zl   : die HNE spaltet auf; zeile+zl ist der Index fuer die
3814 // Zeile des aktuellen Zweigs; (zeile+zl-2) ist die tatsaechl. Zeilennr.
3815 // (bei 0 angefangen) der HNE  ([1] <- intvec(hqs), [2] <- 0. Zeile usw.)
3816 //----------------------------------------------------------------------------
3817
3818 //---------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: ------
3819       M1=M;N1=N;R1=R;Q1=M1/ N1;
3820       while (R1!=0) {
3821        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3822        HNEakut[1][zeile+zl-1]=Q1;
3823        HNEakut[zeile+zl][Q1+1]=x;
3824                                  // markiere das Zeilenende der HNE
3825        zl=zl+1;
3826 //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ------------
3827        HNEakut[zeile+zl]=ideal(0);
3828
3829        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3830       }
3831       if (defined(HNDebugOn)) {
3832         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3833       }
3834       HNEakut[zeile+zl][Q1]  =delt;
3835       HNEakut[zeile+zl][Q1+1]=x;
3836       HNEakut[1][zeile+zl-1] =Q1;     // aktualisiere Vektor mit hqs
3837       HNEakut[zeile+zl+1]=poly(0);
3838       HNEs[hnezaehler]=HNEakut;
3839 //-------------------- Ende der Eintragungen in HNEs -------------------------
3840
3841       if (eis[j]>1) {
3842        transformiert=transformiert/y;
3843        if (subst(transformiert,y,0)==0) {
3844 "THE TEST FOR SQUAREFREENESS WAS BAD!! The polynomial was NOT squarefree!!!";}
3845         else {
3846 //--------- Spezialfall (###) eingetreten: Noch weitere Zweige vorhanden -----
3847          eis[j]=eis[j]-1;
3848       }}
3849      }                           // endif (subst()==0)
3850    }                             // endelse (R<>0)
3851
3852 //========== Falls HNE nicht abbricht: Rekursiver Aufruf von HN: =============
3853 //------------------- Berechne HNE von transformiert -------------------------
3854    if (subst(transformiert,y,0)!=0) {
3855     lastRingnumber=EXTHNEnumber;
3856     list HNerg=HN(transformiert,eis[j],Aufruf_Ebene+1,essential);
3857     if (HNerg[2]==-1) {          // kein Ringwechsel in HN aufgetreten
3858       aneu=HNerg[1];  }
3859     else {
3860       if (defined(HNDebugOn))
3861          {" ring change in HN(",Aufruf_Ebene+1,") detected";}
3862       list aneu=HNerg[1];
3863       poly transfproc=HNerg[2];
3864
3865 //- stelle lokale Var. im neuen Ring wieder her und rette ggf. ihren Inhalt: -
3866       list erg,hilflist,faktoren,HNEakut;
3867       ideal hilfid;
3868       erg=ideal(0); hilflist=erg; faktoren=erg; HNEakut=erg;
3869       poly leitf,teiler,transformiert;
3870
3871       map hole=HNE_noparam,transfproc,x,y;
3872       setring HNE_noparam;
3873       if (lastRingnumber>0) { def letztring=EXTHNEring(lastRingnumber); }
3874       else                  { def letztring=HNEring; }
3875       HNEs=imap(letztring,HNEs);
3876       azeilen=imap(letztring,azeilen);
3877       deltais=imap(letztring,deltais);
3878       delt=imap(letztring,delt);
3879       f=imap(letztring,f);
3880
3881       setring EXTHNEring(EXTHNEnumber);
3882       list HNEs=hole(HNEs);
3883       list azeilen=hole(azeilen);
3884       ideal deltais=hole(deltais);
3885       number delt=number(hole(delt));
3886       poly f=hole(f);
3887     }
3888     kill HNerg;
3889 //----------------------------------------------------------------------------
3890 // HNerg muss jedesmal mit "list" neu definiert werden, weil vorher noch nicht
3891 // ------- klar ist, ob der Ring nach Aufruf von HN noch derselbe ist --------
3892
3893 //============= Verknuepfe bisherige HNE mit von HN gelieferten HNEs: ========
3894     if (R==0) {
3895       HNEs,hnezaehler=constructHNEs(HNEs,hnezaehler,aneu,azeilen,zeile,
3896                       deltais,Q,j);
3897     }
3898     else {
3899      for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3900       hnezaehler++;
3901       HNEakut=azeilen;          // dupliziere den gemeinsamen Anfang der HNE's
3902       zl=2;                     // (kommt schliesslich nach HNEs[hnezaehler])
3903 //---------------- Trage Beitrag dieser Transformation T2 ein: ---------------
3904 //--------- Zur Bedeutung von zeile, zl: siehe Kommentar weiter oben ---------
3905
3906 //--------- vollziehe Euklid.Alg. nach, um die HN-Matrix zu berechnen: -------
3907       M1=M;N1=N;R1=R;Q1=M1/ N1;
3908       while (R1!=0) {
3909        if (defined(HNDebugOn)) { "h("+string(zeile+zl-2)+") =",Q1; }
3910        HNEakut[1][zeile+zl-1]=Q1;
3911        HNEakut[zeile+zl][Q1+1]=x;    // Markierung des Zeilenendes der HNE
3912        zl=zl+1;
3913 //-------- Bereitstellung von Speicherplatz fuer eine neue Zeile: ------------
3914        HNEakut[zeile+zl]=ideal(0);
3915        M1=N1; N1=R1; R1=M1%N1; Q1=M1 / N1;
3916       }
3917       if (defined(HNDebugOn)) {
3918         "a("+string(zeile+zl-2)+","+string(Q1)+") =",delt;
3919       }
3920       HNEakut[zeile+zl][Q1]=delt;
3921
3922 //--- Daten aus T2_Transform sind eingetragen; haenge Daten von HN an: -------
3923       hilfid=HNEakut[zeile+zl];
3924       for (zl1=Q1+1; zl1<=ncols(aneu[zaehler][2]); zl1++) {
3925        hilfid[zl1]=aneu[zaehler][2][zl1];
3926       }
3927       HNEakut[zeile+zl]=hilfid;
3928 //--- vorher HNEs[.][zeile+zl]<-aneu[.][2], jetzt [zeile+zl+1] <- [3] usw.: --
3929       for (zl1=3; zl1<=size(aneu[zaehler]); zl1++) {
3930         HNEakut[zeile+zl+zl1-2]=aneu[zaehler][zl1];
3931       }
3932 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
3933       hilfvec=HNEakut[1],aneu[zaehler][1];
3934       HNEakut[1]=hilfvec;
3935 //----------- weil nicht geht: liste[1]=liste[1],aneu[zaehler][1] ------------
3936       HNEs[hnezaehler]=HNEakut;
3937      }                     // end(for zaehler)
3938     }                      // endelse (R<>0)
3939    }                       // endif (subst()!=0)  (weiteres Aufblasen mit HN)
3940
3941   }                        // end(for j) (Behandlung der einzelnen delta_i)
3942
3943  }
3944  keepring basering;
3945  if (defined(transfproc)) { return(list(HNEs,transfproc)); }
3946  else                     { return(list(HNEs,poly(-1))); }
3947 // -1 als 2. Rueckgabewert zeigt an, dass kein Ringwechsel stattgefunden hat -
3948 }
3949 else {
3950  HNEs[1]=list(hqs)+azeilen+list(f); // f ist das transform. Poly oder Null
3951  keepring basering;
3952  return(list(HNEs,poly(-1)));
3953 //-- in dieser proc trat keine Verzweigung auf, also auch kein Ringwechsel ---
3954 }
3955}
3956///////////////////////////////////////////////////////////////////////////////
3957
3958static proc constructHNEs (list HNEs,int hnezaehler,list aneu,list azeilen,
3959                    int zeile,ideal deltais,int Q,int j)
3960"NOTE: This procedure is only for internal use, it is called via HN"
3961{
3962  int zaehler,zl;
3963  ideal hilfid;
3964  list hilflist;
3965  intvec hilfvec;
3966  for (zaehler=1; zaehler<=size(aneu); zaehler++) {
3967     hnezaehler++;
3968     // HNEs[hnezaehler]=azeilen;            // dupliziere gemeins. Anfang
3969 //----------------------- trage neu berechnete Daten ein ---------------------
3970     hilfid=azeilen[zeile+2];
3971     hilfid[Q]=deltais[j];
3972     for (zl=Q+1; zl<=ncols(aneu[zaehler][2]); zl++) {
3973      hilfid[zl]=aneu[zaehler][2][zl];
3974     }
3975     hilflist=azeilen; hilflist[zeile+2]=hilfid;
3976 //------------------ haenge uebrige Zeilen von aneu[] an: --------------------
3977     for (zl=3; zl<=size(aneu[zaehler]); zl++) {
3978      hilflist[zeile+zl]=aneu[zaehler][zl];
3979     }
3980 //--- setze die hqs zusammen: HNEs[hnezaehler][1]=HNEs[..][1],aneu[..][1] ----
3981     if (hilflist[1]==0) { hilflist[1]=aneu[zaehler][1]; }
3982     else { hilfvec=hilflist[1],aneu[zaehler][1]; hilflist[1]=hilfvec; }
3983     HNEs[hnezaehler]=hilflist;
3984  }
3985  return(HNEs,hnezaehler);
3986}
3987///////////////////////////////////////////////////////////////////////////////
3988
3989proc referencepoly (list newton)
3990"USAGE:   referencepoly(newton);
3991         newton is list of intvec(x,y) which represents points in the Newton
3992         diagram (e.g. output of the proc newtonpoly)
3993RETURN:  a polynomial which has newton as Newton diagram
3994SEE ALSO: newtonpoly
3995EXAMPLE: example referencepoly;  shows an example
3996"
3997{
3998 poly f;
3999 for (int i=1; i<=size(newton); i++) {
4000   f=f+var(1)^newton[i][1]*var(2)^newton[i][2];
4001 }
4002 return(f);
4003}
4004example
4005{ "EXAMPLE:"; echo = 2;
4006 ring exring=0,(x,y),ds;
4007 referencepoly(list(intvec(0,4),intvec(2,3),intvec(5,1),intvec(7,0)));
4008}
4009///////////////////////////////////////////////////////////////////////////////
4010
4011proc factorlist (list L)
4012"USAGE:   factorlist(L);   L a list in the format of `factorize'
4013RETURN:  the nonconstant irreducible factors of
4014         L[1][1]^L[2][1] * L[1][2]^L[2][2] *...* L[1][size(L[1])]^...
4015         with multiplicities (same format as factorize)
4016SEE ALSO: factorize
4017EXAMPLE: example factorlist;  shows an example
4018"
4019{
4020 // eine Sortierung der Faktoren eruebrigt sich, weil keine zwei versch.
4021 // red.Fakt. einen gleichen irred. Fakt. haben koennen (I.3.27 Diplarb.)
4022 int i,gross;
4023 list faktoren,hilf;
4024 ideal hil1,hil2;
4025 intvec v,w;
4026 for (i=1; (L[1][i] == jet(L[1][i],0)) && (i<size(L[1])); i++) {;}
4027 if (L[1][i] != jet(L[1][i],0)) {
4028   hilf=factorize(L[1][i]);
4029 // Achtung!!! factorize(..,2) wirft entgegen der Beschreibung nicht nur
4030 // konstante Faktoren raus, sondern alle Einheiten in der LOKALISIERUNG nach
4031 // der Monomordnung!!! Im Beispiel unten verschwindet der Faktor x+y+1, wenn
4032 // man ds statt dp als Ordnung nimmt!
4033   hilf[2]=hilf[2]*L[2][i];
4034   hil1=hilf[1];
4035   gross=size(hil1);
4036   if (gross>1) {
4037       // faktoren=list(hilf[1][2..gross],hilf[2][2..gross]);
4038       // -->  `? indexed object must have a name'
4039     v=hilf[2];
4040     faktoren=list(ideal(hil1[2..gross]),intvec(v[2..gross]));
4041   }
4042   else         { faktoren=hilf; }
4043 }
4044 else {
4045   faktoren=L;
4046 }
4047
4048 for (i++; i<=size(L[2]); i++) {
4049 //------------------------- linearer Term -- irreduzibel ---------------------
4050   if (L[1][i] == jet(L[1][i],1)) {
4051     if (L[1][i] != jet(L[1][i],0)) {           // konst. Faktoren eliminieren
4052       hil1=faktoren[1];
4053       hil1[size(hil1)+1]=L[1][i];
4054       faktoren[1]=hil1;
4055       v=faktoren[2],L[2][i];
4056       faktoren[2]=v;
4057     }
4058   }
4059 //----------------------- nichtlinearer Term -- faktorisiere -----------------
4060   else {
4061     hilf=factorize(L[1][i]);
4062     hilf[2]=hilf[2]*L[2][i];
4063     hil1=faktoren[1];
4064     hil2=hilf[1];
4065     gross=size(hil2);
4066       // hil2[1] ist konstant, wird weggelassen:
4067     hil1[(size(hil1)+1)..(size(hil1)+gross-1)]=hil2[2..gross];
4068       // ideal+ideal does not work due to simplification;
4069       // ideal,ideal not allowed
4070     faktoren[1]=hil1;
4071     w=hilf[2];
4072     v=faktoren[2],w[2..gross];
4073     faktoren[2]=v;
4074   }
4075 }
4076 return(faktoren);
4077}
4078example
4079{ "EXAMPLE:"; echo = 2;
4080 ring exring=0,(x,y),ds;
4081 list L=ideal(x,(x-y)^2*(x+y+1),x+y),intvec(2,2,1);
4082 L;
4083 factorlist(L);
4084}
4085///////////////////////////////////////////////////////////////////////////////
4086
4087proc deltaHNE(list hne)
4088"USAGE:   deltaHNE(L);  L list
4089NOTE:     command is obsolete, use hnexpansion(f,\"ess\") instead.   
4090SEE ALSO: delta, deltaLoc
4091"
4092{
4093   int i,j,inters;
4094   int n=size(hne);
4095   list INV;
4096   for (i=1;i<=n;i++)
4097   {
4098     INV[i]=invariants(hne[i]);
4099   }
4100   int del=INV[n][5]/2;
4101   for(i=1;i<=n-1;i++)
4102   {
4103      del=del+INV[i][5]/2;
4104      for(j=i+1;j<=n;j++)
4105      {
4106         inters=inters+intersection(hne[i],hne[j]);
4107      }
4108   }   
4109   return(del+inters);
4110}
4111
4112///////////////////////////////////////////////////////////////////////////////
4113
4114proc delta
4115"USAGE:  delta(INPUT);  INPUT a polynomial defining an isolated  plane curve
4116         singularity at 0, or the Hamburger-Noether expansion thereof, i.e.
4117         the output of @code{develop(f)}, or the output of @code{hnexpansion(f[,\"ess\"])},
4118         or (one of the entries of) the list @code{hne} in the ring created
4119         by @code{hnexpansion(f[,\"ess\"])}.
4120RETURN:  the delta invariant of the singularity at 0, the vector space
4121         dimension of R~/R, where R~ is the normalization of the
4122         singularity R=basering/f
4123NOTE:    In case the Hamburger-Noether expansion of the curve f is needed
4124         for other purposes as well it is better to calculate this first
4125         with the aid of @code{hnexpansion} and use it as input instead of
4126         the polynomial itself.
4127SEE ALSO: deltaLoc, invariants
4128KEYWORDS: delta invariant
4129EXAMPLE: example delta;  shows an example
4130"
4131{
4132  if (typeof(#[1])=="poly")
4133  { // INPUT = polynomial defining the curve
4134    list HNEXPANSION=hnexpansion(#[1]);
4135    return(delta(HNEXPANSION));
4136  }
4137  if (typeof(#[1])=="ring")
4138  { // INPUT = HNEring of curve
4139    def r_e_t_t_e_r_i_n_g=basering;
4140    def H_N_E_RING=#[1];
4141    setring H_N_E_RING;
4142    int del=delta(hne);
4143    setring r_e_t_t_e_r_i_n_g;
4144    kill H_N_E_RING;   
4145    return(del);
4146  }
4147  if (typeof(#[1])=="matrix") 
4148  { // INPUT = hne of an irreducible curve 
4149    return(invariants(#)[5]/2);
4150  }
4151  else
4152  { // INPUT = hne of a reducible curve
4153    list INV=invariants(#);
4154    return(INV[size(INV)][3]);
4155  }
4156}
4157example
4158{ "EXAMPLE:"; echo = 2;
4159  ring r = 32003,(x,y),ds;
4160  poly f = x25+x24-4x23-1x22y+4x22+8x21y-2x21-12x20y-4x19y2+4x20+10x19y
4161           +12x18y2-24x18y-20x17y2-4x16y3+x18+60x16y2+20x15y3-9x16y
4162           -80x14y3-10x13y4+36x14y2+60x12y4+2x11y5-84x12y3-24x10y5
4163           +126x10y4+4x8y6-126x8y5+84x6y6-36x4y7+9x2y8-1y9;
4164  delta(f);
4165}
4166
4167///////////////////////////////////////////////////////////////////////////////
4168
4169
4170proc hnexpansion(poly f,list #)
4171"USAGE:   hnexpansion(f); or hnexpansion(f,\"ess\");  f poly
4172
4173USAGE:   hnexpansion(f); f poly
4174ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
4175CREATE:  ring with variables @code{x,y} and ordering @code{ls} over a
4176         field extension of the current basering's ground field,         
4177         since the Hamburger-Noether development usually does not exist
4178         in the originally given basering. The field extension is chosen
4179         minimally.@*
4180         Moreover, in the ring a list @code{hne} of lists @code{hne[i]} is
4181         created (corresponding to the output of @code{develop(f[i])},
4182         f[i] a branch of f, but the last entry being omitted).
4183@texinfo
4184@table @asis
4185@item @code{hne[i][1]}; matrix:
4186         Each row contains the coefficients of the corresponding line of the
4187         Hamburger-Noether expansion (HNE) for f[i]. The end of the line is
4188         marked in the matrix by the first ring variable (usually x).
4189@item @code{hne[i][2]}; intvec:
4190         indicating the length of lines of the HNE
4191@item @code{hne[i][3]}; int:
4192         0  if the 1st ring variable was transversal (with respect to f[i]), @*
4193         1  if the variables were changed at the beginning of the
4194            computation, @*
4195        -1  if an error has occurred.
4196@item @code{hne[i][4]}; poly:
4197         the transformed polynomial of f[i] to make it possible to extend the
4198         Hamburger-Noether development a posteriori without having to do
4199         all the previous calculation once again (0 if not needed)
4200@end table
4201@end texinfo
4202RETURN:  a list, say @code{hn}, containing the created ring
4203NOTE:    to use the ring type: @code{def HNEring=hn[i]; setring HNEring;}.
4204         @*
4205         If f is known to be irreducible as a power series, @code{develop(f)}
4206         could be chosen instead to avoid the change of basering. @*
4207         Increasing  @code{printlevel} leads to more and more comments.
4208
4209USAGE:   hnexpansion(f,\"ess\"); f poly
4210ASSUME:  f is a bivariate polynomial (in the first 2 ring variables)
4211CREATE:  ring with variables @code{x,y} and ordering @code{ls} over a
4212         field extension of the current basering's ground field,         
4213         since the Hamburger-Noether development usually does not exist
4214         in the originally given basering. The field extension is chosen
4215         minimally.
4216         @*
4217         Moreover, in the ring a list @code{hne} of lists @code{hne[i]} is
4218         created (corresponding to the output of @code{develop(f[i])}, f[i] an
4219         \"essential\" branch of f, but the last entry being omitted). See
4220         @code{hnexpansion} above for more details.
4221RETURN:  a list, say @code{hn}, containing the created ring
4222NOTE:    to use the ring type: @code{def hnering=hn[i]; setring hnering;}.
4223         @*
4224         Alternatively you may use the procedure sethnering and type:
4225         @code{sethnering(hn);}
4226         @*
4227         If the HNE needs a field extension, some of the branches will be
4228         conjugate. In this case @code{hnexpansion(f,\"ess\")} reduces the
4229         computation to one representative for each group of conjugate
4230         branches.@*
4231         Note that the degree of each branch is in general less than the degree
4232         of the field extension in which all HNEs can be put.@*
4233         Use @code{hnexpansion(f)} to compute a complete HNE, i.e., a HNE for
4234         all branches.@*
4235         Increasing  @code{printlevel} leads to more and more comments.       
4236SEE ALSO: develop, extdevelop, parametrisation, displayHNE
4237EXAMPLE: example hnexpansion;  shows an example
4238"
4239{
4240  def rettering=basering;
4241  if (defined(HNEring))
4242  {
4243    def @HNEring = HNEring; 
4244    kill HNEring;
4245  }
4246  if (size(#)==1)
4247  {
4248    list hne=essdevelop(f);
4249  }
4250  else
4251  {
4252    list hne=HNdevelop(f);
4253  }
4254  export hne;
4255  list hnereturn=HNEring;
4256  setring rettering;
4257  kill HNEring;
4258  if (defined(@HNEring))
4259  {
4260    def HNEring=@HNEring; 
4261    export(HNEring);
4262  }
4263  dbprint(printlevel-voice+2,"
4264// 'hnexpansion' created a list containing a ring, which
4265// contains the Hamburger-Noether expansion as a list hne.
4266// To see the ring, type (if the name of your list is hn):
4267     show(hn);
4268// To access the ring and list, type:
4269     def hnering = hn[1];
4270     setring hnering;
4271     hne;
4272////////////////////////////////////////////////");
4273
4274  return(hnereturn);
4275}
4276example
4277{
4278  "EXAMPLE:"; echo = 2;
4279  ring r=0,(x,y),ls;
4280  list hn=hnexpansion(x4-y6);
4281  show(hn);
4282 
4283  def hnering=hn[1];
4284  setring hnering;
4285  size(hne);           // number of branches
4286  print(hne[1][1]);    // HN-matrix of 1st branch
4287  parametrisation(hne);    // parametrization of the two branches
4288  /////////////////////////////////////////////////////////
4289  ring s=2,(x,y),ls;
4290  poly f=(x4+x2y+y2)*(x3+xy2+y3);
4291  // --------- compute all branches: ---------
4292  hn=hnexpansion(f);
4293  hnering=hn[1];
4294  setring hnering;
4295  displayHNE(hne[1]);   // HN-matrix of 1st branch
4296  displayHNE(hne[4]);   // HN-matrix of 4th branch
4297  setring s;
4298  // --- compute only one of conjugate branches: ---
4299  hn=hnexpansion(f,"ess");
4300  hnering=hn[1];
4301  setring hnering;
4302  displayHNE(hne);
4303  // no. 1 of hnexpansion(f,"ess") represents no. 1 - 3 of hnexpansion(f) and
4304  // no. 2 of hnexpansion(f,"ess") represents no. 4 + 5 of hnexpansion(f)
4305}
4306///////////////////////////////////////////////////////////////////////////////
4307
4308proc sethnering (list L,list #)
4309"USAGE:  sethnering(L[,s]); L list, s string (optional)
4310ASSUME:  L is a list containing a ring (e.g. the output of @code{hnexpansion}).
4311CREATE:  The procedure creates a ring with name given by the optional parameter
4312         s resp. with name hnering, if no optional parameter is given, and
4313         changes your ring to this ring. The new ring will be the ring given
4314         as the first entry in the list L.         
4315RETURN:  nothing.
4316SEE ALSO: hnexpansion
4317EXAMPLE: example sethnering; shows some examples.
4318"
4319 
4320{
4321  if (typeof(L[1])=="ring")
4322  {
4323    if (size(#)>0)
4324    {
4325      if (typeof(#[1])=="string")
4326      {       
4327        execute("def "+#[1]+"=L[1];");
4328        execute("export "+#[1]+";");
4329        execute("setring "+#[1]+";");
4330        execute("keepring "+#[1]+";");
4331      }
4332      else
4333      {
4334        ERROR("Optional Input was no string.");
4335        return();
4336      }
4337    }
4338    else
4339    {
4340      def hnering=L[1];
4341      export hnering;
4342      setring hnering;
4343      keepring hnering;
4344    }
4345    return();
4346  }
4347  else
4348  {
4349    ERROR("Input was no hnering.");
4350    return();
4351  }
4352}
4353example
4354{
4355  // -------- prepare for example ---------
4356  if (defined(hnering))
4357  {
4358   def rette@ring=hnering;
4359   if (nameof(basering)=="hnering")
4360   {
4361     int wechsel=1;
4362   }
4363   else
4364   {
4365     int wechsel;
4366   }
4367   kill hnering;
4368  }
4369  // ------ the example starts here -------
4370  "EXAMPLE:"; echo = 2;
4371  ring r=0,(x,y),ls;
4372  nameof(basering);
4373  sethnering(hnexpansion(x4-y6)); // Creates hnering and changes to it!
4374  nameof(basering);
4375  echo = 0;
4376  // --- restore HNEring if previously defined ---
4377  kill hnering;
4378  if (defined(rette@ring)) {
4379   def hnering=rette@ring;
4380   export hnering;
4381   if (wechsel==1)
4382   {
4383     setring hnering;
4384   }
4385  }
4386}
Note: See TracBrowser for help on using the repository browser.