source: git/Singular/LIB/hnoether.lib @ 95fdbe

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