Can't access class #property from other #property in Cython - cython

I'm learning Cython and ran into the following weird bug
import cython
cdef double MILES_PER_KILOMETER = 0.621371
cdef class Distance:
cdef double distance, miles, meters, km
def __cinit__(self, double distance) -> None:
self.distance = distance
#property
def miles(self):
print(self.km)
return self.km * MILES_PER_KILOMETER
#property
def meters(self):
print(self.km)
return self.km * 1000.0
#property
def km(self):
return self.distance
Running this I get
In [2]: from distance_compiled import Distance
In [3]: Distance(42)
Out[3]: <distance_compiled.Distance at 0x7f7a132bc5a0>
In [4]: Distance(42).meters
0.0
Out[4]: 0.0
In [5]: Distance(42).km
Out[5]: 42.0
In [6]: Distance(42).miles
0.0
Out[6]: 0.0
Why is self.km set to 0 when I try to read it from miles and meters?

cdef double distance, miles, meters, km
You have two definitions of miles, meters and km - the properties and the cdef variables with the same name.
Cython looks to be reading from the cdef variables, which will be automatically zero initialized.

Related

Cython: Workaround scipy.optimize.cython_optimize.brentq argument ctype to work with class methods ctype

I'm trying to use the root finder scipy.optimize.cython_optimize.brentq inside a class, but the first argument of this function accepts only the type ctypedef double (*callback_type)(double, void*) and my class method is the type of ctypedef double (*w_func)(test,double, void*).
How could I get this working?
The following code is an exemple of the problem.
%%cython
from scipy.optimize.cython_optimize cimport brentq
ctypedef double (*f_func)(test,double, double)
ctypedef double (*w_func)(test,double, void*)
ctypedef double (*callback_type)(double, void*)
ctypedef struct test_params:
double y0
double x1
f_func f
w_func w
cdef class test():
def __init__(self):
cdef test_params myargs
myargs.y0 = 1.0
myargs.x1 = 0.7
myargs.f = self.sum2
myargs.w = self.w
print(self.brentqWrapper(myargs, -10, 10, 1e-3, 1e-3, 10))
cdef double sum2(self, double x1,double y1):
return x1+y1
cdef double w(self, double y1, void *args):
cdef test_params *myargs = <test_params *> args
return y1 - myargs.y0 - myargs.f(self,myargs.x1,y1)
# Cython wrapper function
cdef double brentqWrapper(self,test_params args, double xa, double xb,
double xtol, double rtol, int mitr):
return brentq(args.w, xa, xb, <test_params *> &args, xtol, rtol, mitr, NULL)
test()
ISTM it's easiest and most clean to restructure your code to have a module-level function which receives the class instance in its last argument.

Integrating a function with a very large parameter values in Python

I have a function defined as below
\begin{equation}
f(x) = e^{-k1/x}x^{-2}(k1/x+56)^{81}
\end{equation}
Now I want to find integrate the function from 0 to infinite.
\begin{equation}
S = \int^{\inf}_{0} f(x) dx
\end{equation}
And then I want to find the cumulative function defined as below
\begin{equation}
CDF(p) = \int^{p}_{0} \frac{f(x)}{S} dx
\end{equation}
To do so, I wrote a program in Python.
from matplotlib import pyplot as plt
from scipy.integrate import quad
from math import pi, exp
import numpy as np
def func(x, k1, n):
w = -1.8*n+15 # scale the function down.
return (10**w)*exp(-k1/x)*x**(-2)*(k1/x+56)**n
def S(k1, n):
return quad(func, 0, 1e+28, args=(k1, n))[0] + quad(func, 1e+28, 1e+33, args=(k1, n))[0]
def CDF(x, k1, n):
return quad(func, 0, x, args=(k1, n))[0]/S(k1, n)
k1 = 7.7e+27 # When it's <3, CDF does not generate error.
n = 81
print(S(k1, n))
print(CDF(1.1e+27, k1, n))
But unfortunately, the CDF(1.1e+27) throws the error "results out of range".
How could I obtain CDF(1.1e+27)?

Cython return tuple within cdef?

