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

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