Cython support functions¶
AUTHORS:
- William Stein (2006-01-18): initial version
- William Stein (2007-07-28): update from sagex to cython
- Martin Albrecht & William Stein (2011-08): cfile & cargs
-
sage.misc.cython.
compile_and_load
(code)¶ INPUT:
code
– string containing code that could be in a .pyx file that is attached or put in a %cython block in the notebook.
OUTPUT: a module, which results from compiling the given code and importing it
EXAMPLES:
sage: module = sage.misc.cython.compile_and_load("def f(int n):\n return n*n") sage: module.f(10) 100
-
sage.misc.cython.
cython
(filename, verbose=False, compile_message=False, use_cache=False, create_local_c_file=False, annotate=True, sage_namespace=True, create_local_so_file=False)¶ Compile a Cython file. This converts a Cython file to a C (or C++ file), and then compiles that. The .c file and the .so file are created in a temporary directory.
INPUT:
filename
- the name of the file to be compiled. Should end with ‘pyx’.verbose
(bool, default False) - if True, print debugging information.compile_message
(bool, default False) - if True, print'Compiling <filename>...'
to the standard error.use_cache
(bool, default False) - if True, check the temporary build directory to see if there is already a corresponding .so file. If so, and if the .so file is newer than the Cython file, don’t recompile, just reuse the .so file.create_local_c_file
(bool, default False) - if True, save a copy of the .c file in the current directory.annotate
(bool, default True) - if True, create an html file which annotates the conversion from .pyx to .c. By default this is only created in the temporary directory, but ifcreate_local_c_file
is also True, then save a copy of the .html file in the current directory.sage_namespace
(bool, default True) - if True, importsage.all
.create_local_so_file
(bool, default False) - if True, save a copy of the compiled .so file in the current directory.
TESTS:
Before trac ticket #12975, it would have been needed to write
#clang c++
, but upper caseC++
has resulted in an error:sage: import sysconfig; code = [ ....: "#clang C++", ....: "#cinclude /usr/include/singular /usr/include/singular/singular /usr/include/{0}/singular /usr/include/{0}/singular/singular".format(sysconfig.get_config_var('MULTIARCH')), ....: "#clib m readline singular-Singular givaro ntl gmpxx gmp", ....: "from sage.rings.polynomial.multi_polynomial_libsingular cimport MPolynomial_libsingular", ....: "from sage.libs.singular.polynomial cimport singular_polynomial_pow", ....: "def test(MPolynomial_libsingular p):", ....: " singular_polynomial_pow(&p._poly, p._poly, 2, p._parent_ring)"] sage: cython(os.linesep.join(code))
The function
test
now manipulates internal C data of polynomials, squaring them:sage: P.<x,y>=QQ[] sage: test(x) sage: x x^2
Check that compiling c++ code works:
sage: cython("#clang C++\n"+ ....: "from libcpp.vector cimport vector\n" ....: "cdef vector[int] * v = new vector[int](4)\n")
-
sage.misc.cython.
cython_create_local_so
(filename)¶ Compile filename and make it available as a loadable shared object file.
INPUT:
filename
- string: a Cython (.spyx) file
OUTPUT: None
EFFECT: A compiled, python “importable” loadable shared object file is created.
Note
Shared object files are not reloadable. The intent is for imports in other scripts. A possible development cycle might go thus:
- Attach a .spyx file
- Interactively test and edit it to your satisfaction
- Use
cython_create_local_so
to create the shared object file - Import the .so file in other scripts
EXAMPLES:
sage: curdir = os.path.abspath(os.curdir) sage: dir = tmp_dir(); os.chdir(dir) sage: f = open('hello.spyx', 'w') sage: s = "def hello():\n print('hello')\n" sage: f.write(s) sage: f.close() sage: cython_create_local_so('hello.spyx') Compiling hello.spyx... sage: sys.path.append('.') sage: import hello sage: hello.hello() hello sage: os.chdir(curdir)
AUTHORS:
- David Fu (2008-04-09): initial version
-
sage.misc.cython.
cython_import
(filename, verbose=False, compile_message=False, use_cache=False, create_local_c_file=True, **kwds)¶ Compile a file containing Cython code, then import and return the module. Raises an
ImportError
if anything goes wrong.INPUT:
filename
- a string; name of a file that contains Cython code
See the function
sage.misc.cython.cython()
for documentation for the other inputs.OUTPUT:
- the module that contains the compiled Cython code.
-
sage.misc.cython.
cython_import_all
(filename, globals, verbose=False, compile_message=False, use_cache=False, create_local_c_file=True)¶ Imports all non-private (i.e., not beginning with an underscore) attributes of the specified Cython module into the given context. This is similar to:
from module import *
Raises an
ImportError
exception if anything goes wrong.INPUT:
filename
- a string; name of a file that contains Cython code
-
sage.misc.cython.
cython_lambda
(vars, expr, verbose=False, compile_message=False, use_cache=False)¶ Create a compiled function which evaluates
expr
assuming machine values forvars
.INPUT:
vars
- list of pairs (variable name, c-data type), where the variable names and data types are strings, OR a string such as'double x, int y, int z'
expr
- an expression involving the vars and constants; you can access objects defined in the current module scopeglobals()
usingsage.object_name
.
Warning
Accessing
globals()
doesn’t actually work, see trac ticket #12446.EXAMPLES:
We create a Lambda function in pure Python (using the r to make sure the 3.2 is viewed as a Python float):
sage: f = lambda x,y: x*x + y*y + x + y + 17r*x + 3.2r
We make the same Lambda function, but in a compiled form.
sage: g = cython_lambda('double x, double y', 'x*x + y*y + x + y + 17*x + 3.2') sage: g(2,3) 55.2 sage: g(0,0) 3.2
In order to access Sage globals, prefix them with
sage.
:sage: f = cython_lambda('double x', 'sage.sin(x) + sage.a') sage: f(0) Traceback (most recent call last): ... NameError: global 'a' is not defined sage: a = 25 sage: f(10) 24.45597888911063 sage: a = 50 sage: f(10) 49.45597888911063
-
sage.misc.cython.
environ_parse
(s)¶ Given a string s, find each substring of the form
'$ABC'
. If the environment variable$ABC
is set, replace'$ABC'
with its value and move on to the next such substring. If it is not set, stop parsing there.EXAMPLES:
sage: from sage.misc.cython import environ_parse sage: environ_parse('$SAGE_LOCAL') == SAGE_LOCAL True sage: environ_parse('$THIS_IS_NOT_DEFINED_ANYWHERE') '$THIS_IS_NOT_DEFINED_ANYWHERE' sage: os.environ['DEFINE_THIS'] = 'hello' sage: environ_parse('$DEFINE_THIS/$THIS_IS_NOT_DEFINED_ANYWHERE/$DEFINE_THIS') 'hello/$THIS_IS_NOT_DEFINED_ANYWHERE/$DEFINE_THIS'
-
sage.misc.cython.
import_test
(name)¶ This is used by the testing infrastructure to test building Cython programs.
INPUT:
name
– string; name of a key to the TESTS dictionary above
OUTPUT: a module, which results from compiling the given code and importing it
EXAMPLES:
sage: module = sage.misc.cython.import_test("trac11680b") sage: module.f(2,3,4) 9
-
sage.misc.cython.
parse_keywords
(kwd, s)¶ Given a keyword
kwd
and a strings
, return a list of all arguments on the same line as that keyword ins
, as well as a new copy ofs
in which each occurrence ofkwd
is in a comment. If a comment already occurs on the line containingkwd
, no words after the#
are added to the list.EXAMPLES:
sage: import sage.misc.cython sage: sage.misc.cython.parse_keywords('clib', " clib foo bar baz\n #cinclude bar\n") (['foo', 'bar', 'baz'], ' #clib foo bar baz\n #cinclude bar\n') sage: sage.misc.cython.parse_keywords('clib', "# qux clib foo bar baz\n #cinclude bar\n") (['foo', 'bar', 'baz'], '# qux clib foo bar baz\n #cinclude bar\n') sage: sage.misc.cython.parse_keywords('clib', "# clib foo bar # baz\n #cinclude bar\n") (['foo', 'bar'], '# clib foo bar # baz\n #cinclude bar\n')
-
sage.misc.cython.
pyx_preparse
(s)¶ Preparse a pyx file:
- include
cdefs.pxi
,signals.pxi
fromcysignals
,stdsage.pxi
- parse
clang
pragma (c or c++) - parse
clib
pragma (additional libraries to link in) - parse
cinclude
(additional include directories) - parse
cfile
(additional files to be included) - parse
cargs
(additional parameters passed to the compiler)
The pragmas:
clang
- may be either'c'
or'c++'
indicating whether a C or C++ compiler should be usedclib
- additional libraries to be linked in, the space separated list is split and passed to distutils.cinclude
- additional directories to search for header files. The space separated list is split and passed to distutils.cfile
- additional C or C++ files to be compiled. Also,$SAGE_SRC
and$SAGE_LOCAL
are expanded, but other environment variables are not.cargs
- additional parameters passed to the compiler
OUTPUT: preamble, libs, includes, language, files, args
EXAMPLES:
sage: from sage.misc.cython import pyx_preparse sage: pyx_preparse("") ('\ninclude "cysignals/signals.pxi" # ctrl-c interrupt block support\ninclude "stdsage.pxi"\n\ninclude "cdefs.pxi"\n', ['mpfr', 'gmp', 'gmpxx', 'stdc++', 'pari', 'm', 'ec', 'gsl', ... 'ntl'], ['.../include', '.../include/python...', '.../python.../numpy/core/include', ... '.../sagemath/ext', ... '.../cysignals'...], 'c', [], ['-w', '-O2'],...) sage: s, libs, inc, lang, f, args, libdirs = pyx_preparse("# clang c++\n #clib foo\n # cinclude bar\n") sage: lang 'c++' sage: libs ['foo', 'mpfr', 'gmp', 'gmpxx', 'stdc++', 'pari', 'm', 'ec', 'gsl', ... 'ntl'] sage: libs[1:] == sage.misc.cython.standard_libs True sage: inc ['bar', '.../include', '.../include/python...', '.../python.../numpy/core/include', ... '.../sagemath/ext', ... '.../cysignals'...] sage: s, libs, inc, lang, f, args, libdirs = pyx_preparse("# cargs -O3 -ggdb\n") sage: args ['-w', '-O2', '-O3', '-ggdb']
TESTS:
sage: module = sage.misc.cython.import_test("trac11680") # long time (7s on sage.math, 2012) sage: R.<x> = QQ[] sage: module.evaluate_at_power_of_gen(x^3 + x - 7, 5) # long time x^15 + x^5 - 7
- include
-
sage.misc.cython.
sanitize
(f)¶ Given a filename
f
, replace it by a filename that is a valid Python module name.This means that the characters are all alphanumeric or
_
‘s and doesn’t begin with a numeral.EXAMPLES:
sage: from sage.misc.cython import sanitize sage: sanitize('abc') 'abc' sage: sanitize('abc/def') 'abc_def' sage: sanitize('123/def-hij/file.py') '_123_def_hij_file_py'
-
sage.misc.cython.
subtract_from_line_numbers
(s, n)¶ Given a string
s
and an integern
, for any line ofs
which has the form'text:NUM:text'
subtractn
from NUM and return'text:(NUM-n):text'
. Return other lines ofs
without change.EXAMPLES:
sage: from sage.misc.cython import subtract_from_line_numbers sage: subtract_from_line_numbers('hello:1234:hello', 3) 'hello:1231:hello\n' sage: subtract_from_line_numbers('text:123\nhello:1234:', 3) 'text:123\nhello:1231:\n'