pydata / sparse

Sparse multi-dimensional arrays for the PyData ecosystem

Home Page:https://sparse.pydata.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

sparse.tensordot in v0.11 and 0.12 introduces Numba typing errors

sametz opened this issue · comments

In Issue #493 I showed a case where sparse.tensordot fails a NumPy documentation example when both array arguments are type np.ndarray.

Here, I have an example of a tensordot function that worked for sparse v0.10.0 and earlier but fails for v0.11 and 0.12. If one or both of the arrays are type COO, Numba typing errors result.

The following test is parametrized for different combinations of ndarray vs. COO argument types:

import numpy as np
import pytest
import sparse

v2 =np.array([10.0, 20.0])
Lz2 = np.array(
        [[[0.5 + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j],
          [0. + 0.j, 0.5 + 0.j, 0. + 0.j, 0. + 0.j],
          [0. + 0.j, 0. + 0.j, -0.5 + 0.j, -0. + 0.j],
          [0. + 0.j, 0. + 0.j, -0. + 0.j, -0.5 + 0.j]],

         [[0.5 + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j],
          [0. + 0.j, -0.5 + 0.j, 0. + 0.j, -0. + 0.j],
          [0. + 0.j, 0. + 0.j, 0.5 + 0.j, 0. + 0.j],
          [0. + 0.j, -0. + 0.j, 0. + 0.j, -0.5 + 0.j]]]
    )
v2_coo = sparse.COO(v2)
Lz2_coo = sparse.COO(Lz2)


@pytest.mark.parametrize("v, Lz", [
    (v2, Lz2),
    (v2_coo, Lz2),
    (v2, Lz2_coo),
    (v2_coo, Lz2_coo)
])
def test_twospin_v_Lz(v, Lz):
    H = sparse.tensordot(v, Lz, axes=1)
    if not isinstance(H, np.ndarray):
        H = H.todense()
    assert np.allclose(H,
                    np.array(
                        [[15. + 0.j, 0. + 0.j, 0. + 0.j, 0. + 0.j],
                         [0. + 0.j, -5. + 0.j, 0. + 0.j, 0. + 0.j],
                         [0. + 0.j, 0. + 0.j, 5. + 0.j, 0. + 0.j],
                         [0. + 0.j, 0. + 0.j, 0. + 0.j, -15. + 0.j]]
                    ))

The case where both arrays are type ndarray fails as previously described:
with an error coming from the sparse.tensordot function:

        at = a.transpose(newaxes_a).reshape(newshape_a)
        bt = b.transpose(newaxes_b).reshape(newshape_b)
        res = _dot(at, bt)
>       return res.reshape(olda + oldb)
E       AttributeError: 'NoneType' object has no attribute 'reshape'

../../../.conda/envs/nmrsim/lib/python3.7/site-packages/sparse/_coo/common.py:172: AttributeError

The other three tests pass up to sparse 0.10.0, but fail in 0.11.0 and 0.12.0.
When one of the tensordot arguments is type np.ndarray, and the other COO,
the following numba typing error results:

v = <COO: shape=(2,), dtype=float64, nnz=2, fill_value=0.0>
Lz = array([[[ 0.5+0.j,  0. +0.j,  0. +0.j,  0. +0.j],
        [ 0. +0.j,  0.5+0.j,  0. +0.j,  0. +0.j],
        [ 0. +0.j,... +0.j,  0. +0.j],
        [ 0. +0.j,  0. +0.j,  0.5+0.j,  0. +0.j],
        [ 0. +0.j,  0. +0.j,  0. +0.j, -0.5+0.j]]])

    @pytest.mark.parametrize("v, Lz", [
        (v2, Lz2),
        (v2_coo, Lz2),
        (v2, Lz2_coo),
        (v2_coo, Lz2_coo)
    ])
    def test_twospin_v_Lz(v, Lz):
>       H = sparse.tensordot(v, Lz, axes=1)