Hi I am trying to convert a python code into cython in order to speed up its calculation. I am trying to return multiple arrays within the cython code from a cdef to cpdef. Based on classical C, I could either use a pointer or a tuple. I decide to use tuple because the size varies. I know the following code doesn't work, any help? Thank you!
import numpy as np
cimport numpy as np
cdef tuple funA(double[:] X, double[:] Y):
cdef int nX, nY, i
nX = len(X)
nY = len(Y)
for i in range(nX):
X[i] = X[i]*X[i]
for i in range(nY):
Y[i] = Y[i]*Y[i]
return X,Y
cpdef Run(double[:] X, double[:] Y)
cdef Tuple1, Tuple2 = funA(X,Y)
# Do some calculation with Tuple1 and Tuple2
# Example
cdef int i, nTuple1, nTuple2
nTuple1 = len(Tuple1)
for i in range(nTuple1):
Tuple1[i] = Tuple1[i]**2
nTuple2 = len(Tuple2)
for i in range(nTuple2):
Tuple2[i] = Tuple2[i]/2
return Tuple1, Tuple2
You've got a few indentation errors and missing colons. But your real issue is:
cdef Tuple1, Tuple2 = funA(X,Y)
Remove the cdef and it's fine. It doesn't look like cdef and tuple unpacking quite mix, and since you're treating them as Python objects it should be OK.
However, note that you don't really need to return anything from funA since you modify X and Y them in place there.

Converting from python list to char** and back makes all elements the same in Cython

I have a Cython file called test.pyx with the following code:
from libc.stdlib cimport malloc, free
def test():
x = ["a1", "a2", "a3"]
cdef char** y = <char**> malloc(len(x) * sizeof(char*))
for i in range(len(x)):
item_uni = x[i].encode("UTF-8")
y[i] = item_uni
z = []
for i in range(len(x)):
item = y[i]
z.append(item)
print(z)
The function should seemingly print ["a1", "a2", "a3"]. However, it is giving me three instances of "a3"instead:
>>> test()
[b'a3', b'a3', b'a3']
Why is this happening?
It is because temporary objects are involved. item_uni probably has always the same memory address for its contents, y[i] = item_uni will then point to the same address for all items, and since the last string is "a3", there will be three times "a3".
strdup should fix it (free is needed for those then)
from libc.string cimport strdup
...
y[i] = strdup(item_uni)

Extending Python by compiling C code in Cython

