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

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