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

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