Hi!
I have problems with cython dealing with following example case (python 2.6.5,
cython 0.13):
2 cdef classes, Pdf and GaussPdf; GaussPdf inherits Pdf. Both are written in
pure python file pdfs.py and use augmentation pdfs.pxd for cythoning.
(attached) Both have just cpdef methods, GaussPdf overrides 4 of 5 Pdf's
methods. When tested as Python code, everything is okay, but when compiled
using cython, I get following error:
>>> from pdfs import Pdf
>>> p = Pdf()
>>> p.shape()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "pdfs.py", line 15, in pybayes.pdfs.Pdf.shape (pybayes/pdfs.c:975)
TypeError: Cannot convert pybayes.pdfs.Pdf to pybayes.pdfs.GaussPdf
It should have thrown NotImplementedError, not TypeError!
I think the problem is in the generated C code. First couple of lines from
python wrapper around Pdf.mean() C function:
static PyObject *__pyx_pf_7pybayes_4pdfs_3Pdf_shape(PyObject *__pyx_v_self,
CYTHON_UNUSED PyObject *unused) {
PyObject *__pyx_r = NULL;
PyObject *__pyx_t_1 = NULL;
__Pyx_RefNannySetupContext("shape");
__Pyx_XDECREF(__pyx_r);
if (!(likely(((__pyx_v_self) == Py_None) ||
likely(__Pyx_TypeTest(__pyx_v_self, __pyx_ptype_7pybayes_4pdfs_GaussPdf)))))
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 15; __pyx_clineno = __LINE__; goto
__pyx_L1_error;}
The last line is #975. Notice the __Pyx_TypeTest(..self, ..GaussPdf) - I would
expect it would read __Pyx_TypeTest(..self, .Pdf) instead!
Also, vtabstruct for Pdf seems strange (it contains GaussPdf methods), but
that may be correct inheritance magic.
Is this really a bug in Cython, or am I doing something completely wrong?
Thanks,
Matěj Laitl# Copyright (c) 2010 Matej Laitl <[email protected]>
# Distributed under the terms of the GNU General Public License v2 or any
# later version of the license, at your option.
"""Probability density functions"""
from numpy import any, array, asarray, diag, dot
from numpy.linalg import cholesky
from numpy.random import normal
class Pdf(object):
"""Base class for all (TODO: unconditional?) multivariate pdfs"""
def shape(self):
"""Return shape (in numpy's sense) of the random variable (and mean) as a tuple of ints"""
raise NotImplementedError("Derived classes must implement this function")
def mean(self):
"""Return mean value (a vector) of the pdf"""
raise NotImplementedError("Derived classes must implement this function")
def variance(self):
"""Return variance (diagonal elements of covariance)"""
raise NotImplementedError("Derived classes must implement this function")
def eval_log(self, x):
"""Returning logarithm of likelihood function in point x"""
raise NotImplementedError("Derived classes must implement this function")
def sample(self):
"""Return one random sample from this density"""
raise NotImplementedError("Derived classes must implement this function")
class GaussPdf(Pdf):
"""Unconditional Gaussian (normal)probability density function
.. math: f(x|\mu,b) \propto \exp(-(x-\mu)'R^{-1}(x-\mu))
"""
def __init__(self, mean=array([1]), covariance=array([[1]])):
"""Initialise Gaussian pdf with mean value mu and variance R
mu % mean values
R % variance
"""
mean = asarray(mean)
covariance = asarray(covariance)
if mean.ndim != 1:
raise ValueError("mean must be one-dimensional (" + str(mean.ndim) + " dimensions encountered)")
n = mean.shape[0]
if covariance.shape != (n, n):
raise ValueError("covariance must have shape (" + str(n) + ", " + str(n) + "), " +
str(covariance.shape) + " given")
if any(covariance != covariance.T):
raise ValueError("covariance must be symmetric (complex covariance not supported)")
# TODO: covariance must be positive definite
self.mu = mean
self.R = covariance
def shape(self):
return (self.mu.shape[0],) # this workarounds cython np.ndarray.shape problem
def mean(self):
return self.mu
def variance(self):
return diag(self.R)
# def eval_log(self, x): # TODO!
# return -log(2*self.b)-abs(x-self.mu)/self.b
def sample(self):
z = normal(size=self.mu.shape[0]);
# NumPy's chol(R) is equivalent to Matlab's chol(R).transpose()
return self.mu + dot(cholesky(self.R), z);
# Copyright (c) 2010 Matej Laitl <[email protected]>
# Distributed under the terms of the GNU General Public License v2 or any
# later version of the license, at your option.
"""Cython augmentation file for pdfs.py"""
cimport cython
from numpy cimport ndarray
cdef class Pdf:
cpdef tuple shape(self)
cpdef ndarray mean(self)
cpdef ndarray variance(self)
cpdef object eval_log(self, ndarray x) # TODO: dtype of all arrays
cpdef ndarray sample(self)
cdef class GaussPdf(Pdf):
cdef public ndarray mu # TODO: readonly
cdef public ndarray R # TODO: readonly
cpdef tuple shape(self)
cpdef ndarray mean(self)
cpdef ndarray variance(self)
#cpdef eval_log(self, x): # TODO
@cython.locals(z = ndarray)
cpdef ndarray sample(self)
_______________________________________________
Cython-dev mailing list
[email protected]
http://codespeak.net/mailman/listinfo/cython-dev