tests/test_sparse.py:130: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py:145: in tensordot
    res = _dot(at, bt, return_type)
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py:423: in _dot
    return _dot_coo_ndarray_type(a.dtype, b.dtype)(
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/numba/core/dispatcher.py:420: in _compile_for_args
    error_rewrite(e, 'typing')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = TypingError('Failed in nopython mode pipeline (step: nopython frontend)\nNo implementation of function Function(<built...1:\n                    out[oidx1, oidx2] += data1[didx1] * array2[oidx2, coords1[1, didx1]]\n                    ^\n')
issue_type = 'typing'

    def error_rewrite(e, issue_type):
        """
        Rewrite and raise Exception `e` with help supplied based on the
        specified issue_type.
        """
        if config.SHOW_HELP:
            help_msg = errors.error_extras[issue_type]
            e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
        if config.FULL_TRACEBACKS:
            raise e
        else:
>           raise e.with_traceback(None)
E           numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
E           No implementation of function Function(<built-in function setitem>) found for signature:
E            
E            >>> setitem(array(float64, 2d, C), UniTuple(int64 x 2), complex128)
E            
E           There are 16 candidate implementations:
E                - Of which 16 did not match due to:
E                Overload of function 'setitem': File: <numerous>: Line N/A.
E                  With argument(s): '(array(float64, 2d, C), UniTuple(int64 x 2), complex128)':
E                 No match.
E           
E           During: typing of setitem at /Users/geoffreysametz/anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py (1026)
E           
E           File "../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py", line 1026:
E               def _dot_coo_ndarray(coords1, data1, array2, out_shape):  # pragma: no cover
E                   <source elided>
E                           while didx1 < len(data1) and coords1[0, didx1] == oidx1:
E                               out[oidx1, oidx2] += data1[didx1] * array2[oidx2, coords1[1, didx1]]
E                               ^

../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/numba/core/dispatcher.py:361: TypingError

When both arrays are type COO, a different numba typing error results:

v = <COO: shape=(2,), dtype=float64, nnz=2, fill_value=0.0>, Lz = <COO: shape=(2, 4, 4), dtype=complex128, nnz=8, fill_value=0j>

    @pytest.mark.parametrize("v, Lz", [
        (v2, Lz2),
        (v2_coo, Lz2),
        (v2, Lz2_coo),
        (v2_coo, Lz2_coo)
    ])
    def test_twospin_v_Lz(v, Lz):
>       H = sparse.tensordot(v, Lz, axes=1)

tests/test_sparse.py:130: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py:145: in tensordot
    res = _dot(at, bt, return_type)
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py:401: in _dot
    coords, data = _dot_coo_coo_type(a.dtype, b.dtype)(
../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/numba/core/dispatcher.py:420: in _compile_for_args
    error_rewrite(e, 'typing')
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

e = TypingError('Failed in nopython mode pipeline (step: nopython frontend)\nNo implementation of function Function(<built...oo_coo(\n        <source elided>\n                ):\n                    sums[k] += av * bv\n                    ^\n')
issue_type = 'typing'

    def error_rewrite(e, issue_type):
        """
        Rewrite and raise Exception `e` with help supplied based on the
        specified issue_type.
        """
        if config.SHOW_HELP:
            help_msg = errors.error_extras[issue_type]
            e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
        if config.FULL_TRACEBACKS:
            raise e
        else:
>           raise e.with_traceback(None)
E           numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
E           No implementation of function Function(<built-in function setitem>) found for signature:
E            
E            >>> setitem(array(float64, 1d, C), int64, complex128)
E            
E           There are 16 candidate implementations:
E                 - Of which 16 did not match due to:
E                 Overload of function 'setitem': File: <numerous>: Line N/A.
E                   With argument(s): '(array(float64, 1d, C), int64, complex128)':
E                  No match.
E           
E           During: typing of setitem at /Users/geoffreysametz/anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py (969)
E           
E           File "../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/sparse/_common.py", line 969:
E               def _dot_coo_coo(
E                   <source elided>
E                           ):
E                               sums[k] += av * bv
E                               ^

../../../anaconda3/anaconda3/envs/nmrsim_39/lib/python3.9/site-packages/numba/core/dispatcher.py:361: TypingError

Expected Behavior

  • expected the changes to sparse.tensordot in sparse v0.11 to be backwards-compatible and not break pre-existing, working code.

System
This has been tested on Mac Catalina and Windows 10 (see examples in Issue #493). Here are two combinations re-verified on the Mac where tests pass with Sparse 0.10 but fail for Sparse 0.12.

Failing system config:

  • OS and version: Mac Catalina 10.15.7
  • sparse version 0.12.0
  • NumPy version 1.20.3
  • Numba version 0.53.1

Passing 3/4 tests (i.e. excluding Issue #493 case) system config:

  • OS and version: Mac Catalina 10.15.7
  • sparse version 0.10.0
  • NumPy version 1.18.1
  • Numba version 0.49.1

Additional context

This failure is also noticed in linux cloud servers, e.g. when a Binder launches to run a Jupyter notebook hosted on GitHub. So, it is OS-independent.

@daletovar worked on the dot code last, I believe.