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

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