def genP3code(): autocode = CCodeGen(project="Salvus") r,s,t = symbols("r,s,t") rstn = p3ReferenceNodes() (rn,sn,tn) = rstn Np = len(rn) phi = p3ElementPolynomials(rstn,r,s,t) (dphi_dr,dphi_ds,dphi_dt) = p3ElementDerivatives(phi,r,s,t) dphi_dr_rstn = np.zeros((Np,Np)) dphi_ds_rstn = np.zeros((Np,Np)) dphi_dt_rstn = np.zeros((Np,Np)) for i in range(0,Np): dphi_dr_i = lambdify((r,s,t),dphi_dr[i]) dphi_ds_i = lambdify((r,s,t),dphi_ds[i]) dphi_dt_i = lambdify((r,s,t),dphi_dt[i]) for (n,(ri,si,ti)) in enumerate(zip(rn,sn,tn)): dphi_dr_rstn[i,n] = dphi_dr_i(ri,si,ti) dphi_ds_rstn[i,n] = dphi_ds_i(ri,si,ti) dphi_dt_rstn[i,n] = dphi_dt_i(ri,si,ti) dphi_dr_rstn = Matrix(dphi_dr_rstn) dphi_ds_rstn = Matrix(dphi_ds_rstn) dphi_dt_rstn = Matrix(dphi_dt_rstn) rn = Matrix([ri for (ri,si,ti) in zip(rn,sn,tn)]) sn = Matrix([si for (ri,si,ti) in zip(rn,sn,tn)]) tn = Matrix([ti for (ri,si,ti) in zip(rn,sn,tn)]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_tetrahedra_rn",rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_tetrahedra_sn",sn, argument_sequence=None) tn_routine = autocode.routine("coordinates_p3_tetrahedra_tn",tn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_tetrahedra",wn, argument_sequence=None) # NOTE: writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rstn_routine = autocode.routine("dphi_dr_rstn_p3_tetrahedra", dphi_dr_rstn.transpose(), argument_sequence=None) dphi_ds_rstn_routine = autocode.routine("dphi_ds_rstn_p3_tetrahedra", dphi_ds_rstn.transpose(), argument_sequence=None) dphi_dt_rstn_routine = autocode.routine("dphi_dt_rstn_p3_tetrahedra", dphi_dt_rstn.transpose(), argument_sequence=None) routines = [rn_routine, sn_routine, tn_routine, wn_routine, dphi_dr_rstn_routine, dphi_ds_rstn_routine, dphi_dt_rstn_routine] autocode.write(routines,"p3_tetrahedra",to_files=True) buildVisualizationP3(rn,sn,tn)
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 test_output_arg_c(): from sympy import sin, cos, Equality x, y, z = symbols("x,y,z") r = Routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ('#include "test.h"\n' '#include <math.h>\n' 'double foo(double x, double &y) {\n' ' y = sin(x);\n' ' return cos(x);\n' '}\n') assert result[0][1] == expected
def test_multiple_results_c(): x, y, z = symbols('x,y,z') expr1 = (x + y) * z expr2 = (x - y) * z routine = Routine("test", [expr1, expr2]) code_gen = CCodeGen() raises(CodeGenError, lambda: get_string(code_gen.dump_h, [routine]))
def test_output_arg_c(): from sympy import sin, cos, Equality x, y, z = symbols("x,y,z") r = Routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ( '#include "test.h"\n' '#include <math.h>\n' 'double foo(double x, double &y) {\n' ' y = sin(x);\n' ' return cos(x);\n' '}\n' ) assert result[0][1] == expected
def test_multiple_results_c(): x, y, z = symbols('xyz') expr1 = (x + y) * z expr2 = (x - y) * z routine = Routine("test", [InputArgument(symbol) for symbol in x, y, z], [Result(expr1), Result(expr2)]) code_gen = CCodeGen() raises(CodeGenError, 'get_string(code_gen.dump_h, [routine])')
def _fixed_autowrap(energy_expr, prefix, save_filename=None): codegen = CCodeGen() routines = [] _logger.debug('Writing code for energy_expr') routines.append(codegen.routine('autofunc', energy_expr)) [(c_name, bad_c_code), (h_name, h_code)] = codegen.write( routines, prefix, ) c_code = '#include <complex.h>\n' c_code += bad_c_code c_code = c_code.replace('conjugate', 'conj') write_directory = Path(tempfile.mkdtemp()).absolute() c_path = write_directory / Path(prefix + '.c') h_path = write_directory / Path(prefix + '.h') o_path = write_directory / Path(prefix + '.o') so_path = write_directory / Path(prefix + '.so') with open(c_path, 'w') as fh: fh.write(c_code) fh.write('\n') with open(h_path, 'w') as fh: fh.write(h_code) fh.write('\n') start = time.time() _logger.debug('Start compiling code.') os.system(f'gcc -c -lm {c_path} -o {o_path}') os.system(f'gcc -shared {o_path} -o {so_path}') _logger.debug(f'Compiling code took {time.time()-start} seconds.') if save_filename is not None: if Path(save_filename).exists(): Path(save_filename).unlink() shutil.copy(so_path, save_filename) cost_func = _load_func(so_path) shutil.rmtree(write_directory) return cost_func
def test_output_arg_c_reserved_words(): from sympy import sin, cos, Equality x, y, z = symbols("if, while, z") r = make_routine("foo", [Equality(y, sin(x)), cos(x)]) c = CCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ( '#include "test.h"\n' '#include <math.h>\n' 'double foo(double if_, double *while_) {\n' ' (*while_) = sin(if_);\n' ' double foo_result;\n' ' foo_result = cos(if_);\n' ' return foo_result;\n' '}\n' ) assert result[0][1] == expected
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_numbersymbol_c_code(): routine = Routine("test", pi**Catalan) code_gen = CCodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ("#include \"file.h\"\n" "#include <math.h>\n" "double test() {\n" " double const Catalan = 0.915965594177219;\n" " return pow(M_PI, Catalan);\n" "}\n") assert source == expected
def test_simple_c_header(): x, y, z = symbols('x,y,z') expr = (x + y) * z routine = Routine("test", expr) code_gen = CCodeGen() source = get_string(code_gen.dump_h, [routine]) expected = ("#ifndef PROJECT__FILE__H\n" "#define PROJECT__FILE__H\n" "double test(double x, double y, double z);\n" "#endif\n") assert source == expected
def test_c_code_argument_order(): x, y, z = symbols('x,y,z') expr = x + y routine = Routine("test", expr, argument_sequence=[z, x, y]) code_gen = CCodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ("#include \"file.h\"\n" "#include <math.h>\n" "double test(double z, double x, double y) {\n" " return x + y;\n" "}\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_simple_c_code(): x, y, z = symbols('x,y,z') expr = (x + y) * z routine = Routine("test", expr) code_gen = CCodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ("#include \"file.h\"\n" "#include <math.h>\n" "double test(double x, double y, double z) {\n" " return z*(x + y);\n" "}\n") assert source == expected
def genP3code(): autocode = CCodeGen(project="Salvus") r,s = symbols("r,s") rsn = p3ReferenceNodes() Np = len(rsn) phi = p3ElementPolynomials(rsn,r,s) (dphi_dr,dphi_ds) = p3ElementDerivatives(phi,r,s) dphi_dr_rsn = np.zeros((Np,Np)) dphi_ds_rsn = np.zeros((Np,Np)) for i in range(0,Np): dphi_dr_i = lambdify((r,s),dphi_dr[i]) dphi_ds_i = lambdify((r,s),dphi_ds[i]) for (n,(rn,sn)) in enumerate(rsn): dphi_dr_rsn[i,n] = dphi_dr_i(rn,sn) dphi_ds_rsn[i,n] = dphi_ds_i(rn,sn) dphi_dr_rsn = Matrix(dphi_dr_rsn) dphi_ds_rsn = Matrix(dphi_ds_rsn) print(dphi_dr_rsn[0,:]) rn = Matrix([ri for (ri,si) in rsn]) sn = Matrix([si for (ri,si) in rsn]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_triangle_rn",rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_triangle_sn",sn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_triangle",wn, argument_sequence=None) # NOTE: by default, it writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rsn_routine = autocode.routine("dphi_dr_rsn_p3_triangle", dphi_dr_rsn.transpose(), argument_sequence=None) dphi_ds_rsn_routine = autocode.routine("dphi_ds_rsn_p3_triangle", dphi_ds_rsn.transpose(), argument_sequence=None) routines = [rn_routine, sn_routine, wn_routine, dphi_dr_rsn_routine, dphi_ds_rsn_routine] autocode.write(routines,"p3_triangle",to_files=True)
def tensorized_basis_2D(order): total_integration_points = (order + 1) * (order + 1) eps, eta, rho = sym.symbols('epsilon eta rho') eps_gll = sym.symbols('epsilon_0:%d' % (order + 1)) eta_gll = sym.symbols('eta_0:%d' % (order + 1)) # Get N + 1 lagrange polynomials in each direction. generator_eps = generating_polynomial_lagrange(order, 'epsilon', eps_gll) generator_eta = generating_polynomial_lagrange(order, 'eta', eta_gll) # Get tensorized basis. basis = TensorProduct(generator_eta, generator_eps) basis = basis.subs([(v, c) for v, c in zip(eps_gll, gll_coordinates(order))]) basis = basis.subs([(v, c) for v, c in zip(eta_gll, gll_coordinates(order))]) sym.pprint(basis) # Get gradient of basis functions. basis_gradient_eps = sym.Matrix([sym.diff(i, eps) for i in basis]) basis_gradient_eta = sym.Matrix([sym.diff(i, eta) for i in basis]) # Get diagonal mass matrix mass_matrix = rho * basis * basis.T mass_matrix_diagonal = sym.Matrix( [mass_matrix[i, i] for i in range(total_integration_points)]) # Write code routines = [] autocode = CCodeGen() routines.append( autocode.routine('interpolate_order{}_square'.format(order), basis, argument_sequence=None)) routines.append( autocode.routine( 'interpolate_eps_derivative_order{}_square'.format(order), basis_gradient_eps, argument_sequence=None)) routines.append( autocode.routine( 'interpolate_eta_derivative_order{}_square'.format(order), basis_gradient_eta, argument_sequence=None)) routines.append( autocode.routine('diagonal_mass_matrix_order{}_square'.format(order), mass_matrix_diagonal, argument_sequence=None)) autocode.write(routines, 'order{}_square'.format(order), to_files=True)
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(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" "\n" "def test_c(double x, double y, double z):\n" "\n" " test(x, y, &z)\n" " return z") assert source == expected
def test_empty_c_code_with_comment(): code_gen = CCodeGen() source = get_string(code_gen.dump_c, [], header=True) assert source[:82] == ( "/******************************************************************************\n *" ) # " Code generated with sympy 0.7.2-git " assert source[158:] == ( "*\n" " * *\n" " * See http://www.sympy.org/ for more information. *\n" " * *\n" " * This file is part of 'project' *\n" " ******************************************************************************/\n" "#include \"file.h\"\n" "#include <math.h>\n")
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 tensorized_basis_2D(order): total_integration_points = (order + 1) * (order + 1) eps, eta, rho = sym.symbols("epsilon eta rho") eps_gll = sym.symbols("epsilon_0:%d" % (order + 1)) eta_gll = sym.symbols("eta_0:%d" % (order + 1)) # Get N + 1 lagrange polynomials in each direction. generator_eps = generating_polynomial_lagrange(order, "epsilon", eps_gll) generator_eta = generating_polynomial_lagrange(order, "eta", eta_gll) # Get tensorized basis. basis = TensorProduct(generator_eta, generator_eps) basis = basis.subs([(v, c) for v, c in zip(eps_gll, gll_coordinates(order))]) basis = basis.subs([(v, c) for v, c in zip(eta_gll, gll_coordinates(order))]) sym.pprint(basis) # Get gradient of basis functions. basis_gradient_eps = sym.Matrix([sym.diff(i, eps) for i in basis]) basis_gradient_eta = sym.Matrix([sym.diff(i, eta) for i in basis]) # Get diagonal mass matrix mass_matrix = rho * basis * basis.T mass_matrix_diagonal = sym.Matrix([mass_matrix[i, i] for i in range(total_integration_points)]) # Write code routines = [] autocode = CCodeGen() routines.append(autocode.routine("interpolate_order{}_square".format(order), basis, argument_sequence=None)) routines.append( autocode.routine( "interpolate_eps_derivative_order{}_square".format(order), basis_gradient_eps, argument_sequence=None ) ) routines.append( autocode.routine( "interpolate_eta_derivative_order{}_square".format(order), basis_gradient_eta, argument_sequence=None ) ) routines.append( autocode.routine( "diagonal_mass_matrix_order{}_square".format(order), mass_matrix_diagonal, argument_sequence=None ) ) autocode.write(routines, "order{}_square".format(order), to_files=True)
def test_dummy_loops_c(): from sympy.tensor import IndexedBase, Idx # the following line could also be # [Dummy(s, integer=True) for s in 'im'] # or [Dummy(integer=True) for s in 'im'] i, m = symbols('i m', integer=True, cls=Dummy) x = IndexedBase('x') y = IndexedBase('y') i = Idx(i, m) expected = ( '#include "file.h"\n' '#include <math.h>\n' 'void test_dummies(int m_%(mno)i, double *x, double *y) {\n' ' for (int i_%(ino)i=0; i_%(ino)i<m_%(mno)i; i_%(ino)i++){\n' ' y[i_%(ino)i] = x[i_%(ino)i];\n' ' }\n' '}\n' ) % {'ino': i.label.dummy_index, 'mno': m.dummy_index} r = Routine('test_dummies', Eq(y[i], x[i])) c = CCodeGen() code = get_string(c.dump_c, [r]) assert code == expected
def test_ufuncify_source_multioutput(): x, y, z = symbols('x,y,z') var_symbols = (x, y, z) expr = x + y**3 + 10*z**2 code_wrapper = UfuncifyCodeWrapper(CCodeGen("ufuncify")) CodeWrapper._module_counter = 0 routines = [make_routine("func{}".format(i), expr.diff(var_symbols[i]), var_symbols) for i in range(len(var_symbols))] source = get_string(code_wrapper.dump_c, routines, funcname='multitest') expected = """\ #include "Python.h" #include "math.h" #include "numpy/ndarraytypes.h" #include "numpy/ufuncobject.h" #include "numpy/halffloat.h" #include "file.h" static PyMethodDef wrapper_module_0Methods[] = { {NULL, NULL, 0, NULL} }; static void multitest_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) { npy_intp i; npy_intp n = dimensions[0]; char *in0 = args[0]; char *in1 = args[1]; char *in2 = args[2]; char *out0 = args[3]; char *out1 = args[4]; char *out2 = args[5]; npy_intp in0_step = steps[0]; npy_intp in1_step = steps[1]; npy_intp in2_step = steps[2]; npy_intp out0_step = steps[3]; npy_intp out1_step = steps[4]; npy_intp out2_step = steps[5]; for (i = 0; i < n; i++) { *((double *)out0) = func0(*(double *)in0, *(double *)in1, *(double *)in2); *((double *)out1) = func1(*(double *)in0, *(double *)in1, *(double *)in2); *((double *)out2) = func2(*(double *)in0, *(double *)in1, *(double *)in2); in0 += in0_step; in1 += in1_step; in2 += in2_step; out0 += out0_step; out1 += out1_step; out2 += out2_step; } } PyUFuncGenericFunction multitest_funcs[1] = {&multitest_ufunc}; static char multitest_types[6] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE}; static void *multitest_data[1] = {NULL}; #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "wrapper_module_0", NULL, -1, wrapper_module_0Methods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_wrapper_module_0(void) { PyObject *m, *d; PyObject *ufunc0; m = PyModule_Create(&moduledef); if (!m) { return NULL; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(multitest_funcs, multitest_data, multitest_types, 1, 3, 3, PyUFunc_None, "wrapper_module_0", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "multitest", ufunc0); Py_DECREF(ufunc0); return m; } #else PyMODINIT_FUNC initwrapper_module_0(void) { PyObject *m, *d; PyObject *ufunc0; m = Py_InitModule("wrapper_module_0", wrapper_module_0Methods); if (m == NULL) { return; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(multitest_funcs, multitest_data, multitest_types, 1, 3, 3, PyUFunc_None, "wrapper_module_0", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "multitest", ufunc0); Py_DECREF(ufunc0); } #endif""" assert source == expected
def test_empty_c_header(): code_gen = CCodeGen() source = get_string(code_gen.dump_h, []) assert source == "#ifndef PROJECT__FILE__H\n#define PROJECT__FILE__H\n#endif\n"
def test_empty_c_code(): code_gen = CCodeGen() source = get_string(code_gen.dump_c, []) assert source == "#include \"file.h\"\n#include <math.h>\n"
# Transform derivatives to global co-ordinates. dN[0,:] = (dedx + dndx) * dN[0,:] dN[1,:] = (dedz + dndz) * dN[1,:] for i in range(dof_tot): if (not (i % 2)): dN[2,i] = dN[2,i] * (dedz + dndz) else: dN[2,i] = dN[2,i] * (dedx + dndx) # Split along dimensions. N = TensorProduct(N, crack) # List to hold routines. routines = [] sem_c = CCodeGen(project='SALVUS') # // ABSORBING BOUNDARIES // # boun_shell_left = sym.Matrix.zeros(dof_tot, dof_tot) boun_shell_rght = sym.Matrix.zeros(dof_tot, dof_tot) boun_shell_bttm = sym.Matrix.zeros(dof_tot, dof_tot) boun_shell_tops = sym.Matrix.zeros(dof_tot, dof_tot) boun_matrix = N_EPS.subs(replace_e) boun_matrix_nor = sym.Matrix.zeros(5,1) boun_matrix_tan = sym.Matrix.zeros(5,1) v_n, v_t = sym.symbols('v_n v_t') for c_e, w_x in zip(coords, weights): boun_matrix_nor += v_n * rho * boun_matrix.subs([(e, c_e)]) * w_x * Jdet boun_matrix_tan += v_t * rho * boun_matrix.subs([(e, c_e)]) * w_x * Jdet
def _make_energy_func_chunked(energy_expr_list, prefix, save_filename=None): codegen = CCodeGen() routines = [] for i, expr in enumerate(energy_expr_list): _logger.debug(f'Writing code for expr {i} of {len(energy_expr_list)}') routines.append(codegen.routine('expr' + str(i), expr)) [(c_name, bad_c_code), (h_name, h_code)] = codegen.write( routines, prefix, ) c_code = '#include <complex.h>\n' c_code += bad_c_code c_code += """ double autofunc(double *xs){ double autofunc_result; autofunc_result = %s; return autofunc_result; } """ % ('+'.join( ['expr' + str(i) + '(xs)' for i in range(len(energy_expr_list))])) c_code = c_code.replace('conjugate', 'conj') h_code = h_code.replace('\n#endif', """double autofunc(double *xs); #endif """) write_directory = Path(tempfile.mkdtemp()).absolute() c_path = write_directory / Path(prefix + '.c') h_path = write_directory / Path(prefix + '.h') o_path = write_directory / Path(prefix + '.o') so_path = write_directory / Path(prefix + '.so') with open(c_path, 'w') as fh: fh.write(c_code) fh.write('\n') with open(h_path, 'w') as fh: fh.write(h_code) fh.write('\n') start = time.time() _logger.debug('Start compiling code.') os.system(f'gcc -c -lm -fPIC {c_path} -o {o_path}') os.system(f'gcc -shared -fPIC {o_path} -o {so_path}') _logger.debug(f'Compiling code took {time.time()-start} seconds.') if save_filename is not None: if Path(save_filename).exists(): Path(save_filename).unlink() shutil.copy(so_path, save_filename) cost_func = _load_func(so_path) shutil.rmtree(write_directory) return cost_func
def run_cc_test(label, routines, numerical_tests, friendly=True): """A driver for the codegen tests. This driver assumes that a compiler cc is present in the PATH and that cc is (at least) an ANSI C compiler. The generated code is written in a temporary directory, together with a main program that validates the generated code. The test passes when the compilation and the validation run correctly. """ # Do all the magic to compile, run and validate the test code # 1) prepare the temporary working directory, swith to that dir work = tempfile.mkdtemp("_sympy_cc_test", "%s_" % label) oldwork = os.getcwd() os.chdir(work) # 2) write the generated code if friendly: # interpret the routines as a name_expr list and call the friendly # function codegen codegen(routines, 'C', "codegen", to_files=True) else: code_gen = CCodeGen() code_gen.write(routines, "codegen", to_files=True) # 3) write a simple main program that links to the generated code, and that # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: call_string = "%s(%s)-(%s)" % (fn_name, ",".join( str(arg) for arg in args), expected) test_strings.append(numerical_test_template % { "call": call_string, "threshold": threshold, }) f = file("main.c", "w") f.write(main_template % "".join(test_strings)) f.close() # 4) Compile and link compiled = try_run([ "cc -c codegen.c -o codegen.o", "cc -c main.c -o main.o", "cc main.o codegen.o -lm -o test" ]) # 5) Run if compiled if compiled: executed = try_run(["./test"]) else: executed = False # 6) Clean up stuff clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() if clean not in ('always', 'success', 'never'): raise ValueError( "SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'." ) if clean == 'always' or (clean == 'success' and compiled and executed): def safe_remove(filename): if os.path.isfile(filename): os.remove(filename) safe_remove("codegen.c") safe_remove("codegen.h") safe_remove("codegen.o") safe_remove("main.c") safe_remove("main.o") safe_remove("test") os.chdir(oldwork) os.rmdir(work) else: print >> sys.stderr, "TEST NOT REMOVED: %s" % work os.chdir(oldwork) # 7) Do the assertions in the end assert compiled assert executed
def run_cc_test(label, routines, numerical_tests, friendly=True): """A driver for the codegen tests. This driver assumes that a compiler cc is present in the PATH and that cc is (at least) an ANSI C compiler. The generated code is written in a temporary directory, together with a main program that validates the generated code. The test passes when the compilation and the validation run correctly. """ # Do all the magic to compile, run and validate the test code # 1) prepare the temporary working directory, swith to that dir work = tempfile.mkdtemp("_sympy_cc_test", "%s_" % label) oldwork = os.getcwd() os.chdir(work) # 2) write the generated code if friendly: # interpret the routines as a name_expr list and call the friendly # function codegen codegen(routines, 'C', "codegen", to_files=True) else: code_gen = CCodeGen() code_gen.write(routines, "codegen", to_files=True) # 3) write a simple main program that links to the generated code, and that # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: call_string = "%s(%s)-(%s)" % (fn_name, ",".join(str(arg) for arg in args), expected) test_strings.append(numerical_test_template % { "call": call_string, "threshold": threshold, }) f = file("main.c", "w") f.write(main_template % "".join(test_strings)) f.close() # 4) Compile and link compiled = try_run([ "cc -c codegen.c -o codegen.o", "cc -c main.c -o main.o", "cc main.o codegen.o -lm -o test" ]) # 5) Run if compiled if compiled: executed = try_run(["./test"]) else: executed = False # 6) Clean up stuff clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() if clean not in ('always', 'success', 'never'): raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.") if clean == 'always' or (clean == 'success' and compiled and executed): def safe_remove(filename): if os.path.isfile(filename): os.remove(filename) safe_remove("codegen.c") safe_remove("codegen.h") safe_remove("codegen.o") safe_remove("main.c") safe_remove("main.o") safe_remove("test") os.chdir(oldwork) os.rmdir(work) else: print >> sys.stderr, "TEST NOT REMOVED: %s" % work os.chdir(oldwork) # 7) Do the assertions in the end assert compiled assert executed
def ufuncify(args, expr, language=None, backend='numpy', tempdir=None, flags=None, verbose=False, helpers=None): """Generates a binary function that supports broadcasting on numpy arrays. Parameters ---------- args : iterable Either a Symbol or an iterable of symbols. Specifies the argument sequence for the function. expr A SymPy expression that defines the element wise operation. language : string, optional If supplied, (options: 'C' or 'F95'), specifies the language of the generated code. If ``None`` [default], the language is inferred based upon the specified backend. backend : string, optional Backend used to wrap the generated code. Either 'numpy' [default], 'cython', or 'f2py'. tempdir : string, optional Path to directory for temporary files. If this argument is supplied, the generated code and the wrapper input files are left intact in the specified path. flags : iterable, optional Additional option flags that will be passed to the backend verbose : bool, optional If True, autowrap will not mute the command line backends. This can be helpful for debugging. helpers : iterable, optional Used to define auxillary expressions needed for the main expr. If the main expression needs to call a specialized function it should be put in the ``helpers`` iterable. Autowrap will then make sure that the compiled main expression can link to the helper routine. Items should be tuples with (<funtion_name>, <sympy_expression>, <arguments>). It is mandatory to supply an argument sequence to helper routines. Note ---- The default backend ('numpy') will create actual instances of ``numpy.ufunc``. These support ndimensional broadcasting, and implicit type conversion. Use of the other backends will result in a "ufunc-like" function, which requires equal length 1-dimensional arrays for all arguments, and will not perform any type conversions. References ---------- [1] http://docs.scipy.org/doc/numpy/reference/ufuncs.html Examples ======== >>> from sympy.utilities.autowrap import ufuncify >>> from sympy.abc import x, y >>> import numpy as np >>> f = ufuncify((x, y), y + x**2) >>> type(f) numpy.ufunc >>> f([1, 2, 3], 2) array([ 3., 6., 11.]) >>> f(np.arange(5), 3) array([ 3., 4., 7., 12., 19.]) For the F2Py and Cython backends, inputs are required to be equal length 1-dimensional arrays. The F2Py backend will perform type conversion, but the Cython backend will error if the inputs are not of the expected type. >>> f_fortran = ufuncify((x, y), y + x**2, backend='F2Py') >>> f_fortran(1, 2) 3 >>> f_fortran(numpy.array([1, 2, 3]), numpy.array([1.0, 2.0, 3.0])) array([2., 6., 12.]) >>> f_cython = ufuncify((x, y), y + x**2, backend='Cython') >>> f_cython(1, 2) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: Argument '_x' has incorrect type (expected numpy.ndarray, got int) >>> f_cython(numpy.array([1.0]), numpy.array([2.0])) array([ 3.]) """ if isinstance(args, Symbol): args = (args, ) else: args = tuple(args) if language: _validate_backend_language(backend, language) else: language = _infer_language(backend) helpers = helpers if helpers else () flags = flags if flags else () if backend.upper() == 'NUMPY': routine = make_routine('autofunc', expr, args) helps = [] for name, expr, args in helpers: helps.append(make_routine(name, expr, args)) code_wrapper = UfuncifyCodeWrapper(CCodeGen("ufuncify"), tempdir, flags, verbose) return code_wrapper.wrap_code(routine, helpers=helps) else: # Dummies are used for all added expressions to prevent name clashes # within the original expression. y = IndexedBase(Dummy()) m = Dummy(integer=True) i = Idx(Dummy(integer=True), m) f = implemented_function(Dummy().name, Lambda(args, expr)) # For each of the args create an indexed version. indexed_args = [IndexedBase(Dummy(str(a))) for a in args] # Order the arguments (out, args, dim) args = [y] + indexed_args + [m] args_with_indices = [a[i] for a in indexed_args] return autowrap(Eq(y[i], f(*args_with_indices)), language, backend, tempdir, args, flags, verbose, helpers)
def test_ufuncify_source(): from sympy import Equality x, y, z = symbols('x,y,z') code_wrapper = UfuncifyCodeWrapper(CCodeGen("ufuncify")) CodeWrapper._module_counter = 0 routine = Routine("test", x + y + z) source = get_string(code_wrapper.dump_c, [routine]) expected = """\ #include "Python.h" #include "math.h" #include "numpy/ndarraytypes.h" #include "numpy/ufuncobject.h" #include "numpy/halffloat.h" #include "file.h" static PyMethodDef wrapper_module_0Methods[] = { {NULL, NULL, 0, NULL} }; static void test_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) { npy_intp i; npy_intp n = dimensions[0]; char *in0 = args[0]; char *in1 = args[1]; char *in2 = args[2]; char *out1 = args[3]; npy_intp in0_step = steps[0]; npy_intp in1_step = steps[1]; npy_intp in2_step = steps[2]; npy_intp out1_step = steps[3]; for (i = 0; i < n; i++) { *((double *)out1) = test(*(double *)in0, *(double *)in1, *(double *)in2); in0 += in0_step; in1 += in1_step; in2 += in2_step; out1 += out1_step; } } PyUFuncGenericFunction test_funcs[1] = {&test_ufunc}; static char test_types[4] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE}; static void *test_data[1] = {NULL}; #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "wrapper_module_0", NULL, -1, wrapper_module_0Methods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_wrapper_module_0(void) { PyObject *m, *d; PyObject *ufunc0; m = PyModule_Create(&moduledef); if (!m) { return NULL; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(test_funcs, test_data, test_types, 1, 3, 1, PyUFunc_None, "wrapper_module_0", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "test", ufunc0); Py_DECREF(ufunc0); return m; } #else PyMODINIT_FUNC initwrapper_module_0(void) { PyObject *m, *d; PyObject *ufunc0; m = Py_InitModule("wrapper_module_0", wrapper_module_0Methods); if (m == NULL) { return; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(test_funcs, test_data, test_types, 1, 3, 1, PyUFunc_None, "wrapper_module_0", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "test", ufunc0); Py_DECREF(ufunc0); } #endif""" 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 genP3code(): autocode = CCodeGen(project="Salvus") r, s, t = symbols("r,s,t") rstn = p3ReferenceNodes() (rn, sn, tn) = rstn Np = len(rn) phi = p3ElementPolynomials(rstn, r, s, t) (dphi_dr, dphi_ds, dphi_dt) = p3ElementDerivatives(phi, r, s, t) dphi_dr_rstn = np.zeros((Np, Np)) dphi_ds_rstn = np.zeros((Np, Np)) dphi_dt_rstn = np.zeros((Np, Np)) for i in range(0, Np): dphi_dr_i = lambdify((r, s, t), dphi_dr[i]) dphi_ds_i = lambdify((r, s, t), dphi_ds[i]) dphi_dt_i = lambdify((r, s, t), dphi_dt[i]) for (n, (ri, si, ti)) in enumerate(zip(rn, sn, tn)): dphi_dr_rstn[i, n] = dphi_dr_i(ri, si, ti) dphi_ds_rstn[i, n] = dphi_ds_i(ri, si, ti) dphi_dt_rstn[i, n] = dphi_dt_i(ri, si, ti) dphi_dr_rstn = Matrix(dphi_dr_rstn) dphi_ds_rstn = Matrix(dphi_ds_rstn) dphi_dt_rstn = Matrix(dphi_dt_rstn) rn = Matrix([ri for (ri, si, ti) in zip(rn, sn, tn)]) sn = Matrix([si for (ri, si, ti) in zip(rn, sn, tn)]) tn = Matrix([ti for (ri, si, ti) in zip(rn, sn, tn)]) wn = Matrix(p3QuadratureWeights()) rn_routine = autocode.routine("coordinates_p3_tetrahedra_rn", rn, argument_sequence=None) sn_routine = autocode.routine("coordinates_p3_tetrahedra_sn", sn, argument_sequence=None) tn_routine = autocode.routine("coordinates_p3_tetrahedra_tn", tn, argument_sequence=None) wn_routine = autocode.routine("quadrature_weights_p3_tetrahedra", wn, argument_sequence=None) # NOTE: writes out in Row Major (so we write the # transpose). Salvus (via Eigen) assumes Column Major dphi_dr_rstn_routine = autocode.routine("dphi_dr_rstn_p3_tetrahedra", dphi_dr_rstn.transpose(), argument_sequence=None) dphi_ds_rstn_routine = autocode.routine("dphi_ds_rstn_p3_tetrahedra", dphi_ds_rstn.transpose(), argument_sequence=None) dphi_dt_rstn_routine = autocode.routine("dphi_dt_rstn_p3_tetrahedra", dphi_dt_rstn.transpose(), argument_sequence=None) routines = [ rn_routine, sn_routine, tn_routine, wn_routine, dphi_dr_rstn_routine, dphi_ds_rstn_routine, dphi_dt_rstn_routine ] autocode.write(routines, "p3_tetrahedra", to_files=True) buildVisualizationP3(rn, sn, tn)
n = TensorProduct(nEps, nEta).T # Get gradient of basis functions gn = sym.Matrix(([sym.diff(i, eta) for i in n])).T sym.pprint(gn) # Mass matrix mm = (rho * n.T * n) mm = sym.Matrix([mm[i,i] for i in range(nPtsPelm)]) # Get mapping m = sym.Matrix(getMap(nPtsPvtx, nPtsPedg, nPtsPfac)) # Write code routines = [] sem_c = CCodeGen() routines.append(sem_c.routine( 'interpolateOrder%dDim%d' % (args.order, args.dimension), n, argument_sequence=None)) routines.append(sem_c.routine( 'massMatrixOrder%dDim%d' % (args.order, args.dimension), mm, argument_sequence=None)) routines.append(sem_c.routine( 'gradientOperatorOrder%dDim%d' % (args.order, args.dimension), gn, argument_sequence=None)) routines.append(sem_c.routine( 'mappingOrder%dDim%d' % (args.order, args.dimension), m, argument_sequence=None)) sem_c.write( routines, 'auto/order%dDim%d' % (args.order, args.dimension), to_files=True)
derivs_sfs_calib['dDsc2_d' + s.name] = diff(D_sfs_calib ** 2, s) # 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'])