source: git/Singular/LIB/hnoether.lib @ 5480da

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