Cython: Error in math expression (works fine in Python) - python

I am trying to cythonize my Python code to improve performance.
I didn't make any change to my original python code, I just run the setup.py and get the .c files.
Now I have this issue: when I perform a basic math operation in Python, it works fine, while in Cython it doesn't work as expected.
The code snippet is the following, here I try to calculate the y-coordinate of a given x on a circle of center [3,0] and radius 1:
import math
import numpy as np
def calculateY(x, center, radius):
a = -2*center[0]
b = -2*center[1]
c = center[0]**2 + center[1]**2 - radius**2
tmp = (b)**2 - 4*(c) - 4*(a)*x - 4*(x**2)
return 1/2*(-b + math.sqrt(tmp)) ###### I only want the y>0
C1, R1 = [3,0], 1
Pstart = np.array([2.13766028, 0.50633014])
print(calculateY(Pstart[0], C1, R1))
If I run this in Python, I get y = 0.5063301366799338 which is the right result.
If I cythonize the code and then run it by import my_code, I get y = 0.0 which tells me that the y is empty (actually the code doesn't even print anything, I got this from another function where I print the y)
Am I doing something wrong whit the syntax?
Thanks in advance.
Edit:
here's my setup.py:
import distutils.core
import Cython.Build
distutils.core.setup(
ext_modules = Cython.Build.cythonize("my_code.pyx"))
I run the cython version with:
import my_code
The output is empy.
EDIT 2:
Thanks to joni, I changed the division in my original code and now it works!

I suspect that cdivision=True is enabled inside your setup.py. In C, the division of two integer literals cuts off all decimal places. Consequently, the 1/2 inside your return statement equals 0.0. Instead, simply use floating-point literals, i.e.
# my_code.pyx
def calculateY(x, center, radius):
a = -2*center[0]
b = -2*center[1]
c = center[0]**2 + center[1]**2 - radius**2
tmp = (b)**2 - 4*(c) - 4*(a)*x - 4*(x**2)
return 1.0/2.0*(-b + math.sqrt(tmp)) # <--- Note the 1.0/2.0
Then, after installing the Cython module by python3 setup.py install, you can use it from Python:
# mwe.py
from my_code import calculateY
import numpy as np
C1, R1 = [3,0], 1
Pstart = np.array([2.13766028, 0.50633014])
print(calculateY(Pstart[0], C1, R1)) # Output: 0.5063301366799338
Note that a Cython .pyx file only contains the function and class definitions. You have to call your cythonized module's functions from Python.

Related

How to avoid sym.symbols all the time

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.

How do I run a function from my .py file in the command?

I have a .py file with a function that calculates the gradient of a function at a point and returns the value of that gradient at the point. The function takes a np.array([2,]) as input and outputs another np.array([2,]). I am confused as to how I can call the function from the cmd line and run the function with a specified input.
Here is a code snippet:
import numpy as np
def grad(x):
x_1 = x[0]
x_2 = x[1]
df_dx_1 = 6*x
df_dx_2 = 8*x_2
df_dx = np.array([df_dx_1, df_dx_2])
return np.transpose(df_dx)
I would really appreciate your help!
EDIT: This question differs from the popular command line thread because I have a specific issue of not being able to recognise the numpy input
First change script to (Here it uses if __name__='__main__' to check if it is running from script, then import sys and pass first argument using sys.argv[0] to the function):
import numpy as np
def grad(x):
x_1 = x[0]
x_2 = x[1]
df_dx_1 = 6*x
df_dx_2 = 8*x_2
df_dx = np.array([df_dx_1, df_dx_2])
return np.transpose(df_dx)
if __name__ == '__main__':
import sys
grad(sys.argv[1])
And call it like:
python "YOURSCRIPTPATH.py" argument_1
You can have more than one command line argument:
import sys
import numpy as np
def grad(x):
# your grad function here
arr = np.array([int(sys.argv[1]), int(sys.argv[2])])
print(grad(arr))
Usage:
python gradient.py 10 5
You could just something like this in the command line:
$ python -c 'from YOURFILE import grad; print(grad(your_argument))'

Error evaluating a derivative on Python (with .subs, .evalf and .lambdify)

I am trying to separately compute the elements of a Taylor expansion and did not obtain the results I was supposed to. The function to approximate is x**321, and the first three elements of that Taylor expansion around x=1 should be:
1 + 321(x-1) + 51360(x-1)**2
For some reason, the code associated with the second term is not working.
See my code below.
import sympy as sy
import numpy as np
import math
import matplotlib.pyplot as plt
x = sy.Symbol('x')
f = x**321
x0 = 1
func0 = f.diff(x,0).subs(x,x0)*((x-x0)**0/factorial(0))
print(func0)
func1 = f.diff(x,1).subs(x,x0)*((x-x0)**1/factorial(1))
print(func1)
func2 = f.diff(x,2).subs(x,x0)*((x-x0)**2/factorial(2))
print(func2)
The prints I obtain running this code are
1
321x - 321
51360*(x - 1)**2
I also used .evalf and .lambdify but the results were the same. I can't understand where the error is coming from.
f = x**321
x = sy.Symbol('x')
def fprime(x):
return sy.diff(f,x)
DerivativeOfF = sy.lambdify((x),fprime(x),"numpy")
print(DerivativeOfF(1)*((x-x0)**1/factorial(1)))
321*x - 321
I'm obviously just starting with the language, so thank you for your help.
I found a beginners guide how to Taylor expand in python. Check it out perhaps all your questions are answered there:
http://firsttimeprogrammer.blogspot.com/2015/03/taylor-series-with-python-and-sympy.html
I tested your code and it works fine. like Bazingaa pointed out in the comments it is just an issue how python saves functions internally. One could argument that for a computer it takes less RAM to save 321*x - 321 instead of 321*(x - 1)**1.
In your first output line it also gives you 1 instead of (x - 1)**0

def function gives invalid syntax

As far as I checked, the indentation is correct, no brackets are missing and I have only imported packages in the previous lines But I still get invalid syntax error.
#!/usr/bin/python
import bpy
import mathutils
import numpy as np
from math import radians
from mathutils import Vector
from math import radians
from mathutils import Matrix
from bpy import context
def transform_mesh('parent', 'obj_to_be_transformed', (translate_x, translate_y, translate_z), (rot_x,rot_y,rot_z)):
obj= bpy.data.objects[parent]
obj1= bpy.data.objects[obj_to_be_transformed]
initial_mat = obj1.matrix_world
...some code
(x,y,z) = (translate_x, translate_y, translate_z)
orig_loc_mat = Matrix.Translation(orig_loc+ mathutils.Vector((x,y,z)))
...some more code
eul = mathutils.Euler((radians(rot_x), radians(rot_y), radians(rot_z)), 'XYZ')
rot_mat = eul.to_matrix().to_4x4()
obj.matrix_world = orig_loc_mat * rot_mat * orig_rot_mat * orig_scale_mat
bpy.context.scene.update()
return [initial_loc,initial_rot,initial_scale,loc,rot,scale]
transform_result= transform_mesh('Armature','Coil',(5,0,0),(0,0,1))
print (transform_result)
And error is:
Error: File "D:\users\gayathri\Gayathri\Synthetic_data_generation\Final\HMI_Depth_coilA_final_final.blend\Untitled", line 18
def transform_mesh('parent', 'obj_to_be_transformed', (translate_x, translate_y, translate_z), (rot_x,rot_y,rot_z)):
^
SyntaxError: invalid syntax
location: <unknown location>:-1
def transform_mesh('parent', 'obj_to_be_transformed',
should be
def transform_mesh(parent, obj_to_be_transformed,
surely?
1- Remove strings from arguments
2- Remove tuples from arguments and attribute them in the function (It might be useful to add some checks)
So, here you are:
def transform_mesh(parent, obj_to_be_transformed, translate, rot):
translate_x, translate_y, translate_z= translate
rot_x,rot_y,rot_z = rot
# etc
transform_result= transform_mesh('Armature','Coil',(5,0,0),(0,0,1))
print (transform_result)
Tuple parameters are not supported in Python3, but you can pass it as a variable and unpack it after defining the function.
def transform_mesh(translate_xyz):
translate_x, translate_y, translate_z = translate_xyz
You need to provide variables as arguments to the function.
try something like:
def transform_mesh(parent, obj_to_be_transformed, t1, t2):
Although in the code you have shared, you are always using t1 and t2 as tuples. But in case you want to use x, y and z separately, you can do it by referencing the index:
x = t1[0]
y = t1[1]
In this line the function parameter are passed in incorrect way,
def transform_mesh('parent', 'obj_to_be_transformed', (translate_x, translate_y, translate_z), (rot_x,rot_y,rot_z)):
The Correct syntax would be:
def transform_mesh(parent, obj_to_be_transformed, *translate_xyz, *rot_xyz): #*translate_xyz and *rot-xyz are tuple parameter

Python function as an argument for a R function using rpy2

I wrote a function in Python 2.7:
# Python #
def function_py(par):
#something happens
return(value)
and I want to use this function as an argument for another function in R. More precisely, I want to perform to compute the Sobol' indices using the following function:
# R #
library('sensitivity')
sobol(function_py_translated, X1,X2)
where function_py_translated would b the R equivalent of function_py.
I'm trying to use the rpy2 module, and for a simple function, I could make a working case:
import rpy2.rinterface as ri
import rpy2.robjects.numpy2ri
sensitivity = importr('sensitivity')
radd = ri.baseenv.get('+')
def costfun(X):
a = X[0]
b = X[1]
return(radd(a,b))
costfunr=ri.rternalize(costfun)
X1 = robjects.r('data.frame(matrix(rnorm(2*1000), nrow = 1000))')
X2 = robjects.r('data.frame(matrix(rnorm(2*1000), nrow = 1000))')
sobinde = sensitivity.sobol(costfunr,X1,X2)
print(sobinde.__getitem__(11))
The main problem is that I had to redefine the "+". Is there a way to work around this ? Being able to pass an arbitrary function without prior transformation ? The function I want to analyze is much more complicated.
Thank you very much for your time

Categories

Resources