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

Reply via email to