# HG changeset patch
# User Moritz Minzlaff
# Date 1290278473 3600
# Node ID f60c02c17b794574cdf738c1ba21aa462f9b11f4
# Parent 120c07be6358d93bcff503363d379c26b8342f2b
Trac 8997: fix riemann_roch_basis and documentation
diff r 120c07be6358 r f60c02c17b79 doc/en/constructions/algebraic_geometry.rst
 a/doc/en/constructions/algebraic_geometry.rst Sat Oct 30 16:00:40 2010 0700
+++ b/doc/en/constructions/algebraic_geometry.rst Sat Nov 20 19:41:13 2010 +0100
@@ 306,37 +306,27 @@
RiemannRoch spaces using Singular
==================================
Can you compute a basis of a RiemannRoch space in Sage?
+To compute a basis of the RiemannRoch space of a divisor :math:`D`
+on a curve over a field :math:`F`, one can use Sage's wrapper
+``riemann_roch_basis`` of Singular's implementation of the Brill
+Noether algorithm. Note that this wrapper currently only works when
+:math:`F` is prime and the divisor :math:`D` is supported on rational points.
+Below are examples of how to use ``riemann_roch_basis`` and how to use
+Singular itself to help an understanding of how the wrapper works.
Unfortunately, the answer is "no" at the present time. The version
of Singular currently used by (version 3.0.2) has a BrillNoether
algorithm implementation (computing a basis of a RiemannRoch
space) which appears to be buggy. The rest of this section is
included to illustrate the syntax once the bugs in ``brnoeth`` get
worked out (or to help any developers wishing to work on this
themselves).
+ Using ``riemann_roch_basis``:
To compute a basis for the RiemannRoch space :math:`L(D)`
associated to a divisor :math:`D` on a curve :math:`X` over a
field :math:`F`, you can use 's "wrapper" ``riemann_roch_basis``
to Singular or Singular itself. Both are illustrated below.



