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

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