numpy / numpy/numpy

BUG: np.vectorize (interally _parse_gufunc_signature) can't parse a NEP 20 signature

Open
#12,712 15 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

00 - Bug component: numpy.ufunc
Dominant language
Python
Stars
32.8k
Forks
12.8k
Avg merge
1d 7h
Merged PRs (30d)
197

Description

Hello,

The Debian numpy maintainer filed a a bug against my packaging of Dask (Debian Bug 918204) because some of dasks's tests failed. One of the failures seems to be related to the changes for https://www.numpy.org/neps/nep-0020-gufunc-signature-enhancement.html

(relevant traceback from the dask tests: here (search for "test_matmul ")


    @pytest.mark.skipif(sys.version_info < (3, 5),
                        reason="Matrix multiplication operator only after Py3.5")
    def test_matmul():
        x = np.random.random((5, 5))
        y = np.random.random((5, 2))
        a = from_array(x, chunks=(1, 5))
        b = from_array(y, chunks=(5, 1))
        assert_eq(operator.matmul(a, b), a.dot(b))
        assert_eq(operator.matmul(a, b), operator.matmul(x, y))
>       assert_eq(operator.matmul(a, y), operator.matmul(x, b))

/usr/lib/python3/dist-packages/dask/array/tests/test_array_core.py:849: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
/usr/lib/python3/dist-packages/dask/array/core.py:1054: in __array_ufunc__
    **kwargs)
/usr/lib/python3/dist-packages/dask/array/gufunc.py:264: in apply_gufunc
    input_coredimss, output_coredimss = _parse_gufunc_signature(signature)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

signature = '(n?,k),(k,m?)->(n?,m?)'

The signature '(n?,k),(k,m?)->(n?,m?)' looks like one of the examples from NEP 20, but I tried looking at Numpy's _parse_gufunc_signature to see how to update Dask's version and discovered that numpy's doesn't seem to parse '(n?,k),(k,m?)->(n?,m?)' either.

I looked for a unit test and couldn't find the above signature test, so I added it to commit 30eae3dd24402ca07cd56cae6db646ad61e5d7f1 (not in NumPy: mattip)

--- a/numpy/lib/tests/test_function_base.py
+++ b/numpy/lib/tests/test_function_base.py
@@ -1362,6 +1362,8 @@ class TestVectorize(object):
                      ([('x',)], [('y',), ()]))
         assert_equal(nfb._parse_gufunc_signature('(),(a,b,c),(d)->(d,e)'),
                      ([(), ('a', 'b', 'c'), ('d',)], [('d', 'e')]))
+        assert_equal(nfb._parse_gufunc_signature('(m?,n),(n,p?)->(m?,p?)'),
+                     ([('m?', 'n'),('n','p?')],[('m?', 'p?')]))
         with assert_raises(ValueError):
             nfb._parse_gufunc_signature('(x)(y)->()')
         with assert_raises(ValueError):

and python3 runtests.py fails.

___________________ TestVectorize.test_parse_gufunc_signature ___________________

self = <numpy.lib.tests.test_function_base.TestVectorize object at 0x7f8de58c1f60>

    def test_parse_gufunc_signature(self):
        assert_equal(nfb._parse_gufunc_signature('(x)->()'), ([('x',)], [()]))
        assert_equal(nfb._parse_gufunc_signature('(x,y)->()'),
                     ([('x', 'y')], [()]))
        assert_equal(nfb._parse_gufunc_signature('(x),(y)->()'),
                     ([('x',), ('y',)], [()]))
        assert_equal(nfb._parse_gufunc_signature('(x)->(y)'),
                     ([('x',)], [('y',)]))
        assert_equal(nfb._parse_gufunc_signature('(x)->(y),()'),
                     ([('x',)], [('y',), ()]))
        assert_equal(nfb._parse_gufunc_signature('(),(a,b,c),(d)->(d,e)'),
                     ([(), ('a', 'b', 'c'), ('d',)], [('d', 'e')]))
>       assert_equal(nfb._parse_gufunc_signature('(m?,n),(n,p?)->(m?,p?)'),
                     ([('m?', 'n'),('n','p?')],[('m?', 'p?')]))

self       = <numpy.lib.tests.test_function_base.TestVectorize object at 0x7f8de58c1f60>

numpy/lib/tests/test_function_base.py:1365: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

signature = '(m?,n),(n,p?)->(m?,p?)'

    def _parse_gufunc_signature(signature):
        """
        Parse string signatures for a generalized universal function.
    
        Arguments
        ---------
        signature : string
            Generalized universal function signature, e.g., ``(m,n),(n,p)->(m,p)``
            for ``np.matmul``.
    
        Returns
        -------
        Tuple of input and output core dimensions parsed from the signature, each
        of the form List[Tuple[str, ...]].
        """
        if not re.match(_SIGNATURE, signature):
            raise ValueError(
>               'not a valid gufunc signature: {}'.format(signature))
E           ValueError: not a valid gufunc signature: (m?,n),(n,p?)->(m?,p?)

signature  = '(m?,n),(n,p?)->(m?,p?)'

numpy/lib/function_base.py:1794: ValueError

Should _parse_gufunc_signature handle the signature with question marks? If yes, should there be a test for that case?

Edit: noted that commit is not in NumPy (mattip)

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with _parse_gufunc_signature in numpy/lib/function_base.py and the existing TestVectorize.test_parse_gufunc_signature in numpy/lib/tests/test_function_base.py. Review the NEP 20 signature example and run the focused test or python3 runtests.py. Done means the question-mark signature behavior is resolved and covered by an appropriate test.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data, testing
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.