source: git/Singular/LIB/hnoether.lib @ 3c8425

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