def create_module(module_name, expression_name_tuples, directory): """Generates a cython module that can be imported.""" routines = [] for name, expression, args in expression_name_tuples: try: routine = make_routine(name, [expression], args) except CodeGenArgumentListError as e: new_args = [] for missing in e.missing_args: if not isinstance(missing, OutputArgument): raise new_args.append(missing.name) routine = make_routine(name, expression, list(args) + new_args) routines.append(routine) if not os.path.exists(directory): os.makedirs(directory) cg = CCodeGen() [(cf, cs), (hf, hs)] = cg.write(routines, module_name + '_code') with open(directory + '/' + cf, "w") as text_file: text_file.write(cs) with open(directory + '/' + hf, "w") as text_file: text_file.write(hs) ccw = CythonCodeWrapper(cg) with open(directory + '/' + module_name + '.pyx', "w") as text_file: ccw.dump_pyx(routines, text_file, module_name + '_code') create_setup(module_name + '.pyx', module_name + '_code.c', directory, module_name) open(directory + '/__init__.py', 'w').close() oldwork = os.getcwd() os.chdir(directory) workdir = os.getcwd() command = [sys.executable, "setup.py", "build_ext", "--inplace"] try: sys.path.append(workdir) retoutput = check_output(command, stderr=STDOUT) except CalledProcessError as e: raise CodeWrapError( "Error while executing command: %s. Command output is:\n%s" % (" ".join(command), e.output.decode())) finally: sys.path.remove(workdir) os.chdir(oldwork)
def __init__(self, model, with_jacobian=False, cleanup=True, _logger=None): super(CythonRhsBuilder, self).__init__(model, with_jacobian, cleanup, _logger) routine_names = ["kinetics"] if with_jacobian: routine_names += ["kinetics_jacobian_y", "kinetics_jacobian_o"] # We want more control over various details of code generation and # wrapper module creation than sympy's autowrap provides, so we'll use # the lower-level building blocks directly. routines = {name: self._build_routine(name) for name in routine_names} code_gen = C99CodeGen() extra_compile_args = [ # The RHS evaluation is such a tiny part of overall integration # time, even for huge models, that compiler optimization actually # takes more time than it will ever yield back. Since Cython sets # -O2 by default we need to override it. "-O0", ] # Opt in to the newer numpy C API which is only supported in Cython 3+. import Cython if not Cython.__version__.startswith("0."): extra_compile_args.append( "-DNPY_NO_DEPRECATED_API=NPY_1_7_API_VERSION") code_wrapper = CythonCodeWrapper( code_gen, filepath=self.work_path, extra_compile_args=extra_compile_args, ) # Build a module-name-safe string that identifies the model as uniquely # as possible to assist in debugging. escaped_name = re.sub( r"[^A-Za-z0-9]", "_", self.model_name.encode("unicode_escape").decode(), ) base_name = "pysb_" + escaped_name + "_kinetics" code_wrapper._filename = base_name code_wrapper._module_basename = base_name + "_wrapper" self._logger.debug("Running code generation and Cython compilation") functions = { name: code_wrapper.wrap_code(routine) for name, routine in routines.items() } # Grab specs for the Cython-compiled modules for reloading later. self.module_specs = { name: inspect.getmodule(function).__spec__ for name, function in functions.items() }
def test_cython_wrapper_scalar_function(): x, y, z = symbols('xyz') expr = (x + y) * z routine = Routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected = ('cdef extern from "file.h":\n' ' double test(double x, double y, double z)\n' 'def test_c(double x, double y, double z):\n' ' return test(x, y, z)\n') assert source == expected
def test_cython_wrapper_inoutarg(): from sympy import Equality x, y, z = symbols('xyz') code_gen = CythonCodeWrapper(CCodeGen()) routine = Routine("test", Equality(z, x + y + z)) source = get_string(code_gen.dump_pyx, [routine]) expected = ('cdef extern from "file.h":\n' ' void test(double x, double y, double &z)\n' 'def test_c(double x, double y, double z):\n' ' test(x, y, z)\n' ' return z\n') assert source == expected
def test_cython_wrapper_scalar_function(): x, y, z = symbols('x,y,z') expr = (x + y) * z routine = make_routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected = ("cdef extern from 'file.h':\n" " double test(double x, double y, double z)\n" "\n" "def test_c(double x, double y, double z):\n" "\n" " return test(x, y, z)") assert source == expected
def test_cython_wrapper_inoutarg(): from sympy import Equality x, y, z = symbols('x,y,z') code_gen = CythonCodeWrapper(C99CodeGen()) routine = make_routine("test", Equality(z, x + y + z)) source = get_string(code_gen.dump_pyx, [routine]) expected = ("cdef extern from 'file.h':\n" " void test(double x, double y, double *z)\n" "\n" "def test_c(double x, double y, double z):\n" "\n" " test(x, y, &z)\n" " return z") assert source == expected
def test_cython_wrapper_scalar_function(): x, y, z = symbols('x,y,z') expr = (x + y) * z routine = make_routine("test", expr) with warnings.catch_warnings(): warnings.filterwarnings('ignore', category=SymPyDeprecationWarning) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected = ("cdef extern from 'file.h':\n" " double test(double x, double y, double z)\n" "\n" "def test_c(double x, double y, double z):\n" "\n" " return test(x, y, z)") assert source == expected
def test_cython_wrapper_unique_dummyvars(): from sympy import Dummy, Equality x, y, z = Dummy('x'), Dummy('y'), Dummy('z') x_id, y_id, z_id = [str(d.dummy_index) for d in [x, y, z]] expr = Equality(z, x + y) routine = make_routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected_template = ( "cdef extern from 'file.h':\n" " void test(double x_{x_id}, double y_{y_id}, double *z_{z_id})\n" "\n" "def test_c(double x_{x_id}, double y_{y_id}):\n" "\n" " cdef double z_{z_id} = 0\n" " test(x_{x_id}, y_{y_id}, &z_{z_id})\n" " return z_{z_id}") expected = expected_template.format(x_id=x_id, y_id=y_id, z_id=z_id) assert source == expected
def test_cython_wrapper_compile_flags(): from sympy import Equality x, y, z = symbols('x,y,z') routine = make_routine("test", Equality(z, x + y)) code_gen = CythonCodeWrapper(CCodeGen()) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {} ext_mods = [Extension( 'wrapper_module_0', ['wrapper_module_0.pyx', 'wrapped_code_0.c'], include_dirs=[], library_dirs=[], libraries=[], extra_compile_args=['-std=c99'], extra_link_args=[] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ temp_dir = tempfile.mkdtemp() setup_file_path = os.path.join(temp_dir, 'setup.py') code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected code_gen = CythonCodeWrapper( CCodeGen(), include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math'], extra_link_args=['-lswamp', '-ltrident'], cythonize_options={'compiler_directives': { 'boundscheck': False }}) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} ext_mods = [Extension( 'wrapper_module_0', ['wrapper_module_0.pyx', 'wrapped_code_0.c'], include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} import numpy as np ext_mods = [Extension( 'wrapper_module_0', ['wrapper_module_0.pyx', 'wrapped_code_0.c'], include_dirs=['/usr/local/include', '/opt/booger/include', np.get_include()], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ code_gen._need_numpy = True code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected
def test_cython_wrapper_compile_flags(): from sympy import Equality x, y, z = symbols('x,y,z') routine = make_routine("test", Equality(z, x + y)) code_gen = CythonCodeWrapper(CCodeGen()) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {} ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=[], library_dirs=[], libraries=[], extra_compile_args=['-std=c99'], extra_link_args=[] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} temp_dir = tempfile.mkdtemp() setup_file_path = os.path.join(temp_dir, 'setup.py') code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected code_gen = CythonCodeWrapper(CCodeGen(), include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math'], extra_link_args=['-lswamp', '-ltrident'], cythonize_options={'compiler_directives': {'boundscheck': False}} ) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} import numpy as np ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=['/usr/local/include', '/opt/booger/include', np.get_include()], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} code_gen._need_numpy = True code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected
# Use codegen and autowrap to write c code and wrappers from sympy.utilities.autowrap import CythonCodeWrapper from sympy.utilities.codegen import CCodeGen from sympy.utilities.codegen import Routine routines = [] for ds, args in [(derivs, symbols('st dms sf1 f sf2')), (derivs_sfc, symbols('st dms sfc f sf2')), (derivs_sfs, symbols('st dms sfc f sfs')), (derivs_sfc_calib, symbols('st stm dms sfco sfcs f sf2o sf2s')), (derivs_sfs_calib, symbols('st stm dms sfco sfcs f sfso sfss'))]: for name, expr in ds.iteritems(): routines.append(Routine(name, expr, argument_sequence = args)) cgen = CCodeGen(project = 'P2VV') with open(os.path.join(install_dir, "dilution_impl.c"), "w") as c_file: cgen.dump_c(routines, c_file, 'dilution') with open(os.path.join(install_dir, "dilution.h"), "w") as h_file: cgen.dump_h(routines, h_file, 'dilution') wrapper = CythonCodeWrapper(cgen) with open(os.path.join(install_dir, "dilution.pyx"), "w") as wrapper_file: wrapper.dump_pyx(routines, wrapper_file, 'dilution') # Call cython to create the python wrapper c file. import subprocess pwd = os.path.realpath('.') wd = os.chdir(install_dir) subprocess.call(['cython', 'dilution.pyx']) os.chdir(pwd)