I define the function that calculates the determinant of a matrix here. But sometimes I get the wrong sign. I modeled my function from this answer.
from scipy.linalg.cython_lapack cimport dgetrf
cpdef double det_c(double[:, ::1] A, double[:, ::1] work, double[::1] ipiv):
    '''obtain determinant of float type square matrix A
    Notes
    -----
    As is, this function is not yet computing the sign of the determinant
    correctly, help!
    Parameters
    ----------
    A : memoryview (numpy array)
        n x n array to compute determinant of
    work : memoryview (numpy array)
        n x n array to use within function
    ipiv : memoryview (numpy array)
        length n vector use within function
    Returns
    -------
    detval : float
        determinant of matrix A
    '''
    cdef int n = A.shape[0], info
    work[...] = A
    dgetrf(&n, &n, &work[0,0], &n, &ipiv[0], &info)
    cdef double detval = 1.
    cdef int j
    for j in range(n):
        if j != ipiv[j]:
            detval = -detval*work[j, j]
        else:
            detval = detval*work[j, j]
    return detval
When I test this function and compare it to np.linalg.det, sometimes I got the wrong sign.
>>> a = np.array([[1,2],[3,5.]])
>>> np.linalg.det(a)
>>> -1.0000000000000004
>>> det_c(a, np.zeros((2, 2)), np.zeros(2, dtype=np.int32))
>>> 1
Other times, the right sign.
>>> b = np.array([[1,2,3],[1,2,1],[5,6,1.]])
>>> np.linalg.det(b)
>>> -7.999999999999998
>>> det_c(a, np.zeros((3, 3)), np.zeros(3, dtype=np.int32))
>>> -8.0
dgetrf is a Fortran subroutine, and Fortran uses 1-based indexing, so the values in ipiv are between 1 and n (inclusive).  To account for this, change the test in your loop from
        if j != ipiv[j]:
to
        if j != ipiv[j] - 1:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With