[Cython] Non-deterministic behavoiur?

Dave Hirschfeld dave.hirschfeld at gmail.com
Wed Feb 27 14:17:40 CET 2013


Using the following test code:

import numpy as np
from lapack import dgelsy
from numpy.linalg import lstsq

A = np.array([[ 0.12, -8.19,  7.69, -2.26, -4.71],
       [-6.91,  2.22, -5.12, -9.08,  9.96],
       [-3.33, -8.94, -6.72, -4.4 , -9.98],
       [ 3.97,  3.33, -2.74, -7.92, -3.2 ]])
#
b = np.array([[ 7.3 ,  0.47, -6.28],
       [ 1.33,  6.58, -3.42],
       [ 2.68, -1.71,  3.46],
       [-9.62, -0.79,  0.41]])
#
print '#################'
print '# ACTUAL RESULT #'
print '#################'
print lstsq(A, b)[0]
print
print '#################'
print '# DGELSY RESULT #'
print '#################'
print dgelsy(A, b)

I get:

#################
# ACTUAL RESULT #
#################
[[-0.6858 -0.2431  0.0642]
 [-0.795  -0.0836  0.2118]
 [ 0.3767  0.1208 -0.6541]
 [ 0.2885 -0.2415  0.4176]
 [ 0.2916  0.3525 -0.3015]]

#################
# DGELSY RESULT #
#################
[[-0.6858 -0.2431  0.0642]
 [-0.795  -0.0836  0.2118]
 [ 0.3767  0.1208 -0.6541]
 [ 0.2885 -0.2415  0.4176]
 [ 0.2916  0.3525 -0.3015]]


All well and good, however if I type the `tmp` variable as a memview in the 
following code

cdef double[:] res
cdef double[:,:] tmp
tmp = np.zeros([ldb, nrhs], order='F', dtype=np.float64)
tmp[:b.shape[0]] = b
res = np.ravel(tmp, order='F')

the result changes?!?

#################
# DGELSY RESULT #
#################
[[-0.7137 -0.2429  0.0876]
 [-0.2882 -0.0884 -0.2117]
 [-0.4282  0.1284  0.0185]
 [ 0.9564 -0.2478 -0.1404]
 [ 0.3625  0.3519 -0.3607]]


Remove the `cdef double[:,:] tmp` and I'm back to the correct result.
Does this make any sense?

To try and figure out what was going on I put in a couple of debugging print 
statements:

print 'res = ', repr(np.asarray(res))
print 'res.flags = {{{flags}}}'.format(flags=np.asarray(res).flags)


Only changing these lines resulted in the same incorrect result

#################
# DGELSY RESULT #
#################
res =  array([ 7.3 ,  1.33,  2.68, -9.62,  0.,
               0.47,  6.58, -1.71, -0.79,  0.,
              -6.28, -3.42,  3.46,  0.41,  0.])

res.flags = {  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False}

[[-0.7137 -0.2429  0.0876]
 [-0.2882 -0.0884 -0.2117]
 [-0.4282  0.1284  0.0185]
 [ 0.9564 -0.2478 -0.1404]
 [ 0.3625  0.3519 -0.3607]]


Removing (only) the print statements again gave me the correct results.

So, it seems either typing the array as a memview or printing res
will screw up the calculation.

The cython code is given below. Any ideas if this is a cython bug or something 
I'm doing wrong?

Thanks,
Dave


cdef extern from "mkl_lapack.h" nogil:
    void DGELSY(const MKL_INT* m,
                const MKL_INT* n,
                const MKL_INT* nrhs,
                double* a,
                const MKL_INT* lda,
                double* b,
                const MKL_INT* ldb,
                MKL_INT* jpvt,
                const double* rcond,
                MKL_INT* rank,
                double* work,
                const MKL_INT* lwork,
                MKL_INT* info)


@cython.embedsignature(True)
@cython.boundscheck(False)
@cython.wraparound(False)
@cython.cdivision(True)
def dgelsy(double[:,:] A,
          double[:,:] b,
          double rcond=1e-15,
          overwrite_A=False,
          overwrite_b=False):
    cdef MKL_INT rank, info
    cdef MKL_INT m = A.shape[0]
    cdef MKL_INT n = A.shape[1]
    cdef MKL_INT nrhs = b.shape[1]
    cdef MKL_INT lda = m
    cdef MKL_INT ldb = max(m, n)
    cdef MKL_INT lwork = -1
    cdef double worksize = 0
    #cdef double[:,:] tmp
    cdef double[:] res, work
    cdef MKL_INT[:] jpvt

    if b.shape[0] != m:
        message = "b.shape[0] must be equal to A.shape[0].\n"
        message += "b.shape[0] = {b.shape[0]}\n"
        message += "A.shape[0] = {A.shape[0]}\n"
        raise MKL_LAPACK_ERROR(message.format(A=A, b=b))

    flags = np.asarray(A).flags
    if not flags['F_CONTIGUOUS'] or not overwrite_A:
        A = A.copy_fortran()

    flags = np.asarray(b).flags
    if not flags['F_CONTIGUOUS'] or not overwrite_b or b.shape[0] < n:
        tmp = np.zeros([ldb, nrhs], order='F', dtype=np.float64)
        tmp[:b.shape[0]] = b
        res = np.ravel(tmp, order='F')
    else:
        res = np.ravel(b, order='F')

    #print 'res = ', repr(np.asarray(res))
    #print 'res.flags = {{{flags}}}'.format(flags=np.asarray(res).flags)

    jpvt = np.empty(n, dtype=np.int32)
    DGELSY(&m, &n, &nrhs, &A[0,0], &lda, &res[0], &ldb, &jpvt[0], &rcond, &rank, 
&worksize, &lwork, &info)
    if info != 0:
        message = "Parameter {i} had an illegal value when calling gelsy."
        raise MKL_LAPACK_ERROR(message.format(i=info))

    lwork = int(worksize)
    work = np.empty(lwork, dtype=np.float64)
    DGELSY(&m, &n, &nrhs, &A[0,0], &lda, &res[0], &ldb, &jpvt[0], &rcond, &rank, 
&worksize, &lwork, &info)
    if info != 0:
        message = "Parameter {i} had an illegal value when calling gelsy."
        raise MKL_LAPACK_ERROR(message.format(i=info))
    return np.asarray(res).reshape(nrhs, -1).T[:n]
#








More information about the cython-devel mailing list