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

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