# HG changeset patch
# User Nick Alexander <ncalexander@gmail.com>
# Date 1247109277 25200
# Node ID 3d2791fa34376e7fe00e1206a89d310ab1673d15
# Parent  d6e4600f23539bc7c604c6545d6ef898eaa66ce4
[mq]: smalljac.patch

diff -r d6e4600f2353 -r 3d2791fa3437 module_list.py
--- a/module_list.py	Thu Jun 04 22:47:59 2009 -0700
+++ b/module_list.py	Wed Jul 08 20:14:37 2009 -0700
@@ -415,6 +415,11 @@
               libraries = ["symmetrica"],
               depends = [SAGE_ROOT + "/local/include/symmetrica/def.h"]),
 
+    Extension('sage.libs.smalljac.smalljac',
+              sources = ["sage/libs/smalljac/smalljac.pyx"],
+              include_dirs = [SAGE_ROOT+'/local/include/SMALLJAC/'],
+              libraries = ["smalljac"]),
+
     Extension('sage.libs.mpmath.utils',
               sources = ["sage/libs/mpmath/utils.pyx"],
               libraries = ['mpfr', 'gmp']),
diff -r d6e4600f2353 -r 3d2791fa3437 sage/libs/smalljac/__init__.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/libs/smalljac/__init__.py	Wed Jul 08 20:14:37 2009 -0700
@@ -0,0 +1,5 @@
+# -*- sage -*-
+
+# The presence of a file __init__.py in a directory makes Python treat
+# the Python files in that directory as part of a package. That is the
+# sole purpose of having this file here.
diff -r d6e4600f2353 -r 3d2791fa3437 sage/libs/smalljac/all.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/libs/smalljac/all.py	Wed Jul 08 20:14:37 2009 -0700
@@ -0,0 +1,1 @@
+from smalljac import demo1
diff -r d6e4600f2353 -r 3d2791fa3437 sage/libs/smalljac/smalljac.pyx
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sage/libs/smalljac/smalljac.pyx	Wed Jul 08 20:14:37 2009 -0700
@@ -0,0 +1,156 @@
+# -*- sage -*-
+
+include "../../ext/cdefs.pxi" # required by gmp.pxi
+include "../../ext/gmp.pxi" # used all over
+include "../../ext/stdsage.pxi" # for PY_NEW
+from sage.rings.all import ZZ, QQ
+
+cdef extern from "smalljac.h": 
+    cdef enum:
+        SMALLJAC_PARSE_ERROR
+    cdef enum:
+        SMALLJAC_UNSUPPORTED_CURVE
+    cdef enum:
+        SMALLJAC_SINGULAR_CURVE
+    cdef enum:
+        SMALLJAC_WRONG_GENUS
+#     cdef enum:
+#         SMALLJAC_GENUS
+
+    ctypedef struct smalljac_Qcurve_t:
+        pass
+
+    smalljac_Qcurve_t smalljac_Qcurve_init (char *str, int *err)
+
+    long smalljac_Lpolys (smalljac_Qcurve_t c,
+                     unsigned long start,
+                     unsigned long end,
+                     unsigned long flags,
+                     int (*callback)(smalljac_Qcurve_t c,
+                                     unsigned long p,
+                                     int good,
+                                     long a[],
+                                     int n,
+                                     void *arg),
+                    void *arg)
+
+    int smalljac_Qcurve_genus (smalljac_Qcurve_t c)
+
+    void smalljac_Qcurve_clear (smalljac_Qcurve_t c)
+
+cdef int callback (smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void* arg): # with gil:
+    cdef list L = (<list>arg)
+    cdef list A = []
+    cdef int i
+    for i in range(n):
+        A.append(a[i])
+    L.append( (p, good, n, tuple(A)) )
+    return 1 # 1 to continue, 0 to stop
+
+cdef smalljac_Qcurve_t my_init(f):
+    f = QQ['x'](f)
+    if not f.is_monic():
+        raise NotImplementedError, "smalljac handles only Weierstrass models of the form y^2 = f(x) with f monic"
+    cdef object s = str(f).replace(' ', '').replace('*', '') # easy way to convert to smalljac form
+
+    cdef smalljac_Qcurve_t curve
+
+    cdef int err
+    curve = smalljac_Qcurve_init(s, &err)
+    if <void*>curve == NULL:
+        if err == SMALLJAC_PARSE_ERROR:
+            raise ValueError, "Unable to parse curve string: %s" % s
+        if err == SMALLJAC_UNSUPPORTED_CURVE:
+            raise ValueError, "Specified curve not supported - should be degree 3, 5, or 7"
+        if err == SMALLJAC_SINGULAR_CURVE:
+            raise ValueError, "Specified curve is singular"
+        if err == SMALLJAC_WRONG_GENUS:
+            raise ValueError, "Specified curve has the wrong genus, demo compiled for genus %d" % 2 # XXX SMALLJAC_GENUS
+        raise ValueError, "smalljac_Qcurve_init returned error %d" % err
+    return curve
+
+def smalljac_Lpolys_list(object f, int start, int end):
+    r"""
+    EXAMPLES::
+
+        sage: from sage.libs.smalljac.smalljac import smalljac_Lpolys_list
+        sage: x = QQ['x'].0
+        sage: smalljac_Lpolys_list(x^5 + x, 0, 10)
+        [(2L, 0, 0, ()), (3L, 1, 2, (0, 2)), (5L, 1, 2, (0, 10)), (7L, 1, 2, (0, 14))]
+
+    The start is included (7), the end is not (19)::
+
+        sage: smalljac_Lpolys_list(x^5 + 1, 7, 19)
+        [(7L, 1, 2, (0, 0)), (11L, 1, 2, (-4, 6)), (13L, 1, 2, (0, 0)), (17L, 1, 2, (0, 0))]
+
+    Let's verify we're at least getting some correct answers::
+
+        sage: p = 37
+        sage: f = x^5 + 1001*x + 250001
+        sage: H = HyperellipticCurve(GF(p)['x'](f))
+        sage: T = ZZ['T'].0
+
+        sage: _, _, _, (a, b) = smalljac_Lpolys_list(f, 35, 40)[0]
+        sage: Fr = p^2*T^4 + a*p*T^3 + b*T^2 + a*T + 1; Fr
+        1369*T^4 - 111*T^3 + 48*T^2 - 3*T + 1
+        sage: Fr.list() == H.frobenius_polynomial().reverse().list()
+        True
+    """
+    cdef smalljac_Qcurve_t curve
+    curve = my_init(f)
+
+    cdef int result = 0
+    cdef list L = []
+    try:
+        result = smalljac_Lpolys (curve, start, end-1, 0, callback, <void*>L)
+    finally:
+        smalljac_Qcurve_clear(curve)
+    if result < 0:
+        raise ValueError, "smalljac returned an error %s" % result
+    return L
+
+cdef int callbackcbk (smalljac_Qcurve_t curve, unsigned long p, int good, long a[], int n, void* arg) with gil:
+    cdef object cbk = (<object>arg)
+    cdef list A = []
+    cdef int i
+    for i in range(n):
+        A.append(a[i])
+    cdef bint cont = cbk( p, good, n, tuple(A) )
+    return cont
+
+def smalljac_Lpolys_callback(object f, int start, int end, object cbk):
+    r"""
+    EXAMPLES::
+
+        sage: from sage.libs.smalljac.smalljac import smalljac_Lpolys_callback
+        sage: def cbk(*args): print args; return args[0] < 10
+        sage: x = QQ['x'].0
+
+    We stop after the first failing callback (at 11)::
+
+        sage: smalljac_Lpolys_callback(x^5 + x, 0, 20, cbk)
+        (2L, 0, 0, ())
+        (3L, 1, 2, (0, 2))
+        (5L, 1, 2, (0, 10))
+        (7L, 1, 2, (0, 14))
+        (11L, 1, 2, (0, -14))
+
+    The start (2) is included; the end (7) is not::
+
+        sage: f = x^5 + 1001*x + 250001
+        sage: smalljac_Lpolys_callback(f, 2, 7, cbk)
+        (2L, 0, 0, ())
+        (3L, 1, 2, (-3, 7))
+        (5L, 1, 2, (0, 10))
+    """
+    cdef smalljac_Qcurve_t curve
+    curve = my_init(f)
+
+    cdef int result = 0
+    try:
+        result = smalljac_Lpolys (curve, start, end-1, 0, callbackcbk, <void*>cbk)
+    finally:
+        smalljac_Qcurve_clear(curve)
+
+    if result < 0:
+        raise ValueError, "smalljac returned an error %s" % result
diff -r d6e4600f2353 -r 3d2791fa3437 setup.py
--- a/setup.py	Thu Jun 04 22:47:59 2009 -0700
+++ b/setup.py	Wed Jul 08 20:14:37 2009 -0700
@@ -783,6 +783,7 @@
                      'sage.lfunctions',
 
                      'sage.libs',
+                     'sage.libs.smalljac',
                      'sage.libs.fplll',
                      'sage.libs.linbox',
                      'sage.libs.mwrank',
