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

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