source: git/Singular/LIB/brnoeth.lib @ e182c8

spielwiese
Last change on this file since e182c8 was e182c8, checked in by Hans Schönemann <hannes@…>, 19 years ago
*lossen/greuel/hannes: new libs git-svn-id: file:///usr/local/Singular/svn/trunk@7847 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 139.7 KB
Line 
1version="$Id: brnoeth.lib,v 1.14 2005-04-19 15:23:38 Singular Exp $";
2category="Coding theory";
3info="
4LIBRARY:   brnoeth.lib  Brill-Noether Algorithm, Weierstrass-SG and AG-codes
5AUTHORS:   Jose Ignacio Farran Martin, ignfar@eis.uva.es
6           Christoph Lossen,           lossen@mathematik.uni-kl.de
7
8OVERVIEW:
9 Implementation of the Brill-Noether algorithm for solving the
10 Riemann-Roch problem and applications in Algebraic Geometry codes.
11 The computation of Weierstrass semigroups is also implemented.@*
12 The procedures are intended only for plane (singular) curves defined over
13 a prime field of positive characteristic.@*
14 For more information about the library see the end of the file brnoeth.lib.
15
16MAIN PROCEDURES:
17 Adj_div(f);            computes the conductor of a curve
18 NSplaces(h,A);         computes non-singular places with given degrees
19 BrillNoether(D,C);     computes a vector space basis of the linear system L(D)
20 Weierstrass(P,m,C);    computes the Weierstrass semigroup of C at P up to m
21 extcurve(d,C);         extends the curve C to an extension of degree d
22 AGcode_L(G,D,E);       computes the evaluation AG code with divisors G and D
23 AGcode_Omega(G,D,E);   computes the residual AG code with divisors G and D
24 prepSV(G,D,F,E);       preprocessing for the basic decoding algorithm
25 decodeSV(y,K);         decoding of a word with the basic decoding algorithm
26
27AUXILIARY PROCEDURES:
28 closed_points(I);      computes the zero-set of a zero-dim. ideal in 2 vars
29 dual_code(C);          computes the dual code
30 sys_code(C);           computes an equivalent systematic code
31 permute_L(L,P);        applies a permutation to a list
32
33SEE ALSO:  hnoether_lib, triang_lib
34
35KEYWORDS:  Weierstrass semigroup; Algebraic Geometry codes;
36           Brill-Noether algorithm
37";
38
39LIB "matrix.lib";
40LIB "triang.lib";
41LIB "hnoether.lib";
42LIB "inout.lib";
43
44///////////////////////////////////////////////////////////////////////////////
45
46// **********************************************************
47// * POINTS, PLACES AND DIVISORS OF (SINGULAR) PLANE CURVES *
48// **********************************************************
49
50proc closed_points (ideal I)
51"USAGE:     closed_points(I); I an ideal
52RETURN:     list of prime ideals (each a Groebner basis), corresponding to
53            the (distinct affine closed) points of V(I)
54NOTE:       The ideal must have dimension 0, the basering must have 2
55            variables, the ordering must be lp, and the base field must
56            be finite and prime.@*
57            It might be convenient to set the option(redSB) in advance.
58SEE ALSO:   triang_lib
59EXAMPLE:    example closed_points; shows an example
60"
61{
62  ideal II=std(I);
63  if (II==1)
64  {
65    return(list());
66  }
67  list TL=triangMH(II);
68  int s=size(TL);
69  list L=list();
70  int i,j,k;
71  ideal Facts;
72  poly G2;
73  for (i=1;i<=s;i=i+1)
74  {
75    Facts=factorize(TL[i][1],1);
76    k=size(Facts);
77    G2=TL[i][2];
78    for (j=1;j<=k;j=j+1)
79    {
80      L=L+pd2(Facts[j],G2);
81    }
82  }
83  // eliminate possible repetitions
84  s=size(L);
85  list LP=list();
86  LP[1]=std(L[1]);
87  int counter=1;
88  for (i=2;i<=s;i=i+1)
89  {
90    if (isPinL(L[i],LP)==0)
91    {
92      counter=counter+1;
93      LP[counter]=std(L[i]);
94    }
95  }
96  return(LP);
97}
98example
99{
100  "EXAMPLE:";  echo = 2;
101  ring s=2,(x,y),lp;
102  // this is just the affine plane over F_4 :
103  ideal I=x4+x,y4+y;
104  list L=closed_points(I);
105  // and here you have all the points :
106  L;
107}
108///////////////////////////////////////////////////////////////////////////////
109
110static proc pd2 (poly g1,poly g2)
111{
112  // If g1,g2 is a std. resp. lex. in (x,y) then the procedure
113  //    factorizes g2 in the "extension given by g1"
114  //    (then g1 must be irreducible) and returns a list of
115  //    ideals with always g1 as first component and the
116  //    distinct factors of g2 as second components
117  list L=list();
118  ideal J=g1;
119  int i,s;
120  if (deg(g1)==1)
121  {
122    poly A=-subst(g1,var(2),0);
123    poly B=subst(g2,var(2),A);
124    ideal facts=factorize(B,1);
125    s=size(facts);
126    for (i=1;i<=s;i=i+1)
127    {
128      J[2]=facts[i];
129      L[i]=J;
130    }
131  }
132  else
133  {
134    def BR=basering;
135    poly A=g1;
136    poly B=g2;
137    ring raux1=char(basering),(x,y,@a),lp;
138    poly G;
139    ring raux2=(char(basering),@a),(x,y),lp;
140    map psi=BR,x,@a;
141    minpoly=number(psi(A));
142    poly f=psi(B);
143    ideal facts=factorize(f,1);
144    s=size(facts);
145    poly g;
146    string sg;
147    for (i=1;i<=s;i=i+1)
148    {
149      g=facts[i];
150      sg=string(g);
151      setring raux1;
152      execute("G="+sg+";");
153      G=subst(G,@a,y);
154      setring BR;
155      map ppssii=raux1,var(1),var(2),0;
156      J[2]=ppssii(G);
157      L[i]=J;
158      kill(ppssii);
159      setring raux2;
160    }
161    setring BR;
162    kill(raux1,raux2);
163  }
164  return(L);
165}
166///////////////////////////////////////////////////////////////////////////////
167static proc isPinL (ideal P,list L)
168{
169  // checks if a (plane) point P is in a list of (plane) points L
170  //    by just comparing generators
171  // it works only if all (prime) ideals are given in a "canonical way",
172  // namely:
173  //    the first generator is monic and irreducible,
174  //        and depends only on the second variable,
175  //    and the second one is monic in the first variable
176  //        and irreducible over the field extension determined by
177  //        the second variable and the first generator as minpoly
178  int s=size(L);
179  int i;
180  for (i=1;i<=s;i=i+1)
181  {
182    if ( P[1]==L[i][1] && P[2]==L[i][2] )
183    {
184      return(1);
185    }
186  }
187  return(0);
188}
189///////////////////////////////////////////////////////////////////////////////
190static proc s_locus (poly f)
191{
192  // computes : ideal of affine singular locus
193  // the equation f must be affine
194  // warning : if there is an error message then the output is "none"
195  // option(redSB) is convenient to be set in advance
196  ideal I=f,jacob(f);
197  I=std(I);
198  if (dim(I)>0)
199  {
200    // dimension check (has to be 0)
201    ERROR("something was wrong; possibly non-reduced curve");
202  }
203  else
204  {
205    return(I);
206  }
207}
208///////////////////////////////////////////////////////////////////////////////
209static proc curve (poly f)
210"USAGE:      curve(f), where f is a polynomial (affine or projective)
211CREATE:     poly CHI in both rings aff_r=p,(x,y),lp and Proj_R=p,(x,y,z),lp
212            also ideal (std) Aff_SLocus of affine singular locus in the ring
213            aff_r
214RETURN:     list (size 3) with two rings aff_r,Proj_R and an integer deg(f)
215NOTE:       f must be absolutely irreducible, but this is not checked
216            it is not implemented yet for extensions of prime fields
217"
218{
219  def base_r=basering;
220  ring aff_r=char(basering),(x,y),lp;
221  ring Proj_R=char(basering),(x,y,z),lp;
222  setring base_r;
223  int degX=deg(f);
224  if (nvars(basering)==2)
225  {
226    setring aff_r;
227    map embpol=base_r,x,y;
228    poly CHI=embpol(f);
229    export(CHI);
230    kill(embpol);
231    ideal Aff_SLocus=s_locus(CHI);
232    export(Aff_SLocus);
233    setring Proj_R;
234    poly CHI=homog(imap(aff_r,CHI),z);
235    export(CHI);
236    setring base_r;
237    list L=list();
238    L[1]=aff_r;
239    L[2]=Proj_R;
240    L[3]=degX;
241    kill(aff_r,Proj_R);
242    return(L);
243  }
244  if (nvars(basering)==3)
245  {
246    setring Proj_R;
247    map embpol=base_r,x,y,z;
248    poly CHI=embpol(f);
249    export(CHI);
250    kill(embpol);
251    string s=string(subst(CHI,z,1));
252    setring aff_r;
253    execute("poly CHI="+s+";");
254    export(CHI);
255    ideal Aff_SLocus=s_locus(CHI);
256    export(Aff_SLocus);
257    setring base_r;
258    list L=list();
259    L[1]=aff_r;
260    L[2]=Proj_R;
261    L[3]=degX;
262    kill(aff_r,Proj_R);
263    return(L);
264  }
265  ERROR("basering must have 2 or 3 variables");
266}
267///////////////////////////////////////////////////////////////////////////////
268static proc Aff_SL (ideal ISL)
269{
270  // computes : affine singular (closed) points as a list of lists of
271  //     prime ideals and intvec (for storing the places over each point)
272  // the ideal ISL=s_locus(CHI) is assumed to be computed in advance for
273  //     a plane curve CHI, and it must be given by a standard basis
274  // for our purpose the function must called with the "global" ideal
275  //     "Aff_SLocus"
276  list SL=list();
277  ideal I=ISL;
278  if ( I != 1 )
279  {
280    list L=list();
281    ideal aux;
282    intvec iv;
283    int i,s;
284    L=closed_points(I);
285    s=size(L);
286    for (i=1;i<=s;i=i+1)
287    {
288      aux=std(L[i]);
289      SL[i]=list(aux,iv);
290    }
291  }
292  return(SL);
293}
294///////////////////////////////////////////////////////////////////////////////
295static proc inf_P (poly f)
296{
297  // computes : all (closed) points at infinity as homogeneous polynomials
298  // output : two lists with respectively singular and non-singular points
299  intvec iv;
300  def base_r=basering;
301  ring r_auxz=char(basering),(x,y,z),lp;
302  poly f=imap(base_r,f);
303  poly F=homog(f,z);                    // equation of projective curve
304  poly f_inf=subst(F,z,0);
305  setring base_r;
306  poly f_inf=imap(r_auxz,f_inf);
307  ideal I=factorize(f_inf,1);           // points at infinity as homogeneous
308                                        // polynomials
309  int s=size(I);
310  int i;
311  list IP_S=list();                     // for singular points at infinity
312  list IP_NS=list();                    // for non-singular points at infinity
313  int counter_S;
314  int counter_NS;
315  poly aux;
316  for (i=1;i<=s;i=i+1)
317  {
318    aux=subst(I[i],y,1);
319    if (aux==1)
320    {
321      // the point is (1:0:0)
322      setring r_auxz;
323      poly f_yz=subst(F,x,1);
324      if ( subst(subst(diff(f_yz,y),y,0),z,0)==0 &&
325           subst(subst(diff(f_yz,z),y,0),z,0)==0 )
326      {
327        // the point is singular
328        counter_S=counter_S+1;
329        kill(f_yz);
330        setring base_r;
331        IP_S[counter_S]=list(I[i],iv);
332      }
333      else
334      {
335        // the point is non-singular
336        counter_NS=counter_NS+1;
337        kill(f_yz);
338        setring base_r;
339        IP_NS[counter_NS]=list(I[i],iv);
340      }
341    }
342    else
343    {
344      // the point is (a:1:0) | a is root of aux
345      if (deg(aux)==1)
346      {
347        // the point is rational and no field extension is needed
348        setring r_auxz;
349        poly f_xz=subst(F,y,1);
350        poly aux=imap(base_r,aux);
351        number A=-number(subst(aux,x,0));
352        map phi=r_auxz,x+A,0,z;
353        poly f_origin=phi(f_xz);
354        if ( subst(subst(diff(f_origin,x),x,0),z,0)==0 &&
355             subst(subst(diff(f_origin,z),x,0),z,0)==0 )
356        {
357          // the point is singular
358          counter_S=counter_S+1;
359          kill(f_xz,aux,A,phi,f_origin);
360          setring base_r;
361          IP_S[counter_S]=list(I[i],iv);
362        }
363        else
364        {
365          // the point is non-singular
366          counter_NS=counter_NS+1;
367          kill(f_xz,aux,A,phi,f_origin);
368          setring base_r;
369          IP_NS[counter_NS]=list(I[i],iv);
370        }
371      }
372      else
373      {
374        // the point is non-rational and a field extension with minpoly=aux
375        // is needed
376        ring r_ext=(char(basering),@a),(x,y,z),lp;
377        poly F=imap(r_auxz,F);
378        poly f_xz=subst(F,y,1);
379        poly aux=imap(base_r,aux);
380        minpoly=number(subst(aux,x,@a));
381        map phi=r_ext,x+@a,0,z;
382        poly f_origin=phi(f_xz);
383        if ( subst(subst(diff(f_origin,x),x,0),z,0)==0 &&
384             subst(subst(diff(f_origin,z),x,0),z,0)==0 )
385        {
386          // the point is singular
387          counter_S=counter_S+1;
388          setring base_r;
389          kill(r_ext);
390          IP_S[counter_S]=list(I[i],iv);
391        }
392        else
393        {
394          // the point is non-singular
395          counter_NS=counter_NS+1;
396          setring base_r;
397          kill(r_ext);
398          IP_NS[counter_NS]=list(I[i],iv);
399        }
400      }
401    }
402  }
403  kill(r_auxz);
404  return(list(IP_S,IP_NS));
405}
406///////////////////////////////////////////////////////////////////////////////
407static proc closed_points_ext (poly f,int d,ideal SL)
408{
409  // computes : (closed affine non-singular) points over an extension of
410  //            degree d
411  // remark(1) : singular points are supposed to be listed appart
412  // remark(2) : std SL=s_locus(f) is supposed to be computed in advance
413  // remark(3) : ideal SL is used to remove those points which are singular
414  // output : list of list of prime ideals with an intvec for storing the
415  //          places
416  int Q=char(basering)^d;             // cardinality of the extension field
417  ideal I=f,x^Q-x,y^Q-y;              // ideal of the searched points
418  I=std(I);
419  if (I==1)
420  {
421    return(list());
422  }
423  list LP=list();
424  int m=size(SL);
425  list L=list();
426  ideal aux;
427  intvec iv;
428  int i,s,j,counter;
429  L=closed_points(I);
430  s=size(L);
431  for (i=1;i<=s;i=i+1)
432  {
433    aux=std(L[i]);
434    for (j=1;j<=m;j=j+1)
435    {
436      // check if singular i.e. if SL is contained in aux
437      if ( NF(SL[j],aux) != 0 )
438      {
439        counter=counter+1;
440        LP[counter]=list(aux,iv);
441        break;
442      }
443    }
444  }
445  return(LP);
446}
447///////////////////////////////////////////////////////////////////////////////
448static proc degree_P (list P)
449"USAGE:      degree_P(P), where P is either a polynomial or an ideal
450RETURN:     integer with the degree of the closed point given by P
451SEE ALSO:   closed_points
452NOTE:       If P is a (homogeneous irreducible) polynomial the point is at
453            infinity, and if P is a (prime) ideal the points is affine, and
454            the ideal must be given by 2 generators: the first one irreducible
455            and depending only on y, and the second one irreducible over the
456            extension given by y with the first generator as minimal polynomial
457"
458{
459  // computes : the degree of a given point
460  // remark(1) : if the input is (irreducible homogeneous) poly => the point
461  //             is at infinity
462  // remark(2) : it the input is (std. resp. lp. prime) ideal => the point is
463  //             affine
464  if (typeof(P[1])=="ideal")
465  {
466    if (size(P[1])==2)
467    {
468      int d=deg(P[1][1]);
469      poly aux=subst(P[1][2],y,1);
470      d=d*deg(aux);
471      return(d);
472    }
473    else
474    {
475      // this should not happen in principle
476      ERROR("non-valid parameter");
477    }
478  }
479  else
480  {
481    if (typeof(P[1])=="poly")
482    {
483      return(deg(P[1]));
484    }
485    else
486    {
487      ERROR("parameter must have a poly or ideal in the first component");
488    }
489  }
490}
491///////////////////////////////////////////////////////////////////////////////
492static proc closed_points_deg (poly f,int d,ideal SL)
493{
494  // computes : (closed affine non-singular) points of degree d
495  // remark(1) : singular points are supposed to be listed appart
496  // remark(2) : std SL=s_locus(f) is supposed to be computed in advance
497  list L=closed_points_ext(f,d,SL);
498  int s=size(L);
499  int i,counter;
500  list LP=list();
501  for (i=1;i<=s;i=i+1)
502  {
503    if (degree_P(L[i])==d)
504    {
505      counter=counter+1;
506      LP[counter]=L[i];
507    }
508  }
509  return(LP);
510}
511///////////////////////////////////////////////////////////////////////////////
512static proc subset (ideal I,ideal J)
513{
514  // checks wether I is contained in J and returns a boolean
515  // remark : J is assumed to be given by a standard basis
516  int s=ncols(I);
517  int i;
518  for (i=1;i<=s;i=i+1)
519  {
520    if ( NF(I[i],std(J)) != 0 )
521    {
522      return(0);
523    }
524  }
525  return(1);
526}
527///////////////////////////////////////////////////////////////////////////////
528static proc belongs (list P,ideal I)
529{
530  // checks if affine point P is contained in V(I) and returns a boolean
531  // remark : P[1] is assumed to be an ideal given by a standard basis
532  if (typeof(P[1])=="ideal")
533  {
534    return(subset(I,P[1]));
535  }
536  else
537  {
538    ERROR("first argument must be an affine point");
539  }
540}
541///////////////////////////////////////////////////////////////////////////////
542static proc equals (ideal I,ideal J)
543{
544  // checks if I is equal to J and returns a boolean
545  // remark : I and J are assumed to be given by a standard basis
546  int answer=0;
547  if (subset(I,J)==1)
548  {
549    if (subset(J,I)==1)
550    {
551      answer=1;
552    }
553  }
554  return(answer);
555}
556///////////////////////////////////////////////////////////////////////////////
557static proc isInLP (ideal P,list LP)
558{
559  // checks if affine point P is a list LP and returns either its position or
560  //   zero
561  // remark : all points in LP and P itself are assumed to be given by a
562  //   standard basis
563  // warning : the procedure does not check whether the points are affine or
564  //   not
565  int s=size(LP);
566  if (s==0)
567  {
568    return(0);
569  }
570  int i;
571  for (i=1;i<=s;i=i+1)
572  {
573    if (equals(P,LP[i][1])==1)
574    {
575      return(i);
576    }
577  }
578  return(0);
579}
580///////////////////////////////////////////////////////////////////////////////
581static proc res_deg ()
582{
583  // computes the residual degree of the basering with respect to its prime
584  //   field
585  // warning : minpoly must depend on a parameter called "a"
586  int ext;
587  string s_m=string(minpoly);
588  if (s_m=="0")
589  {
590    ext=1;
591  }
592  else
593  {
594    ring auxr=char(basering),a,lp;
595    execute("poly minp="+s_m+";");
596    ext=deg(minp);
597  }
598  return(ext);
599}
600///////////////////////////////////////////////////////////////////////////////
601static proc Frobenius (etwas,int r)
602{
603  // applies the Frobenius map over F_{p^r} to an object defined over an
604  //   extension of such field
605  // usually it is called with r=1, i.e. the Frobenius map over the prime
606  //   field F_p
607  // returns always an object of the same type, and works correctly on
608  // numbers, polynomials, ideals, matrices or lists of the above types
609  // maybe : types vector and module should be added in the future, but they
610  //   are not needed now
611  int q=char(basering)^r;
612  if (typeof(etwas)=="number")
613  {
614    return(etwas^q);
615  }
616  if (typeof(etwas)=="poly")
617  {
618    int s=size(etwas);
619    poly f;
620    int i;
621    for (i=1;i<=s;i=i+1)
622    {
623      f=f+(leadcoef(etwas[i])^q)*leadmonom(etwas[i]);
624    }
625    return(f);
626  }
627  if (typeof(etwas)=="ideal")
628  {
629    int s=ncols(etwas);
630    ideal I;
631    int i;
632    for (i=1;i<=s;i=i+1)
633    {
634      I[i]=Frobenius(etwas[i],r);
635    }
636    return(I);
637  }
638  if (typeof(etwas)=="matrix")
639  {
640    int m=nrows(etwas);
641    int n=ncols(etwas);
642    matrix A[m][n];
643    int i,j;
644    for (i=1;i<=m;i=i+1)
645    {
646      for (j=1;j<=n;j=j+1)
647      {
648        A[i,j]=Frobenius(etwas[i,j],r);
649      }
650    }
651    return(A);
652  }
653  if (typeof(etwas)=="list")
654  {
655    int s=size(etwas);
656    list L=list();
657    int i;
658    for (i=1;i<=s;i=i+1)
659    {
660      if (typeof(etwas[i])<>"none")
661      {
662        L[i]=Frobenius(etwas[i],r);
663      }
664    }
665    return(L);
666  }
667  return(etwas);
668}
669///////////////////////////////////////////////////////////////////////////////
670static proc conj_b (list L,int r)
671{
672  // applies the Frobenius map over F_{p^r} to a list of type HNE defined over
673  //   a larger extension
674  // when r=1 it turns to be the Frobenius map over the prime field F_{p}
675  // returns : a list of type HNE which is either conjugate of the input or
676  //     the same list in case of L being actually defined over the base field
677  //     F_{p^r}
678  int p=char(basering);
679  int Q=p^r;
680  list LL=list();
681  int m=nrows(L[1]);
682  int n=ncols(L[1]);
683  matrix A[m][n];
684  poly f;
685  poly aux;
686  int i,j;
687  for (i=1;i<=m;i=i+1)
688  {
689    for (j=1;j<=n;j=j+1)
690    {
691      aux=L[1][i,j];
692      if (aux<>x)
693      {
694        A[i,j]=aux^Q;
695      }
696      else
697      {
698        A[i,j]=aux;
699        break;
700      }
701    }
702  }
703  m=size(L[4]);
704  for (i=1;i<=m;i=i+1)
705  {
706    f=f+(leadcoef(L[4][i])^Q)*leadmonom(L[4][i]);
707  }
708  LL[1]=A;
709  LL[2]=L[2];
710  LL[3]=L[3];
711  LL[4]=f;
712  return(LL);
713}
714///////////////////////////////////////////////////////////////////////////////
715static proc grad_b (list L,int r)
716{
717  // computes the degree of a list of type HNE which is actually defined over
718  //    F_{p^r} eventhough it is given in an extension of such field
719  int gr=1;
720  int rd=res_deg() div r;
721  list LL=L;
722  int i;
723  for (i=1;i<=rd;i=i+1)
724  {
725    LL=conj_b(LL,r);
726    if ( LL[1]==L[1] && LL[4]==L[4] )
727    {
728      break;
729    }
730    else
731    {
732      gr=gr+1;
733    }
734  }
735  return(gr);
736}
737///////////////////////////////////////////////////////////////////////////////
738static proc conj_bs (list L,int r)
739{
740  // computes all the conjugates over F_{p^r} of a list of type HNE defined
741  //   over an extension
742  // returns : a list of lists of type HNE, where the first one is the input
743  //   list
744  // remark : notice that the degree of the branch is then the size of the
745  //   output
746  list branches=list();
747  int gr=1;
748  branches[1]=L;
749  int rd=res_deg() div r;
750  list LL=L;
751  int i;
752  for (i=1;i<=rd;i=i+1)
753  {
754    LL=conj_b(LL,r);
755    if ( LL[1]==L[1] && LL[4]==L[4] )
756    {
757      break;
758    }
759    else
760    {
761      gr=gr+1;
762      branches[gr]=LL;
763    }
764  }
765  return(branches);
766}
767///////////////////////////////////////////////////////////////////////////////
768static proc subfield (sf)
769{
770  // writes the generator "a" of a subfield of the coefficients field of
771  //   basering in terms of the current generator (also called "a") as a
772  //   string sf is an existing ring whose coefficient field is such a subfield
773  // warning : in basering there must be a variable called "x" and subfield
774  //   must not be prime
775  def base_r=basering;
776  string new_m=string(minpoly);
777  setring sf;
778  string old_m=string(minpoly);
779  if (old_m==new_m)
780  {
781    setring base_r;
782    return("a");
783  }
784  else
785  {
786    if (old_m<>string(0))
787    {
788      ring auxring=char(basering),(a,x),lp;
789      execute("poly mpol="+old_m+";");
790      mpol=subst(mpol,a,x);
791      setring base_r;
792      poly mpol=imap(auxring,mpol);
793      kill(auxring);
794      string answer="? error : non-primitive element";
795      int r=res_deg();
796      int q=char(basering)^r;
797      int i;
798      number b;
799      for (i=1;i<=q-2;i=i+1)
800      {
801        b=a^i;
802        if (subst(mpol,x,b)==0)
803        {
804          answer=string(b);
805          break;
806        }
807      }
808      if (answer<>"? error : non-primitive element")
809      {
810        return(answer);
811      }
812      else
813      {
814        // list all the elements of the finite field F_q
815        int p=char(basering);
816        list FF1,FF2;
817        for (i=0;i<p;i=i+1)
818        {
819          FF1[i+1]=number(i);
820        }
821        int s,j,k;
822        for (i=1;i<r;i=i+1)
823        {
824          s=size(FF1);
825          for (j=1;j<=s;j=j+1)
826          {
827            FF1[j]=FF1[j]*a;
828          }
829          FF2=FF1;
830          for (k=1;k<p;k=k+1)
831          {
832            for (j=1;j<=s;j=j+1)
833            {
834              FF1[j]=FF1[j]+number(1);
835            }
836            FF2=FF2+FF1;
837          }
838          FF1=FF2;
839          FF2=list();
840        }
841        kill(FF2);
842        for (i=1;i<=q-1;i=i+1)
843        {
844          b=FF1[i];
845          if (subst(mpol,x,b)==0)
846          {
847            answer=string(b);
848            break;
849          }
850        }
851      }
852      kill(FF1);
853      return(answer);
854    }
855    else
856    {
857      dbprint(printlevel+1,"warning : minpoly=0 in the subfield;
858                              you should check that nothing is wrong");
859      return(string(1));
860    }
861  }
862}
863///////////////////////////////////////////////////////////////////////////////
864static proc importdatum (sf,string datum,string rel)
865{
866  // fetchs a poly with name "datum" to the current basering from the ring sf
867  //   such that the generator is given by string "rel"
868  // warning : ring sf must have only variables (x,y) and basering must have
869  //   at least (x,y)
870  // warning : the case of minpoly=0 is not regarded; there you can use "imap"
871  //   instead
872  def base_r=basering;
873  if (rel=="a")
874  {
875    setring sf;
876    execute("poly pdatum="+datum+";");
877    setring base_r;
878    poly pdatum=imap(sf,pdatum);
879    return(pdatum);
880  }
881  else
882  {
883    setring sf;
884    execute("string sdatum=string("+datum+");");
885    ring auxring=char(basering),(a,x,y),lp;
886    execute("poly pdatum="+sdatum+";");
887    execute("map phi=basering,"+rel+",x,y;");
888    pdatum=phi(pdatum);
889    string snewdatum=string(pdatum);
890    setring base_r;
891    execute("poly pdatum="+snewdatum+";");
892    kill(auxring);
893    return(pdatum);
894  }
895}
896///////////////////////////////////////////////////////////////////////////////
897static proc rationalize (lf,string datum,string rel)
898{
899  // fetchs a poly with name "datum" to the current basering from the ring lf
900  //   and larger coefficients field, where the generator of current ring is
901  //   given by string "rel" and "datum" is actually defined over the small
902  //   field
903  // warning : "ring lf must have only variables (x,y) and basering must have
904  //           at least (x,y)
905  // warning : the case of minpoly=0 is supposed unnecessary, since then
906  //           "datum" should be
907  //   already written only int the right way, i.e. in terms of the prime field
908  def base_r=basering;
909  if (rel=="a")
910  {
911    setring lf;
912    execute("poly pdatum="+datum+";");
913    setring base_r;
914    poly pdatum=imap(lf,pdatum);
915    return(pdatum);
916  }
917  else
918  {
919    setring lf;
920    execute("string sdatum=string("+datum+");");
921    ring auxring=char(basering),(a,b,x,y,t),lp;
922    execute("poly pdatum="+sdatum+";");
923    execute("poly prel=b-"+rel+";");
924    ideal I=pdatum,prel;
925    I=eliminate(I,a);
926    poly newdatum=I[1];   // hopefully it was done correctly and size(I)=1 !!!!
927    newdatum=subst(newdatum,b,a);
928    string snewdatum=string(newdatum);
929    setring base_r;
930    execute("poly newdatum="+snewdatum+";");
931    kill(auxring);
932    return(newdatum);
933  }
934}
935///////////////////////////////////////////////////////////////////////////////
936static proc place (intvec Pp,int sing,list CURVE)
937{
938  // computes the "rational" places which are defined over a (closed) point
939  // Pp points to an appropriate point of the given curve
940  // creates : local rings (if they do not exist yet) and then add the
941  //   places to a list
942  //   each place is given basically by the coordinates of the point and a
943  //   list HNdevelop
944  // returns : list with all updated data of the curve
945  // if the places already exist they are not computed again
946  // if sing==1 the point is assumed singular and computes the local conductor
947  //   for all places using the local invariants of the branches
948  // if sing==2 the point is assumed singular and computes the local conductor
949  //   for all places using the Dedekind formula and local parametrizations
950  //   of the branches
951  // if sing<>1&2 the point is assumed non-singular and the local conductor
952  //   should be zero
953  list PP=list();
954  if (Pp[1]==0)
955  {
956    if (Pp[2]==0)
957    {
958      PP=Aff_SPoints[Pp[3]];
959    }
960    if (Pp[2]==1)
961    {
962      PP=Inf_Points[1][Pp[3]];
963    }
964    if (Pp[2]==2)
965    {
966      PP=Inf_Points[2][Pp[3]];
967    }
968  }
969  else
970  {
971    PP=Aff_Points(Pp[2])[Pp[3]];
972  }
973  if (PP[2]<>0)
974  {
975    return(CURVE);
976  }
977  intvec PtoPl;
978  def base_r=basering;
979  int ext1;
980  list Places=CURVE[3];
981  intvec Conductor=CURVE[4];
982  list update_CURVE=CURVE;
983  if (typeof(PP[1])=="ideal")
984  {
985    ideal P=PP[1];
986    if (size(P)==2)
987    {
988      int d=deg(P[1]);
989      poly aux=subst(P[2],y,1);
990      d=d*deg(aux);
991      ext1=d;
992      // the point is (A:B:1) but one must distinguish several cases
993      // P is assumed to be a std. resp. "(x,y),lp" and thus P[1] depends
994      // only on "y"
995      if (d==1)
996      {
997        // the point is rational
998        number B=-number(subst(P[1],y,0));
999        poly aux2=subst(P[2],y,B);
1000        number A=-number(subst(aux2,x,0));
1001        // the point is (A:B:1)
1002        ring local_aux=char(basering),(x,y),ls;
1003        number coord@1=imap(base_r,A);
1004        number coord@2=imap(base_r,B);
1005        number coord@3=number(1);
1006        map phi=base_r,x+coord@1,y+coord@2;
1007        poly CHI=phi(CHI);
1008      }
1009      else
1010      {
1011        if (deg(P[1])==1)
1012        {
1013          // the point is non-rational but the second component needs no
1014          // field extension
1015          number B=-number(subst(P[1],y,0));
1016          poly aux2=subst(P[2],y,B);
1017          // the point has degree d>1
1018          // careful : the parameter will be called "a" anyway
1019          ring local_aux=(char(basering),a),(x,y),ls;
1020          map psi=base_r,a,0;
1021          minpoly=number(psi(aux2));
1022          number coord@1=a;
1023          number coord@2=imap(base_r,B);
1024          number coord@3=number(1);
1025          // the point is (a:B:1)
1026          map phi=base_r,x+a,y+coord@2;
1027          poly CHI=phi(CHI);
1028        }
1029        else
1030        {
1031          if (deg(subst(P[2],y,1))==1)
1032          {
1033            // the point is non-rational but the needed minpoly is just P[1]
1034            // careful : the parameter will be called "a" anyway
1035            poly P1=P[1];
1036            poly P2=P[2];
1037            ring local_aux=(char(basering),a),(x,y),ls;
1038            map psi=base_r,0,a;
1039            minpoly=number(psi(P1));
1040            // the point looks like (A:a:1)
1041            // A is computed by substituting y=a in P[2]
1042            poly aux1=imap(base_r,P2);
1043            poly aux2=subst(aux1,y,a);
1044            number coord@1=-number(subst(aux2,x,0));
1045            number coord@2=a;
1046            number coord@3=number(1);
1047            map phi=base_r,x+coord@1,y+a;
1048            poly CHI=phi(CHI);
1049          }
1050          else
1051          {
1052            // this is the most complicated case of non-rational point
1053            // firstly : construct an extension of degree d and guess the
1054            //           minpoly
1055            poly P1=P[1];
1056            poly P2=P[2];
1057            int p=char(basering);
1058            int Q=p^d;
1059            ring aux_r=(Q,a),(x,y,t),ls;
1060            string minpoly_string=string(minpoly);
1061            ring local_aux=(char(basering),a),(x,y),ls;
1062            execute("minpoly="+minpoly_string+";");
1063            // secondly : compute one root of P[1]
1064            poly P_1=imap(base_r,P1);
1065            poly P_2=imap(base_r,P2);
1066            ideal factors1=factorize(P_1,1);       // hopefully this works !!!!
1067            number coord@2=-number(subst(factors1[1],y,0));
1068            // thirdly : compute one of the first components for the above root
1069            poly P_0=subst(P_2,y,coord@2);
1070            ideal factors2=factorize(P_0,1);       // hopefully this works !!!!
1071            number coord@1=-number(subst(factors2[1],x,0));
1072            number coord@3=number(1);
1073            map phi=base_r,x+coord@1,y+coord@2;
1074            poly CHI=phi(CHI);
1075            kill(aux_r);
1076          }
1077        }
1078      }
1079    }
1080    else
1081    {
1082      // this should not happen in principle
1083      ERROR("non-valid parameter");
1084    }
1085  }
1086  else
1087  {
1088    if (typeof(PP[1])=="poly")
1089    {
1090      poly P=PP[1];
1091      ring r_auxz=char(basering),(x,y,z),lp;
1092      poly CHI=imap(base_r,CHI);
1093      CHI=homog(CHI,z);
1094      setring base_r;
1095      poly aux=subst(P,y,1);
1096      if (aux==1)
1097      {
1098        // the point is (1:0:0)
1099        ring local_aux=char(basering),(x,y),ls;
1100        number coord@1=number(1);
1101        number coord@2=number(0);
1102        number coord@3=number(0);
1103        map Phi=r_auxz,1,x,y;
1104        poly CHI=Phi(CHI);
1105        ext1=1;
1106      }
1107      else
1108      {
1109        // the point is (A:1:0) where A is a root of aux
1110        int d=deg(aux);
1111        ext1=d;
1112        if (d==1)
1113        {
1114          // the point is rational
1115          number A=-number(subst(aux,x,0));
1116          ring local_aux=char(basering),(x,y),ls;
1117          number coord@1=imap(base_r,A);
1118          number coord@2=number(1);
1119          number coord@3=number(0);
1120          map Phi=r_auxz,x+coord@1,1,y;
1121          poly CHI=Phi(CHI);
1122        }
1123        else
1124        {
1125          // the point has degree d>1
1126          // careful : the parameter will be called "a" anyway
1127          ring local_aux=(char(basering),a),(x,y),ls;
1128          map psi=base_r,a,1;
1129          minpoly=number(psi(P));
1130          number coord@1=a;
1131          number coord@2=number(1);
1132          number coord@3=number(0);
1133          map Phi=r_auxz,x+a,1,y;
1134          poly CHI=Phi(CHI);
1135        }
1136      }
1137      kill(r_auxz);
1138    }
1139    else
1140    {
1141      ERROR("a point must have a poly or ideal in the first component");
1142    }
1143  }
1144  export(coord@1);
1145  export(coord@2);
1146  export(coord@3);
1147  export(CHI);
1148  int i,j,k;
1149  int m,n;
1150//  list L@HNE=essdevelop(CHI); 
1151  list LLL=ratdevelop(CHI);
1152  if (typeof(LLL[1])=="ring") {
1153    def altring=basering;
1154    def HNEring = LLL[1]; setring HNEring;
1155    def L@HNE = hne;
1156    kill hne;
1157  }
1158  else {
1159    def L@HNE=LLL;
1160    def HNEring=basering;
1161    setring HNEring;
1162  }
1163  kill LLL;
1164  export(L@HNE);
1165  int n_branches=size(L@HNE);
1166  list Li_aux=list();
1167  int N_branches;
1168  int N=size(Places);
1169  if (sing==1)
1170  {
1171    list delta2=list();
1172    for (i=1;i<=n_branches;i=i+1)
1173    {
1174      delta2[i]=invariants(L@HNE[i])[5];
1175    }
1176    int dq;
1177  }
1178  int ext2=res_deg();
1179  list dgs=list();
1180  int ext_0;
1181  int check;
1182  string sss,olda,newa;
1183  if (defined(Q)==0)
1184  {
1185    int Q;
1186  }
1187  if (ext1==1)
1188  {
1189    if (ext2==1)
1190    {
1191      if (sing==1)
1192      {
1193        intmat I_mult[n_branches][n_branches];
1194        if (n_branches>1)
1195        {
1196          for (i=1;i<=n_branches-1;i=i+1)
1197          {
1198            for (j=i+1;j<=n_branches;j=j+1)
1199            {
1200              I_mult[i,j]=intersection(L@HNE[i],L@HNE[j]);
1201              I_mult[j,i]=I_mult[i,j];
1202            }
1203          }
1204        }
1205      }
1206////////
1207check=0;
1208////////
1209      if (size(update_CURVE[5])>0)
1210      {
1211        if (typeof(update_CURVE[5][1])=="list")
1212        {
1213          check=1;
1214        }
1215      }
1216      if (check==0)
1217      {
1218        intvec dgs_points(1);
1219        ring S(1)=char(basering),(x,y,t),ls;
1220        list BRANCHES=list();
1221        list POINTS=list();
1222        list LOC_EQS=list();
1223        list PARAMETRIZATIONS=list();
1224        export(BRANCHES);
1225        export(POINTS);
1226        export(LOC_EQS);
1227        export(PARAMETRIZATIONS);
1228      }
1229      else
1230      {
1231        intvec dgs_points(1)=update_CURVE[5][1][2];
1232        def S1=update_CURVE[5][1][1];
1233        execute("ring S(1)="+string(update_CURVE[5][1][1])+";");
1234        fetchall(S1);
1235        kill(S1);
1236      }
1237      N_branches=size(BRANCHES);
1238      for (i=1;i<=n_branches;i=i+1)
1239      {
1240        dgs_points(1)[N_branches+i]=1;
1241        POINTS[N_branches+i]=list();
1242        POINTS[N_branches+i][1]=imap(local_aux,coord@1);
1243        POINTS[N_branches+i][2]=imap(local_aux,coord@2);
1244        POINTS[N_branches+i][3]=imap(local_aux,coord@3);
1245        LOC_EQS[N_branches+i]=imap(local_aux,CHI);
1246        setring HNEring;
1247        Li_aux=L@HNE[i];
1248        setring S(1);
1249        BRANCHES=insert(BRANCHES,imap(HNEring,Li_aux),N_branches+i-1);
1250        PARAMETRIZATIONS[N_branches+i]=param(BRANCHES[N_branches+i],0);
1251        N=N+1;
1252        intvec iw=1,N_branches+i;
1253        Places[N]=iw;
1254        if (sing==1)
1255        {
1256          dq=delta2[i];
1257          for (j=1;j<=n_branches;j=j+1)
1258          {
1259            dq=dq+I_mult[i,j];
1260          }
1261          Conductor[N]=dq;
1262        }
1263        if (sing==2)
1264        {
1265          Conductor[N]=local_conductor(iw[2],S(1));
1266        }
1267        kill(iw);
1268        PtoPl[i]=N;
1269      }
1270      setring base_r;
1271      update_CURVE[5][1]=list();
1272      update_CURVE[5][1][1]=S(1);
1273      update_CURVE[5][1][2]=dgs_points(1);
1274    }
1275    else
1276    {
1277      // we start with a rational point but we get non-rational branches
1278      // they may have different degrees and then we may need reduce the
1279      // field extensions for each one, and finally check if the minpoly
1280      // fetchs with S(i) or not
1281      // if one of the branches is rational, we may trust that is is written
1282      // correctly
1283      if (sing==1)
1284      {
1285        int n_geobrs;
1286        int counter_c;
1287        list auxgb=list();
1288        list geobrs=list();
1289        for (i=1;i<=n_branches;i=i+1)
1290        {
1291          auxgb=conj_bs(L@HNE[i],1);
1292          dgs[i]=size(auxgb);
1293          n_geobrs=n_geobrs+dgs[i];
1294          for (j=1;j<=dgs[i];j=j+1)
1295          {
1296            counter_c=counter_c+1;
1297            geobrs[counter_c]=auxgb[j];
1298          }
1299        }
1300        intmat I_mult[n_geobrs][n_geobrs];
1301        for (i=1;i<n_geobrs;i=i+1)
1302        {
1303          for (j=i+1;j<=n_geobrs;j=j+1)
1304          {
1305            I_mult[i,j]=intersection(geobrs[i],geobrs[j]);
1306            I_mult[j,i]=I_mult[i,j];
1307          }
1308        }
1309        kill(auxgb,geobrs);
1310      }
1311      else
1312      {
1313        for (i=1;i<=n_branches;i=i+1)
1314        {
1315          dgs[i]=grad_b(L[i],1);
1316        }
1317      }
1318      // the actual degree of each branch is computed and now check if the
1319      // local ring exists
1320      for (i=1;i<=n_branches;i=i+1)
1321      {
1322        ext_0=dgs[i];
1323////////
1324check=0;
1325////////
1326        if (size(update_CURVE[5])>=ext_0)
1327        {
1328          if (typeof(update_CURVE[5][ext_0])=="list")
1329          {
1330            check=1;
1331          }
1332        }
1333        if (check==0)
1334        {
1335          if (ext_0>1)
1336          {
1337            if (ext_0==ext2)
1338            {
1339              sss=string(minpoly);
1340            }
1341            else
1342            {
1343              Q=char(basering)^ext_0;
1344              ring auxxx=(Q,a),z,lp;
1345              sss=string(minpoly);
1346              setring base_r;
1347              kill(auxxx);
1348            }
1349            ring S(ext_0)=(char(basering),a),(x,y,t),ls;
1350            execute("minpoly="+sss+";");
1351          }
1352          else
1353          {
1354            ring S(ext_0)=char(basering),(x,y,t),ls;
1355          }
1356          intvec dgs_points(ext_0);
1357          list BRANCHES=list();
1358          list POINTS=list();
1359          list LOC_EQS=list();
1360          list PARAMETRIZATIONS=list();
1361          export(BRANCHES);
1362          export(POINTS);
1363          export(LOC_EQS);
1364          export(PARAMETRIZATIONS);
1365        }
1366        else
1367        {
1368          intvec dgs_points(ext_0)=update_CURVE[5][ext_0][2];
1369          def Sext_0=update_CURVE[5][ext_0][1];
1370          setring Sext_0;
1371          string SM=string(minpoly);
1372          string SR=string(update_CURVE[5][ext_0][1]);
1373          execute("ring S("+string(ext_0)+")="+SR+";");
1374          execute("minpoly="+SM+";");
1375          kill(SM,SR);
1376          fetchall(Sext_0);
1377          kill(Sext_0);
1378        }
1379        N_branches=size(BRANCHES);
1380        dgs_points(ext_0)[N_branches+1]=1;
1381        POINTS[N_branches+1]=list();
1382        POINTS[N_branches+1][1]=imap(local_aux,coord@1);
1383        POINTS[N_branches+1][2]=imap(local_aux,coord@2);
1384        POINTS[N_branches+1][3]=imap(local_aux,coord@3);
1385        LOC_EQS[N_branches+1]=imap(local_aux,CHI);
1386        // now fetch the branches into the new local ring
1387        if (ext_0==1)
1388        {
1389          setring HNEring;
1390          Li_aux=L@HNE[i];
1391          setring S(1);
1392          BRANCHES=insert(BRANCHES,imap(HNEring,Li_aux),N_branches);
1393        }
1394        else
1395        {
1396          // rationalize branche
1397          setring HNEring;
1398          newa=subfield(S(ext_0));
1399          m=nrows(L@HNE[i][1]);
1400          n=ncols(L@HNE[i][1]);
1401          setring S(ext_0);
1402          list Laux=list();
1403          poly paux=rationalize(HNEring,"L@HNE["+string(i)+"][4]",newa);
1404          matrix Maux[m][n];
1405          for (j=1;j<=m;j=j+1)
1406          {
1407            for (k=1;k<=n;k=k+1)
1408            {
1409              Maux[j,k]=rationalize(HNEring,"L@HNE["+string(i)+"][1]["+
1410                           string(j)+","+string(k)+"]",newa);
1411            }
1412          }
1413          setring HNEring;
1414          intvec Li2=L@HNE[i][2];
1415          int Li3=L@HNE[i][3];
1416          setring S(ext_0);
1417          Laux[1]=Maux;
1418          Laux[2]=Li2;
1419          Laux[3]=Li3;
1420          Laux[4]=paux;
1421          BRANCHES=insert(BRANCHES,Laux,N_branches);
1422          kill(Laux,Maux,paux,Li2,Li3);
1423        }
1424        PARAMETRIZATIONS[N_branches+1]=param(BRANCHES[N_branches+1],0);
1425        N=N+1;
1426        intvec iw=ext_0,N_branches+1;
1427        Places[N]=iw;
1428        if (sing==2)
1429        {
1430          Conductor[N]=local_conductor(iw[2],S(ext_0));
1431        }
1432        kill(iw);
1433        PtoPl[i]=N;
1434        setring HNEring;
1435        update_CURVE[5][ext_0]=list();
1436        update_CURVE[5][ext_0][1]=S(ext_0);
1437        update_CURVE[5][ext_0][2]=dgs_points(ext_0);
1438      }
1439      if (sing==1)
1440      {
1441        int N_ini=N-n_branches;
1442        counter_c=1;
1443        for (i=1;i<=n_branches;i=i+1)
1444        {
1445          dq=delta2[i];
1446          for (j=1;j<=n_geobrs;j=j+1)
1447          {
1448            dq=dq+I_mult[counter_c,j];
1449          }
1450          Conductor[N_ini+i]=dq;
1451          counter_c=counter_c+dgs[i];
1452        }
1453      }
1454      setring base_r;
1455    }
1456  }
1457  else
1458  {
1459    if (ext1==ext2)
1460    {
1461      // the degree of the point equals to the degree of all branches
1462      // one must just fetch the minpoly's of local_aux, HNEring and S(ext2)
1463      if (sing==1)
1464      {
1465        intmat I_mult[n_branches][n_branches];
1466        if (n_branches>1)
1467        {
1468          for (i=1;i<=n_branches-1;i=i+1)
1469          {
1470            for (j=i+1;j<=n_branches;j=j+1)
1471            {
1472              I_mult[i,j]=intersection(L@HNE[i],L@HNE[j]);
1473              I_mult[j,i]=I_mult[i,j];
1474            }
1475          }
1476        }
1477      }
1478////////
1479check=0;
1480////////
1481      if (size(update_CURVE[5])>=ext2)
1482      {
1483        if (typeof(update_CURVE[5][ext2])=="list")
1484        {
1485          check=1;
1486        }
1487      }
1488      if (check==0)
1489      {
1490        sss=string(minpoly);
1491        ring S(ext2)=(char(basering),a),(x,y,t),ls;
1492        execute("minpoly="+sss+";");
1493        intvec dgs_points(ext2);
1494        list BRANCHES=list();
1495        list POINTS=list();
1496        list LOC_EQS=list();
1497        list PARAMETRIZATIONS=list();
1498        export(BRANCHES);
1499        export(POINTS);
1500        export(LOC_EQS);
1501        export(PARAMETRIZATIONS);
1502      }
1503      else
1504      {
1505        intvec dgs_points(ext2)=update_CURVE[5][ext2][2];
1506        def Sext2=update_CURVE[5][ext2][1];
1507        setring Sext2;
1508        string SM=string(minpoly);
1509        string SR=string(update_CURVE[5][ext2][1]);
1510        execute("ring S("+string(ext2)+")="+SR+";");
1511        execute("minpoly="+SM+";");
1512        kill(SM,SR);
1513        fetchall(Sext2);
1514        kill(Sext2);
1515      }
1516      N_branches=size(BRANCHES);
1517      for (i=1;i<=n_branches;i=i+1)
1518      {
1519        // fetch all the data into the new local ring
1520        olda=subfield(local_aux);
1521        dgs_points(ext2)[N_branches+i]=ext1;
1522        POINTS[N_branches+i]=list();
1523        POINTS[N_branches+i][1]=number(importdatum(local_aux,"coord@1",olda));
1524        POINTS[N_branches+i][2]=number(importdatum(local_aux,"coord@2",olda));
1525        POINTS[N_branches+i][3]=number(importdatum(local_aux,"coord@3",olda));
1526        LOC_EQS[N_branches+i]=importdatum(local_aux,"CHI",olda);
1527        newa=subfield(HNEring);
1528        setring HNEring;
1529        m=nrows(L@HNE[i][1]);
1530        n=ncols(L@HNE[i][1]);
1531        setring S(ext2);
1532        list Laux=list();
1533        poly paux=importdatum(HNEring,"L@HNE["+string(i)+"][4]",newa);
1534        matrix Maux[m][n];
1535        for (j=1;j<=m;j=j+1)
1536        {
1537          for (k=1;k<=n;k=k+1)
1538          {
1539            Maux[j,k]=importdatum(HNEring,"L@HNE["+string(i)+"][1]["+
1540                                   string(j)+","+string(k)+"]",newa);
1541          }
1542        }
1543        setring HNEring;
1544        intvec Li2=L@HNE[i][2];
1545        int Li3=L@HNE[i][3];
1546        setring S(ext2);
1547        Laux[1]=Maux;
1548        Laux[2]=Li2;
1549        Laux[3]=Li3;
1550        Laux[4]=paux;
1551        BRANCHES=insert(BRANCHES,Laux,N_branches+i-1);
1552        kill(Laux,Maux,paux,Li2,Li3);
1553        PARAMETRIZATIONS[N_branches+i]=param(BRANCHES[N_branches+i],0);
1554        N=N+1;
1555        intvec iw=ext2,N_branches+i;
1556        Places[N]=iw;
1557        if (sing==1)
1558        {
1559          dq=delta2[i];
1560          for (j=1;j<=n_branches;j=j+1)
1561          {
1562            dq=dq+I_mult[i,j];
1563          }
1564          Conductor[N]=dq;
1565        }
1566        if (sing==2)
1567        {
1568          Conductor[N]=local_conductor(iw[2],S(ext2));
1569        }
1570        kill(iw);
1571        PtoPl[i]=N;
1572      }
1573      setring base_r;
1574      update_CURVE[5][ext2]=list();
1575      update_CURVE[5][ext2][1]=S(ext2);
1576      update_CURVE[5][ext2][2]=dgs_points(ext2);
1577    }
1578    else
1579    {
1580      // this is the most complicated case
1581      if (sing==1)
1582      {
1583        int n_geobrs;
1584        int counter_c;
1585        list auxgb=list();
1586        list geobrs=list();
1587        for (i=1;i<=n_branches;i=i+1)
1588        {
1589          auxgb=conj_bs(L@HNE[i],ext1);
1590          dgs[i]=size(auxgb);
1591          n_geobrs=n_geobrs+dgs[i];
1592          for (j=1;j<=dgs[i];j=j+1)
1593          {
1594            counter_c=counter_c+1;
1595            geobrs[counter_c]=auxgb[j];
1596          }
1597        }
1598        intmat I_mult[n_geobrs][n_geobrs];
1599        for (i=1;i<n_geobrs;i=i+1)
1600        {
1601          for (j=i+1;j<=n_geobrs;j=j+1)
1602          {
1603            I_mult[i,j]=intersection(geobrs[i],geobrs[j]);
1604            I_mult[j,i]=I_mult[i,j];
1605          }
1606        }
1607        kill(auxgb,geobrs);
1608      }
1609      else
1610      {
1611        for (i=1;i<=n_branches;i=i+1)
1612        {
1613          dgs[i]=grad_b(L@HNE[i],ext1);
1614        }
1615      }
1616      for (i=1;i<=n_branches;i=i+1)
1617      {
1618        // first compute the actual degree of each branch and check if the
1619        // local ring exists
1620        ext_0=ext1*dgs[i];
1621////////
1622check=0;
1623////////
1624        if (size(update_CURVE[5])>=ext_0)
1625        {
1626          if (typeof(update_CURVE[5][ext_0])=="list")
1627          {
1628            check=1;
1629          }
1630        }
1631        if (check==0)
1632        {
1633          if (ext_0>ext1)
1634          {
1635            if (ext_0==ext2)
1636            {
1637              sss=string(minpoly);
1638            }
1639            else
1640            {
1641              Q=char(basering)^ext_0;
1642              ring auxxx=(Q,a),z,lp;
1643              sss=string(minpoly);
1644              setring base_r;
1645              kill(auxxx);
1646            }
1647          }
1648          else
1649          {
1650            setring local_aux;
1651            sss=string(minpoly);
1652          }
1653          ring S(ext_0)=(char(basering),a),(x,y,t),ls;
1654          execute("minpoly="+sss+";");
1655          intvec dgs_points(ext_0);
1656          list BRANCHES=list();
1657          list POINTS=list();
1658          list LOC_EQS=list();
1659          list PARAMETRIZATIONS=list();
1660          export(BRANCHES);
1661          export(POINTS);
1662          export(LOC_EQS);
1663          export(PARAMETRIZATIONS);
1664        }
1665        else
1666        {
1667          intvec dgs_points(ext_0)=update_CURVE[5][ext_0][2];
1668          def Sext_0=update_CURVE[5][ext_0][1];
1669          setring Sext_0;
1670          string SM=string(minpoly);
1671          string SR=string(update_CURVE[5][ext_0][1]);
1672          execute("ring S("+string(ext_0)+")="+SR+";");
1673          execute("minpoly="+SM+";");
1674          kill(SM,SR);
1675          fetchall(badring);
1676          kill(badring);
1677        }
1678        N_branches=size(BRANCHES);
1679        // now fetch all the data into the new local ring
1680        olda=subfield(local_aux);
1681        dgs_points(ext_0)[N_branches+1]=ext1;
1682        POINTS[N_branches+1]=list();
1683        POINTS[N_branches+1][1]=number(importdatum(local_aux,"coord@1",olda));
1684        POINTS[N_branches+1][2]=number(importdatum(local_aux,"coord@2",olda));
1685        POINTS[N_branches+1][3]=number(importdatum(local_aux,"coord@3",olda));
1686        LOC_EQS[N_branches+1]=importdatum(local_aux,"CHI",olda);
1687        setring HNEring;
1688        newa=subfield(S(ext_0));
1689        m=nrows(L@HNE[i][1]);
1690        n=ncols(L@HNE[i][1]);
1691        setring S(ext_0);
1692        list Laux=list();
1693        poly paux=rationalize(HNEring,"L@HNE["+string(i)+"][4]",newa);
1694        matrix Maux[m][n];
1695        for (j=1;j<=m;j=j+1)
1696        {
1697          for (k=1;k<=n;k=k+1)
1698          {
1699            Maux[j,k]=rationalize(HNEring,"L@HNE["+string(i)+"][1]["+
1700               string(j)+","+string(k)+"]",newa);
1701          }
1702        }
1703        setring HNEring;
1704        intvec Li2=L@HNE[i][2];
1705        int Li3=L@HNE[i][3];
1706        setring S(ext_0);
1707        Laux[1]=Maux;
1708        Laux[2]=Li2;
1709        Laux[3]=Li3;
1710        Laux[4]=paux;
1711        BRANCHES=insert(BRANCHES,Laux,N_branches);
1712        kill(Laux,Maux,paux,Li2,Li3);
1713        PARAMETRIZATIONS[N_branches+1]=param(BRANCHES[N_branches+1],0);
1714        N=N+1;
1715        intvec iw=ext_0,N_branches+1;
1716        Places[N]=iw;
1717        if (sing==2)
1718        {
1719          Conductor[N]=local_conductor(iw[2],S(ext_0));
1720        }
1721        kill(iw);
1722        PtoPl[i]=N;
1723        setring HNEring;
1724        update_CURVE[5][ext_0]=list();
1725        update_CURVE[5][ext_0][1]=S(ext_0);
1726        update_CURVE[5][ext_0][2]=dgs_points(ext_0);
1727      }
1728      if (sing==1)
1729      {
1730        int N_ini=N-n_branches;
1731        counter_c=1;
1732        for (i=1;i<=n_branches;i=i+1)
1733        {
1734          dq=delta2[i];
1735          for (j=1;j<=n_geobrs;j=j+1)
1736          {
1737            dq=dq+I_mult[counter_c,j];
1738          }
1739          Conductor[N_ini+i]=dq;
1740          counter_c=counter_c+dgs[i];
1741        }
1742      }
1743      setring base_r;
1744    }
1745  }
1746  update_CURVE[3]=Places;
1747  update_CURVE[4]=Conductor;
1748  PP[2]=PtoPl;
1749  if (Pp[1]==0)
1750  {
1751    if (Pp[2]==0)
1752    {
1753      Aff_SPoints[Pp[3]]=PP;
1754    }
1755    if (Pp[2]==1)
1756    {
1757      Inf_Points[1][Pp[3]]=PP;
1758    }
1759    if (Pp[2]==2)
1760    {
1761      Inf_Points[2][Pp[3]]=PP;
1762    }
1763  }
1764  else
1765  {
1766    Aff_Points(Pp[2])[Pp[3]]=PP;
1767  }
1768  update_CURVE[1][1]=base_r;
1769  kill(HNEring);
1770  kill(local_aux);
1771  return(update_CURVE);
1772}
1773///////////////////////////////////////////////////////////////////////////////
1774static proc local_conductor (int k,SS)
1775{
1776  // computes the degree of the local conductor at a place of a plane curve
1777  // if the point is non-singular the result will be zero
1778  // the computation is carried out with the "Dedekind formula" via
1779  // parametrizations
1780  int a,b,Cq;
1781  def b_ring=basering;
1782  setring SS;
1783  poly fx=diff(LOC_EQS[k],x);
1784  poly fy=diff(LOC_EQS[k],y);
1785  int nr=ncols(BRANCHES[k][1]);
1786  poly xt=PARAMETRIZATIONS[k][1][1];
1787  poly yt=PARAMETRIZATIONS[k][1][2];
1788  int ordx=PARAMETRIZATIONS[k][2][1];
1789  int ordy=PARAMETRIZATIONS[k][2][2];
1790  map phi_t=basering,xt,yt,1;
1791  poly derf;
1792  if (fx<>0)
1793  {
1794    derf=fx;
1795    poly tt=diff(yt,t);
1796    b=mindeg(tt);
1797    if (ordy>-1)
1798    {
1799      while (b>=ordy)
1800      {
1801        BRANCHES[k]=extdevelop(BRANCHES[k],2*nr);
1802        nr=ncols(BRANCHES[k][1]);
1803        PARAMETRIZATIONS[k]=param(BRANCHES[k],0);
1804        ordy=PARAMETRIZATIONS[k][2][2];
1805        yt=PARAMETRIZATIONS[k][1][2];
1806        tt=diff(yt,t);
1807        b=mindeg(tt);
1808      }
1809      xt=PARAMETRIZATIONS[k][1][1];
1810      ordx=PARAMETRIZATIONS[k][2][1];
1811    }
1812    poly ft=phi_t(derf);
1813  }
1814  else
1815  {
1816    derf=fy;
1817    poly tt=diff(xt,t);
1818    b=mindeg(tt);
1819    if (ordx>-1)
1820    {
1821      while (b>=ordx)
1822      {
1823        BRANCHES[k]=extdevelop(BRANCHES[k],2*nr);
1824        nr=ncols(BRANCHES[k][1]);
1825        PARAMETRIZATIONS[k]=param(BRANCHES[k],0);
1826        ordx=PARAMETRIZATIONS[k][2][1];
1827        xt=PARAMETRIZATIONS[k][1][1];
1828        tt=diff(xt,t);
1829        b=mindeg(tt);
1830      }
1831      yt=PARAMETRIZATIONS[k][1][2];
1832      ordy=PARAMETRIZATIONS[k][2][2];
1833    }
1834    poly ft=phi_t(derf);
1835  }
1836  a=mindeg(ft);
1837  if ( ordx>-1 || ordy>-1 )
1838  {
1839    if (ordy==-1)
1840    {
1841      while (a>ordx)
1842      {
1843        BRANCHES[k]=extdevelop(BRANCHES[k],2*nr);
1844        nr=ncols(BRANCHES[k][1]);
1845        PARAMETRIZATIONS[k]=param(BRANCHES[k],0);
1846        ordx=PARAMETRIZATIONS[k][2][1];
1847        xt=PARAMETRIZATIONS[k][1][1];
1848        ft=phi_t(derf);
1849        a=mindeg(ft);
1850      }
1851    }
1852    else
1853    {
1854      if (ordx==-1)
1855      {
1856        while (a>ordy)
1857        {
1858          BRANCHES[k]=extdevelop(BRANCHES[k],2*nr);
1859          nr=ncols(BRANCHES[k][1]);
1860          PARAMETRIZATIONS[k]=param(BRANCHES[k],0);
1861          ordy=PARAMETRIZATIONS[k][2][2];
1862          yt=PARAMETRIZATIONS[k][1][2];
1863          ft=phi_t(derf);
1864          a=mindeg(ft);
1865        }
1866      }
1867      else
1868      {
1869        int ordf=ordx;
1870        if (ordx>ordy)
1871        {
1872          ordf=ordy;
1873        }
1874        while (a>ordf)
1875        {
1876          BRANCHES[k]=extdevelop(BRANCHES[k],2*nr);
1877          nr=ncols(BRANCHES[k][1]);
1878          PARAMETRIZATIONS[k]=param(BRANCHES[k],0);
1879          ordx=PARAMETRIZATIONS[k][2][1];
1880          ordy=PARAMETRIZATIONS[k][2][2];
1881          ordf=ordx;
1882          if (ordx>ordy)
1883          {
1884            ordf=ordy;
1885          }
1886          xt=PARAMETRIZATIONS[k][1][1];
1887          yt=PARAMETRIZATIONS[k][1][2];
1888          ft=phi_t(derf);
1889          a=mindeg(ft);
1890        }
1891      }
1892    }
1893  }
1894  Cq=a-b;
1895  setring b_ring;
1896  return(Cq);
1897}
1898///////////////////////////////////////////////////////////////////////////////
1899static proc max_D (intvec D1,intvec D2)
1900{
1901  // computes the maximum of two divisors (intvec)
1902  int s1=size(D1);
1903  int s2=size(D2);
1904  int i;
1905  if (s1>s2)
1906  {
1907    for (i=1;i<=s2;i=i+1)
1908    {
1909      if (D2[i]>D1[i])
1910      {
1911        D1[i]=D2[i];
1912      }
1913    }
1914    for (i=s2+1;i<=s1;i=i+1)
1915    {
1916      if (D1[i]<0)
1917      {
1918        D1[i]=0;
1919      }
1920    }
1921    return(D1);
1922  }
1923  else
1924  {
1925    for (i=1;i<=s1;i=i+1)
1926    {
1927      if (D1[i]>D2[i])
1928      {
1929        D2[i]=D1[i];
1930      }
1931    }
1932    for (i=s1+1;i<=s2;i=i+1)
1933    {
1934      if (D2[i]<0)
1935      {
1936        D2[i]=0;
1937      }
1938    }
1939    return(D2);
1940  }
1941}
1942///////////////////////////////////////////////////////////////////////////////
1943static proc deg_D (intvec D,list PP)
1944{
1945  // computes the degree of a divisor (intvec or list of integers)
1946  int i;
1947  int d=0;
1948  int s=size(D);
1949  for (i=1;i<=s;i=i+1)
1950  {
1951    d=d+D[i]*PP[i][1];
1952  }
1953  return(d);
1954}
1955///////////////////////////////////////////////////////////////////////////////
1956
1957// ============================================================================
1958// *******  MAIN PROCEDURES for the "preprocessing" of Brill-Noether   ********
1959// ============================================================================
1960
1961proc Adj_div (poly f,list #)
1962"USAGE:    Adj_div( f [,l] ); f a poly, [l a list]
1963RETURN:   list L with the computed data:
1964  @format
1965  L[1] a list of rings: L[1][1]=aff_r (affine), L[1][2]=Proj_R (projective),
1966  L[2] an intvec with 2 entries (degree, genus),
1967  L[3] a list of intvec (closed places),
1968  L[4] an intvec (conductor),
1969  L[5] a list of lists:
1970     L[5][d][1] a (local) ring over an extension of degree d,
1971     L[5][d][2] an intvec (degrees of base points of places of degree d)
1972  @end format
1973NOTE:     @code{Adj_div(f);} computes and stores the fundamental data of the
1974          plane curve defined by f as needed for AG codes.
1975          In the affine ring you can find the following data:
1976   @format
1977   poly CHI:  affine equation of the curve,
1978   ideal Aff_SLocus:  affine singular locus (std),
1979   list Inf_Points:  points at infinity
1980            Inf_Points[1]:  singular points
1981            Inf_Points[2]:  non-singular points,
1982   list Aff_SPoints:  affine singular points (if not empty).
1983   @end format
1984          In the projective ring you can find the projective equation
1985          CHI of the curve (poly).
1986          In the local rings L[5][d][1] you find:
1987   @format
1988   list POINTS:  base points of the places of degree d,
1989   list LOC_EQS:  local equations of the curve at the base points,
1990   list BRANCHES:  Hamburger-Noether developments of the places,
1991   list PARAMETRIZATIONS:  local parametrizations of the places,
1992   @end format
1993          Each entry of the list L[3] corresponds to one closed place (i.e.,
1994          a place and all its conjugates) which is represented by an intvec
1995          of size two, the first entry is the degree of the place (in
1996          particular, it tells the local ring where to find the data
1997          describing one representative of the closed place), and the
1998          second one is the position of those data in the lists POINTS, etc.,
1999          inside this local ring.@*
2000          In the intvec L[4] (conductor) the i-th entry corresponds to the
2001          i-th entry in the list of places L[3].
2002
2003          With no optional arguments, the conductor is computed by
2004          local invariants of the singularities; otherwise it is computed
2005          by the Dedekind formula. @*
2006          An affine point is represented by a list P where P[1] is std
2007          of a prime ideal and P[2] is an intvec containing the position
2008          of the places above P in the list of closed places L[3]. @*
2009          If the point is at infinity, P[1] is a homogeneous irreducible
2010          polynomial in two variables.
2011
2012          If @code{printlevel>=0} additional comments are displayed (default:
2013          @code{printlevel=0}).
2014WARNING:  The parameter of the needed field extensions is called 'a'. Thus,
2015          there should be no global object named 'a' when executing Adj_div.
2016KEYWORDS: Hamburger-Noether expansions; adjunction divisor
2017SEE ALSO: closed_points, NSplaces
2018EXAMPLE:  example Adj_div; shows an example
2019"
2020{
2021  // computes the adjunction divisor and the genus of a (singular) plane curve
2022  // as a byproduct, it computes all the singular points with the corresponding
2023  //      places and the genus of the curve
2024  // the adjunction divisor is stored in an intvec
2025  // also the non-singular places at infinity are computed
2026  // returns a list with all the computed data
2027  if (char(basering)==0)
2028  {
2029    ERROR("Base field not implemented");
2030  }
2031  if (npars(basering)>0)
2032  {
2033    ERROR("Base field not implemented");
2034  }
2035  if (defined(a)==1)
2036  {
2037    if ((typeof(a)=="int") or (typeof(a)=="intvec") or (typeof(a)=="intmat") or
2038        (typeof(a)=="string") or (typeof(a)=="proc") or (typeof(a)=="list"))
2039    {
2040      print("WARNING: There is an object named 'a' of the global type "
2041             + typeof(a)+".");
2042      print("This will cause problems when "
2043             + "executing Adj_div, as 'a' is used for "
2044             + "the name of the parameter of the field extensions needed.");
2045      ERROR("Please rename or kill the object named 'a'");
2046    }
2047  }
2048  intvec opgt=option(get);
2049  option(redSB);
2050  def Base_R=basering;
2051  list CURVE=curve(f);
2052  def aff_r=CURVE[1];
2053  def Proj_R=CURVE[2];
2054  int degX=CURVE[3];
2055  int genusX=(degX-1)*(degX-2);
2056  genusX = genusX div 2;
2057  intvec iivv=degX,genusX;
2058  intvec Conductor;
2059  setring aff_r;
2060  dbprint(printlevel+1,"Computing affine singular points ... ");
2061  list Aff_SPoints=Aff_SL(Aff_SLocus);
2062  int s=size(Aff_SPoints);
2063  if (s>0)
2064  {
2065    export(Aff_SPoints);
2066  }
2067  dbprint(printlevel+1,"Computing all points at infinity ... ");
2068  list Inf_Points=inf_P(CHI);
2069  export(Inf_Points);
2070  list update_CURVE=list();
2071  update_CURVE[1]=list();
2072  update_CURVE[1][1]=aff_r;
2073  update_CURVE[1][2]=Proj_R;
2074  update_CURVE[2]=iivv;
2075  update_CURVE[3]=list();
2076  update_CURVE[4]=Conductor;
2077  update_CURVE[5]=list();
2078  int i;
2079  intvec pP=0,0,0;
2080  if (size(#)==0)
2081  {
2082    dbprint(printlevel+1,"Computing affine singular places ... ");
2083    if (s>0)
2084    {
2085      for (i=1;i<=s;i=i+1)
2086      {
2087        pP[3]=i;
2088        update_CURVE=place(pP,1,update_CURVE);
2089      }
2090    }
2091    dbprint(printlevel+1,"Computing singular places at infinity ... ");
2092    s=size(Inf_Points[1]);
2093    if (s>0)
2094    {
2095      pP[2]=1;
2096      for (i=1;i<=s;i=i+1)
2097      {
2098        pP[3]=i;
2099        update_CURVE=place(pP,1,update_CURVE);
2100      }
2101    }
2102  }
2103  else
2104  {
2105    dbprint(printlevel+1,"Computing affine singular places ... ");
2106    s=size(Aff_SPoints);
2107    if (s>0)
2108    {
2109      for (i=1;i<=s;i=i+1)
2110      {
2111        pP[3]=i;
2112        update_CURVE=place(pP,2,update_CURVE);
2113      }
2114    }
2115    dbprint(printlevel+1,"Computing singular places at infinity ... ");
2116    s=size(Inf_Points[1]);
2117    if (s>0)
2118    {
2119      pP[2]=1;
2120      for (i=1;i<=s;i=i+1)
2121      {
2122        pP[3]=i;
2123        update_CURVE=place(pP,2,update_CURVE);
2124      }
2125    }
2126  }
2127  dbprint(printlevel+1,"Computing non-singular places at infinity ... ");
2128  s=size(Inf_Points[2]);
2129  if (s>0)
2130  {
2131    pP[2]=2;
2132    for (i=1;i<=s;i=i+1)
2133    {
2134      pP[3]=i;
2135      update_CURVE=place(pP,0,update_CURVE);
2136    }
2137  }
2138  dbprint(printlevel+1,"Adjunction divisor computed successfully");
2139  list Places=update_CURVE[3];
2140  Conductor=update_CURVE[4];
2141  genusX = genusX - (deg_D(Conductor,Places) div 2);
2142  update_CURVE[2][2]=genusX;
2143  setring Base_R;
2144  dbprint(printlevel+1," ");
2145  dbprint(printlevel+2,"The genus of the curve is "+string(genusX));
2146  option(set,opgt);
2147  return(update_CURVE);
2148}
2149example
2150{
2151  "EXAMPLE:";  echo = 2;
2152  int plevel=printlevel;
2153  printlevel=-1;
2154  ring s=2,(x,y),lp;
2155  list C=Adj_div(y9+y8+xy6+x2y3+y2+x3);
2156  def aff_R=C[1][1];      // the affine ring
2157  setring aff_R;
2158  listvar(aff_R);         // data in the affine ring
2159  CHI;                    // affine equation of the curve
2160  Aff_SLocus;             // ideal of the affine singular locus
2161  Aff_SPoints[1];         // 1st affine singular point: (1:1:1), no.1
2162  Inf_Points[1];          // singular point(s) at infinity: (1:0:0), no.4
2163  Inf_Points[2];          // list of non-singular points at infinity
2164  //
2165  pause("press RETURN");
2166  def proj_R=C[1][2];     // the projective ring
2167  setring proj_R;
2168  CHI;                    // projective equation of the curve
2169  C[2][1];                // degree of the curve
2170  C[2][2];                // genus of the curve
2171  C[3];                   // list of computed places
2172  C[4];                   // adjunction divisor (all points are singular!)
2173  //
2174  pause("press RETURN");
2175  // we look at the place(s) of degree 2 by changing to the ring
2176  C[5][2][1];
2177  def S(2)=C[5][2][1];
2178  setring S(2);
2179  POINTS;                // base point(s) of place(s) of degree 2: (1:a:1)
2180  LOC_EQS;               // local equation(s)
2181  PARAMETRIZATIONS;      // parametrization(s) and exactness
2182  BRANCHES;              // Hamburger-Noether development
2183  printlevel=plevel;
2184}
2185///////////////////////////////////////////////////////////////////////////////
2186
2187proc NSplaces (intvec h,list CURVE)
2188"USAGE:   NSplaces( h, CURVE ), where h is an intvec and CURVE is a list
2189RETURN:   list L with updated data of CURVE after computing all non-singular
2190          affine closed places whose degrees are in the intvec h: @*
2191   @format
2192   in L[1][1]: (affine ring) lists Aff_Points(d) with affine non-singular
2193               (closed) points of degree d (if non-empty),
2194   in L[3]:    the newly computed closed places are added,
2195   in L[5]:    local rings created/updated to store (repres. of) new places.
2196   @end format
2197          See @ref{Adj_div} for a description of the entries in L.
2198NOTE:     The list_expression should be the output of the procedure Adj_div.@*
2199          Raising @code{printlevel}, additional comments are displayed
2200          (default: @code{printlevel=0}).
2201WARNING:  The parameter of the needed field extensions is called 'a'. Thus,
2202          there should be no global object named 'a' when executing NSplaces.
2203SEE ALSO: closed_points, Adj_div
2204EXAMPLE:  example NSplaces; shows an example
2205"
2206{
2207  // computes all the non-singular affine (closed) places with fixed degrees
2208  // creates lists of points and the corresponding places
2209  // list CURVE must be the output of the procedure "Adj_div"
2210  // notice : if h==0 then nothing is done
2211  // warning : non-positive entries are forgotten
2212  if (defined(a)==1)
2213  {
2214    if ((typeof(a)=="int") or (typeof(a)=="intvec") or (typeof(a)=="intmat") or
2215        (typeof(a)=="string") or (typeof(a)=="proc") or (typeof(a)=="list"))
2216    {
2217      print("WARNING: There is an object named 'a' of the global type "
2218             + typeof(a)+".");
2219      print("This will cause problems when "
2220             + "executing Adj_div, as 'a' is used for "
2221             + "the name of the parameter of the field extensions needed.");
2222      ERROR("Please rename or kill the object named 'a'");
2223    }
2224  }
2225  if (h==0)
2226  {
2227    return(CURVE);
2228  }
2229  intvec opgt=option(get);
2230  option(redSB);
2231  def Base_R=basering;
2232  def aff_r=CURVE[1][1];
2233  int M=size(h);
2234  list update_CURVE=CURVE;
2235  int i,j,l,s;
2236  setring aff_r;
2237  intvec pP=1,0,0;
2238  for (i=1;i<=M;i=i+1)
2239  {
2240    l=h[i];
2241    if (l>0)
2242    {
2243      dbprint(printlevel+1,"Computing non-singular affine places of degree "
2244                             +string(l)+" ... ");
2245      if (defined(Aff_Points(l))==0)
2246      {
2247        list Aff_Points(l)=closed_points_deg(CHI,l,Aff_SLocus);
2248        s=size(Aff_Points(l));
2249        if (s>0)
2250        {
2251          export(Aff_Points(l));
2252          pP[2]=l;
2253          for (j=1;j<=s;j=j+1)
2254          {
2255            dbprint(printlevel-voice-2,"Place No.\ "+string(j));
2256            pP[3]=j;
2257            update_CURVE=place(pP,0,update_CURVE);
2258          }
2259        }
2260      }
2261    }
2262  }
2263  setring Base_R;
2264  option(set,opgt);
2265  return(update_CURVE);
2266}
2267example
2268{
2269  "EXAMPLE:";  echo = 2;
2270  int plevel=printlevel;
2271  printlevel=-1;
2272  ring s=2,(x,y),lp;
2273  list C=Adj_div(x3y+y3+x);
2274  // The list of computed places:
2275  C[3];
2276  // create places up to degree 4
2277  list L=NSplaces(1..4,C);
2278  // The list of computed places is now:
2279  L[3];
2280  // e.g., affine non-singular points of degree 4 :
2281  def aff_r=L[1][1];
2282  setring aff_r;
2283  Aff_Points(4);
2284  // e.g., base point of the 1st place of degree 4 :
2285  def S(4)=L[5][4][1];
2286  setring S(4);
2287  POINTS[1];
2288  printlevel=plevel;
2289}
2290///////////////////////////////////////////////////////////////////////////////
2291
2292// ** SPECIAL PROCEDURES FOR LINEAR ALGEBRA **
2293
2294static proc Ker (matrix A)
2295{
2296  // warning : "lp" ordering is necessary
2297  intvec opgt=option(get);
2298  option(redSB);
2299  matrix M=transpose(syz(A));
2300  option(set,opgt);
2301  return(M);
2302}
2303///////////////////////////////////////////////////////////////////////////////
2304static proc get_NZsol (matrix A)
2305{
2306  matrix sol=Ker(A);
2307  return(submat(sol,1..1,1..ncols(sol)));
2308}
2309///////////////////////////////////////////////////////////////////////////////
2310static proc supplement (matrix W,matrix V)
2311"USAGE:     supplement(W,V), where W,V are matrices of numbers such that the
2312            vector space generated by the rows of W is contained in that
2313            generated by the rows of V
2314RETURN:     matrix whose rows generate a supplementary vector space of W in V,
2315            or a zero row-matrix if <W>==<V>
2316NOTE:       W,V must be given with maximal rank
2317"
2318{
2319  // W and V represent independent sets of vectors and <W> is assumed to be
2320  // contained in <V>
2321  // computes matrix S whose rows are l.i. vectors s.t. <W> union <S> is a
2322  // basis of <V>
2323  // careful : the size of all vectors is assumed to be the same but it is
2324  //  not checked and neither the linear independence of the vectors is checked
2325  // the trivial case W=0 is not covered by this procedure (and thus V<>0)
2326  // if <W>=<V> then a zero row-matrix is returned
2327  // warning : option(redSB) must be set in advance
2328  int n1=nrows(W);
2329  int n2=nrows(V);
2330  int s=n2-n1;
2331  if (s==0)
2332  {
2333    int n=ncols(W);
2334    matrix HH[1][n];
2335    return(HH);
2336  }
2337  matrix H=transpose(lift(transpose(V),transpose(W)));
2338  H=supplem(H);
2339  return(H*V);
2340}
2341///////////////////////////////////////////////////////////////////////////////
2342static proc supplem (matrix M)
2343"USAGE:      suplement(M), where M is a matrix of numbers with maximal rank
2344RETURN:     matrix whose rows generate a supplementary vector space of <M> in
2345            k^n, where k is the base field and n is the number of columns
2346SEE ALSO:   supplement
2347NOTE:       The rank r is assumed to be 1<r<n.
2348"
2349{
2350  // warning : the linear independence of the rows is not checked
2351  int r=nrows(M);
2352  int n=ncols(M);
2353  int s=n-r;
2354  matrix A=M;
2355  matrix supl[s][n];
2356  int counter=0;
2357  int h=r+1;
2358  int i;
2359  for (i=1;i<=n;i=i+1)
2360  {
2361    matrix TT[1][n];
2362    TT[1,i]=1;
2363    A=transpose(concat(transpose(A),transpose(TT)));
2364    r=mat_rank(A);
2365    if (r==h)
2366    {
2367      h=h+1;
2368      counter=counter+1;
2369      supl=transpose(concat(transpose(supl),transpose(TT)));
2370      if (counter==s)
2371      {
2372        break;
2373      }
2374    }
2375    kill(TT);
2376  }
2377  supl=transpose(compress(transpose(supl)));
2378  return(supl);
2379}
2380///////////////////////////////////////////////////////////////////////////////
2381static proc mat_rank (matrix A)
2382{
2383  // warning : "lp" ordering is necessary
2384  intvec opgt=option(get);
2385  option(redSB);
2386  int r=size(std(module(transpose(A))));
2387  option(set,opgt);
2388  return(r);
2389}
2390///////////////////////////////////////////////////////////////////////////////
2391
2392// ***************************************************************
2393// * PROCEDURES FOR INTERPOLATION, INTERSECTION AND EXTRA PLACES *
2394// ***************************************************************
2395
2396static proc estim_n (intvec Dplus,int dgX,list PL)
2397{
2398  // computes an estimate for the degree n in the Brill-Noether algorithm
2399  int estim=2*deg_D(Dplus,PL)+dgX*(dgX-3);
2400  estim=estim div (2*dgX);
2401  estim=estim+1;
2402  if (estim<dgX)
2403  {
2404    estim=dgX;
2405  }
2406  return(estim);
2407}
2408///////////////////////////////////////////////////////////////////////////////
2409static proc nforms (int n)
2410{
2411  // computes the list of all homogeneous monomials of degree n>=0
2412  // exports ideal nFORMS(n) whose generators are ranged with lp order
2413  //   in Proj_R and returns size(nFORMS(n))
2414  // warning : it is supposed to be called inside Proj_R
2415  // if n<=0 then nFORMS(0) is "computed fast"
2416  ideal nFORMS(n);
2417  int N;
2418  if (n>0)
2419  {
2420    N=(n+1)*(n+2);
2421    N=N div 2;
2422    N=N+1;
2423    int i,j,k;
2424    for (i=0;i<=n;i=i+1)
2425    {
2426      for (j=0;j<=n-i;j=j+1)
2427      {
2428        k=k+1;
2429        nFORMS(n)[N-k]=x^i*y^j*z^(n-i-j);
2430      }
2431    }
2432    export(nFORMS(n));
2433  }
2434  else
2435  {
2436    N=2;
2437    nFORMS(0)=1;
2438    export(nFORMS(0));
2439  }
2440  return(N-1);
2441}
2442///////////////////////////////////////////////////////////////////////////////
2443static proc nmultiples (int n,int dgX,poly f)
2444{
2445  // computes a basis of the space of forms of degree n which are multiple of
2446  //     CHI
2447  // returns a matrix whose rows are the coordinates (related to nFORMS(n))
2448  //     of such a basis
2449  // warning : it is supposed to be called inside Proj_R
2450  // warning : nFORMS(n) is created in the way, together with nFORMS(n-degX)
2451  // warning : n must be greater or equal than the degree of the curve
2452  if (defined(nFORMS(n))==0)
2453  {
2454    dbprint(printlevel+1,string(nforms(n)));
2455  }
2456  int m=n-dgX;
2457  if (defined(nFORMS(m))==0)
2458  {
2459    int k=nforms(m);
2460  }
2461  else
2462  {
2463    int k=size(nFORMS(m));
2464  }
2465  ideal nmults;
2466  int i;
2467  for (i=1;i<=k;i=i+1)
2468  {
2469    nmults[i]=f*nFORMS(m)[i];
2470  }
2471  return(transpose(lift(nFORMS(n),nmults)));
2472}
2473///////////////////////////////////////////////////////////////////////////////
2474static proc interpolating_forms (intvec D,int n,list CURVE)
2475{
2476  // computes a vector basis of the space of forms of degree n whose
2477  //     intersection divisor with the curve is greater or equal than D>=0
2478  // the procedure is supposed to be called inside the ring Proj_R and
2479  //     assumes that the forms nFORMS(n) are previously computed
2480  // the output is a matrix whose rows are the coordinates in nFORMS(n) of
2481  //     such a basis
2482  // remark : the support of D may contain "extra" places
2483  def BR=basering;
2484  def aff_r=CURVE[1][1];
2485  int N=size(nFORMS(n));
2486  matrix totalM[1][N];
2487  int s=size(D);
2488  list Places=CURVE[3];
2489  int NPls=size(Places);
2490  int i,j,k,kk,id,ip,RR,ordx,ordy,nr,NR;
2491  if (s<=NPls)
2492  {
2493    for (i=1;i<=s;i=i+1)
2494    {
2495      if (D[i]>0)
2496      {
2497        id=Places[i][1];
2498        ip=Places[i][2];
2499        RR=D[i];
2500        def SS=CURVE[5][id][1];
2501        setring SS;
2502        poly xt=PARAMETRIZATIONS[ip][1][1];
2503        poly yt=PARAMETRIZATIONS[ip][1][2];
2504        ordx=PARAMETRIZATIONS[ip][2][1];
2505        ordy=PARAMETRIZATIONS[ip][2][2];
2506        nr=ncols(BRANCHES[ip][1]);
2507        if ( ordx>-1 || ordy>-1 )
2508        {
2509          while ( ( RR>ordx && ordx>-1 ) || ( RR>ordy && ordy>-1 ) )
2510          {
2511            BRANCHES[ip]=extdevelop(BRANCHES[ip],2*nr);
2512            nr=ncols(BRANCHES[ip][1]);
2513            PARAMETRIZATIONS[ip]=param(BRANCHES[ip],0);
2514            xt=PARAMETRIZATIONS[ip][1][1];
2515            yt=PARAMETRIZATIONS[ip][1][2];
2516            ordx=PARAMETRIZATIONS[ip][2][1];
2517            ordy=PARAMETRIZATIONS[ip][2][2];
2518          }
2519        }
2520        if (POINTS[ip][3]==number(1))
2521        {
2522          number A=POINTS[ip][1];
2523          number B=POINTS[ip][2];
2524          map Mt=BR,A+xt,B+yt,1;
2525          kill(A,B);
2526        }
2527        else
2528        {
2529          if (POINTS[ip][2]==number(1))
2530          {
2531            number A=POINTS[ip][1];
2532            map Mt=BR,A+xt,1,yt;
2533            kill(A);
2534          }
2535          else
2536          {
2537            map Mt=BR,1,xt,yt;
2538          }
2539        }
2540        ideal nFORMS(n)=Mt(nFORMS(n));
2541        // rewrite properly the above conditions to obtain the local equations
2542        matrix partM[RR][N];
2543        matrix auxMC=coeffs(nFORMS(n),t);
2544        NR=nrows(auxMC);
2545        if (RR<=NR)
2546        {
2547          for (j=1;j<=RR;j=j+1)
2548          {
2549            for (k=1;k<=N;k=k+1)
2550            {
2551              partM[j,k]=number(auxMC[j,k]);
2552            }
2553          }
2554        }
2555        else
2556        {
2557          for (j=1;j<=NR;j=j+1)
2558          {
2559            for (k=1;k<=N;k=k+1)
2560            {
2561              partM[j,k]=number(auxMC[j,k]);
2562            }
2563          }
2564          for (j=NR+1;j<=RR;j=j+1)
2565          {
2566            for (k=1;k<=N;k=k+1)
2567            {
2568              partM[j,k]=number(0);
2569            }
2570          }
2571        }
2572        matrix localM=partM;
2573        matrix conjM=partM;
2574        for (j=2;j<=id;j=j+1)
2575        {
2576          conjM=Frobenius(conjM,1);
2577          localM=transpose(concat(transpose(localM),transpose(conjM)));
2578        }
2579        localM=gauss_row(localM);
2580        setring BR;
2581        totalM=transpose(concat(transpose(totalM),transpose(imap(SS,localM))));
2582        totalM=transpose(compress(transpose(totalM)));
2583        setring SS;
2584        kill(xt,yt,Mt,nFORMS(n),partM,auxMC,conjM,localM);
2585        setring BR;
2586        kill(SS);
2587      }
2588    }
2589  }
2590  else
2591  {
2592    // distinguish between "standard" places and "extra" places
2593    for (i=1;i<=NPls;i=i+1)
2594    {
2595      if (D[i]>0)
2596      {
2597        id=Places[i][1];
2598        ip=Places[i][2];
2599        RR=D[i];
2600        def SS=CURVE[5][id][1];
2601        setring SS;
2602        poly xt=PARAMETRIZATIONS[ip][1][1];
2603        poly yt=PARAMETRIZATIONS[ip][1][2];
2604        ordx=PARAMETRIZATIONS[ip][2][1];
2605        ordy=PARAMETRIZATIONS[ip][2][2];
2606        nr=ncols(BRANCHES[ip][1]);
2607        if ( ordx>-1 || ordy>-1 )
2608        {
2609          while ( ( RR>ordx && ordx>-1 ) || ( RR>ordy && ordy>-1 ) )
2610          {
2611            BRANCHES[ip]=extdevelop(BRANCHES[ip],2*nr);
2612            nr=ncols(BRANCHES[ip][1]);
2613            PARAMETRIZATIONS[ip]=param(BRANCHES[ip],0);
2614            xt=PARAMETRIZATIONS[ip][1][1];
2615            yt=PARAMETRIZATIONS[ip][1][2];
2616            ordx=PARAMETRIZATIONS[ip][2][1];
2617            ordy=PARAMETRIZATIONS[ip][2][2];
2618          }
2619        }
2620        if (POINTS[ip][3]==number(1))
2621        {
2622          number A=POINTS[ip][1];
2623          number B=POINTS[ip][2];
2624          map Mt=BR,A+xt,B+yt,1;
2625          kill(A,B);
2626        }
2627        else
2628        {
2629          if (POINTS[ip][2]==number(1))
2630          {
2631            number A=POINTS[ip][1];
2632            map Mt=BR,A+xt,1,yt;
2633            kill(A);
2634          }
2635          else
2636          {
2637            map Mt=BR,1,xt,yt;
2638          }
2639        }
2640        ideal nFORMS(n)=Mt(nFORMS(n));
2641        // rewrite properly the above conditions to obtain the local equations
2642        matrix partM[RR][N];
2643        matrix auxMC=coeffs(nFORMS(n),t);
2644        NR=nrows(auxMC);
2645        if (RR<=NR)
2646        {
2647          for (j=1;j<=RR;j=j+1)
2648          {
2649            for (k=1;k<=N;k=k+1)
2650            {
2651              partM[j,k]=number(auxMC[j,k]);
2652            }
2653          }
2654        }
2655        else
2656        {
2657          for (j=1;j<=NR;j=j+1)
2658          {
2659            for (k=1;k<=N;k=k+1)
2660            {
2661              partM[j,k]=number(auxMC[j,k]);
2662            }
2663          }
2664          for (j=NR+1;j<=RR;j=j+1)
2665          {
2666            for (k=1;k<=N;k=k+1)
2667            {
2668              partM[j,k]=number(0);
2669            }
2670          }
2671        }
2672        matrix localM=partM;
2673        matrix conjM=partM;
2674        for (j=2;j<=id;j=j+1)
2675        {
2676          conjM=Frobenius(conjM,1);
2677          localM=transpose(concat(transpose(localM),transpose(conjM)));
2678        }
2679        localM=gauss_row(localM);
2680        setring BR;
2681        totalM=transpose(concat(transpose(totalM),transpose(imap(SS,localM))));
2682        totalM=transpose(compress(transpose(totalM)));
2683        setring SS;
2684        kill(xt,yt,Mt,nFORMS(n),partM,auxMC,conjM,localM);
2685        setring BR;
2686        kill(SS);
2687      }
2688    }
2689    k=s-NPls;
2690    int l;
2691    for (i=1;i<=k;i=i+1)
2692    {
2693      // in this case D[NPls+i]>0 is assumed to be true during the
2694      // Brill-Noether algorithm
2695      RR=D[NPls+i];
2696      setring aff_r;
2697      def SS=@EXTRA@[2][i];
2698      def extra_dgs=@EXTRA@[3];
2699      setring SS;
2700      poly xt=PARAMETRIZATION[1][1];
2701      poly yt=PARAMETRIZATION[1][2];
2702      ordx=PARAMETRIZATION[2][1];
2703      ordy=PARAMETRIZATION[2][2];
2704      nr=ncols(BRANCH[1]);
2705      if ( ordx>-1 || ordy>-1 )
2706      {
2707        while ( ( RR>ordx && ordx>-1 ) || ( RR>ordy && ordy>-1 ) )
2708        {
2709          BRANCH[1]=extdevelop(BRANCH,2*nr);
2710          nr=ncols(BRANCH[1]);
2711          PARAMETRIZATION=param(BRANCH,0);
2712          xt=PARAMETRIZATION[1][1];
2713          yt=PARAMETRIZATION[1][2];
2714          ordx=PARAMETRIZATION[2][1];
2715          ordy=PARAMETRIZATION[2][2];
2716        }
2717      }
2718      number A=POINT[1];
2719      number B=POINT[2];
2720      map Mt=BR,A+xt,B+yt,1;
2721      kill(A,B);
2722      ideal nFORMS(n)=Mt(nFORMS(n));
2723      // rewrite properly the above conditions to obtain the local equations
2724      matrix partM[RR][N];
2725      matrix auxMC=coeffs(nFORMS(n),t);
2726      NR=nrows(auxMC);
2727      if (RR<=NR)
2728      {
2729        for (j=1;j<=RR;j=j+1)
2730        {
2731          for (kk=1;kk<=N;kk=kk+1)
2732          {
2733            partM[j,kk]=number(auxMC[j,kk]);
2734          }
2735        }
2736      }
2737      else
2738      {
2739        for (j=1;j<=NR;j=j+1)
2740        {
2741          for (kk=1;kk<=N;kk=kk+1)
2742          {
2743            partM[j,kk]=number(auxMC[j,kk]);
2744          }
2745        }
2746        for (j=NR+1;j<=RR;j=j+1)
2747        {
2748          for (kk=1;kk<=N;kk=kk+1)
2749          {
2750            partM[j,kk]=number(0);
2751          }
2752        }
2753      }
2754      matrix localM=partM;
2755      matrix conjM=partM;
2756      l=extra_dgs[i];
2757      for (j=2;j<=l;j=j+1)
2758      {
2759        conjM=Frobenius(conjM,1);
2760        localM=transpose(concat(transpose(localM),transpose(conjM)));
2761      }
2762      localM=gauss_row(localM);
2763      setring BR;
2764      totalM=transpose(concat(transpose(totalM),transpose(imap(SS,localM))));
2765      totalM=transpose(compress(transpose(totalM)));
2766      setring SS;
2767      kill(xt,yt,Mt,nFORMS(n),partM,auxMC,conjM,localM);
2768      setring BR;
2769      kill(SS);
2770    }
2771  }
2772  return(Ker(totalM));
2773}
2774///////////////////////////////////////////////////////////////////////////////
2775static proc local_IN (poly h,int m)
2776{
2777  // computes the intersection number of h and the curve CHI at a certain place
2778  // returns a list with the intersection number and the "leading coefficient"
2779  // the procedure must be called inside a local ring, h must be a local
2780  //     equation with respect to the desired place, and m indicates the
2781  //     number of place inside that local ring, containing lists
2782  //     POINT(S)/BRANCH(ES)/PARAMETRIZATION(S) when m=0 an "extra place" is
2783  //     considered
2784  def BR=basering;
2785  if (m>0)
2786  {
2787    int nr=ncols(BRANCHES[m][1]);
2788    poly xt=PARAMETRIZATIONS[m][1][1];
2789    poly yt=PARAMETRIZATIONS[m][1][2];
2790    int ordx=PARAMETRIZATIONS[m][2][1];
2791    int ordy=PARAMETRIZATIONS[m][2][2];
2792    map phi=BR,xt,yt,1;
2793    poly ht=phi(h);
2794    int inum=mindeg(ht);
2795    if ( ordx>-1 || ordy>-1 )
2796    {
2797      while ( ( inum>ordx && ordx>-1 ) || ( inum>ordy && ordy>-1 ) )
2798      {
2799        BRANCHES[m]=extdevelop(BRANCHES[m],2*nr);
2800        nr=ncols(BRANCHES[m][1]);
2801        PARAMETRIZATIONS[m]=param(BRANCHES[m],0);
2802        xt=PARAMETRIZATIONS[m][1][1];
2803        yt=PARAMETRIZATIONS[m][1][2];
2804        ordx=PARAMETRIZATIONS[m][2][1];
2805        ordy=PARAMETRIZATIONS[m][2][2];
2806        ht=phi(h);
2807        inum=mindeg(ht);
2808      }
2809    }
2810  }
2811  else
2812  {
2813    int nr=ncols(BRANCH[1]);
2814    poly xt=PARAMETRIZATION[1][1];
2815    poly yt=PARAMETRIZATION[1][2];
2816    int ordx=PARAMETRIZATION[2][1];
2817    int ordy=PARAMETRIZATION[2][2];
2818    map phi=basering,xt,yt,1;
2819    poly ht=phi(h);
2820    int inum=mindeg(ht);
2821    if ( ordx>-1 || ordy>-1 )
2822    {
2823      while ( ( inum>ordx && ordx>-1 ) || ( inum>ordy && ordy>-1 ) )
2824      {
2825        BRANCH=extdevelop(BRANCH,2*nr);
2826        nr=ncols(BRANCH[1]);
2827        PARAMETRIZATION=param(BRANCH,0);
2828        xt=PARAMETRIZATION[1][1];
2829        yt=PARAMETRIZATION[1][2];
2830        ordx=PARAMETRIZATION[2][1];
2831        ordy=PARAMETRIZATION[2][2];
2832        ht=phi(h);
2833        inum=mindeg(ht);
2834      }
2835    }
2836  }
2837  list answer=list();
2838  answer[1]=inum;
2839  number AA=number(coeffs(ht,t)[inum+1,1]);
2840  answer[2]=AA;
2841  return(answer);
2842}
2843///////////////////////////////////////////////////////////////////////////////
2844static proc extra_place (ideal P)
2845{
2846  // computes the "rational" place which is defined over a (closed) "extra"
2847  //     point
2848  // an "extra" point will be necessarily affine, non-singular and non-rational
2849  // creates : a specific local ring to deal with the (unique) place above it
2850  // returns : list with the above local ring and the degree of the point/place
2851  // warning : the procedure must be called inside the affine ring aff_r
2852  def base_r=basering;
2853  int ext=deg(P[1]);
2854  poly aux=subst(P[2],y,1);
2855  ext=ext*deg(aux);
2856  // P is assumed to be a std. resp. "(x,y),lp" and thus P[1] depends only
2857  // on "y"
2858  if (deg(P[1])==1)
2859  {
2860    // the point is non-rational but the second component needs no field
2861    // extension
2862    number B=-number(subst(P[1],y,0));
2863    poly aux2=subst(P[2],y,B);
2864    // careful : the parameter will be called "a" anyway
2865    ring ES=(char(basering),a),(x,y,t),ls;
2866    map psi=base_r,a,0;
2867    minpoly=number(psi(aux2));
2868    kill(psi);
2869    number A=a;
2870    number B=imap(base_r,B);
2871  }
2872  else
2873  {
2874    if (deg(subst(P[2],y,1))==1)
2875    {
2876      // the point is non-rational but the needed minpoly is just P[1]
2877      // careful : the parameter will be called "a" anyway
2878      poly P1=P[1];
2879      poly P2=P[2];
2880      ring ES=(char(basering),a),(x,y,t),ls;
2881      map psi=base_r,0,a;
2882      minpoly=number(psi(P1));
2883      kill(psi);
2884      poly aux1=imap(base_r,P2);
2885      poly aux2=subst(aux1,y,a);
2886      number A=-number(subst(aux2,x,0));
2887      number B=a;
2888    }
2889    else
2890    {
2891      // this is the most complicated case of non-rational point
2892      poly P1=P[1];
2893      poly P2=P[2];
2894      int p=char(basering);
2895      int Q=p^ext;
2896      ring aux_r=(Q,a),(x,y,t),ls;
2897      string minpoly_string=string(minpoly);
2898      ring ES=(char(basering),a),(x,y,t),ls;
2899      execute("minpoly="+minpoly_string+";");
2900      poly P_1=imap(base_r,P1);
2901      poly P_2=imap(base_r,P2);
2902      ideal factors1=factorize(P_1,1);
2903      number B=-number(subst(factors1[1],y,0));
2904      poly P_0=subst(P_2,y,B);
2905      ideal factors2=factorize(P_0,1);
2906      number A=-number(subst(factors2[1],x,0));
2907      kill(aux_r);
2908    }
2909  }
2910  list POINT=list();
2911  POINT[1]=A;
2912  POINT[2]=B;
2913  export(POINT);
2914  map phi=base_r,x+A,y+B;
2915  poly LOC_EQ=phi(CHI);
2916  kill(A,B,phi);
2917  list LLL=essdevelop(LOC_EQ);
2918  if (typeof(LLL[1])=="ring") {
2919    def altring=basering;
2920    def HNEring = LLL[1];
2921    setring HNEring;
2922    def L@HNE = hne[1];
2923    kill hne;
2924    export(L@HNE);
2925    int m=nrows(L@HNE[1]);
2926    int n=ncols(L@HNE[1]);
2927    intvec Li2=L@HNE[2];
2928    int Li3=L@HNE[3];
2929    setring ES;
2930    string newa=subfield(HNEring);
2931    poly paux=importdatum(HNEring,"L@HNE[4]",newa);
2932    matrix Maux[m][n];
2933    int i,j;
2934    for (i=1;i<=m;i=i+1)
2935    {
2936      for (j=1;j<=n;j=j+1)
2937      {
2938        Maux[i,j]=importdatum(HNEring,"L@HNE[1]["+string(i)+","+
2939                                                  string(j)+"]",newa);
2940      }
2941    }
2942  }
2943  else {
2944    def L@HNE=LLL[1][1];
2945    matrix Maux=L@HNE[1];
2946    intvec Li2=L@HNE[2];
2947    int Li3=L@HNE[3];
2948    poly paux=L@HNE[4];
2949    def HNEring=basering;
2950    setring HNEring;
2951  }
2952  kill LLL;
2953 
2954  list BRANCH=list();
2955  BRANCH[1]=Maux;
2956  BRANCH[2]=Li2;
2957  BRANCH[3]=Li3;
2958  BRANCH[4]=paux;
2959  export(BRANCH);
2960  list PARAMETRIZATION=param(BRANCH,0);
2961  export(PARAMETRIZATION);
2962  kill(HNEring);
2963  setring base_r;
2964  list answer=list();
2965  answer[1]=ES;
2966  answer[2]=ext;
2967  kill(ES);
2968  return(answer);
2969}
2970///////////////////////////////////////////////////////////////////////////////
2971static proc intersection_div (poly H,list CURVE)
2972"USAGE:     intersection_div(H,CURVE), where H is a homogeneous polynomial
2973            in ring Proj_R=p,(x,y,z),lp and CURVE is the list of data for
2974            the given curve
2975CREATE:     new places which had not been computed in advance if necessary
2976            those places are stored each one in a local ring where you find
2977            lists POINT,BRANCH,PARAMETRIZATION for the place living in that
2978            ring; the degree of the point/place in such a ring is stored in
2979            an intvec, and the base points in the remaining list
2980            Everything is exported in a list @EXTRA@ inside the ring
2981            aff_r=CURVE[1][1] and returned with the updated CURVE
2982RETURN:     list with the intersection divisor (intvec) between the underlying
2983            curve and H=0, and the list CURVE updated
2984SEE ALSO:   Adj_div, NSplaces, closed_points
2985NOTE:       The procedure must be called from the ring Proj_R=CURVE[1][2]
2986            (projective).
2987            If @EXTRA@ already exists, the new places are added to the
2988            previous data.
2989"
2990{
2991  // computes the intersection divisor of H and the curve CHI
2992  // returns a list with (possibly) "extra places" and it must be called
2993  //     inside Proj_R
2994  // in case of extra places, some local rings ES(1) ... ES(m) are created
2995  //     together with an integer list "extra_dgs" containing the degrees of
2996  //     those places
2997  intvec opgt=option(get);
2998  option(redSB);
2999  intvec interdiv;
3000  def BRing=basering;
3001  int Tz1=deg(H);
3002  list Places=CURVE[3];
3003  int N=size(Places);
3004  def aff_r=CURVE[1][1];
3005  setring aff_r;
3006  if (defined(@EXTRA@)==0)
3007  {
3008    list @EXTRA@=list();
3009    list EP=list();
3010    list ES=list();
3011    list extra_dgs=list();
3012  }
3013  else
3014  {
3015    list EP=@EXTRA@[1];
3016    list ES=@EXTRA@[2];
3017    list extra_dgs=@EXTRA@[3];
3018  }
3019  int NN=size(extra_dgs);
3020  int counterEPl=0;
3021  setring BRing;
3022  poly h=subst(H,z,1);
3023  int Tz2=deg(h);
3024  int Tz3=Tz1-Tz2;
3025  int i,j,k,l,m,n,s,np,NP,I_N;
3026  if (Tz3==0)
3027  {
3028    // if this still does not work -> try always with ALL points in
3029    // Inf_Points !!!!
3030    poly Hinf=subst(H,z,0);
3031    setring aff_r;
3032    // compute the points at infinity of H and see which of them are in
3033    // Inf_Points
3034    poly h=imap(BRing,h);
3035    poly hinf=imap(BRing,Hinf);
3036    ideal pinf=factorize(hinf,1);
3037    list TIP=Inf_Points[1]+Inf_Points[2];
3038    s=size(TIP);
3039    NP=size(pinf);
3040    for (i=1;i<=NP;i=i+1)
3041    {
3042      for (j=1;j<=s;j=j+1)
3043      {
3044        if (pinf[i]==TIP[j][1])
3045        {
3046          np=size(TIP[j][2]);
3047          for (k=1;k<=np;k=k+1)
3048          {
3049            n=TIP[j][2][k];
3050            l=Places[n][1];
3051            m=Places[n][2];
3052            def SS=CURVE[5][l][1];
3053            setring SS;
3054            // local equation h of H
3055            if (POINTS[m][2]==number(1))
3056            {
3057              number A=POINTS[m][1];
3058              map psi=BRing,x+A,1,y;
3059              kill(A);
3060            }
3061            else
3062            {
3063              map psi=BRing,1,x,y;
3064            }
3065            poly h=psi(H);
3066            I_N=local_IN(h,m)[1];
3067            interdiv[n]=I_N;
3068            kill(h,psi);
3069            setring aff_r;
3070            kill(SS);
3071          }
3072          break;
3073        }
3074      }
3075    }
3076    kill(hinf,pinf);
3077  }
3078  else
3079  {
3080    // H is a multiple of z and hence all the points in Inf_Points intersect
3081    // with H
3082    setring aff_r;
3083    poly h=imap(BRing,h);
3084    list TIP=Inf_Points[1]+Inf_Points[2];
3085    s=size(TIP);
3086    for (j=1;j<=s;j=j+1)
3087    {
3088      np=size(TIP[j][2]);
3089      for (k=1;k<=np;k=k+1)
3090      {
3091        n=TIP[j][2][k];
3092        l=Places[n][1];
3093        m=Places[n][2];
3094        def SS=CURVE[5][l][1];
3095        setring SS;
3096        // local equation h of H
3097        if (POINTS[m][2]==number(1))
3098        {
3099          number A=POINTS[m][1];
3100          map psi=BRing,x+A,1,y;
3101          kill(A);
3102        }
3103        else
3104        {
3105          map psi=BRing,1,x,y;
3106        }
3107        poly h=psi(H);
3108        I_N=local_IN(h,m)[1];
3109        interdiv[n]=I_N;
3110        kill(h,psi);
3111        setring aff_r;
3112        kill(SS);
3113      }
3114    }
3115  }
3116  // compute common affine points of H and CHI
3117  ideal CAL=h,CHI;
3118  CAL=std(CAL);
3119  if (CAL<>1)
3120  {
3121    list TAP=list();
3122    TAP=closed_points(CAL);
3123    NP=size(TAP);
3124    list auxP=list();
3125    int dP;
3126    for (i=1;i<=NP;i=i+1)
3127    {
3128      if (belongs(TAP[i],Aff_SLocus)==1)
3129      {
3130        // search the point in the list Aff_SPoints
3131        j=isInLP(TAP[i],Aff_SPoints);
3132        np=size(Aff_SPoints[j][2]);
3133        for (k=1;k<=np;k=k+1)
3134        {
3135          n=Aff_SPoints[j][2][k];
3136          l=Places[n][1];
3137          m=Places[n][2];
3138          def SS=CURVE[5][l][1];
3139          setring SS;
3140          // local equation h of H
3141          number A=POINTS[m][1];
3142          number B=POINTS[m][2];
3143          map psi=BRing,x+A,y+B,1;
3144          poly h=psi(H);
3145          I_N=local_IN(h,m)[1];
3146          interdiv[n]=I_N;
3147          kill(A,B,h,psi);
3148          setring aff_r;
3149          kill(SS);
3150        }
3151      }
3152      else
3153      {
3154        auxP=list();
3155        auxP[1]=TAP[i];
3156        dP=degree_P(auxP);
3157        if (defined(Aff_Points(dP))<>0)
3158        {
3159          // search the point in the list Aff_Points(dP)
3160          j=isInLP(TAP[i],Aff_Points(dP));
3161          n=Aff_Points(dP)[j][2][1];
3162          l=Places[n][1];
3163          m=Places[n][2];
3164          def SS=CURVE[5][l][1];
3165          setring SS;
3166          // local equation h of H
3167          number A=POINTS[m][1];
3168          number B=POINTS[m][2];
3169          map psi=BRing,x+A,y+B,1;
3170          poly h=psi(H);
3171          I_N=local_IN(h,m)[1];
3172          interdiv[n]=I_N;
3173          kill(A,B,h,psi);
3174          setring aff_r;
3175          kill(SS);
3176        }
3177        else
3178        {
3179          // previously check if it is an existing "extra place"
3180          j=isInLP(TAP[i],EP);
3181          if (j>0)
3182          {
3183            def SS=ES[j];
3184            setring SS;
3185            // local equation h of H
3186            number A=POINT[1];
3187            number B=POINT[2];
3188            map psi=BRing,x+A,y+B,1;
3189            poly h=psi(H);
3190            I_N=local_IN(h,0)[1];
3191            interdiv[N+j]=I_N;
3192            setring aff_r;
3193            kill(SS);
3194          }
3195          else
3196          {
3197            // then we must create a new "extra place"
3198            counterEPl=counterEPl+1;
3199            list EXTRA_PLACE=extra_place(TAP[i]);
3200            def SS=EXTRA_PLACE[1];
3201            ES[NN+counterEPl]=SS;
3202            extra_dgs[NN+counterEPl]=EXTRA_PLACE[2];
3203            EP[NN+counterEPl]=list();
3204            EP[NN+counterEPl][1]=TAP[i];
3205            EP[NN+counterEPl][2]=0;
3206            setring SS;
3207            // local equation h of H
3208            number A=POINT[1];
3209            number B=POINT[2];
3210            map psi=BRing,x+A,y+B,1;
3211            poly h=psi(H);
3212            I_N=local_IN(h,0)[1];
3213            kill(A,B,h,psi);
3214            interdiv[N+NN+counterEPl]=I_N;
3215            setring aff_r;
3216            kill(SS);
3217          }
3218        }
3219      }
3220    }
3221    kill(TAP,auxP);
3222  }
3223  kill(h,CAL,TIP);
3224  @EXTRA@[1]=EP;
3225  @EXTRA@[2]=ES;
3226  @EXTRA@[3]=extra_dgs;
3227  kill(EP);
3228  list update_CURVE=CURVE;
3229  if (size(extra_dgs)>0)
3230  {
3231    export(@EXTRA@);
3232    update_CURVE[1][1]=basering;
3233  }
3234  else
3235  {
3236    kill(@EXTRA@);
3237  }
3238  setring BRing;
3239  kill(h);
3240  kill(aff_r);
3241  list answer=list();
3242  answer[1]=interdiv;
3243  answer[2]=update_CURVE;
3244  option(set,opgt);
3245  return(answer);
3246}
3247///////////////////////////////////////////////////////////////////////////////
3248static proc local_eq (poly H,SS,int m)
3249{
3250  // computes a local equation of poly H in the ring SS related to the place
3251  //     "m"
3252  // list POINT/POINTS is searched depending on wether m=0 or m>0 respectively
3253  // warning : the procedure must be called from ring "Proj_R" and returns a
3254  //     string
3255  def BRing=basering;
3256  setring SS;
3257  if (m>0)
3258  {
3259    if (POINTS[m][3]==number(1))
3260    {
3261      number A=POINTS[m][1];
3262      number B=POINTS[m][2];
3263      map psi=BRing,x+A,y+B,1;
3264    }
3265    else
3266    {
3267      if (POINTS[m][2]==number(1))
3268      {
3269        number A=POINTS[m][1];
3270        map psi=BRing,x+A,1,y;
3271      }
3272      else
3273      {
3274        map psi=BRing,1,x,y;
3275      }
3276    }
3277  }
3278  else
3279  {
3280    number A=POINT[1];
3281    number B=POINT[2];
3282    map psi=BRing,x+A,y+B,1;
3283  }
3284  poly h=psi(H);
3285  string str_h=string(h);
3286  setring BRing;
3287  return(str_h);
3288}
3289///////////////////////////////////////////////////////////////////////////////
3290static proc min_wt_rmat (matrix M)
3291{
3292  // finds the row of M with minimum non-zero entries, i.e. minimum
3293  // "Hamming-weight"
3294  int m=nrows(M);
3295  int n=ncols(M);
3296  int i,j;
3297  int Hwt=0;
3298  for (j=1;j<=n;j=j+1)
3299  {
3300    if (M[1,j]<>0)
3301    {
3302      Hwt=Hwt+1;
3303    }
3304  }
3305  int minHwt=Hwt;
3306  int k=1;
3307  for (i=2;i<=m;i=i+1)
3308  {
3309    Hwt=0;
3310    for (j=1;j<=n;j=j+1)
3311    {
3312      if (M[i,j]<>0)
3313      {
3314        Hwt=Hwt+1;
3315      }
3316    }
3317    if (Hwt<minHwt)
3318    {
3319      minHwt=Hwt;
3320      k=i;
3321    }
3322  }
3323  return(k);
3324}
3325///////////////////////////////////////////////////////////////////////////////
3326
3327// ============================================================================
3328// *******    MAIN PROCEDURE : the Brill-Noether algorithm             ********
3329// ============================================================================
3330
3331proc BrillNoether (intvec G,list CURVE)
3332"USAGE:    BrillNoether(G,CURVE); G an intvec, CURVE a list
3333RETURN:   list of ideals (each of them with two homogeneous generators,
3334          which represent the numerator, resp. denominator, of a rational
3335          function).@*
3336          The corresponding rational functions form a vector basis of the
3337          linear system L(G), G a rational divisor over a non-singular curve.
3338NOTE:     The procedure must be called from the ring CURVE[1][2], where
3339          CURVE is the output of the procedure @code{NSplaces}. @*
3340          The intvec G represents a rational divisor supported on the closed
3341          places of CURVE[3] (e.g. @code{G=2,0,-1;} means 2 times the closed
3342          place 1 minus 1 times the closed place 3).
3343SEE ALSO: Adj_div, NSplaces, Weierstrass
3344EXAMPLE:  example BrillNoether; shows an example
3345"
3346{
3347  // computes a vector basis for the space L(G),
3348  //     where G is a given rational divisor over the non-singular curve
3349  // returns : list of ideals in R each with 2 elements H,Ho such that
3350  //           the set of functions {H/Ho} is the searched basis
3351  // warning : the conductor and sufficiently many points of the plane
3352  //           curve should be computed in advance, in list CURVE
3353  // the algorithm of Brill-Noether is carried out in the procedure
3354  def BRing=basering;
3355  int degX=CURVE[2][1];
3356  list Places=CURVE[3];
3357  intvec Conductor=CURVE[4];
3358  if (deg_D(G,Places)<0)
3359  {
3360    return(list());
3361  }
3362  intvec nuldiv;
3363  if (G==nuldiv)
3364  {
3365    list quickL=list();
3366    ideal quickId;
3367    quickId[1]=1;
3368    quickId[2]=1;
3369    quickL[1]=quickId;
3370    return(quickL);
3371  }
3372  intvec J=max_D(G,nuldiv)+Conductor;
3373  int n=estim_n(J,degX,Places);
3374  dbprint(printlevel+1,"Forms of degree "+string(n)+" : ");
3375  matrix W=nmultiples(n,degX,CHI);
3376  kill(nFORMS(n-degX));
3377  list update_CURVE=CURVE;
3378  matrix V=interpolating_forms(J,n,update_CURVE);
3379  matrix VmW=supplement(W,V);
3380  int k=min_wt_rmat(VmW);
3381  int N=size(nFORMS(n));
3382  matrix H0[1][N];
3383  int i,j;
3384  for (i=1;i<=N;i=i+1) { H0[1,i]=VmW[k,i]; }
3385  poly Ho;
3386  for (i=1;i<=N;i=i+1) { Ho=Ho+(H0[1,i]*nFORMS(n)[i]); }
3387  list INTERD=intersection_div(Ho,update_CURVE);
3388  intvec NHo=INTERD[1];
3389  update_CURVE=INTERD[2];
3390  intvec AR=NHo-G;
3391  matrix V2=interpolating_forms(AR,n,update_CURVE);
3392  def aux_RING=update_CURVE[1][1];
3393  setring aux_RING;
3394  if (defined(@EXTRA@)<>0)
3395  {
3396    kill(@EXTRA@);
3397  }
3398  setring BRing;
3399  update_CURVE[1][1]=aux_RING;
3400  kill(aux_RING);
3401  matrix B0=supplement(W,V2);
3402  if (Hamming_wt(B0)==0)
3403  {
3404    return(list());
3405  }
3406  int ld=nrows(B0);
3407  list Bres=list();
3408  ideal HH;
3409  poly H;
3410  for (j=1;j<=ld;j=j+1)
3411  {
3412    H=0;
3413    for (i=1;i<=N;i=i+1)
3414    {
3415      H=H+(B0[j,i]*nFORMS(n)[i]);
3416    }
3417    HH=H,Ho;
3418    Bres[j]=simplifyRF(HH);
3419  }
3420  kill(nFORMS(n));
3421  dbprint(printlevel+1," ");
3422  dbprint(printlevel+2,"Vector basis successfully computed ");
3423  dbprint(printlevel+1," ");
3424  return(Bres);
3425}
3426example
3427{
3428  "EXAMPLE:";  echo = 2;
3429  int plevel=printlevel;
3430  printlevel=-1;
3431  ring s=2,(x,y),lp;
3432  list C=Adj_div(x3y+y3+x);
3433  C=NSplaces(1..4,C);
3434  // the first 3 Places in C[3] are of degree 1.
3435  // we define the rational divisor G = 4*C[3][1]+4*C[3][3] (of degree 8):
3436  intvec G=4,0,4;
3437  def R=C[1][2];
3438  setring R;
3439  list LG=BrillNoether(G,C);
3440  // here is the vector basis of L(G):
3441  LG;
3442  printlevel=plevel;
3443}
3444///////////////////////////////////////////////////////////////////////////////
3445
3446// *** procedures for dealing with "RATIONAL FUNCTIONS" over a plane curve ***
3447// a rational function F may be given by (homogeneous) ideal or (affine) poly
3448// (or number)
3449
3450static proc polytoRF (F)
3451{
3452  // converts a poly (or number) into a "rational function" of type "ideal"
3453  // warning : it must be called inside "R" and poly should be affine
3454  ideal RF;
3455  RF[1]=homog(F,z);
3456  RF[2]=z^(deg(F));
3457  return(RF);
3458}
3459///////////////////////////////////////////////////////////////////////////////
3460static proc simplifyRF (ideal F)
3461{
3462  // simplifies a rational function f/g extracting the gcd(f,g)
3463  // maybe add a "restriction" to the curve "CHI" but it is not easy to
3464  // programm
3465  poly auxp=gcd(F[1],F[2]);
3466  return(ideal(division(F,auxp)[1]));
3467}
3468///////////////////////////////////////////////////////////////////////////////
3469static proc sumRF (F,G)
3470{
3471  // sum of two "rational functions" F,G given by either a pair
3472  // numerator/denominator or a poly
3473  if ( typeof(F)=="ideal" && typeof(G)=="ideal" )
3474  {
3475    ideal FG;
3476    FG[1]=F[1]*G[2]+F[2]*G[1];
3477    FG[2]=F[2]*G[2];
3478    return(simplifyRF(FG));
3479  }
3480  else
3481  {
3482    if (typeof(F)=="ideal")
3483    {
3484      ideal GG=polytoRF(G);
3485      ideal FG;
3486      FG[1]=F[1]*GG[2]+F[2]*GG[1];
3487      FG[2]=F[2]*GG[2];
3488      return(simplifyRF(FG));
3489    }
3490    else
3491    {
3492      if (typeof(G)=="ideal")
3493      {
3494        ideal FF=polytoRF(F);
3495        ideal FG;
3496        FG[1]=FF[1]*G[2]+FF[2]*G[1];
3497        FG[2]=FF[2]*G[2];
3498        return(simplifyRF(FG));
3499      }
3500      else
3501      {
3502        return(F+G);
3503      }
3504    }
3505  }
3506}
3507///////////////////////////////////////////////////////////////////////////////
3508static proc negRF (F)
3509{
3510  // returns -F as rational function
3511  if (typeof(F)=="ideal")
3512  {
3513    ideal FF=F;
3514    FF[1]=-F[1];
3515    return(FF);
3516  }
3517  else
3518  {
3519    return(-F);
3520  }
3521}
3522///////////////////////////////////////////////////////////////////////////////
3523static proc escprodRF (l,F)
3524{
3525  // computes l*F as rational function
3526  // l should be either a number or a poly of degree zero
3527  if (typeof(F)=="ideal")
3528  {
3529    ideal lF=F;
3530    lF[1]=l*F[1];
3531    return(lF);
3532  }
3533  else
3534  {
3535    return(l*F);
3536  }
3537}
3538///////////////////////////////////////////////////////////////////////////////
3539
3540// ******** procedures to compute Weierstrass semigroups ********
3541
3542static proc orderRF (ideal F,SS,int m)
3543"USAGE:  orderRF(F,SS,m); F an ideal, SS a ring and m an integer
3544RETURN: list with the order (int) and the leading coefficient (number)
3545NOTE:   F represents a rational function, thus the procedure must be
3546        called from global ring R or R(d).
3547        SS contains the name of a local ring where rational places are
3548        stored, and then we take that which is in position m in the
3549        corresponding lists of data.
3550        The order of F at the place given by SS,m is returned together
3551        with the coefficient of minimum degree in the corresponding power
3552        series.
3553"
3554{
3555  // computes the order of a rational function F at a RATIONAL place given by
3556  //     a local ring SS and a position "m" inside SS
3557  // warning : the procedure must be called from global projective ring "R" or
3558  //     "R(i)"
3559  // returns a list with the order (int) and the "leading coefficient" (number)
3560  def BR=basering;
3561  poly f=F[1];
3562  string sf=local_eq(f,SS,m);
3563  poly g=F[2];
3564  string sg=local_eq(g,SS,m);
3565  setring SS;
3566  execute("poly ff="+sf+";");
3567  execute("poly gg="+sg+";");
3568  list o1=local_IN(ff,m);
3569  list o2=local_IN(gg,m);
3570  int oo=o1[1]-o2[1];
3571  number lc=o1[2]/o2[2];
3572  setring BR;
3573  number LC=number(imap(SS,lc));
3574  return(list(oo,LC));
3575}
3576///////////////////////////////////////////////////////////////////////////////
3577
3578proc Weierstrass (int P,int m,list CURVE)
3579"USAGE:    Weierstrass( i, m, CURVE );  i,m integers and CURVE a list
3580RETURN:   list WS of two lists:
3581  @format
3582  WS[1] list of integers (Weierstr. semigroup of the curve at place i up to m)
3583  WS[2] list of ideals (the associated rational functions)
3584  @end format
3585NOTE:     The procedure must be called from the ring CURVE[1][2],
3586          where CURVE is the output of the procedure @code{NSplaces}.
3587@*        i represents the place CURVE[3][i].
3588@*        Rational functions are represented by numerator/denominator
3589          in form of ideals with two homogeneous generators.
3590WARNING:  The place must be rational, i.e., necessarily CURVE[3][i][1]=1. @*
3591SEE ALSO: Adj_div, NSplaces, BrillNoether
3592EXAMPLE:  example Weierstrass; shows an example
3593"
3594{
3595  // computes the Weierstrass semigroup at a RATIONAL place P up to a bound "m"
3596  //   together with the functions achieving each value up to m, via
3597  //   Brill-Noether
3598  // returns 2 lists : the first consists of all the poles up to m in
3599  //   increasing order and the second consists of the corresponging rational
3600  //   functions
3601  list Places=CURVE[3];
3602  intvec pl=Places[P];
3603  int dP=pl[1];
3604  int nP=pl[2];
3605  if (dP<>1)
3606  {
3607    ERROR("the given place is not defined over the prime field");
3608  }
3609  if (m<=0)
3610  {
3611    if (m==0)
3612    {
3613      list semig=list();
3614      int auxint=0;
3615      semig[1]=auxint;
3616      list funcs=list();
3617      ideal auxF;
3618      auxF[1]=1;
3619      auxF[2]=1;
3620      funcs[1]=auxF;
3621      return(list(semig,funcs));
3622    }
3623    else
3624    {
3625      ERROR("second argument must be non-negative");
3626    }
3627  }
3628  int auxint=0;
3629  ideal auxF;
3630  auxF[1]=1;
3631  auxF[2]=1;
3632  // Brill-Noether algorithm
3633  intvec mP;
3634  mP[P]=m;
3635  list LmP=BrillNoether(mP,CURVE);
3636  int lmP=size(LmP);
3637  if (lmP==1)
3638  {
3639    list semig=list();
3640    semig[1]=auxint;
3641    list funcs=list();
3642    funcs[1]=auxF;
3643    return(list(semig,funcs));
3644  }
3645  def SS=CURVE[5][dP][1];
3646  list ordLmP=list();
3647  list polLmP=list();
3648  list sortpol=list();
3649  int maxpol;
3650  int i,j,k;
3651  for (i=1;i<=lmP-1;i=i+1)
3652  {
3653    for (j=1;j<=lmP-i+1;j=j+1)
3654    {
3655      ordLmP[j]=orderRF(LmP[j],SS,nP);
3656      polLmP[j]=-ordLmP[j][1];
3657    }
3658    sortpol=sort(polLmP);
3659    polLmP=sortpol[1];
3660    maxpol=polLmP[lmP-i+1];
3661    LmP=permute_L(LmP,sortpol[2]);
3662    ordLmP=permute_L(ordLmP,sortpol[2]);
3663    // triangulate LmP
3664    for (k=1;k<=lmP-i;k=k+1)
3665    {
3666      if (polLmP[lmP-i+1-k]==maxpol)
3667      {
3668        LmP[lmP-i+1-k]=sumRF(LmP[lmP-i+1-k],negRF(escprodRF(
3669                       ordLmP[lmP-i+1-k][2]/ordLmP[lmP-i+1][2],LmP[lmP-i+1])));
3670      }
3671      else
3672      {
3673        break;
3674      }
3675    }
3676  }
3677  polLmP[1]=auxint;
3678  LmP[1]=auxF;
3679  return(list(polLmP,LmP));
3680}
3681example
3682{
3683  "EXAMPLE:";  echo = 2;
3684  int plevel=printlevel;
3685  printlevel=-1;
3686  ring s=2,(x,y),lp;
3687  list C=Adj_div(x3y+y3+x);
3688  C=NSplaces(1..4,C);
3689  def R=C[1][2];
3690  setring R;
3691  // Place C[3][1] has degree 1 (i.e it is rational);
3692  list WS=Weierstrass(1,7,C);
3693  // the first part of the list is the Weierstrass semigroup up to 7 :
3694  WS[1];
3695  // and the second part are the corresponding functions :
3696  WS[2];
3697  printlevel=plevel;
3698}
3699///////////////////////////////////////////////////////////////////////////////
3700
3701// axiliary procedure for permuting a list or intvec
3702
3703proc permute_L (L,P)
3704"USAGE:    permute_L( L, P ); L,P either intvecs or lists
3705RETURN:   list obtained from L by applying the permutation given by P.
3706NOTE:     If P is a list, all entries must be integers.
3707SEE ALSO: sys_code, AGcode_Omega, prepSV
3708EXAMPLE:  example permute_L; shows an example
3709"
3710{
3711  // permutes the list L according to the permutation P (both intvecs or
3712  //  lists of integers)
3713  int s=size(L);
3714  int n=size(P);
3715  int i;
3716  if (s<n)
3717  {
3718    for (i=s+1;i<=n;i=i+1)
3719    {
3720      L[i]=0;
3721    }
3722    s=size(L);
3723  }
3724  list auxL=L;
3725  for (i=1;i<=n;i=i+1)
3726  {
3727    auxL[i]=L[P[i]];
3728  }
3729  return(auxL);
3730}
3731example
3732{
3733  "EXAMPLE:";  echo = 2;
3734  list L=list();
3735  L[1]="a";
3736  L[2]="b";
3737  L[3]="c";
3738  L[4]="d";
3739  intvec P=1,3,4,2;
3740  // the list L is permuted according to P :
3741  permute_L(L,P);
3742}
3743///////////////////////////////////////////////////////////////////////////////
3744static proc evalRF (ideal F,SS,int m)
3745"USAGE:     evalRF(F,SS,m), where F is an ideal, SS is a ring and m is an
3746            integer
3747RETURN:     the evaluation (number) of F at the place given by SS,m if it is
3748            well-defined
3749NOTE:       F represents a rational function, thus the procedure must be
3750            called from R or R(d).
3751            SS contains the name of a local ring where rational places are
3752            stored, and then we take that which is in position m in the
3753            corresponding lists of data.
3754"
3755{
3756  // evaluates a rational function F at a RATIONAL place given by
3757  //     a local ring SS and a position "m" inside SS
3758  list olc=orderRF(F,SS,m);
3759  int oo=olc[1];
3760  if (oo==0)
3761  {
3762    return(olc[2]);
3763  }
3764  else
3765  {
3766    if (oo>0)
3767    {
3768      return(number(0));
3769    }
3770    else
3771    {
3772      ERROR("the function is not well-defined at the given place");
3773    }
3774  }
3775}
3776///////////////////////////////////////////////////////////////////////////////
3777//
3778// ******** procedures for constructing AG codes ********
3779//
3780///////////////////////////////////////////////////////////////////////////////
3781
3782static proc gen_mat (list LF,intvec LP,RP)
3783"USAGE:      gen_mat(LF,LP,RP); LF list of rational functions,
3784            LP intvec of rational places and RP a local ring
3785RETURN:     a generator matrix of the evaluation code given by LF and LP
3786SEE ALSO:   extcurve
3787KEYWORDS:   evaluation codes
3788NOTE:       Rational places are searched in local ring RP
3789            The procedure must be called from R or R(d) fromlist CURVE
3790            after having executed extcurve(d,CURVE)
3791"
3792{
3793  // computes a generator matrix (with numbers) of the evaluation code given
3794  //    by a list of rational functions LF and a list of RATIONAL places LP
3795  int m=size(LF);
3796  int n=size(LP);
3797  matrix GM[m][n];
3798  int i,j;
3799  for (i=1;i<=m;i=i+1)
3800  {
3801    for (j=1;j<=n;j=j+1)
3802    {
3803      GM[i,j]=evalRF(LF[i],RP,LP[j]);
3804    }
3805  }
3806  return(GM);
3807}
3808///////////////////////////////////////////////////////////////////////////////
3809
3810proc dual_code (matrix G)
3811"USAGE:   dual_code(G); G a matrix of numbers
3812RETURN:   a generator matrix of the dual code generated by G
3813NOTE:     The input should be a matrix G of numbers. @*
3814          The output is also a parity check matrix for the code defined by G
3815KEYWORDS: linear code, dual
3816EXAMPLE:  example dual_code; shows an example
3817"
3818{
3819  // computes the dual code of C given by a generator matrix G
3820  //     i.e. computes a parity-check matrix H of C
3821  // conversely : computes also G if H is given
3822  return(Ker(G));
3823}
3824example
3825{
3826  "EXAMPLE:";  echo = 2;
3827  ring s=2,T,lp;
3828  // here is the Hamming code of length 7 and dimension 3
3829  matrix G[3][7]=1,0,1,0,1,0,1,0,1,1,0,0,1,1,0,0,0,1,1,1,1;
3830  print(G);
3831  matrix H=dual_code(G);
3832  print(H);
3833}
3834///////////////////////////////////////////////////////////////////////////////
3835
3836// ======================================================================
3837// *********** initial test for disjointness ***************
3838// ======================================================================
3839
3840static proc disj_divs (intvec H,intvec P,list EC)
3841{
3842  int s1=size(H);
3843  int s2=size(P);
3844  list PLACES=EC[3];
3845  def BRing=basering;
3846  def auxR=EC[1][5];
3847  setring auxR;
3848  int s=res_deg();
3849  setring BRing;
3850  kill(auxR);
3851  int i,j,k,d,l,N,M;
3852  intvec auxIV,iw;
3853  for (i=1;i<=s;i=i+1)
3854  {
3855    if ( (s mod i) == 0 )
3856    {
3857      if (typeof(EC[5][i])=="list")
3858      {
3859        def auxR=EC[5][i][1];
3860        setring auxR;
3861        auxIV[i]=size(POINTS);
3862        setring BRing;
3863        kill(auxR);
3864      }
3865      else
3866      {
3867        auxIV[i]=0;
3868      }
3869    }
3870    else
3871    {
3872      auxIV[i]=0;
3873    }
3874  }
3875  for (i=1;i<=s1;i=i+1)
3876  {
3877    if (H[i]<>0)
3878    {
3879      iw=PLACES[i];
3880      d=iw[1];
3881      if ( (s mod d) == 0 )
3882      {
3883        l=iw[2];
3884        // check that this place(s) is/are not in sup(D)
3885        if (d==1)
3886        {
3887          for (j=1;j<=s2;j=j+1)
3888          {
3889            if (l==P[j])
3890            {
3891              return(0);
3892            }
3893          }
3894        }
3895        else
3896        {
3897          N=0;
3898          for (j=1;j<d;j=j+1)
3899          {
3900            N=N+j*auxIV[j];
3901          }
3902          N=N+d*(l-1);
3903          M=N+d;
3904          for (k=N+1;k<=M;k=k+1)
3905          {
3906            for (j=1;j<=s2;j=j+1)
3907            {
3908              if (k==P[j])
3909              {
3910                return(0);
3911              }
3912            }
3913          }
3914        }
3915      }
3916    }
3917  }
3918  kill(auxIV,iw);
3919  return(1);
3920}
3921///////////////////////////////////////////////////////////////////////////////
3922
3923proc AGcode_L (intvec G,intvec D,list EC)
3924"USAGE:    AGcode_L( G, D, EC );  G,D intvec, EC a list
3925RETURN:   a generator matrix for the evaluation AG code defined by the
3926          divisors G and D.
3927NOTE:     The procedure must be called within the ring EC[1][4],
3928          where EC is the output of @code{extcurve(d)} (or within
3929          the ring EC[1][2] if d=1). @*
3930          The entry i in the intvec D refers to the i-th rational
3931          place in EC[1][5] (i.e., to POINTS[i], etc., see @ref{extcurve}).@*
3932          The intvec G represents a rational divisor (see @ref{BrillNoether}
3933          for more details).@*
3934          The code evaluates the vector basis of L(G) at the rational
3935          places given by D.
3936WARNINGS: G should satisfy @math{ 2*genus-2 < deg(G) < size(D) }, which is
3937          not checked by the algorithm.
3938          G and D should have disjoint supports (checked by the algorithm).
3939SEE ALSO: Adj_div, BrillNoether, extcurve, AGcode_Omega
3940EXAMPLE:  example AGcode_L; shows an example
3941"
3942{
3943  // returns a generator matrix for the evaluation AG code given by G and D
3944  // G must be a divisor defined over the prime field and D an intvec of
3945  // "rational places"
3946  // it must be called inside R or R(d) and requires previously "extcurve(d)"
3947  def BR=basering;
3948  if (disj_divs(G,D,EC)==0)
3949  {
3950    dbprint(printlevel+3,"? the divisors do not have disjoint supports,
3951                                 0-matrix returned ?");
3952    matrix answer;
3953    return(answer);
3954  }
3955  if (res_deg()>1)
3956  {
3957    def R=EC[1][2];
3958    setring R;
3959    list LG=BrillNoether(G,EC);
3960    setring BR;
3961    list LG=imap(R,LG);
3962    setring R;
3963    kill(LG);
3964    setring BR;
3965    kill(R);
3966  }
3967  else
3968  {
3969    list LG=BrillNoether(G,EC);
3970  }
3971  def RP=EC[1][5];
3972  matrix M=gen_mat(LG,D,RP);
3973  kill(LG);
3974  return(M);
3975}
3976example
3977{
3978  "EXAMPLE:";  echo = 2;
3979  int plevel=printlevel;
3980  printlevel=-1;
3981  ring s=2,(x,y),lp;
3982  list HC=Adj_div(x3+y2+y);
3983  HC=NSplaces(1..2,HC);
3984  HC=extcurve(2,HC);
3985  def ER=HC[1][4];
3986  setring ER;
3987  intvec G=5;      // the rational divisor G = 5*HC[3][1]
3988  intvec D=2..9;   // D = sum of the rational places no. 2..9 over F_4
3989  // let us construct the corresponding evaluation AG code :
3990  matrix C=AGcode_L(G,D,HC);
3991  // here is a linear code of type [8,5,>=3] over F_4
3992  print(C);
3993  printlevel=plevel;
3994}
3995///////////////////////////////////////////////////////////////////////////////
3996
3997proc AGcode_Omega (intvec G,intvec D,list EC)
3998"USAGE:    AGcode_Omega( G, D, EC ); G,D intvec, EC a list
3999RETURN:   a generator matrix for the residual AG code defined by the
4000          divisors G and D.
4001NOTE:     The procedure must be called within the ring EC[1][4],
4002          where EC is the output of @code{extcurve(d)} (or within
4003          the ring EC[1][2] if d=1). @*
4004          The entry i in the intvec D refers to the i-th rational
4005          place in EC[1][5] (i.e., to POINTS[i], etc., see @ref{extcurve}).@*
4006          The intvec G represents a rational divisor (see @ref{BrillNoether}
4007          for more details).@*
4008          The code computes the residues of a vector space basis of
4009          @math{\Omega(G-D)} at the rational places given by D.
4010WARNINGS: G should satisfy @math{ 2*genus-2 < deg(G) < size(D) }, which is
4011          not checked by the algorithm.
4012          G and D should have disjoint supports (checked by the algorithm).
4013SEE ALSO: Adj_div, BrillNoether, extcurve, AGcode_L
4014EXAMPLE:  example AGcode_Omega; shows an example
4015"
4016{
4017  // returns a generator matrix for the residual AG code given by G and D
4018  // G must be a divisor defined over the prime field and D an intvec or
4019  // "rational places"
4020  // it must be called inside R or R(d) and requires previously "extcurve(d)"
4021  return(dual_code(AGcode_L(G,D,EC)));
4022}
4023example
4024{
4025  "EXAMPLE:";  echo = 2;
4026  int plevel=printlevel;
4027  printlevel=-1;
4028  ring s=2,(x,y),lp;
4029  list HC=Adj_div(x3+y2+y);
4030  HC=NSplaces(1..2,HC);
4031  HC=extcurve(2,HC);
4032  def ER=HC[1][4];
4033  setring ER;
4034  intvec G=5;      // the rational divisor G = 5*HC[3][1]
4035  intvec D=2..9;   // D = sum of the rational places no. 2..9 over F_4
4036  // let us construct the corresponding residual AG code :
4037  matrix C=AGcode_Omega(G,D,HC);
4038  // here is a linear code of type [8,3,>=5] over F_4
4039  print(C);
4040  printlevel=plevel;
4041}
4042///////////////////////////////////////////////////////////////////////////////
4043
4044// ============================================================================
4045// *******   auxiliary procedure to define AG codes over extensions    ********
4046// ============================================================================
4047
4048proc extcurve (int d,list CURVE)
4049"USAGE:    extcurve( d, CURVE ); d an integer, CURVE a list
4050RETURN:   list L which is the update of the list CURVE with additional entries
4051   @format
4052   L[1][3]: ring (p,a),(x,y),lp (affine),
4053   L[1][4]: ring (p,a),(x,y,z),lp (projective),
4054   L[1][5]: ring (p,a),(x,y,t),ls (local),
4055   L[2][3]: int  (the number of rational places),
4056   @end format
4057          the rings being defined over a field extension of degree d. @*
4058          If d<2 then @code{extcurve(d,CURVE);} creates a list L which
4059          is the update of the list CURVE with additional entries
4060   @format
4061   L[1][5]: ring p,(x,y,t),ls,
4062   L[2][3]: int  (the number of computed places over the base field).
4063   @end format
4064          In both cases, in the ring L[1][5] lists with the data for all the
4065          computed rational places (after a field extension of degree d) are
4066          created (see @ref{Adj_div}):
4067   @format
4068   lists POINTS, LOC_EQS, BRANCHES, PARAMETRIZATIONS.
4069   @end format
4070NOTE:     The list CURVE should be the output of @code{NSplaces},
4071          and must contain (at least) one place of degree d. @*
4072          You actually need all the places with degree dividing d.
4073          Otherwise, not all the places are computed, but only part of them. @*
4074          This procedure must be executed before constructing AG codes,
4075          even if no extension is needed. The ring L[1][4] must be active
4076          when constructing codes over the field extension.@*
4077SEE ALSO: closed_points, Adj_div, NSplaces, AGcode_L, AGcode_Omega
4078EXAMPLE:  example extcurve; shows an example
4079"
4080{
4081  // extends the underlying curve and all its associated objects to a larger
4082  //     base field in order to evaluate points over such a extension
4083  // if d<2 then the only change is that a local ring "RatPl" (which is a
4084  //     copy of "S(1)") is created in order to store the rational places
4085  //     where we can do evaluations
4086  // otherwise, such a ring contains all places which are rational over the
4087  //     extension
4088  // warning : list Places does not change so that only divisors which are
4089  //     "rational over the prime field" are allowed; this probably will
4090  //     change in the future
4091  // warning : the places in RatPl are ranged in increasing degree, respecting
4092  //     the order from list Places and placing the conjugate branches all
4093  //     together
4094  def BR=basering;
4095  list ext_CURVE=CURVE;
4096  if (d<2)
4097  {
4098    def SS=CURVE[5][1][1];
4099    ring RatPl=char(basering),(x,y,t),ls;
4100    list POINTS=imap(SS,POINTS);
4101    list LOC_EQS=imap(SS,LOC_EQS);
4102    list BRANCHES=imap(SS,BRANCHES);
4103    list PARAMETRIZATIONS=imap(SS,PARAMETRIZATIONS);
4104    export(POINTS);
4105    export(LOC_EQS);
4106    export(BRANCHES);
4107    export(PARAMETRIZATIONS);
4108    int NrRatPl=size(POINTS);
4109    ext_CURVE[2][3]=NrRatPl;
4110    setring BR;
4111    ext_CURVE[1][5]=RatPl;
4112    dbprint(printlevel+1,"");
4113    dbprint(printlevel+2,"Total number of rational places : "+string(NrRatPl));
4114    dbprint(printlevel+1,"");
4115    kill(RatPl);
4116    return(ext_CURVE);
4117  }
4118  else
4119  {
4120    // exclude the case when no place of degree d was previously computed/found
4121    int dd=size(CURVE[5]);
4122    if (dd<d)
4123    {
4124      ERROR("you did not compute/find any place of degree "+string(d));
4125    }
4126    if (typeof(CURVE[5][d])<>"list")
4127    {
4128      ERROR("you did not compute/find any place of degree "+string(d));
4129    }
4130
4131    // Define the ring "RatPl" :
4132    def S(d)=CURVE[5][d][1];
4133    setring S(d);
4134    string smin=string(minpoly);
4135    setring BR;
4136    ring RatPl=(char(basering),a),(x,y,t),ls;
4137    execute("minpoly="+smin+";");
4138
4139    // import data from local ring S(d)
4140    list POINTS=imap(S(d),POINTS);
4141    list LOC_EQS=imap(S(d),LOC_EQS);
4142    list BRANCHES=imap(S(d),BRANCHES);
4143    list PARAMETRIZATIONS=imap(S(d),PARAMETRIZATIONS);
4144    kill(S(d));
4145
4146    // conjugate data from S(d)
4147    int s=size(POINTS);
4148    int counter=0;
4149    int piv=0;
4150    int i,j,k;
4151    for (j=1;j<=s;j=j+1)
4152    {
4153      counter=counter+1;
4154      piv=counter;
4155      for (k=1;k<d;k=k+1)
4156      {
4157        POINTS=insert(POINTS,Frobenius(POINTS[piv],1),counter);
4158        LOC_EQS=insert(LOC_EQS,Frobenius(LOC_EQS[piv],1),counter);
4159        BRANCHES=insert(BRANCHES,conj_b(BRANCHES[piv],1),counter);
4160        PARAMETRIZATIONS=insert(PARAMETRIZATIONS,Frobenius(
4161                                  PARAMETRIZATIONS[piv],1),counter);
4162        counter=counter+1;
4163        piv=counter;
4164      }
4165    }
4166
4167    // now the same thing for smaller base fields
4168    string olda;
4169    poly paux;
4170    intvec iv,iw;
4171    int ii,jj,kk,m,n;
4172    for (i=d-1;i>=2;i=i-1)
4173    {
4174      if ( (d mod i)==0 )
4175      {
4176        if (typeof(CURVE[5][i])=="list")
4177        {
4178          def S(i)=CURVE[5][i][1];
4179          // embedd S(i) inside basering == RatPl " ==S(d) "
4180          olda=subfield(S(i));
4181          setring S(i);
4182          s=size(POINTS);
4183          setring RatPl;
4184          // import data from S(i)
4185          for (j=s;j>=1;j=j-1)
4186          {
4187            counter=0;
4188            POINTS=insert(POINTS,list(),0);
4189            POINTS[1][1]=number(importdatum(S(i),"POINTS["+string(j)
4190                                                          +"][1]",olda));
4191            POINTS[1][2]=number(importdatum(S(i),"POINTS["+string(j)
4192                                                          +"][2]",olda));
4193            POINTS[1][3]=number(importdatum(S(i),"POINTS["+string(j)
4194                                                          +"][3]",olda));
4195            LOC_EQS=insert(LOC_EQS,importdatum(S(i),"LOC_EQS["+string(j)
4196                                                          +"]",olda),0);
4197            BRANCHES=insert(BRANCHES,list(),0);
4198            setring S(i);
4199            m=nrows(BRANCHES[j][1]);
4200            n=ncols(BRANCHES[j][1]);
4201            iv=BRANCHES[j][2];
4202            kk=BRANCHES[j][3];
4203            poly par@1=subst(PARAMETRIZATIONS[j][1][1],t,x);
4204            poly par@2=subst(PARAMETRIZATIONS[j][1][2],t,x);
4205            export(par@1);
4206            export(par@2);
4207            iw=PARAMETRIZATIONS[j][2];
4208            setring RatPl;
4209            paux=importdatum(S(i),"BRANCHES["+string(j)+"][4]",olda);
4210            matrix Maux[m][n];
4211            for (ii=1;ii<=m;ii=ii+1)
4212            {
4213              for (jj=1;jj<=n;jj=jj+1)
4214              {
4215                Maux[ii,jj]=importdatum(S(i),"BRANCHES["+string(j)
4216                               +"][1]["+string(ii)+","+string(jj)+"]",olda);
4217              }
4218            }
4219            BRANCHES[1][1]=Maux;
4220            BRANCHES[1][2]=iv;
4221            BRANCHES[1][3]=kk;
4222            BRANCHES[1][4]=paux;
4223            kill(Maux);
4224            PARAMETRIZATIONS=insert(PARAMETRIZATIONS,list(),0);
4225            PARAMETRIZATIONS[1][1]=ideal(0);
4226            PARAMETRIZATIONS[1][1][1]=importdatum(S(i),"par@1",olda);
4227            PARAMETRIZATIONS[1][1][2]=importdatum(S(i),"par@2",olda);
4228            PARAMETRIZATIONS[1][1][1]=subst(PARAMETRIZATIONS[1][1][1],x,t);
4229            PARAMETRIZATIONS[1][1][2]=subst(PARAMETRIZATIONS[1][1][2],x,t);
4230            PARAMETRIZATIONS[1][2]=iw;
4231            for (k=1;k<i;k=k+1)
4232            {
4233              counter=counter+1;
4234              piv=counter;
4235              POINTS=insert(POINTS,Frobenius(POINTS[piv],1),counter);
4236              LOC_EQS=insert(LOC_EQS,Frobenius(LOC_EQS[piv],1),counter);
4237              BRANCHES=insert(BRANCHES,conj_b(BRANCHES[piv],1),counter);
4238              PARAMETRIZATIONS=insert(PARAMETRIZATIONS,Frobenius(
4239                                        PARAMETRIZATIONS[piv],1),counter);
4240            }
4241            setring S(i);
4242            kill(par@1,par@2);
4243            setring RatPl;
4244          }
4245          kill(S(i));
4246        }
4247      }
4248    }
4249    kill(iw);
4250    kill(paux);
4251
4252    // finally add points from S(1)
4253    if (typeof(CURVE[5][1])=="list")
4254    {
4255      def S(1)=CURVE[5][1][1];
4256      POINTS=imap(S(1),POINTS)+POINTS;
4257      LOC_EQS=imap(S(1),LOC_EQS)+LOC_EQS;
4258      BRANCHES=imap(S(1),BRANCHES)+BRANCHES;
4259      PARAMETRIZATIONS=imap(S(1),PARAMETRIZATIONS)+PARAMETRIZATIONS;
4260    }
4261
4262    // prepare data for output
4263    export(POINTS);
4264    export(LOC_EQS);
4265    export(BRANCHES);
4266    export(PARAMETRIZATIONS);
4267    int NrRatPl=size(POINTS);
4268    ext_CURVE[2][3]=NrRatPl;
4269    setring BR;
4270    ext_CURVE[1][5]=RatPl;
4271    ring r(d)=(char(basering),a),(x,y),lp;
4272    execute("minpoly="+smin+";");
4273    setring BR;
4274    ext_CURVE[1][3]=r(d);
4275    ring R(d)=(char(basering),a),(x,y,z),lp;
4276    execute("minpoly="+smin+";");
4277    setring BR;
4278    ext_CURVE[1][4]=R(d);
4279    dbprint(printlevel+1,"");
4280    dbprint(printlevel+2,"Total number of rational places : NrRatPl = "
4281                                   +string(NrRatPl));
4282    dbprint(printlevel+1,"");
4283    kill(S(1));
4284    kill(R(d));
4285    kill(RatPl);
4286    return(ext_CURVE);
4287  }
4288}
4289example
4290{
4291  "EXAMPLE:";  echo = 2;
4292  int plevel=printlevel;
4293  printlevel=-1;
4294  ring s=2,(x,y),lp;
4295  list C=Adj_div(x5+y2+y);
4296  C=NSplaces(1..4,C);
4297  // since we have all points up to degree 4, we can extend the curve
4298  // to that extension, in order to get rational points over F_16;
4299  C=extcurve(4,C);
4300  // e.g., display the basepoint of place no. 32:
4301  def R=C[1][5];
4302  setring R;
4303  POINTS[32];
4304  printlevel=plevel;
4305}
4306///////////////////////////////////////////////////////////////////////////////
4307
4308// specific procedures for linear/AG codes
4309
4310static proc Hamming_wt (matrix A)
4311"USAGE:     Hamming_wt(A), where A is any matrix
4312RETURN:     the Hamming weight (number of non-zero entries) of the matrix A
4313"
4314{
4315  // computes the Hamming weight (number of non-zero entries) of any matrix
4316  // notice that "words" are represented by matrices of size 1xn
4317  // computing the Hamming distance between two matrices can be done by
4318  // Hamming_wt(A-B)
4319  int m=nrows(A);
4320  int n=ncols(A);
4321  int i,j;
4322  int w=0;
4323  for (i=1;i<=m;i=i+1)
4324  {
4325    for (j=1;j<=n;j=j+1)
4326    {
4327      if (A[i,j]<>0)
4328      {
4329        w=w+1;
4330      }
4331    }
4332  }
4333  return(w);
4334}
4335///////////////////////////////////////////////////////////////////////////////
4336
4337// Basic Algorithm of Skorobogatov and Vladut for decoding AG codes
4338// warning : the user must choose carefully the parameters for the code and
4339//     the decoding since they will never be checked by the procedures
4340
4341proc prepSV (intvec G,intvec D,intvec F,list EC)
4342"USAGE:    prepSV( G, D, F, EC ); G,D,F intvecs and EC a list
4343RETURN:   list E of size n+3, where n=size(D). All its entries but E[n+3]
4344          are matrices:
4345   @format
4346   E[1]:  parity check matrix for the current AG code
4347   E[2] ... E[n+2]:  matrices used in the procedure decodeSV
4348   E[n+3]:  intvec with
4349       E[n+3][1]: correction capacity @math{epsilon} of the algorithm
4350       E[n+3][2]: designed Goppa distance @math{delta} of the current AG code
4351   @end format
4352NOTE:     Computes the preprocessing for the basic (Skorobogatov-Vladut)
4353          decoding algorithm.@*
4354          The procedure must be called within the ring EC[1][4], where EC is
4355          the output of @code{extcurve(d)} (or in the ring EC[1][2] if d=1) @*
4356          The intvec G and F represent rational divisors (see
4357          @ref{BrillNoether} for more details).@*
4358          The intvec D refers to rational places (see @ref{AGcode_Omega}
4359          for more details.).
4360          The current AG code is @code{AGcode_Omega(G,D,EC)}.@*
4361          If you know the exact minimum distance d and you want to use it in
4362          @code{decodeSV} instead of @math{delta}, you can change the value
4363          of E[n+3][2] to d before applying decodeSV.
4364          If you have a systematic encoding for the current code and want to
4365          keep it during the decoding, you must previously permute D (using
4366          @code{permute_L(D,P);}), e.g., according to the permutation
4367          P=L[3], L being the output of @code{sys_code}.
4368WARNINGS: F must be a divisor with support disjoint from the support of D and
4369          with degree @math{epsilon + genus}, where
4370          @math{epsilon:=[(deg(G)-3*genus+1)/2]}.@*
4371          G should satisfy @math{ 2*genus-2 < deg(G) < size(D) }, which is
4372          not checked by the algorithm.
4373          G and D should also have disjoint supports (checked by the
4374          algorithm).
4375KEYWORDS: SV-decoding algorithm, preprocessing
4376SEE ALSO: extcurve, AGcode_Omega, decodeSV, sys_code, permute_L
4377EXAMPLE:  example prepSV; shows an example
4378"
4379{
4380  if (disj_divs(F,D,EC)==0)
4381  {
4382    dbprint(printlevel+3,"? the divisors do not have disjoint supports,
4383                            empty list returned ?");
4384    return(list());
4385  }
4386  list E=list();
4387  list Places=EC[3];
4388  int m=deg_D(G,Places);
4389  int genusX=EC[2][2];
4390  int e=(m+1-3*genusX)/2;
4391  if (e<1)
4392  {
4393    dbprint(printlevel+3,"? the correction capacity of the basic algorithm
4394                            is zero, empty list returned ?");
4395    return(list());
4396  }
4397  // deg(F)==e+genusX should be satisfied, and sup(D),sup(F) should be
4398  // disjoint !!!!
4399  int n=size(D);
4400  // 2*genusX-2<m<n should also be satisfied !!!!
4401  matrix EE=AGcode_L(G,D,EC);
4402  int l=nrows(EE);
4403  E[1]=EE;
4404  matrix GP=AGcode_L(F,D,EC);
4405  int r=nrows(GP);
4406  intvec H=G-F;
4407  matrix HP=AGcode_L(H,D,EC);
4408  int s=nrows(HP);
4409  int i,j,k;
4410  kill(EE);
4411  for (k=1;k<=n;k=k+1)
4412  {
4413    E[k+1]=GP[1,k]*submat(HP,1..s,k..k);
4414    for (i=2;i<=r;i=i+1)
4415    {
4416      E[k+1]=concat(E[k+1],GP[i,k]*submat(HP,1..s,k..k));
4417    }
4418  }
4419  E[n+2]=GP;
4420  intvec IW=e,m+2-2*genusX;
4421  E[n+3]=IW;
4422  kill(IW);
4423  return(E);
4424}
4425example
4426{
4427  "EXAMPLE:";  echo = 2;
4428  int plevel=printlevel;
4429  printlevel=-1;
4430  ring s=2,(x,y),lp;
4431  list HC=Adj_div(x3+y2+y);
4432  HC=NSplaces(1..2,HC);
4433  HC=extcurve(2,HC);
4434  def ER=HC[1][4];
4435  setring ER;
4436  intvec G=5;      // the rational divisor G = 5*HC[3][1]
4437  intvec D=2..9;   // D = sum of the rational places no. 2..9 over F_4
4438  // construct the corresp. residual AG code of type [8,3,>=5] over F_4:
4439  matrix C=AGcode_Omega(G,D,HC);
4440  // we can correct 1 error and the genus is 1, thus F must have degree 2
4441  // and support disjoint from that of D;
4442  intvec F=2;
4443  list SV=prepSV(G,D,F,HC);
4444  // now everything is prepared to decode with the basic algorithm;
4445  // for example, here is a parity check matrix to compute the syndrome :
4446  print(SV[1]);
4447  // and here you have the correction capacity of the algorithm :
4448  int epsilon=SV[size(D)+3][1];
4449  epsilon;
4450  printlevel=plevel;
4451}
4452///////////////////////////////////////////////////////////////////////////////
4453
4454proc decodeSV (matrix y,list K)
4455"USAGE:     decodeSV( y, K ); y a row-matrix and K a list
4456RETURN:     a codeword (row-matrix) if possible, resp. the 0-matrix (of size
4457            1) if decoding is impossible.
4458            For decoding the basic (Skorobogatov-Vladut) decoding algorithm
4459            is applied.
4460NOTE:       The list_expression should be the output K of the procedure
4461            @code{prepSV}.@*
4462            The matrix_expression should be a (1 x n)-matrix,  where
4463            n = ncols(K[1]).@*
4464            The decoding may fail if the number of errors is greater than
4465            the correction capacity of the algorithm.
4466KEYWORDS:   SV-decoding algorithm
4467SEE ALSO:   extcurve, AGcode_Omega, prepSV
4468EXAMPLE:    example decodeSV; shows an example
4469"
4470{
4471  // decodes y with the "basic decoding algorithm", if possible
4472  // requires the preprocessing done by the procedure "prepSV"
4473  // the procedure must be called from ring R or R(d)
4474  // returns either a codeword (matrix) of none (in case of too many errors)
4475  matrix syndr=K[1]*transpose(y);
4476  if (Hamming_wt(syndr)==0)
4477  {
4478    return(y);
4479  }
4480  matrix Ey=y[1,1]*K[2];
4481  int n=ncols(y);
4482  int i;
4483  for (i=2;i<=n;i=i+1)
4484  {
4485    Ey=Ey+y[1,i]*K[i+1];
4486  }
4487  matrix Ky=get_NZsol(Ey);
4488  if (Hamming_wt(Ky)==0)
4489  {
4490    dbprint(printlevel+3,"? no error-locator found ?");
4491    dbprint(printlevel+3,"? too many errors occur, 0-matrix returned ?");
4492    matrix answer;
4493    return(answer);
4494  }
4495  int r=nrows(K[n+2]);
4496  matrix ErrLoc[1][n];
4497  list Z=list();
4498  list NZ=list();
4499  int j;
4500  for (j=1;j<=n;j=j+1)
4501  {
4502    for (i=1;i<=r;i=i+1)
4503    {
4504      ErrLoc[1,j]=ErrLoc[1,j]+K[n+2][i,j]*Ky[1,i];
4505    }
4506    if (ErrLoc[1,j]==0)
4507    {
4508      Z=insert(Z,j,size(Z));
4509    }
4510    else
4511    {
4512      NZ=insert(NZ,j,size(NZ));
4513    }
4514  }
4515  int k=size(NZ);
4516  int l=nrows(K[1]);
4517  int s=l+k;
4518  matrix A[s][n];
4519  matrix b[s][1];
4520  for (i=1;i<=l;i=i+1)
4521  {
4522    for (j=1;j<=n;j=j+1)
4523    {
4524      A[i,j]=K[1][i,j];
4525    }
4526    b[i,1]=syndr[i,1];
4527  }
4528  for (i=1;i<=k;i=i+1)
4529  {
4530    A[l+i,NZ[i]]=number(1);
4531  }
4532  intvec opgt=option(get);
4533  option(redSB);
4534  matrix L=transpose(syz(concat(A,-b)));
4535  if (nrows(L)==1)
4536  {
4537    if (L[1,n+1]<>0)
4538    {
4539      poly pivote=L[1,n+1];
4540      matrix sol=submat(L,1..1,1..n);
4541      if (pivote<>1)
4542      {
4543        sol=(number(1)/number(pivote))*sol;
4544      }
4545      // check at least that the number of comitted errors is less than half
4546      //     the Goppa distance
4547      // imposing Hamming_wt(sol)<=K[n+3][1] would be more correct, but maybe
4548      //     is too strong
4549      // on the other hand, if Hamming_wt(sol) is too large the decoding may
4550      //     not be acceptable
4551      if ( Hamming_wt(sol) <= (K[n+3][2]-1)/2 )
4552      {
4553        option(set,opgt);
4554        return(y-sol);
4555      }
4556      else
4557      {
4558        dbprint(printlevel+3,"? non-acceptable decoding ?");
4559      }
4560    }
4561    else
4562    {
4563      dbprint(printlevel+3,"? no solution found ?");
4564    }
4565  }
4566  else
4567  {
4568    dbprint(printlevel+3,"? non-unique solution ?");
4569  }
4570  option(set,opgt);
4571  dbprint(printlevel+3,"? too many errors occur, 0-matrix returned ?");
4572  matrix answer;
4573  return(answer);
4574}
4575example
4576{
4577  "EXAMPLE:";  echo = 2;
4578  int plevel=printlevel;
4579  printlevel=-1;
4580  ring s=2,(x,y),lp;
4581  list HC=Adj_div(x3+y2+y);
4582  HC=NSplaces(1..2,HC);
4583  HC=extcurve(2,HC);
4584  def ER=HC[1][4];
4585  setring ER;
4586  intvec G=5;      // the rational divisor G = 5*HC[3][1]
4587  intvec D=2..9;   // D = sum of the rational places no. 2..9 over F_4
4588  // construct the corresp. residual AG code of type [8,3,>=5] over F_4:
4589  matrix C=AGcode_Omega(G,D,HC);
4590  // we can correct 1 error and the genus is 1, thus F must have degree 2
4591  // and support disjoint from that of D
4592  intvec F=2;
4593  list SV=prepSV(G,D,F,HC);
4594  // now we produce 1 error on the zero-codeword :
4595  matrix y[1][8];
4596  y[1,3]=a;
4597  // and then we decode :
4598  print(decodeSV(y,SV));
4599  printlevel=plevel;
4600}
4601///////////////////////////////////////////////////////////////////////////////
4602
4603proc sys_code (matrix C)
4604"USAGE:    sys_code(C); C is a matrix of constants
4605RETURN:   list L with:
4606   @format
4607   L[1] is the generator matrix in standard form of an equivalent code,
4608   L[2] is the parity check matrix in standard form of such code,
4609   L[3] is an intvec which represents the needed permutation.
4610   @end format
4611NOTE:     Computes a systematic code which is equivalent to the given one.@*
4612          The input should be a matrix of numbers.@*
4613          The output has to be interpreted as follows: if the input was
4614          the generator matrix of an AG code then one should apply the
4615          permutation L[3] to the divisor D of rational points by means
4616          of @code{permute_L(D,L[3]);} before continuing to work with the
4617          code (for instance, if you want to use the systematic encoding
4618          together with a decoding algorithm).
4619KEYWORDS: linear code, systematic
4620SEE ALSO: permute_L, AGcode_Omega, prepSV
4621EXAMPLE:  example sys_code; shows an example
4622"
4623{
4624  // computes a systematic code which is equivalent to that given by C
4625  int i,j,k,l,h,r;
4626  int m=nrows(C);
4627  int n=ncols(C);
4628  int mr=m;
4629  matrix A[m][n]=C;
4630  poly c,p;
4631  list corners=list();
4632  if(m>n)
4633  {
4634    mr=n;
4635  }
4636  // first the matrix A will be reduced with elementary operations by rows
4637  for(i=1;i<=mr;i=i+1)
4638  {
4639    if((i+l)>n)
4640    {
4641      // the process is finished
4642      break;
4643    }
4644    // look for a non-zero element
4645    if(A[i,i+l]==0)
4646    {
4647      h=i;
4648      p=0;
4649      for (j=i+1;j<=m;j=j+1)
4650      {
4651        c=A[j,i+l];
4652        if (c!=0)
4653        {
4654          p=c;
4655          h=j;
4656          break;
4657        }
4658      }
4659      if (h!=i)
4660      {
4661        // permutation of rows i and h
4662        for (j=1;j<=n;j=j+1)
4663        {
4664          c=A[i,j];
4665          A[i,j]=A[h,j];
4666          A[h,j]=c;
4667        }
4668      }
4669      if(p==0)
4670      {
4671        // non-zero element not found in the current column
4672        l=l+1;
4673        continue;
4674      }
4675    }
4676    // non-zero element was found in "strategic" position
4677    corners[i]=i+l;
4678    // make zeros below that position
4679    for(j=i+1;j<=m;j=j+1)
4680    {
4681      c=A[j,i+l]/A[i,i+l];
4682      for(k=i+l+1;k<=n;k=k+1)
4683      {
4684        A[j,k]=A[j,k]-A[i,k]*c;
4685      }
4686      A[j,i+l]=0;
4687      A[j,i]=0;
4688    }
4689    // the rank is at least r
4690    // when the process stops the last r is actually the true rank of A=a
4691    r=i;
4692  }
4693  if (r<m)
4694  {
4695    ERROR("the given matrix does not have maximum rank");
4696  }
4697  // set the corners to the beginning and construct the permutation
4698  intvec PCols=1..n;
4699  for (j=1;j<=m;j=j+1)
4700  {
4701    if (corners[j]>j)
4702    {
4703      // interchange columns j and corners[j]
4704      for (i=1;i<=m;i=i+1)
4705      {
4706        c=A[i,j];
4707        A[i,j]=A[i,corners[j]];
4708        A[i,corners[j]]=c;
4709      }
4710      k=PCols[j];
4711      PCols[j]=PCols[corners[j]];
4712      PCols[corners[j]]=k;
4713    }
4714  }
4715  // convert the diagonal into ones
4716  for (i=1;i<=m;i=i+1)
4717  {
4718    for (j=i+1;j<=n;j=j+1)
4719    {
4720      A[i,j]=A[i,j]/A[i,i];
4721    }
4722    A[i,i]=1;
4723  }
4724  // complete a block with the identity matrix
4725  for (k=1;k<m;k=k+1)
4726  {
4727    for (i=k+1;i<=m;i=i+1)
4728    {
4729      for (j=i+1;j<=n;j=j+1)
4730      {
4731        A[k,j]=A[k,j]-A[i,j]*A[k,i];
4732      }
4733      A[k,i]=0;
4734    }
4735  }
4736  // compute a parity-check matrix in standard form
4737  matrix B=concat(-transpose(submat(A,1..m,m+1..n)),diag(1,n-m));
4738  list L=list();
4739  L[1]=A;
4740  L[2]=B;
4741  L[3]=PCols;
4742  return(L);
4743}
4744example
4745{
4746  "EXAMPLE:";  echo = 2;
4747  ring s=3,T,lp;
4748  matrix C[2][5]=0,1,0,1,1,0,1,0,0,1;
4749  print(C);
4750  list L=sys_code(C);
4751  L[3];
4752  // here is the generator matrix in standard form
4753  print(L[1]);
4754  // here is the control matrix in standard form
4755  print(L[2]);
4756  // we can check that both codes are dual to each other
4757  print(L[1]*transpose(L[2]));
4758}
4759
4760////////////// this procedure should move in hnoether.lib /////////
4761static proc ratdevelop (poly chi)
4762{
4763  int ring_is_changed;
4764  int k1=res_deg();
4765  list L=essdevelop(chi);
4766  if (typeof(L[1])=="ring") {
4767    def altring=basering;
4768    def HNring = L[1]; setring HNring;
4769    def HND = hne;
4770    kill hne;
4771    ring_is_changed=1;
4772  }
4773  else {
4774    def HND=L[1];
4775  }
4776  int k2=res_deg();
4777  if (k1<k2)
4778  {
4779    int N=size(HND);
4780    list CB=list();
4781    int i,j,k,d;
4782    intvec dgs;
4783    list auxL=list();
4784    intvec auxiv;
4785    for (i=1;i<=N;i++)
4786    {
4787      CB[i]=conj_bs(HND[i],k1);
4788      dgs[i]=size(CB[i]);
4789    }
4790    for (i=1;i<N;i++)
4791    {
4792      for (j=i+1;j<=N;j++)
4793      {
4794        if (dgs[i]==dgs[j])
4795        {
4796          d=dgs[i];
4797          for (k=1;k<=d;k++)
4798          {
4799            if (intersection(CB[i][1],CB[j][k])==-1)
4800            {
4801              HND=delete(HND,j);
4802              CB=delete(CB,j);
4803//              dgs=delete(dgs,j);
4804              execute("auxL="+string(dgs)+";");
4805              auxL=delete(auxL,j);
4806              execute("dgs="+string(auxL)+";");
4807              N=N-1;
4808              j=j-1;
4809              break;
4810            }
4811          }
4812        }
4813      }
4814    }
4815  }
4816  if (ring_is_changed==0) { return(HND); }
4817  else { export HND; setring altring; return(HNring); }
4818}
4819
4820
4821
4822///////////////////////////////////////////////////////////////////////////////
4823
4824/*
4825// ============================================================================
4826// *******       ADDITIONAL INFORMATION ABOUT THE LIBRARY              ********
4827// ============================================================================
4828
4829A SINGULAR library for plane curves, Weierstrass semigroups and AG codes
4830Also available via http://wmatem.eis.uva.es/~ignfar/singular/
4831
4832PREVIOUS WARNINGS :
4833
4834   (1) The procedures will work only in positive characteristic
4835   (2) The base field must be prime (this may change in the future)
4836           This limitation is not too serious, since in coding theory
4837           the used curves are usually (if not always) defined over a
4838           prime field, and extensions are only considered for
4839           evaluating functions in a field with many points;
4840           by the same reason, auxiliary divisors are usually defined
4841           over the prime field,
4842           with the exception of that consisting of "rational points"
4843   (3) The curve must be absolutely irreducible (but it is not checked)
4844   (4) Only (algebraic projective) plane curves are considered
4845
4846GENERAL CONCEPTS :
4847
4848   (1) An affine point P is represented by a std of a prime ideal,
4849       and an intvec containing the position of the places above P
4850       in the list of Places; if the point is at infinity, the ideal is
4851       changed by a homogeneous irreducible polynomial in two variables
4852   (2) A place is represented by :
4853       a base point (list of homogeneous coordinates),
4854       a local equation for the curve at the base point,
4855       a Hamburger-Noether expansion of the corresponding branch,
4856       and a local parametrization (in "t") of such branch; everything is
4857       stored in a local ring "_[5][d][1]", d being the degree of the place,
4858       by means of lists "POINTS,LOC_EQS,BRANCHES,PARAMETRIZATIONS", and
4859       the degrees of the base points corresponding to the places in the
4860       ring "_[5][d][1]" are stored in an intvec "_[5][d][2]"
4861   (3) A divisor is represented by an intvec, where the integer at the
4862       position i means the coefficient of the i-th place in the divisor
4863   (4) Rational functions are represented by numerator/denominator
4864       in form of ideals with two homogeneous generators
4865
4866OUTLINE/EXAMPLE OF THE USE OF THE LIBRARY :
4867
4868Plane curves :
4869
4870      (1.0) ring s=p,(x,y[,z]),lp;
4871
4872            Notice that if you use 3 variables, then the equation
4873            of the curve is assumed to be a homogeneous polynomial.
4874
4875      (1.1) list CURVE=Adj_div(equation);
4876
4877            In CURVE[3] are listed all the (singular closed) places
4878            with their corresponding degrees; thus, you can now decide
4879            how many other points you want to compute with NSplaces.
4880
4881      (1.2) CURVE=NSplaces(degrees,CURVE);
4882
4883            "degrees" is an intvec with the degrees we want to compute
4884
4885      (1.3) CURVE=extcurve(extension,CURVE);
4886
4887            The rational places over the extension are ranged in
4888            the ring CURVE[1][5] with the following rules:
4889
4890                (i)    all the representatives of the same closed point
4891                       are listed in consecutive positions;
4892                (ii)   if deg(P)<deg(Q), then the representatives of P
4893                       are listed before those of Q;
4894                (iii)  if two closed points P,Q have the same degree,
4895                       then the representatives of P are listed before
4896                       if P appears before in the list CURVE[3].
4897
4898Rational functions :
4899
4900      (2.0) def R=CURVE[1][2];
4901            setring R;
4902      (2.1) list LG=BrillNoether(intvec divisor,CURVE);
4903      (2.2) list WS=Weierstrass(int place,int bound,CURVE);
4904
4905Algebraic Geometry codes :
4906
4907      (3.0) def ER=CURVE[1][4];    // if extension>1; else use R instead
4908            setring ER;
4909
4910            Now you have to decide the divisor G and the sequence of
4911            rational points D to use for constructing the codes;
4912            first notice that the syntax for G and D is different:
4913
4914                (a) G is a divisor supported on the closed places of
4915                    CURVE[3], and you must say just the coefficient
4916                    of each such a point; for example, G=2,0,-1 means
4917                    2 times the place 1 minus 1 times the place 3.
4918
4919                (b) D is a sequence of rational points (all different
4920                    and counted 1 time each one), whose data are read
4921                    from the lists inside CURVE[1][5] and now you must
4922                    say just the order how you range the chosen point;
4923                    for example, D=2,4,1 means that you choose the
4924                    rational places 1,2,4 and you range them as 2,4,1.
4925
4926      (3.1) matrix C=AGcode_L(divisor,places,CURVE);
4927
4928      (3.2) AGcode_Omega(divisor,places,CURVE);
4929
4930            In the same way as for defining the codes, the auxiliary
4931            divisor F must have disjoint support to that of D, and
4932            its degree has to be given by a formula (see help prepSV).
4933
4934      (3.3) list SV=prepSV(divisor,places,auxiliary_divisor,CURVE);
4935
4936      (3.4) decodeSV(word,SV);
4937
4938Special Issues :
4939
4940      (I)  AG codes with systematic encoding :
4941
4942              matrix C=AGcode_Omega(G,D,CURVE);
4943              list CODE=sys_code(G);
4944              C=CODE[1];               // generator matrix in standard form
4945              D=permute_L(D,CODE[3]);  // suitable permutation of coordinates
4946              list SV=prepSV(G,D,F,CURVE);
4947              SV[1]=CODE[2];           // parity-check matrix in standard form
4948
4949      (II) Using the true minimum distance d for decoding :
4950
4951              matrix C=AGcode_Omega(G,D,CURVE);
4952              int n=size(D);
4953              list SV=prepSV(G,D,F,CURVE);
4954              SV[n+3][2]=d;            // then use decodeSV(y,SV);
4955
4956
4957// ============================================================================
4958// ***   Some "macros" with typical examples of curves in Coding Theory    ****
4959// ============================================================================
4960
4961
4962proc Klein ()
4963{
4964  list KLEIN=Adj_div(x3y+y3+x);
4965  KLEIN=NSplaces(1..3,KLEIN);
4966  KLEIN=extcurve(3,KLEIN);
4967  dbprint(printlevel+1,"Klein quartic over F_8 successfully constructed");
4968  return(KLEIN);
4969}
4970
4971proc Hermite (int m)
4972{
4973  int p=char(basering);
4974  int r=p^m;
4975  list HERMITE=Adj_div(y^r+y-x^(r+1));
4976  HERMITE=NSplaces(1..2*m,HERMITE);
4977  HERMITE=extcurve(2*m,HERMITE);
4978  dbprint(printlevel+1,"Hermitian curve over F_("+string(r)+"^2)
4979                          successfully constructed");
4980  return(HERMITE);
4981}
4982
4983proc Suzuki ()
4984{
4985  list SUZUKI=Adj_div(x10+x3+y8+y);
4986  SUZUKI=NSplaces(1..3,SUZUKI);
4987  SUZUKI=extcurve(3,SUZUKI);
4988  dbprint(printlevel+1,"Suzuki curve over F_8 successfully constructed");
4989  return(SUZUKI);
4990}
4991
4992// **** Other interesting examples :
4993
4994// A hyperelliptic curve with 33 rational points over F_16
4995
4996list CURVE=Adj_div(x5+y2+y);
4997CURVE=NSplaces(1..4,CURVE);
4998CURVE=extcurve(4,CURVE);
4999
5000// A nice curve with 113 rational points over F_64
5001
5002list CURVE=Adj_div(y9+y8+xy6+x2y3+y2+x3);
5003intvec ww=1,2,3,6;
5004CURVE=NSplaces(ww,CURVE);
5005CURVE=extcurve(6,CURVE);
5006
5007*/
Note: See TracBrowser for help on using the repository browser.