::
sage: x, y, z = PolynomialRing(GF(5), 3, 'xyz').gens()
sage: f = x^7 + y^7 + z^7
 sage: C = Curve(f); pts = C.rational_points()
 sage: D = C.divisor([ (3, pts[0]), (1,pts[1]), (10, pts[5]) ])
 sage: C.riemann_roch_basis(D)
 [x^8*y/(x^6*z^3  x^5*y*z^3 + ... # 32bit
 [(x^9 + x^8*y)/(x^6*z^3  ... # 64bit
+ sage: X = Curve(f); pts = X.rational_points()
+ sage: D = X.divisor([ (3, pts[0]), (1,pts[1]), (10, pts[5]) ])
+ sage: X.riemann_roch_basis(D)
+ [(2*x + y)/(x + y), (x + z)/(x + y)]
 The output is somewhat random.

 Singular's ``BrillNoether`` command (for details on this command,
 see the section BrillNoether in the Singular online documentation
+ Using Singular's ``BrillNoether`` command (for details see the section
+ BrillNoether in the Singular online documentation
(http://www.singular.unikl.de/Manual/html/sing_960.htm and the
paper {CF}):
@@ 353,9 +343,8 @@
Adjunction divisor computed successfully
The genus of the curve is 2
 sage: print singular.eval("X = NSplaces(1..2,X);")
+ sage: print singular.eval("X = NSplaces(1,X);")
Computing nonsingular affine places of degree 1 ...
 Computing nonsingular affine places of degree 2 ...
sage: print singular("X[3];")
[1]:
1,1
@@ 370,8 +359,20 @@
[6]:
1,6
 The 6 Places in X[3] are of degree 1. We define the rational
 divisor {G = 4\*C[3][1]+4\*C[3][2]+4\*C[3][3]} (of degree 12):
+ The first integer of each pair in the above list is the degree
+ `d` of a point. The second integer is the index of this point
+ in the list POINTS of the ring X[5][`d`][1]. Note that the
+ order of this latter list is different every time the algorithm
+ is run, e.g. `1`, `1` in the above list refers to a different
+ rational point each time. A divisor is given by defining a list
+ `G` of integers of the same length as X[3] such that if the
+ `k`th entry of X[3] is `d`, `i`, then the `k`th entry of `G` is
+ the multiplicity of the divisor at the `i`th point in the list
+ POINTS of the ring X[5][`d`][1]. Let us proceed by defining a
+ "random" divisor of degree 12 and computing a basis of its
+ RiemannRoch space:
+
+ .. link
::
@@ 388,26 +389,6 @@
Vector basis successfully computed
 Here is the vector basis of L(G):

 .. link

 ::

 sage: print singular.eval("LG;")
 [1]: # 32bit
 _[1]=x2 # 32bit
 _[2]=x2+z2 # 32bit
 [2]: # 32bit
 _[1]=x4+x2z2 # 32bit
 _[2]=x2y2+y2z2 # 32bit
 [1]: # 64bit
 _[1]=x5+x4zx3y2+2x3z2+x2y2z # 64bit
 _[2]=x4z+x3y2+z5 # 64bit
 [2]: # 64bit
 _[1]=2x5x4z+2x3y2+2x3z2+x2z3 # 64bit
 _[2]=x4z+x3y2+z5 # 64bit
 ...
.. index::
pair: codes; algebraicgeometric
@@ 421,9 +402,10 @@
and the divisor :math:`D`, you must also specify the evaluation
divisor :math:`E`.
As in the previous section, until the bugs in ``brnoth`` are worked
out, this section is only included to illustrate syntax (or to help
any developers wishing to work on this themselves).
+Note that this section has not been updated since the wrapper
+``riemann_roch_basis`` has been fixed. See above for how to
+properly define a divisor for Singular's ``BrillNoether``
+command.
Here's an example, one which computes a generator matrix of an
associated AG code. This time we use Singular's ``AGCode_L``
diff r 120c07be6358 r f60c02c17b79 sage/schemes/plane_curves/projective_curve.py
 a/sage/schemes/plane_curves/projective_curve.py Sat Oct 30 16:00:40 2010 0700
+++ b/sage/schemes/plane_curves/projective_curve.py Sat Nov 20 19:41:13 2010 +0100
@@ 8,6 +8,8 @@
 David Joyner (20051113)
 David Kohel (200601)
+
+ Moritz Minzlaff (201011)
"""
#*****************************************************************************
@@ 538,45 +540,38 @@
r"""
Return a basis for the RiemannRoch space corresponding to
`D`.

 .. warning::
 This function calls a Singular function that
 appears to be very buggy and should not be trusted.

This uses Singular's BrillNoether implementation.
INPUT:


  ``sort``  bool (default: True), if True return the
 point list sorted. If False, returns the points in the order
 computed by Singular.

+
+  ``D``  a divisor
+
+ OUTPUT:
+
+ A list of function field elements that form a basis of the RiemannRoch space
EXAMPLE::
sage: R. = GF(2)[]
sage: f = x^3*y + y^3*z + x*z^3
sage: C = Curve(f); pts = C.rational_points()
 sage: D = C.divisor([ (4, pts[0]), (0,pts[1]), (4, pts[2]) ])
+ sage: D = C.divisor([ (4, pts[0]), (4, pts[2]) ])
sage: C.riemann_roch_basis(D)
[x/y, 1, z/y, z^2/y^2, z/x, z^2/(x*y)]
 The following example illustrates that the RiemannRoch space
 function in Singular doesn't *not* work correctly.

::
sage: R. = GF(5)[]
sage: f = x^7 + y^7 + z^7
sage: C = Curve(f); pts = C.rational_points()
sage: D = C.divisor([ (3, pts[0]), (1,pts[1]), (10, pts[5]) ])
 sage: C.riemann_roch_basis(D) # output is random (!!!!)
 [x/(y + x), (z + y)/(y + x)]

 The answer has dimension 2 (confirmed via Magma). But it varies
 between 1 and quite large with Singular.
+ sage: C.riemann_roch_basis(D)
+ [(2*x + y)/(x + y), (x + z)/(x + y)]
+
+
+ .. NOTE::
+ Currently this only works over prime field and divisors supported on rational points.
"""
f = self.defining_polynomial()._singular_()
singular = f.parent()
@@ 585,25 +580,31 @@
X1 = f.Adj_div()
except (TypeError, RuntimeError), s:
raise RuntimeError, str(s) + "\n\n ** Unable to use the BrillNoether Singular package to compute all points (see above)."

X2 = singular.NSplaces(1, X1)
 X3 = singular.extcurve(1, X2)
 R = X3[1][5]
+ # retrieve list of all computed closed points (possibly of degree >1)
+ v = X2[3].sage_flattened_str_list() # We use sage_flattened_str_list since iterating through
+ # the entire list through the sage/singular interface directly
+ # would involve hundreds of calls to singular, and timing issues with
+ # the expect interface could crop up. Also, this is vastly
+ # faster (and more robust).
+ v = [ v[i].partition(',') for i in range(len(v)) ]
+ pnts = [ ( int(v[i][0]), int(v[i][2])1 ) for i in range(len(v))]
+ # retrieve coordinates of rational points
+ R = X2[5][1][1]
singular.set_ring(R)

 # We use sage_flattened_str_list since iterating through
 # the entire list through the sage/singular interface directly
 # would involve hundreds of calls to singular, and timing issues with
 # the expect interface could crop up. Also, this is vastly
 # faster (and more robust).
v = singular('POINTS').sage_flattened_str_list()
 pnts = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)/3)]
+ coords = [self(int(v[3*i]), int(v[3*i+1]), int(v[3*i+2])) for i in range(len(v)/3)]
+ # build correct representation of D for singular
Dsupport = D.support()
Dcoeffs = []
for x in pnts:
 Dcoeffs.append(D.coefficient(x))
+ if x[0] == 1:
+ Dcoeffs.append(D.coefficient(coords[x[1]]))
+ else:
+ Dcoeffs.append(0)
Dstr = str(tuple(Dcoeffs))
G = singular(','.join([str(x) for x in Dcoeffs]), type='intvec')
+ # call singular's brill noether routine and return
T = X2[1][2]
T.set_ring()
LG = G.BrillNoether(X2)