I'm working on producing compiled functions using sympy.code.autowrap, specifically the make_routine, autowrap, and ufuncify functions of that module. I would like to be able to use sympy.codegen.ast to generate code to be wrapped. For instance:
import sympy as sy
from sympy.codegen.ast import (Assignment, CodeBlock, Return, Element,
Pointer, Declaration, float64,
FunctionPrototype, FunctionDefinition)
zlist = sy.symarray('z', (5,), real=True)
d1expz = sy.apply_finite_diff(1, x_list=range(-2,3), y_list=zlist)
d2expz = sy.apply_finite_diff(2, x_list=range(-2,3), y_list=zlist)
d1p = Pointer('d1p', float64)
d2p = Pointer('d2p', float64)
d1p0 = Element('d1p', '0')
d2p0 = Element('d2p', '0')
d12fpa = FunctionPrototype(float64, 'd12funca', [d1p, d2p] + list(zlist))
body12a = [
CodeBlock(
Assignment(d1p0, d1expz),
Assignment(d2p0, d2expz),
).cse(),
]
d12funca = FunctionDefinition.from_FunctionPrototype(
d12fpa, body12a
)
print(sy.ccode(d12funca))
This results in the following C code, which looks good:
double d12funca(double * d1p, double * d2p, double z_0, double z_1, double z_2, double z_3, double z_4){
x0 = (1.0/12.0)*z_0;
x1 = -1.0/12.0*z_4;
d1p[0] = x0 + x1 - 2.0/3.0*z_1 + (2.0/3.0)*z_3;
d2p[0] = -x0 + x1 + (4.0/3.0)*z_1 - 5.0/2.0*z_2 + (4.0/3.0)*z_3;
}
sympy.utilities.codegen.codegen also understands this, e.g. the following produces just the kind of results you'd expect.
[(c_name, c_code), (h_name, c_header)] = codegen(
('d12func',
[
sy.Eq(sy.Symbol('d1'), d1expz),
sy.Eq(sy.Symbol('d2'), d2expz)
]),
language='c'
)
I can also produce a nicely wrapped function that does essentially the same thing as follows:
from sympy.utilities.autowrap import autowrap
autowrap_dir = <some path>
derivs = sy.Matrix(
[[
d1expz,
d2expz
]]
)
dvraw = autowrap(
expr=derivs,
args=list(zlist),
backend='Cython',
tempdir=autowrap_dir,
verbose=True
)
But is there any way to use the ast module to specify functions to be wrapped with autowrap? It appears that autowrap, make_routine, and ufuncify cannot accept arbitrary code. The expressions they take can be either lists of straightforward sympy expressions, or lists of sympy.Eq expressions (in which case the wrapped function assigns the RHS of each equality to its LHS and returns each LHS as an output argument).
The problem is that I would like to be able to wrap more involved functions including such things as for loops and branching. The ast module provides the tools to write such functions. But as far as I can tell, autowrap and ast don't play with each other at all.
Any thoughts on how to accomplish this would be appreciated. Thanks.
Related
I was wondering if is there is a way to define a function that is a derivative of a function. I'm new to python so I don't no much, I tired looking up stuff that might be similar but nothing has worked so far. This is what I have for my code right now.
import sympy as sp
import math
x = sp.Symbol('x')
W = 15 #kN/m
E = 70 # Gpa
I = 52.9*10**(-6) #m**4
L = 3 #m
e = 0.01
xi = 1.8
y = 9
def f(x):
return ( ( y*3*(math.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*math.cos(math.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (math.pi**3)*(x**3) ) )/(3*L*(math.pi**3))**(1/2)
def derv(f,x):
return sp.diff(f)
print (derv(f,x))
Also, I don't understand whatx = sp.Symbol('x') does, so if someone could explain that, that would be awesome.
Any help is appreciated.
You are conflating two different things: python functions like f and math functions, which you can express with sympy like y = π * x/3. f is a python function that returns a sympy expression. sympy lets you stay in the world of symbolic math functions by defining variables like x = sp.Symbol('x') So calling f() produces a symbolic math function like:
You can use sympy to find the derivative of the symbolic function returned by f() but you need to define it with the sympy versions of the cos() function (and sp.pi if you want to keep it symbolic).
For example:
import sympy as sp
x = sp.Symbol('x')
W = 15 #kN/m
E = 70 # Gpa
I = 52.9*10**(-6) #m**4
L = 3 #m
e = 0.01
xi = 1.8
y = 9
def f(x):
return ( ( y*3*(sp.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*sp.cos(sp.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (sp.pi**3)*(x**3) ) )/(3*L*(sp.pi**3))**(1/2)
def derv(f,x):
return sp.diff(f(x)) # pass the result of f() which is a sympy function
derv(f,x)
You've programmed the function. it appears to be a simple function of two independent variables x and y.
Could be that x = sp.Symbol('x') is how SymPy defines the independent variable x. I don't know if you need one or another one for y.
You know enough about calculus to know that you need a derivative. Do you know how to differentiate a function of a single independent variable? It helps to know the answer before you start coding.
y*3*(math.pi**4)*E*I/(W*L) ) - ( 48*(L**3)*math.cos(math.pi*x/(2*L)) ) + ( 48*(L**3) ) + ( (math.pi**3)*(x**3) ) )/(3*L*(math.pi**3))**(1/2)
Looks simple.
There's only one term with y in it. The partial derivative w.r.t. y leaves you with 3*(math.pi**4)*E*I/(W*L) )
There's only one term with Cx**3 in it. That's easy to differentiate: 3C*x**2.
What's so hard? What's the problem?
In traditional programming, each function you write is translated to a series of commands that are then sent to the CPU and the result of the calculation is returned. Therefore, symbolic manipulation, like what we humans do with algebra and calculus, doesn't make any sense to the computer. Sympy gets around this by overriding Python's normal arithmetic operators, allowing you to do generate algebraic functions that can be manipulated similarly to how we humans do math. That's what sp.Symbols('x') is doing: providing you with a symbolic variable you can work with (you're also naming it in sympy).
If you want to evaluate your derivative, simply call evalf with the numerical value you want to assign to x.
I am trying to use the symbolic libraries of the python Symp. I am getting lots of errors. How to overcome this. every time I don't want to type sym.symobls for defining some thing new.
from sympy import *
from math import *
W1, W2, W3,z1, z2, b, a,g,l = symbols('W1 W2 W3 z1 z2 b a g l')
l = b**2(g/sqrt(a));
#Beam Functions
W1 = simplify(c1*cos(b*x) + c2*sin(b*x) + c3*cosh(b*x) + c4*sinh(b*x));
The expression l = b**2(g/sqrt(a)) isn't valid. You need e.g. a * between the 2 and the opening bracket. Also note that after the assignment, l isn't a symbol anymore, but a symbolic expression.
You can avoid declaring many variables by using sympify(). That function gets a string as input and creates symbolic variables on the fly. With sympify a lot of standard functions also get their correct symbolic version.
As mentioned in the comments, from sympy import * can be problematic, especially if you also work with other libraries. For convenience, a lot of examples in the docs do use import *, but only for short programs which don't use other libraries.
Here is a simple standalone example which assigns a symbolic expression to l and shows the internal representation (note that the expression is placed into quotes):
from sympy import sympify, srepr
l = sympify("b**2*(g/sqrt(a))")
print(srepr(l))
W1 = sympify("simplify(c1*cos(b*x) + c2*sin(b*x) + c3*cosh(b*x) + c4*sinh(b*x))")
print(srepr(W1))
Output:
Mul(Pow(Symbol('a'), Rational(-1, 2)), Pow(Symbol('b'), Integer(2)), Symbol('g'))
Add(Mul(Symbol('c1'), cos(Mul(Symbol('b'), Symbol('x')))), Mul(Symbol('c2'), sin(Mul(Symbol('b'), Symbol('x')))), Mul(Symbol('c3'), cosh(Mul(Symbol('b'), Symbol('x')))), Mul(Symbol('c4'), sinh(Mul(Symbol('b'), Symbol('x')))))
Often, routines will allow string input so you can just refer to variables created automatically through sympifying an expression with a string:
>>> from sympy import S
>>> S('x')
x
>>> _.subs('x',42)
42
>>> S('2*x').coeff('x')
2
If all you are doing is working with single letter symbols and SymPy functions (and no other libraries) you can (and this is how I always start my sessions):
>>> from sympy.abc import *
>>> from sympy import *
I put the second import there so I get S as the shortcut to sympify rather than as symbol S.
I am little confused by R syntax formula
I created the following python function with Rpy2:
objects.r('''
project_var <- function(grid,points) {
coordinates(points) = ~X + Y
gridded(grid) = ~X+Y
grid = idw(Z~1, points,grid)
grid <- as.data.frame(grid)
return(grid)
}
''')
Then I import it
project_var = robjects.globalenv['project_var']
Then I call it:
test = project_var(model,points_top)
And it works as expected!
I would like to'Z' to be set by an argument of my function, something like this:
project_var <- function(grid,points,feature_name) {
...
grid = idw(feature_name~1, points,grid)
My Problem :
idw(feature_name~1, points,grid)
I do not really understand this line and what is really feature name (because it is not a string nor known variable at this point, but the name of a column as a formula).
for info idw comes from gstat library... and I do not know R...
here is the doc:
idw.locations(formula, locations, data, newdata, nmax = Inf, nmin = 0,
omax = 0, maxdist = Inf, block, na.action = na.pass, idp = 2.0,
debug.level = 1)
https://cran.r-project.org/web/packages/gstat/gstat.pdf
So what should I put for feature_name in the python side ? or how to build it in R so it would transform the string feature_name into something that would work ?
Any help would be appreciate.
Thank you for reading so far.
I do not really understand this line and what is really feature name (because it is not a string nor known variable at this point, but the name of a column).
R differs from Python as expressions in a function call (here idw(Z~1, points,grid)) will only be evaluated within the function, and the unevaluated expression itself is available to the code in the body of the function.
In addition to that, Z~1 is itself a special thing: it is an R formula. You could write fml <- Z ~ 1 in R and the object fml will be a "formula". The constructor for the formula is somewhat hidden as <something> ~ <something> is considered a language construct in R, but in fact you have something like build_formula(<left_side_expression>, <right_side_expression>). You can try in R fml <- get("~")(Z, 1) and see that this is exactly that happening.
okay, just need to use as.formula to convert a string to a formula :-)
idw(as.formula(feature_name), points,grid)
I need to know how transfer string input into executable function.
For example - user write string 'x*Sin(x**2)' and then programm takes it as function, can calculate a value for given x, can plot derivation of this function etc. I've read that there is module called scitools.stringfunction, but as far as I know this module is not callable in python-3.
Any ideas how to make it?
For Python 2.X
f = lambda x: input() # the user inputs: x**2 + 1
y = f(3)
print y # outputs: 10
For Python 3.X
f = lambda x: eval(input())
y = f(5)
print y
Just make sure to import the required mathematical functions. And make sure the user inputs a valid Python arithmetic expression.
using sympy you could do something like this:
from sympy import var
from sympy import sympify
x = var('x') # the possible variable names must be known beforehand...
user_input = 'x * sin(x**2)'
expr = sympify(user_input)
res = expr.subs(x, 3.14)
print(res) # -1.322...
if you want to turn the user input into a function you can call you could to this:
from sympy.utilities.lambdify import lambdify
f = lambdify(x, expr)
# f(3.14) -> -1.322...
sympy can do sybolic calculations (including derivatives); if you want to make plots i strongly suggest matplotlib.
the advantage of using a math library opposed to eval is that you do not need to sanitize the user input (against malicious code).
(deleted this thanks to a comment from ejm).
I have a large (>2000 equations) system of ODE's that I want to solve with python scipy's odeint.
I have three problems that I want to solve (maybe I will have to ask 3 different questions?).
For simplicity, I will explain them here with a toy model, but please keep in mind that my system is large.
Suppose I have the following system of ODE's:
dS/dt = -beta*S
dI/dt = beta*S - gamma*I
dR/dt = gamma*I
with beta = cpI
where c, p and gamma are parameters that I want to pass to odeint.
odeint is expecting a file like this:
def myODEs(y, t, params):
c,p, gamma = params
beta = c*p
S = y[0]
I = y[1]
R = y[2]
dydt = [-beta*S*I,
beta*S*I - gamma*I,
- gamma*I]
return dydt
that then can be passed to odeint like this:
myoutput = odeint(myODEs, [1000, 1, 0], np.linspace(0, 100, 50), args = ([c,p,gamma], ))
I generated a text file in Mathematica, say myOdes.txt, where each line of the file corresponds to the RHS of my system of ODE's, so it looks like this
#myODEs.txt
-beta*S*I
beta*S*I - gamma*I
- gamma*I
My text file looks similar to what odeint is expecting, but I am not quite there yet.
I have three main problems:
How can I pass my text file so that odeint understands that this is the RHS of my system?
How can I define my variables in a smart way, that is, in a systematic way? Since there are >2000 of them, I cannot manually define them. Ideally I would define them in a separate file and read that as well.
How can I pass the parameters (there are a lot of them) as a text file too?
I read this question that is close to my problems 1 and 2 and tried to copy it (I directly put values for the parameters so that I didn't have to worry about my point 3 above):
systemOfEquations = []
with open("myODEs.txt", "r") as fp :
for line in fp :
systemOfEquations.append(line)
def dX_dt(X, t):
vals = dict(S=X[0], I=X[1], R=X[2], t=t)
return [eq for eq in systemOfEquations]
out = odeint(dX_dt, [1000,1,0], np.linspace(0, 1, 5))
but I got the error:
odepack.error: Result from function call is not a proper array of floats.
ValueError: could not convert string to float: -((12*0.01/1000)*I*S),
Edit: I modified my code to:
systemOfEquations = []
with open("SIREquationsMathematica2.txt", "r") as fp :
for line in fp :
pattern = regex.compile(r'.+?\s+=\s+(.+?)$')
expressionString = regex.search(pattern, line)
systemOfEquations.append( sympy.sympify( expressionString) )
def dX_dt(X, t):
vals = dict(S=X[0], I=X[1], R=X[2], t=t)
return [eq for eq in systemOfEquations]
out = odeint(dX_dt, [1000,1,0], np.linspace(0, 100, 50), )
and this works (I don't quite get what the first two lines of the for loop are doing). However, I would like to do the process of defining the variables more automatic, and I still don't know how to use this solution and pass parameters in a text file. Along the same lines, how can I define parameters (that will depend on the variables) inside the dX_dt function?
Thanks in advance!
This isn't a full answer, but rather some observations/questions, but they are too long for comments.
dX_dt is called many times by odeint with a 1d array y and tuple t. You provide t via the args parameter. y is generated by odeint and varies with each step. dX_dt should be streamlined so it runs fast.
Usually an expresion like [eq for eq in systemOfEquations] can be simplified to systemOfEquations. [eq for eq...] doesn't do anything meaningful. But there may be something about systemOfEquations that requires it.
I'd suggest you print out systemOfEquations (for this small 3 line case), both for your benefit and ours. You are using sympy to translated the strings from the file into equations. We need to see what it produces.
Note that myODEs is a function, not a file. It may be imported from a module, which of course is a file.
The point to vals = dict(S=X[0], I=X[1], R=X[2], t=t) is to produce a dictionary that the sympy expressions can work with. A more direct (and I think faster) dX_dt function would look like:
def myODEs(y, t, params):
c,p, gamma = params
beta = c*p
dydt = [-beta*y[0]*y[1],
beta*y[0]*y[1] - gamma*y[1],
- gamma*y[1]]
return dydt
I suspect that the dX_dt that runs sympy generated expressions will be a lot slower than a 'hardcoded' one like this.
I'm going add sympy tag, because, as written, that is the key to translating your text file into a function that odeint can use.
I'd be inclined to put the equation variability in the t parameters, rather a list of sympy expressions.
That is replace:
dydt = [-beta*y[0]*y[1],
beta*y[0]*y[1] - gamma*y[1],
- gamma*y[1]]
with something like
arg12=np.array([-beta, beta, 0])
arg1 = np.array([0, -gamma, -gamma])
arg0 = np.array([0,0,0])
dydt = arg12*y[0]*y[1] + arg1*y[1] + arg0*y[0]
Once this is right, then the argxx definitions can be move outside dX_dt, and passed via args. Now dX_dt is just a simple, and fast, calculation.
This whole sympy approach may work fine, but I'm afraid that in practice it will be slow. But someone with more sympy experience may have other insights.