source: git/Singular/LIB/hnoether.lib @ 1b36de3

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