def runtest_issue_15337(language, backend): has_module('numpy') # NOTE : autowrap was originally designed to only accept an iterable for # the kwarg "helpers", but in issue 10274 the user mistakenly thought that # if there was only a single helper it did not need to be passed via an # iterable that wrapped the helper tuple. There were no tests for this # behavior so when the code was changed to accept a single tuple it broke # the original behavior. These tests below ensure that both now work. a, b, c, d, e = symbols('a, b, c, d, e') expr = (a - b + c - d + e)**13 exp_res = (1. - 2. + 3. - 4. + 5.)**13 f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=('f1', a - b + c, (a, b, c))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d)))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
def runtest_autowrap_twice(language, backend): f = autowrap((((a + b) / c)**5).expand(), language, backend) g = autowrap((((a + b) / c)**4).expand(), language, backend) # check that autowrap updates the module name. Else, g gives the same as f assert f(1, -2, 1) == -1.0 assert g(1, -2, 1) == 1.0
def fill_Params_And_Functions(self): # first argument of function is position, second is unpacked arguments such as length # or strength of elements #only for drift elements. finishes the process if it was deferred. This is so that elements can be placed #and the length of the drift region determined after self.zVar = sym.symbols('z', real=True, positive=True) args = self.PLS.sympyVarList if self.velocityVar == False: self.v = self.PLS.v0 else: self.v = sym.symbols('v', real=True, positive=True, nonzero=True) args.append(self.v) self.Mz = self.calc_M(L=self.zVar) self.M = self.Mz.subs(self.zVar, self.Length) tempList = [self.zVar] tempList.extend(args) # add the other variables which appear self.M_Funcz = symWrap.autowrap(self.Mz, args=tempList) self.M_Func = symWrap.autowrap(self.M, args=args) if self.elType == 'LENS': self.rpFunc = symWrap.autowrap(self.rp, args=args) self.rtFunc = 'penis' if self.elType == 'BEND': self.rpFunc = symWrap.autowrap(self.rp, args=args) self.rtFunc = symWrap.autowrap( self.rp / 2, args=args) # vacuum tube radius is half of bore radius
def test_autowrap_args(): x, y, z = symbols("x y z") raises( CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y), backend="dummy", args=[x]), ) f = autowrap(Eq(z, x + y), backend="dummy", args=[y, x]) assert f() == str(x + y) assert f.args == "y, x" assert f.returns == "z" raises( CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y + z), backend="dummy", args=[x, y]), ) f = autowrap(Eq(z, x + y + z), backend="dummy", args=[y, x, z]) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z" f = autowrap(Eq(z, x + y + z), backend="dummy", args=(y, x, z)) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z"
def runtest_autowrap_twice(language, backend): f = autowrap((((a + b)/c)**5).expand(), language, backend) g = autowrap((((a + b)/c)**4).expand(), language, backend) # check that autowrap updates the module name. Else, g gives the same as f assert f(1, -2, 1) == -1.0 assert g(1, -2, 1) == 1.0
def test_autowrap(self): x = sp.Symbol('x') f = x**2 print 'yo' try: autowrap(f, backend='cython', tempdir='/Users/benorn/code_tmp', verbose=True) except Exception as ex: print ex import sys print sys.path
def codegen(codegen_path): from sympy.utilities.autowrap import autowrap print('codegen...') expr = ode_dVdt_expr() names = ['res_x', 'res_phi', 'res_b', 'res_c', 'res_s', 'res_z'] print('generating...') for i in range(len(expr)): print('free sym of %s:' % names[i]) print(expr[i].free_symbols) autowrap(expr[i], language='C', backend='cython', tempdir=codegen_path)
def get_symbolic_jacobians(): p = sp.Matrix(sp.symbols("px py pz")) t = sp.Matrix(sp.symbols("tx ty tz")) w = sp.Matrix(sp.symbols("wx wy wz")) uv = sp.Matrix(proj(p, t, w)) fuv = autowrap(uv) fjp = autowrap(uv.jacobian(p)) fjt = autowrap(uv.jacobian(t)) fjw = autowrap(uv.jacobian(w)) return fuv, fjp, fjt, fjw
def test_issue_15230(): has_module('f2py') x, y = symbols('x, y') expr = Mod(x, 3.0) - Mod(y, -2.0) f = autowrap(expr, args=[x, y], language='F95') exp_res = float(expr.xreplace({x: 3.5, y: 2.7}).evalf()) assert abs(f(3.5, 2.7) - exp_res) < 1e-14 x, y = symbols('x, y', integer=True) expr = Mod(x, 3) - Mod(y, -2) f = autowrap(expr, args=[x, y], language='F95') assert f(3, 2) == expr.xreplace({x: 3, y: 2})
def test_autowrap_args(): x, y, z = symbols('x y z') raises(CodeGenArgumentListError, "autowrap(Eq(z, x + y), backend='dummy', args=[x])") f = autowrap(Eq(z, x + y), backend='dummy', args=[y, x]) assert f() == str(x + y) assert f.args == "y, x" assert f.returns == "z" raises(CodeGenArgumentListError, "autowrap(Eq(z, x + y + z), backend='dummy', args=[x, y])") f = autowrap(Eq(z, x + y + z), backend='dummy', args=[y, x, z]) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z"
def test_autowrap_args(): x, y, z = symbols("x y z") raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y), backend="dummy", args=[x])) f = autowrap(Eq(z, x + y), backend="dummy", args=[y, x]) assert f() == str(x + y) assert f.args == "y, x" assert f.returns == "z" raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y + z), backend="dummy", args=[x, y])) f = autowrap(Eq(z, x + y + z), backend="dummy", args=[y, x, z]) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z"
def _generate_and_save_function(self, filename, expression, parameters): """ Creates a folder, saves generated cython functions Create a folder in the users cache directory, named based on a hash of the current robot_config subclass. If use_cython is True, uses the created folder to save the autowrap binaries, so that they can be loaded in quickly later. """ # check for / create the save folder for this expression folder = self.config_folder + '/' + filename if not os.path.exists(folder): abr_control.utils.os_utils.makedirs(folder) function = None if self.use_cython is True: # binaries saved by specifying tempdir parameter function = autowrap(expression, backend="cython", args=parameters, tempdir=folder) else: function = sp.lambdify(parameters, expression, "numpy") folder += '.f' print "saving function:", folder, function cloudpickle.dump(function, open(folder, 'wb')) return function
def runtest_autowrap_trace(language, backend): has_module('numpy') A = IndexedBase('A') n = symbols('n', integer=True) i = Idx('i', n) trace = autowrap(A[i, i], language, backend) assert trace(numpy.eye(100)) == 100
def sympy_function(sympy_expression, sympy_symbols, mode=None, lambdify_modules=None, apply_factory=generic_applier): """ Convert a sympy expression into a function whose arguments reflect a particular vector structure. :param sympy_expression: A sympy expression in a flattened set of variables. :param sympy_symbols: The symbols from the expression, assembled into arrays reflecting their vector structure. Examples: [[x_1, x_2], [y_1, y_2]] : expects two vectors (iterables) of length 2 [[x_1, x_2], y] : expects a vector of length 2 and a scalar. :param mode: Either 'lambda' or 'compile'. 'lambda' will use sympy.lambdify while 'compile' will use sympy.autowrap default: Lambda :param apply_factory: An expression which will apply the flattening operator to the arguments, and then pass to the sympy expression. :return: The callable expression """ from sympy import lambdify from sympy.utilities import autowrap flattened = [] for s in sympy_symbols: if type(s) is list: flattened += s else: flattened.append(s) if mode is None or mode.lower() == "lambda": sympyd = lambdify(flattened, sympy_expression, modules=lambdify_modules) elif mode.lower() in ["cython", "f2py"]: sympyd = autowrap.autowrap(sympy_expression, backend=mode.lower(), args=flattened) else: raise Exception("Mode for generation of sympy function {} not understood.".format(mode)) return apply_factory(sympyd, sympy_symbols)
def runtest_issue_10274(language, backend): expr = (a - b + c)**(13) tmp = tempfile.mkdtemp() f = autowrap(expr, language, backend, tempdir=tmp, helpers=('helper', a - b + c, (a, b, c))) assert f(1, 1, 1) == 1 for file in os.listdir(tmp): if file.startswith("wrapped_code_") and file.endswith(".c"): fil = open(tmp + '/' + file) assert fil.read() == ("/******************************************************************************\n" " * Code generated with sympy "+ sympy.__version__+" *\n" " * *\n" " * See http://www.sympy.org/ for more information. *\n" " * *\n" " * This file is part of 'autowrap' *\n" " ******************************************************************************/\n" "#include " + '"' + file[:-1]+ 'h"' + "\n" "#include <math.h>\n" "\n" "double helper(double a, double b, double c) {\n" "\n" " double helper_result;\n" " helper_result = a - b + c;\n" " return helper_result;\n" "\n" "}\n" "\n" "double autofunc(double a, double b, double c) {\n" "\n" " double autofunc_result;\n" " autofunc_result = pow(helper(a, b, c), 13);\n" " return autofunc_result;\n" "\n" "}\n")
def compile_homogenous(a, alpha, d, theta, is_revolute): if is_revolute: theta = sp.symbols('theta') + theta else: d = sp.symbols('d') + d m = homogenous_transform(a, alpha, d, theta) return autowrap(m)
def try_compiling_point_jacobian_func(self, path, jac_prep_func): """ Attempts to load jacobian function from given location, generate (and save) if does not exist. """ print("Loading point estimate jacobian...", file=sys.stderr) if isfile(path): jac, args = pickle.load(open(path, 'r')) print("... file found, jacobian loaded.", file=sys.stderr) else: print( "... file not found, regenerating jacobian. This may take some time...", file=sys.stderr) t = time() jac, args = jac_prep_func() pickle.dump((jac, args), open(path, 'w'), protocol=pickle.HIGHEST_PROTOCOL) print("... done (%f seconds elapsed), saved to file." % (time() - t), file=sys.stderr) print("Compiling to fortran...", file=sys.stderr) t = time() jac_lambda = autowrap(args=tuple(args), expr=jac, tempdir='tmp_dir') print("... done (%f seconds elapsed)." % (time() - t), file=sys.stderr) # move static object to current folder for later use shutil.copy('tmp_dir/wrapper_module_0.so', 'wrapper_module_0.so') # delete temporary directory shutil.rmtree('tmp_dir') return jac_lambda
def link_metrics(self, g, verbose): if verbose: print("Linking {} to the Geodesic Engine".format(g.name)) self.metric = g self.eq_x = g.eq_x self.eq_u = g.eq_u self.u0_s_null = g.u0_s_null self.u0_s_timelike = g.u0_s_timelike self.metric.geodesic_engine_linked = True self.metric.geodesic_engine = self self.motion_eq_f = [] for eq in [*self.eq_x, *self.eq_u]: self.motion_eq_f.append( autowrap(eq, backend='cython', args=[ *self.metric.x, *self.metric.u, *self.metric.get_constants_symb() ])) self.evaluate_constants() if verbose: print("Metric linking complete.")
def end_Lattice(self): #must be called after ending lattice. Prepares functions that will be used later if self.catchErrors==True: self._catch_Errors() self._update_Element_Parameters_And_Functions() self.set_apetures() self.MTot = self._compute_M_Total() #sympy version of full transfer function self.MTotFunc = symWrap.autowrap(self.MTot,args=self.sympyVarList) #this loop does 2 things # 1:make an array function where each entry is the length of the corresping optic. #2: make an array function each entry is the sum of the lengths of the preceding optics and that optic. ie, the total length at that point temp1 = []#temporary array for case 1 temp2 = [] #temporary aray for case 2 for i in range(len(self.lattice)): temp1.append(self.lattice[i].Length) temp2.append(self.lattice[i].Length) for j in range(i): #do the sum up to that point temp2[i] += self.lattice[j].Length self.lengthListFunc = sym.lambdify(self.sympyVarList,temp1) #A function that returns a list where # each entry is length of that element self.totalLengthListFunc = sym.lambdify(self.sympyVarList,temp2) #each entry is an inclusive cumulative sum #of element lengths print("Lattice model completed")
def test_autowrap_store_files(): x, y = symbols('x y') tmp = tempfile.mkdtemp() TmpFileManager.tmp_folder(tmp) f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK)
def compile(self): self.numeric_eqn = sp.lambdify(self.all_symbols, sp.Matrix(self.symbolic_eqns)) self.numeric_nullcline_eqn = sp.lambdify( [self.state_symbols[0], *self.all_symbols[2:]], self.nullcline_eqn) self.compiled_eqn = autowrap(sp.Matrix(self.symbolic_eqns), args=self.all_symbols, backend='f2py')
def __init__(self, backend=None): ''' Initializing the class. Automatically checks which backend is available. Currently only those linked to numpy are used where those linked with Theano are not. ''' if backend is None: self._backend = None x = sympy.Symbol('x') expr = sympy.sin(x) / x # lets assume that we can't do theano.... (for now) # now lets explore the other options try: # first, f2py. This is the best because Cython below may # throw out errors with older versions of sympy due to a # bug (calling numpy.h, a c header file which has problem # dealing with vector output). a = autowrap(expr, args=[x]) a(1) # congrats! self._backend = 'f2py' except: try: import cython a = autowrap(expr, args=[x], backend='Cython') a(1) # also need to test the matrix version because # previous version of sympy does not work when compiling # a matrix exprMatrix = sympy.zeros(2,1) exprMatrix[0] = expr exprMatrix[1] = expr a = autowrap(exprMatrix, args=[x], backend='Cython') a(1) self._backend = 'Cython' except: # we have truely failed in life. A standard lambda function! # unfortunately, this may be the case when we are running # stuff in a parallel setting where we create objects in # pure computation nodes with no compile mechanism self._backend = 'lambda' else: self._backend = backend
def test_autowrap_dummy(): x, y, z = symbols('x y z') # Uses DummyWrapper to test that codegen works as expected f = autowrap(x + y, backend='dummy') assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "nameless" f = autowrap(Eq(z, x + y), backend='dummy') assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "z" f = autowrap(Eq(z, x + y + z), backend='dummy') assert f() == str(x + y + z) assert f.args == "x, y, z" assert f.returns == "z"
def __init__(self, backend=None): ''' Initializing the class. Automatically checks which backend is available. Currently only those linked to numpy are used where those linked with Theano are not. ''' if backend is None: self._backend = None x = sympy.Symbol('x') expr = sympy.sin(x) / x # lets assume that we can't do theano.... (for now) # now lets explore the other options try: # first, f2py. This is the best because Cython below may # throw out errors with older versions of sympy due to a # bug (calling numpy.h, a c header file which has problem # dealing with vector output). a = autowrap(expr, args=[x]) a(1) # congrats! self._backend = 'f2py' except: try: import cython a = autowrap(expr, args=[x], backend='Cython') a(1) # also need to test the matrix version because # previous version of sympy does not work when compiling # a matrix exprMatrix = sympy.zeros(2, 1) exprMatrix[0] = expr exprMatrix[1] = expr a = autowrap(exprMatrix, args=[x], backend='Cython') a(1) self._backend = 'Cython' except: # we have truely failed in life. A standard lambda function! # unfortunately, this may be the case when we are running # stuff in a parallel setting where we create objects in # pure computation nodes with no compile mechanism self._backend = 'lambda' else: self._backend = backend
def test_autowrap_dummy(): x, y, z = symbols("x y z") # Uses DummyWrapper to test that codegen works as expected f = autowrap(x + y, backend="dummy") assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "nameless" f = autowrap(Eq(z, x + y), backend="dummy") assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "z" f = autowrap(Eq(z, x + y + z), backend="dummy") assert f() == str(x + y + z) assert f.args == "x, y, z" assert f.returns == "z"
def test_autowrap_store_files_issue_gh12939(): x, y = symbols('x y') tmp = './tmp' try: f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) finally: shutil.rmtree(tmp)
def __init__(self, points, index, dimension=1): x = sy.symbols('x') x_i = points[index][0] def f(j): return (x - points[j][0]) / (x_i - points[j][0]) if dimension == 1: self._L = product(f, 1, index) * product(f, index+2, len(points)) self._value = autowrap(self._L) self._grad = autowrap(sy.diff(self._L, x), args=(x,)) else: self._L = sy.Matrix([product(f, 1, index) * product(f, index+2, len(points)) for index in range(dimension)]) self._value = autowrap(self._L, args=[x]) self._grad = autowrap( sy.Matrix([sy.diff(self._L[i], x) for i in range(dimension)]), args=[x] )
def runtest_issue_15337(language, backend): # NOTE : autowrap was originally designed to only accept an iterable for # the kwarg "helpers", but in issue 10274 the user mistakenly thought that # if there was only a single helper it did not need to be passed via an # iterable that wrapped the helper tuple. There were no tests for this # behavior so when the code was changed to accept a single tuple it broke # the original behavior. These tests below ensure that both now work. a, b, c, d, e = symbols('a, b, c, d, e') expr = (a - b + c - d + e)**13 exp_res = (1. - 2. + 3. - 4. + 5.)**13 f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=('f1', a - b + c, (a, b, c))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d)))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res)
def test_autowrap_store_files(): x, y = symbols("x y") tmp = tempfile.mkdtemp() try: f = autowrap(x + y, backend="dummy", tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) finally: shutil.rmtree(tmp)
def test_autowrap_store_files(): x, y = symbols('x y') tmp = tempfile.mkdtemp() try: f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) finally: shutil.rmtree(tmp)
def fill_Parameters_And_Functions(self): #fill various functions and parameters of the injector. #its convenient to attach these values to the injector rather than the element self.M=self.el.M self.MVelCor=self.el.MVelCor self.Li=self.el.Li self.rp=self.el.rp self.MFunc=symWrap.autowrap(self.M,args=self.sympyVarList) #function that return numeric valued transfer matrix self.LiFunc=sym.lambdify(self.sympyVarList,self.el.Li) #function that return numeric value for shaper image distance self.rpFunc = symWrap.autowrap(self.rp, args=self.sympyVarList) #function that return numeric value for bore #radius of shaper. This account for wanting to use only self.sigma of the apeture args=self.sympyVarList.copy() A = self.M[0, 0] #0,0 entry of transfer matrix, sympy version C = self.M[1, 0] #1,0 entry of transfer matrix, sympy version D = self.M[1, 1] #1,1 entry of transfer matrix, sympy version ACor = self.MVelCor[0, 0] # component of the correction matrix for particle speed, sympy version CCor = self.MVelCor[1, 0] # component of the correction matrix for particle speed, sympy version DCor = self.MVelCor[1, 1] # component of the correction matrix for particle speed, sympy version #----convert above sympy expressions into fast fortran/c code funcA=symWrap.autowrap(A,args=args) funcC = symWrap.autowrap(C, args=args) funcD = symWrap.autowrap(D, args=args) funcACor=symWrap.autowrap(ACor,args=args) funcCCor = symWrap.autowrap(CCor, args=args) funcDCor = symWrap.autowrap(DCor, args=args) #now construct a function that returns a list of emittance values for each particle. def temp(x,beta,alpha): sOffset=x[2] #offset from focal plane A0=funcA(*x) #0,0 entry of transfer matrix C0 = funcC(*x) #1,0 entry of transfer matrix D0 = funcD(*x) #1,1 entry of transfer matrix ACor0 = funcACor(*x) #correction factors to transfer matrix for particle speed CCor0 = funcCCor(*x) #correction factors to transfer matrix for particle speed DCor0 = funcDCor(*x) #correction factors to transfer matrix for particle speed epsList=[] for particle in self.particles: xi=particle.xi xdi=particle.xdi/self.PLS.v0 #convert to angles xi=xdi*sOffset+xi deltaV=particle.deltaV xf=(A0+ACor0*deltaV)*xi xdf=(C0+CCor0*deltaV)*xi+(D0+DCor0*deltaV)*xdi eps=(xf**2+(beta*xdf)**2+(alpha*xf)**2+2*alpha*xdf*xf*beta)/beta epsList.append(eps) #this can't go negative. I've tested for many values and by inspection it seems #like it can't. It could be proven no doubt return epsList self.epsFunc=temp
def test_autowrap_store_files(): x, y = symbols('x y') tmp = tempfile.mkdtemp() TmpFileManager.tmp_folder(tmp) f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) TmpFileManager.cleanup()
def propensities_as_function(self): all_symbols = self.species + self.parameters wrapping_func = lambda x: autowrap(x, args=all_symbols, language='C', backend='Cython') wrapped_functions = map(wrapping_func, self.propensities) def f(*args): ans = np.array([w_f(*args) for w_f in wrapped_functions]) return ans return f
def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') expr = Eq(C[i, j], A[i, k]*B[k, j]) matmat = autowrap(expr, language, backend) # compare with numpy's dot product M1 = numpy.random.rand(10, 20) M2 = numpy.random.rand(20, 15) M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') expr = Eq(C[i, j], A[i, k] * B[k, j]) matmat = autowrap(expr, language, backend) # compare with numpy's dot product M1 = numpy.random.rand(10, 20) M2 = numpy.random.rand(20, 15) M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') x, y = symbols('x y', cls=IndexedBase) expr = Eq(y[i], A[i, j] * x[j]) mv = autowrap(expr, language, backend) # compare with numpy's dot product M = numpy.random.rand(10, 20) x = numpy.random.rand(20) y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') x, y = symbols('x y', cls=IndexedBase) expr = Eq(y[i], A[i, j]*x[j]) mv = autowrap(expr, language, backend) # compare with numpy's dot product M = numpy.random.rand(10, 20) x = numpy.random.rand(20) y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
def _wrap(self, expr): vars = self.prob.var_scalars x = sym.MatrixSymbol('x', len(vars), 1) subs = dict(zip(vars, sym.flatten(x))) expr = expr.subs(subs) args = (x, ) + tuple(p.symbol for p in self.prob.params) if self.simplify: expr = expr.simplify() if self.wrap_using == 'autowrap': return autowrap(expr, args=args) else: return reshape_args(lambdify(args, expr), args)
def triangular_source_coefficient(): p2dv = sp.symbols('x1_1:3') p3dv = sp.symbols('x0_1:4') p2d = sp.Matrix(p2dv + (1, )) p3d = sp.Matrix(p3dv) equation = p2d.cross(p3d) coeff = extract_coefficient(equation, p3dv) fn = autowrap(coeff, args=p2dv) def generator(pt): return fn(pt[0], pt[1]) return generator
def __init__(self, loss_type): """ set up symbolic derivations """ from sympy.utilities.autowrap import autowrap self.x = x = sympy.Symbol("x") self.y = y = sympy.Symbol("y") self.cx = cx = sympy.Symbol("cx") self.cy = cy = sympy.Symbol("cy") self.r = r = sympy.Symbol("r") if loss_type == "eucledian_squared": self.fun = (sympy.sqrt((x-cx)**2 + (y-cy)**2) - r)**2 if loss_type == "eucledian_abs": self.fun = sympy.sqrt((sympy.sqrt((x-cx)**2 + (y-cy)**2) - r)**2 + 0.001) if loss_type == "algebraic_squared": self.fun = ((x-cx)**2 + (y-cy)**2 - r)**2 #TODO replace x**2 with x*x self.fun = self.fun.expand(deep=True) sympy.pprint(self.fun) self.d_cx = self.fun.diff(cx).expand(deep=True) self.d_cy = self.fun.diff(cy).expand(deep=True) self.d_r = self.fun.diff(r).expand(deep=True) # generate native code native_lang = "C" # generate native code if native_lang == "fortran": self.c_fun = autowrap(self.fun, language="F95", backend="f2py") self.c_d_cx = autowrap(self.d_cx) self.c_d_cy = autowrap(self.d_cy) self.c_d_r = autowrap(self.d_r) else: self.c_fun = autowrap(self.fun, language="C", backend="Cython", tempdir=".") self.c_d_cx = autowrap(self.d_cx, language="C", backend="Cython", tempdir=".") self.c_d_cy = autowrap(self.d_cy, language="C", backend="Cython", tempdir=".") self.c_d_r = autowrap(self.d_r, language="C", backend="Cython", tempdir=".") self.grads = {"cx": self.d_cx, "cy": self.d_cy, "r": self.d_r} self.c_grads = {"cx": self.c_d_cx, "cy": self.c_d_cy, "r": self.c_d_r}
def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') A, x, y = map(IndexedBase, ['A', 'x', 'y']) n, m = symbols('n m', integer=True) i = Idx('i', m) j = Idx('j', n) expr = Eq(y[i], A[i, j]*x[j]) mv = autowrap(expr, language, backend) # compare with numpy's dot product M = numpy.random.rand(10, 20) x = numpy.random.rand(20) y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') A, x, y = map(IndexedBase, ['A', 'x', 'y']) n, m = symbols('n m', integer=True) i = Idx('i', m) j = Idx('j', n) expr = Eq(y[i], A[i, j] * x[j]) mv = autowrap(expr, language, backend) # compare with numpy's dot product M = numpy.random.rand(10, 20) x = numpy.random.rand(20) y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13
def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') A, B, C = map(IndexedBase, ['A', 'B', 'C']) n, m, d = symbols('n m d', integer=True) i = Idx('i', m) j = Idx('j', n) k = Idx('k', d) expr = Eq(C[i, j], A[i, k]*B[k, j]) matmat = autowrap(expr, language, backend) # compare with numpy's dot product M1 = numpy.random.rand(10, 20) M2 = numpy.random.rand(20, 15) M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
def target_coefficient(): p2dv = sp.symbols('x0_1:3') p3dv = sp.symbols('x1_1:4') p2d = sp.Matrix(p2dv + (1, )) p3d = sp.Matrix(p3dv + (1, )) pv = sp.symbols('p1:13') p = sp.Matrix(pv).reshape(3, 4) equation = p2d.cross(p * p3d) coeff = extract_coefficient(equation, p3dv) fn = autowrap(coeff, args=p2dv + pv) def generator(pt, proj): return fn(pt[0], pt[1], *list(proj.ravel())) return generator
def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') A, B, C = map(IndexedBase, ['A', 'B', 'C']) n, m, d = symbols('n m d', integer=True) i = Idx('i', m) j = Idx('j', n) k = Idx('k', d) expr = Eq(C[i, j], A[i, k] * B[k, j]) matmat = autowrap(expr, language, backend) # compare with numpy's dot product M1 = numpy.random.rand(10, 20) M2 = numpy.random.rand(20, 15) M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13
def test_autowrap_custom_printer(): has_module('Cython') from sympy import pi from sympy.utilities.codegen import C99CodeGen from sympy.printing.ccode import C99CodePrinter from sympy.functions.elementary.exponential import exp class PiPrinter(C99CodePrinter): def _print_Pi(self, expr): return "S_PI" printer = PiPrinter() gen = C99CodeGen(printer=printer) gen.preprocessor_statements.append('#include "shortpi.h"') expr = pi * a expected = ( '#include "%s"\n' '#include <math.h>\n' '#include "shortpi.h"\n' '\n' 'double autofunc(double a) {\n' '\n' ' double autofunc_result;\n' ' autofunc_result = S_PI*a;\n' ' return autofunc_result;\n' '\n' '}\n' ) tmpdir = tempfile.mkdtemp() # write a trivial header file to use in the generated code open(os.path.join(tmpdir, 'shortpi.h'), 'w').write('#define S_PI 3.14') func = autowrap(expr, backend='cython', tempdir=tmpdir, code_gen=gen) assert func(4.2) == 3.14 * 4.2 # check that the generated code is correct for filename in os.listdir(tmpdir): if filename.startswith('wrapped_code') and filename.endswith('.c'): with open(os.path.join(tmpdir, filename)) as f: lines = f.readlines() expected = expected % filename.replace('.c', '.h') assert ''.join(lines[7:]) == expected
from sympy import symbols, Eq from sympy.external import import_module from sympy.tensor import IndexedBase, Idx from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError from sympy.utilities.pytest import XFAIL, skip numpy = import_module('numpy') Cython = import_module('Cython') f2py = import_module('numpy.f2py', __import__kwargs={'fromlist':['f2py']}) f2pyworks = False if f2py: try: autowrap(symbols('x'), 'f95', 'f2py') except CodeWrapError: f2pyworks = False else: f2pyworks = True def has_module(module): """ Return True if module exists, otherwise run skip(). module should be a string. """ # To give a string of the module name to skip(), this function takes a # string. So we don't waste time running import_module() more than once, # just map the three modules tested here in this dict. modnames = {'numpy':numpy, 'Cython':Cython, 'f2py':f2py} if modnames[module]:
def main(): print(__doc__) # arrays are represented with IndexedBase, indices with Idx m = Symbol('m', integer=True) i = Idx('i', m) A = IndexedBase('A') B = IndexedBase('B') x = Symbol('x') print("Compiling ufuncs for radial harmonic oscillator solutions") # setup a basis of ho-solutions (for l=0) basis_ho = {} for n in range(basis_dimension): # Setup the radial ho solution for this n expr = R_nl(n, orbital_momentum_l, omega2, x) # Reduce the number of operations in the expression by eval to float expr = expr.evalf(15) print("The h.o. wave function with l = %i and n = %i is" % ( orbital_momentum_l, n)) pprint(expr) # implement, compile and wrap it as a ufunc basis_ho[n] = ufuncify(x, expr) # now let's see if we can express a hydrogen radial wave in terms of # the ho basis. Here's the solution we will approximate: H_ufunc = ufuncify(x, hydro_nl(hydrogen_n, orbital_momentum_l, 1, x)) # The transformation to a different basis can be written like this, # # psi(r) = sum_i c(i) phi_i(r) # # where psi(r) is the hydrogen solution, phi_i(r) are the H.O. solutions # and c(i) are scalar coefficients. # # So in order to express a hydrogen solution in terms of the H.O. basis, we # need to determine the coefficients c(i). In position space, it means # that we need to evaluate an integral: # # psi(r) = sum_i Integral(R**2*conj(phi(R))*psi(R), (R, 0, oo)) phi_i(r) # # To calculate the integral with autowrap, we notice that it contains an # element-wise sum over all vectors. Using the Indexed class, it is # possible to generate autowrapped functions that perform summations in # the low-level code. (In fact, summations are very easy to create, and as # we will see it is often necessary to take extra steps in order to avoid # them.) # we need one integration ufunc for each wave function in the h.o. basis binary_integrator = {} for n in range(basis_dimension): # # setup basis wave functions # # To get inline expressions in the low level code, we attach the # wave function expressions to a regular SymPy function using the # implemented_function utility. This is an extra step needed to avoid # erroneous summations in the wave function expressions. # # Such function objects carry around the expression they represent, # but the expression is not exposed unless explicit measures are taken. # The benefit is that the routines that searches for repeated indices # in order to make contractions will not search through the wave # function expression. psi_ho = implemented_function('psi_ho', Lambda(x, R_nl(n, orbital_momentum_l, omega2, x))) # We represent the hydrogen function by an array which will be an input # argument to the binary routine. This will let the integrators find # h.o. basis coefficients for any wave function we throw at them. psi = IndexedBase('psi') # # setup expression for the integration # step = Symbol('step') # use symbolic stepsize for flexibility # let i represent an index of the grid array, and let A represent the # grid array. Then we can approximate the integral by a sum over the # following expression (simplified rectangular rule, ignoring end point # corrections): expr = A[i]**2*psi_ho(A[i])*psi[i]*step if n == 0: print("Setting up binary integrators for the integral:") pprint(Integral(x**2*psi_ho(x)*Function('psi')(x), (x, 0, oo))) # Autowrap it. For functions that take more than one argument, it is # a good idea to use the 'args' keyword so that you know the signature # of the wrapped function. (The dimension m will be an optional # argument, but it must be present in the args list.) binary_integrator[n] = autowrap(expr, args=[A.label, psi.label, step, m]) # Lets see how it converges with the grid dimension print("Checking convergence of integrator for n = %i" % n) for g in range(3, 8): grid, step = np.linspace(0, rmax, 2**g, retstep=True) print("grid dimension %5i, integral = %e" % (2**g, binary_integrator[n](grid, H_ufunc(grid), step))) print("A binary integrator has been set up for each basis state") print("We will now use them to reconstruct a hydrogen solution.") # Note: We didn't need to specify grid or use gridsize before now grid, stepsize = np.linspace(0, rmax, gridsize, retstep=True) print("Calculating coefficients with gridsize = %i and stepsize %f" % ( len(grid), stepsize)) coeffs = {} for n in range(basis_dimension): coeffs[n] = binary_integrator[n](grid, H_ufunc(grid), stepsize) print("c(%i) = %e" % (n, coeffs[n])) print("Constructing the approximate hydrogen wave") hydro_approx = 0 all_steps = {} for n in range(basis_dimension): hydro_approx += basis_ho[n](grid)*coeffs[n] all_steps[n] = hydro_approx.copy() if pylab: line = pylab.plot(grid, all_steps[n], ':', label='max n = %i' % n) # check error numerically diff = np.max(np.abs(hydro_approx - H_ufunc(grid))) print("Error estimate: the element with largest deviation misses by %f" % diff) if diff > 0.01: print("This is much, try to increase the basis size or adjust omega") else: print("Ah, that's a pretty good approximation!") # Check visually if pylab: print("Here's a plot showing the contribution for each n") line[0].set_linestyle('-') pylab.plot(grid, H_ufunc(grid), 'r-', label='exact') pylab.legend() pylab.show() print("""Note: These binary integrators were specialized to find coefficients for a harmonic oscillator basis, but they can process any wave function as long as it is available as a vector and defined on a grid with equidistant points. That is, on any grid you get from numpy.linspace. To make the integrators even more flexible, you can setup the harmonic oscillator solutions with symbolic parameters omega and l. Then the autowrapped binary routine will take these scalar variables as arguments, so that the integrators can find coefficients for *any* isotropic harmonic oscillator basis. """)
def compileExpr(self, inputSymb, inputExpr, backend=None, compileType=False): ''' Compiles the expression given the symbols. Determines the backend if required. Parameters ---------- inputSymb: list the set of symbols for the input expression inputExpr: expr expression in sympy backend: optional the backend we want to use to compile compileType: optional defaults to False. If True, return an extra output that informs the end user of the method used to compile the equation, can be one of (numpy, mpmath, sympy) Returns ------- Compiled function taking arguments of the input symbols ''' if backend is None: backend = self._backend # unless specified, we are always going to use numpy and forget # about the floating point importance compiledFunc = None compileTypeChosen = None try: if self._backend == 'f2py': compiledFunc = autowrap(expr=inputExpr, args=inputSymb, backend='f2py') compileTypeChosen = 'numpy' elif self._backend == 'lambda': compiledFunc = lambdify(expr=inputExpr, args=inputSymb, modules='numpy') compileTypeChosen = 'numpy' elif self._backend == 'Cython': # note that we have another test layer because of the bug previously # mentioned in __init__ of this class try: compiledFunc = autowrap(expr=inputExpr, args=inputSymb, backend='Cython') compileTypeChosen = 'numpy' except: # although we don't think it is possible given the checks # previously performed, we should still try it try: compiledFunc = autowrap(expr=inputExpr, args=inputSymb, backend='f2py') compileTypeChosen = 'numpy' except: compiledFunc = lambdify(expr=inputExpr, args=inputSymb, modules='numpy') compileTypeChosen = 'numpy' else: raise ExpressionErrror("The problem is too tough") except: try: compiledFunc = lambdify(expr=inputExpr, args=inputSymb, modules='mpmath') compileTypeChosen = 'mpmath' except: compiledFunc = lambdify(expr=inputExpr, args=inputSymb, modules='sympy') compileTypeChosen = 'sympy' if compileType: return compiledFunc, compileTypeChosen else: return compiledFunc
from sympy import symbols, Eq from sympy.external import import_module from sympy.tensor import IndexedBase, Idx from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError from sympy.utilities.pytest import XFAIL, skip numpy = import_module("numpy") Cython = import_module("Cython") f2py = import_module("numpy.f2py", __import__kwargs={"fromlist": ["f2py"]}) f2pyworks = False if f2py: try: autowrap(symbols("x"), "f95", "f2py") except (CodeWrapError, ImportError): f2pyworks = False else: f2pyworks = True a, b, c = symbols("a b c") n, m, d = symbols("n m d", integer=True) A, B, C = symbols("A B C", cls=IndexedBase) i = Idx("i", m) j = Idx("j", n) k = Idx("k", d) def has_module(module): """ Return True if module exists, otherwise run skip().
def ufuncify(args, expr, **kwargs): """ Generates a binary ufunc-like lambda function for numpy arrays ``args`` Either a Symbol or a tuple of symbols. Specifies the argument sequence for the ufunc-like function. ``expr`` A SymPy expression that defines the element wise operation ``kwargs`` Optional keyword arguments are forwarded to autowrap(). The returned function can only act on one array at a time, as only the first argument accept arrays as input. .. Note:: a *proper* numpy ufunc is required to support broadcasting, type casting and more. The function returned here, may not qualify for numpy's definition of a ufunc. That why we use the term ufunc-like. 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) >>> f([1, 2, 3], [2, 2, 2]) [ 3. 6. 11.] >>> a = f(np.arange(5), 3 * np.ones(5)) >>> isinstance(a, np.ndarray) True >>> print a [ 3. 4. 7. 12. 19.] """ y = sy.IndexedBase(sy.Dummy('y')) # result array i = sy.Dummy('i', integer=True) # index of the array m = sy.Dummy('m', integer=True) # length of array (dimension) i = sy.Idx(i, m) # index of the array l = sy.Lambda(args, expr) # A lambda function that represents the inputs and outputs of the expression f = implemented_function('f', l) # maps an UndefinedFunction('f') to the lambda function if isinstance(args, sy.Symbol): args = [args] else: args = list(args) # For each of the args create an indexed version. indexed_args = [sy.IndexedBase(sy.Dummy(str(a))) for a in args] # ensure correct order of arguments kwargs['args'] = [y] + indexed_args + [m] args_with_indices = [a[i] for a in indexed_args] return autowrap(sy.Eq(y[i], f(*args_with_indices)), **kwargs)
def __init__(self, compiled=False) : from sympy import S, symbols, sqrt, Lambda, lambdify, Matrix from sympy.utilities.autowrap import autowrap x,y,z = symbols("x y z") self.order = order self.sn3d = np.array([[None]*(order+1)]*(order+1)) self.sn3d[shi(0, 0)] = S(1) self.sn3d[shi(1,+1)] = x self.sn3d[shi(1, 0)] = z self.sn3d[shi(1,-1)] = y self.sn3d[shi(2,-2)] = (x*y)*2 * sqrt(S(3)/4) self.sn3d[shi(2,-1)] = (y*z)*2 * sqrt(S(3)/4) self.sn3d[shi(2, 0)] = (3*z*z -1)/2 self.sn3d[shi(2,+1)] = (x*z)*2 * sqrt(S(3)/4) self.sn3d[shi(2,+2)] = (x*x - y*y) * sqrt(S(3)/4) self.sn3d[shi(3,+3)] = x*(x*x-3*y*y) * sqrt(S(5)/8) self.sn3d[shi(3,+2)] = z*(x*x-y*y) * sqrt(S(15)/4) self.sn3d[shi(3,+1)] = x*(5*z*z -1) * sqrt(S(3)/8) self.sn3d[shi(3, 0)] = z*(5*z*z -3) * sqrt(S(1)/4) self.sn3d[shi(3,-1)] = y*(5*z*z -1) * sqrt(S(3)/8) self.sn3d[shi(3,-2)] = z*x*y*2 * sqrt(S(15)/4) self.sn3d[shi(3,-3)] = y*(3*x*x-y*y) * sqrt(S(5)/8) self.sn3d[shi(4,+4)] = (x**4 -6*x*x*y*y +y**4) * sqrt(S(35)/64) self.sn3d[shi(4,+3)] = z*x*(x*x -3*y*y) * sqrt(S(35)/8) self.sn3d[shi(4,+2)] = (x*x-y*y)*(7*z*z -1) * sqrt(S(5)/16) self.sn3d[shi(4,+1)] = z*x*(7*z*z -3) * sqrt(S(5)/8) self.sn3d[shi(4, 0)] = (3+z*z*(-30+z*z*35)) * sqrt(S(1)/64) self.sn3d[shi(4,-1)] = z*y*(7*z*z -3) * sqrt(S(5)/8) self.sn3d[shi(4,-2)] = 2*x*y*(7*z*z -1) * sqrt(S(5)/16) self.sn3d[shi(4,-3)] = z*y*(3*x*x -y*y) * sqrt(S(35)/8) self.sn3d[shi(4,-4)] = 4*x*y*(x*x -y*y) * sqrt(S(35)/64) self.sn3d[shi(5,+5)] = x*(x**4 -10*x*x*y*y +5*y**4) * sqrt(S(9)*7/64/2) self.sn3d[shi(5,+4)] = z*(x**4 -6*x*x*y*y +y**4) * sqrt(S(35)*9/64) self.sn3d[shi(5,+3)] = x*(x*x-3*y*y)*(9*z*z-1) * sqrt(S(5)*7/128) self.sn3d[shi(5,+2)] = 3*z*(x*x-y*y)*(3*z*z-1) * sqrt(S(7)*5/3/16) self.sn3d[shi(5,+1)] = x*(21*z**4 -14*z**2 + 1) * sqrt(S(3)*5/64) self.sn3d[shi(5, 0)] = z*(63*z**4 -70*z**2 + 15) * sqrt(S(1)/64) self.sn3d[shi(5,-1)] = y*(21*z**4 -14*z**2 + 1) * sqrt(S(3)*5/64) self.sn3d[shi(5,-2)] = 2*x*y*z*(3*z*z -1) * sqrt(S(105)/16) self.sn3d[shi(5,-3)] = y*(9*z*z-1)*(3*x*x-y*y) * sqrt(S(35)/8/16) self.sn3d[shi(5,-4)] = 4*x*y*z*(x*x -y*y) * sqrt(S(9)*35./64) self.sn3d[shi(5,-5)] = y*(5*x**4 -7*x*x*y*y +y**4) * sqrt(S(9)/10) self.sn3d[shi(5,-5)] = y*( 5*x**4 -10*x*x*y*y +y**4 ) * sqrt(S(9)*7/64/2) if compiled : # TODO: Get a single function that returns the whole matrix # Compiling a library for each cell takes soooo long # Hints for future work: # http://ojensen.wordpress.com/2010/08/10/fast-ufunc-ish-hydrogen-solutions/ # https://groups.google.com/forum/?fromgroups=#!topic/sympy/KXoO-BvmD_w for i in xrange(self.order+1) : for j in xrange(self.order+1) : self.sn3d[i,j] = autowrap( self.sn3d[i,j], language='c', backend='cython', args=(x,y,z)) else : for i in xrange(self.order+1) : for j in xrange(self.order+1) : # self.sn3d[i,j] = Lambda( # (x,y,z), # self.sn3d[i,j], # ) self.sn3d[i,j] = lambdify( (x,y,z), self.sn3d[i,j], )
def _right_hand_side_as_numeric_functions(self): all_symbols = self.parameters + self.variables wrapping_func = lambda x: autowrap(x, args=all_symbols, language='C', backend='Cython') return map(wrapping_func, self.right_hand_side)
def get_cb_from_rel( rel, subs_fs, varied, cb_args=(), use_numexpr=False, unitless=False, bincompile=False, store_dir=None, mod_name=None, verbose=False, ): """ Turn a symbolic (sympy) equation into a python callback of one variable. subs_fs is preferable of form: frozenset(dict.items()) Some rules of thumb: If the callback will be evaluated for large vectors set use_numexpr = True If the expression is very complicated and will be called pointwise set bincompile = True TODO: Cache compiled binaries """ global NUMEXPR_AVAILABLE from sympy import symbols # If varied is general function dep. on (x,y) we cannot # substitute for x and y without error. Therefore we # mask `varied` as dummy and resubstitute it later dummy = symbols("DUMMY") subsrel = rel.subs({varied: dummy}) subsrel = subsrel.subs(dict(subs_fs)) if bincompile: assert not use_numexpr assert unitless if store_dir: from mod_autowrap import autowrap_and_store assert mod_name != None import sys try: added_path = False if not store_dir in sys.path: added_path = True sys.path.append(store_dir) mod_obj = __import__(mod_name) cb = mod_obj.autofunc if verbose: fmtstr = "Found precompiled binary `{}` in {}" print fmtstr.format(mod_name, store_dir) except ImportError: if verbose: print "Autowrapping binary..." cb = autowrap_and_store( subsrel, args=(dummy,) + cb_args, tempdir=store_dir, verbose=verbose, mod_name=mod_name ) if added_path: sys.path.pop(sys.path.index(store_dir)) return cb else: from sympy.utilities.autowrap import autowrap return autowrap(subsrel, args=(dummy,) + cb_args) else: if use_numexpr: if NUMEXPR_AVAILABLE == False: raise ImportError def f0(x, *args): subsrel2 = subsrel.subs(dict(zip(cb_args, args))) return ne.evaluate(str(subsrel2), {str(dummy): x}) else: subsrel = subsrel.subs({dummy: varied}) def f0(x, *args): args_subsd = dict(zip(cb_args, args)) subsrel2 = subsrel.subs(args_subsd) return subsrel2.subs({varied: x}) return f0
def runtest_autowrap_trace(language, backend): has_module('numpy') trace = autowrap(A[i, i], language, backend) assert trace(numpy.eye(100)) == 100