I'm having trouble compiling a particular source file in C from an R package (fastclime) so that I can use it as a Python module. This is my code to extract the R package online:
from __future__ import division
import os
import sys
import glob
if not os.path.exists('fastlp.h'):
! wget http://cran.r-project.org/src/contrib/fastclime_1.2.4.tar.gz
! tar -xzvf fastclime_1.2.4.tar.gz
Within the R package (in the [src] folder) is the source file [parametric.c]. I'd like to compile this in Python as a module with numpy inputs. Since I can't immediately test the the functionality of this code, I first tried to compile the [fastlp.c] source file. With fastlp, I can create a toy example to test if I successfully compiled a version of fastlp in Python. Then I can probably extend the steps to compile [parametric.c]
Here is my attempt:
1) First I create the header file since it does not exist
%%file fastclime/src/fastlp.h
int ratio_test0(double *dy, int *idy,int ndy, double *y, double *ybar, double mu);
void fastlp(double *obj, double *mat, double *rhs, int *m0 , int *n0, double *opt, int *status, double *lam)
void solver20(int m,int n,int nz,int *ia, int *ka, double *a,double *b, double *c)
int ratio_test0(double *dy, int *idy,int ndy,double *y, double *ybar, double mu)
2) Next, I write the files for wrapping the C code in Cython:
%%file fastlp.pxd
cdef extern from "fastclime/src/fastlp.h":
void fastlp(double *obj, double *mat, double *rhs, int *m0 , int *n0, double *opt, int *status, double *lam)
%%file fastlp.pyx
cimport fastlp
def fastlp(double *obj, double *mat, double *rhs, int *m0 , int *n0, double *opt, int *status, double *lam):
fastlp.fastlp(*obj, *mat, *rhs, *m0, *n0, *opt, *status, *lam)
3) Next I use the distutils build system to compile.
%%file setup.py
from distutils.core import setup, Extension
from Cython.Build import cythonize
ext = Extension("fastlp",
sources=["fastlp.pyx", "fastclime/src/fastlp.c"])
setup(name="fastlp",
ext_modules = cythonize([ext]))
4) Finally I compile
! python setup.py build_ext -i
#4 is where things fail big time. Not sure how to resolve it in steps 1-3.
5) If all is successful (which it's not), I should be able to run this code (taken from the vignette)
import fastlp as flp
import numpy as np
A=np.array([-1.0,-1,0,1,-2,1]).reshape((3,2))
b=np.array([-1.0,-2,1])
c=np.array([-2.0,3])
flp.fastlp(c,A,b)
This should output the vector [2., 1.].
I'm not very experienced with Cython or Python for that matter, but getting this functionality would help out a lot with future projects. Could someone please let me know the proper way of taking a source file in C and getting through the steps in interfacing with numpy to create a Python module?
Thanks!
UPDATE:
I'm trying to follow the Numpy+Cython example on this site: https://scipy-lectures.github.io/advanced/interfacing_with_c/interfacing_with_c.html
I've since updated my code
%%cython
# import both numpy and the Cython declarations for numpy
import numpy as np
cimport numpy as np
# if you want to use the Numpy-C-API from Cython
# (not strictly necessary for this example)
np.import_array()
# cdefine the signature of our c function
cdef extern from "/home/bitnami/STA663-pura-project/fastclime/src/fastlp.h":
void fastlp(double *obj, double *mat, double *rhs, int *m0 , int *n0, double *opt, int *status, double *lam)
# create the wrapper code, with numpy type annotations
def fastlp_func(np.ndarray[double, ndim=1, mode="c"] obj not None,
np.ndarray[double, ndim=2, mode="c"] mat not None,
np.ndarray[double, ndim=1, mode="c"] rhs not None,
double lam):
cdef int m1 = mat.shape[0]
cdef int m2 = mat.shape[1]
cdef np.ndarray[double, ndim=1, mode='c'] z = np.zeros(obj.shape[0])
cdef double [:] zp = z #convert from Python to C object
cdef int stat = 0
cdef double lambd = 0
fastlp(<double*> np.PyArray_DATA(obj),
<double*> np.PyArray_DATA(mat.T),
<double*> np.PyArray_DATA(rhs),
&m1,
&m2,
&zp[0],
&stat,
&lambd
)
However, I get the following error (which I don't understand at all):
---------------------------------------------------------------------------
ImportError Traceback (most recent call last)
<ipython-input-85-29981393af41> in <module>()
----> 1 get_ipython().run_cell_magic(u'cython', u'', u'# import both numpy and the Cython declarations for numpy\nimport numpy as np\ncimport numpy as np\n\n# if you want to use the Numpy-C-API from Cython\n# (not strictly necessary for this example)\nnp.import_array()\n\n# cdefine the signature of our c function\ncdef extern from "/home/bitnami/STA663-pura-project/fastclime/src/fastlp.h":\n void fastlp(double *obj, double *mat, double *rhs, int *m0 , int *n0, double *opt, int *status, double *lam)\n \n# create the wrapper code, with numpy type annotations\ndef fastlp_func(np.ndarray[double, ndim=1, mode="c"] obj not None,\n np.ndarray[double, ndim=2, mode="c"] mat not None,\n np.ndarray[double, ndim=1, mode="c"] rhs not None,\n double lam):\n cdef int m1 = mat.shape[0]\n cdef int m2 = mat.shape[1]\n cdef np.ndarray[double, ndim=1, mode=\'c\'] z = np.zeros(obj.shape[0])\n cdef double [:] zp = z #convert from Python to C object\n cdef int stat = 0\n cdef double lambd = 0\n fastlp(<double*> np.PyArray_DATA(obj),\n <double*> np.PyArray_DATA(mat.T),\n <double*> np.PyArray_DATA(rhs),\n &m1,\n &m2,\n &zp[0], \n &stat, \n &lambd \n )')
/home/bitnami/anaconda/lib/python2.7/site-packages/IPython/core/interactiveshell.pyc in run_cell_magic(self, magic_name, line, cell)
2160 magic_arg_s = self.var_expand(line, stack_depth)
2161 with self.builtin_trap:
-> 2162 result = fn(magic_arg_s, cell)
2163 return result
2164
/home/bitnami/anaconda/lib/python2.7/site-packages/IPython/extensions/cythonmagic.pyc in cython(self, line, cell)
/home/bitnami/anaconda/lib/python2.7/site-packages/IPython/core/magic.pyc in <lambda>(f, *a, **k)
191 # but it's overkill for just that one bit of state.
192 def magic_deco(arg):
--> 193 call = lambda f, *a, **k: f(*a, **k)
194
195 if callable(arg):
/home/bitnami/anaconda/lib/python2.7/site-packages/IPython/extensions/cythonmagic.pyc in cython(self, line, cell)
269 self._code_cache[key] = module_name
270
--> 271 module = imp.load_dynamic(module_name, module_path)
272 self._import_all(module)
273
ImportError: /home/bitnami/.cache/ipython/cython/_cython_magic_16feaf686ed172960f59fa6333ae74b5.so: undefined symbol: fastlp