Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Jitclass + numpy functions can't compile with attribute as second parameter #9522

Open
JulVandenBroeck opened this issue Apr 3, 2024 · 8 comments
Labels
feature_request question Notes an issue as a question

Comments

@JulVandenBroeck
Copy link

Hello everyone!

Thanks for the great work on numba.

I believe I have encountered a bug that happens when the second argument of numpy.broadcast_to is an object attribute.

Below is a MWE that triggers the bug (notice the self.n as the second argument of np.broadcast_to):

import numpy as np
from numba import int32, float64
from numba.experimental import jitclass

@jitclass([
    ("n" , int32     ),
    ("a" , float64[:]),
])
class Foo:
    def __init__(self, a, n):
        self.n = n
        self.a = np.broadcast_to([a], self.n)

Foo(1., 6)

Running this code raises the following exceptions:

Traceback (most recent call last):
  File "c:\Users\julvd\repos\transport\wigner\NpNNp\test.py", line 12, in <module>
    Test(1., 6)
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\experimental\jitclass\base.py", line 124, in __call__
    return cls._ctor(*bind.args[1:], **bind.kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function broadcast_to at 0x000001737F643D80>) found for signature:
 
 >>> broadcast_to(list(float64)<iv=None>, int32)
 
There are 2 candidate implementations:
      - Of which 2 did not match due to:
      Overload in function 'numpy_broadcast_to': File: numba\np\arrayobj.py: Line 1461.
        With argument(s): '(list(float64)<iv=None>, int32)':
       Rejected as the implementation raised a specific error:
         TypingError: Failed in nopython mode pipeline (step: nopython frontend)
       No implementation of function Function(<function broadcast_to at 0x000001737F643D80>) found for signature:
        
        >>> broadcast_to(list(float64)<iv=None>, UniTuple(int32 x 1))
        
       There are 2 candidate implementations:
             - Of which 2 did not match due to:
             Overload in function 'numpy_broadcast_to': File: numba\np\arrayobj.py: Line 1461.
               With argument(s): '(list(float64)<iv=None>, UniTuple(int32 x 1))':
              Rejected as the implementation raised a specific error:
                AssertionError: Failed in nopython mode pipeline (step: native lowering)
       
         raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\llvmlite\ir\instructions.py:317

       During: resolving callee type: Function(<function broadcast_to at 0x000001737F643D80>)
       During: typing of call at c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\np\arrayobj.py (1469)
       

       File ".venv\Lib\site-packages\numba\np\arrayobj.py", line 1469:
               def impl(array, shape):
                   return np.broadcast_to(array, (shape,))
                   ^

  raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\typeinfer.py:1091

During: resolving callee type: Function(<function broadcast_to at 0x000001737F643D80>)
During: typing of call at c:\Users\julvd\repos\transport\wigner\NpNNp\test.py (11)


File "wigner\NpNNp\test.py", line 11:
    def __init__(self, a, n):
        <source elided>
        self.n = n
        self.a = np.broadcast_to([a], self.n)
        ^

During: resolving callee type: jitclass.Test#17301c50ec0<n:int32,a:array(float64, 1d, A)>
During: typing of call at <string> (3)

During: resolving callee type: jitclass.Test#17301c50ec0<n:int32,a:array(float64, 1d, A)>
During: typing of call at <string> (3)


File "<string>", line 3:
<source missing, REPL/exec in use?>


(.venv) C:\Users\julvd\repos\transport>c:\Users\julvd\repos\transport\.venv\Scripts\python.exe "c:\Users\julvd\repos\transport\mwe.py"
Traceback (most recent call last):
  File "c:\Users\julvd\repos\transport\mwe.py", line 12, in <module>
    Foo(1., 6)
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\experimental\jitclass\base.py", line 124, in __call__
    return cls._ctor(*bind.args[1:], **bind.kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function broadcast_to at 0x000002A60B9C3D80>) found for signature:
 
 >>> broadcast_to(list(float64)<iv=None>, int32)
 
There are 2 candidate implementations:
      - Of which 2 did not match due to:
      Overload in function 'numpy_broadcast_to': File: numba\np\arrayobj.py: Line 1461.
        With argument(s): '(list(float64)<iv=None>, int32)':
       Rejected as the implementation raised a specific error:
         TypingError: Failed in nopython mode pipeline (step: nopython frontend)
       No implementation of function Function(<function broadcast_to at 0x000002A60B9C3D80>) found for signature:
        
        >>> broadcast_to(list(float64)<iv=None>, UniTuple(int32 x 1))
        
       There are 2 candidate implementations:
             - Of which 2 did not match due to:
             Overload in function 'numpy_broadcast_to': File: numba\np\arrayobj.py: Line 1461.
               With argument(s): '(list(float64)<iv=None>, UniTuple(int32 x 1))':
              Rejected as the implementation raised a specific error:
                AssertionError: Failed in nopython mode pipeline (step: native lowering)
       
         raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\llvmlite\ir\instructions.py:317

       During: resolving callee type: Function(<function broadcast_to at 0x000002A60B9C3D80>)
       During: typing of call at c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\np\arrayobj.py (1469)
       

       File ".venv\Lib\site-packages\numba\np\arrayobj.py", line 1469:
               def impl(array, shape):
                   return np.broadcast_to(array, (shape,))
                   ^

  raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\typeinfer.py:1091

During: resolving callee type: Function(<function broadcast_to at 0x000002A60B9C3D80>)
During: typing of call at c:\Users\julvd\repos\transport\mwe.py (11)


File "mwe.py", line 11:
    def __init__(self, a, n):
        <source elided>
        self.n = n
        self.a = np.broadcast_to([a], self.n)
        ^

During: resolving callee type: jitclass.Foo#2a60bc9df10<n:int32,a:array(float64, 1d, A)>
During: typing of call at <string> (3)

During: resolving callee type: jitclass.Foo#2a60bc9df10<n:int32,a:array(float64, 1d, A)>
During: typing of call at <string> (3)


File "<string>", line 3:
<source missing, REPL/exec in use?>

In contrast, using the constructor argument n itself gives no errors:

import numpy as np
from numba import int32, float64
from numba.experimental import jitclass
@jitclass([
    ("n" , int32     ),
    ("a" , float64[:]),
])
class Foo:
    def __init__(self, a, n):
        self.n = n
        self.a = np.broadcast_to([a], n)
Foo(1., 6)

Thanks for taking the time.

Kind regards
Jul

@JulVandenBroeck
Copy link
Author

JulVandenBroeck commented Apr 3, 2024

I just noticed that a similar thing happens for np.trapz.

MWE:

import numpy as np
from numba import float64
from numba.experimental import jitclass
@jitclass([
    ("xx" , float64[:]),
    ("res", float64   ),
])
class Foo:
    def __init__(self, aa, xx):
        self.xx = xx
        self.res = np.trapz(aa, x=self.xx)
aa = np.asarray([1,4,9,16,25], dtype=np.float_)
xx = np.asarray([1,2,3,4,5], dtype=np.float_)
print(Foo(aa, xx).res)

This throws the following error:

Traceback (most recent call last):
  File "c:\Users\julvd\repos\transport\mwe.py", line 14, in <module>
    print(Foo(aa, xx).res)
          ^^^^^^^^^^^
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\experimental\jitclass\base.py", line 124, in __call__
    return cls._ctor(*bind.args[1:], **bind.kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<function trapz at 0x000001D97FECC720>) found for signature:
 
 >>> trapz(array(float64, 1d, C), x=array(float64, 1d, A))
 
There are 2 candidate implementations:
  - Of which 2 did not match due to:
  Overload in function 'np_trapz': File: numba\np\arraymath.py: Line 2214.
    With argument(s): '(array(float64, 1d, C), x=array(float64, 1d, A))':
   Rejected as the implementation raised a specific error:
     TypingError: Failed in nopython mode pipeline (step: nopython frontend)
   No implementation of function Function(<function _get_d at 0x000001D924360400>) found for signature:
    
    >>> _get_d(array(float64, 1d, A), float64)
    
   There are 2 candidate implementations:
         - Of which 2 did not match due to:
         Overload in function 'get_d_impl': File: numba\np\arraymath.py: Line 2203.
           With argument(s): '(array(float64, 1d, A), float64)':
          Rejected as the implementation raised a specific error:
            TypingError: Failed in nopython mode pipeline (step: nopython frontend)
          No implementation of function Function(<function diff at 0x000001D97FEC5A80>) found for signature:

           >>> diff(array(float64, 1d, A))

          There are 2 candidate implementations:
                - Of which 2 did not match due to:
                Overload in function 'np_diff_impl': File: numba\np\arraymath.py: Line 3525.
                  With argument(s): '(array(float64, 1d, A))':
                 Rejected as the implementation raised a specific error:
                   TypingError: Failed in nopython mode pipeline (step: nopython frontend)
                 - Resolution failure for literal arguments:
                 reshape() supports contiguous array only
                 - Resolution failure for non-literal arguments:
                 reshape() supports contiguous array only

                 During: resolving callee type: BoundFunction(array.reshape for array(float64, 1d, A))
                 During: typing of call at c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\np\arraymath.py (3543)


                 File ".venv\Lib\site-packages\numba\np\arraymath.py", line 3543:
                     def diff_impl(a, n=1):
                         <source elided>
                         # To make things easier, normalize input and output into 2d arrays
                         a2 = a.reshape((-1, size))
                         ^

            raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\typeinfer.py:1091

          During: resolving callee type: Function(<function diff at 0x000001D97FEC5A80>)
          During: typing of call at c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\np\arraymath.py (2210)


          File ".venv\Lib\site-packages\numba\np\arraymath.py", line 2210:
                  def impl(x, dx):
                      return np.diff(np.asarray(x))
                      ^

     raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\typeinfer.py:1091

   During: resolving callee type: Function(<function _get_d at 0x000001D924360400>)
   During: typing of call at c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\np\arraymath.py (2227)
   

   File ".venv\Lib\site-packages\numba\np\arraymath.py", line 2227:
       def impl(y, x=None, dx=1.0):
           <source elided>
           yarr = np.asarray(y)
           d = _get_d(x, dx)
           ^

  raised from c:\Users\julvd\repos\transport\.venv\Lib\site-packages\numba\core\typeinfer.py:1091

During: resolving callee type: Function(<function trapz at 0x000001D97FECC720>)
During: typing of call at c:\Users\julvd\repos\transport\mwe.py (11)


File "mwe.py", line 11:
    def __init__(self, aa, xx):
        <source elided>
        self.xx = xx
        self.res = np.trapz(aa, x=self.xx)
        ^

During: resolving callee type: jitclass.Foo#1d904880ad0<xx:array(float64, 1d, A),res:float64>
During: typing of call at <string> (3)

During: resolving callee type: jitclass.Foo#1d904880ad0<xx:array(float64, 1d, A),res:float64>
During: typing of call at <string> (3)


File "<string>", line 3:
<source missing, REPL/exec in use?>

Using xx instead of self.xx works:

import numpy as np
from numba import float64
from numba.experimental import jitclass
@jitclass([
    ("xx" , float64[:]),
    ("res", float64   ),
])
class Foo:
    def __init__(self, aa, xx):
        self.xx = xx
        self.res = np.trapz(aa, x=xx)
aa = np.asarray([1,4,9,16,25], dtype=np.float_)
xx = np.asarray([1,2,3,4,5], dtype=np.float_)
print(Foo(aa, xx).res)

This prints the expected 42.0.

@JulVandenBroeck JulVandenBroeck changed the title Jitclass + numpy.broadcast_to can't compile with attribute as second parameter Jitclass + numpy functions can't compile with attribute as second parameter Apr 3, 2024
@JulVandenBroeck
Copy link
Author

JulVandenBroeck commented Apr 3, 2024

This behavior is not observed when the first argument is an attribute.

The error can be circumvented by creating a copy of the attribute, using np.copy, before using it as the second argument.

@gmarkall
Copy link
Member

gmarkall commented Apr 3, 2024

Thanks for the report - I can reproduce the issue in the original post.

I also note that calling np.broadcast_to with a similar signature even without a jitclass results in a gigantic unintelligible error from type inference:

import numpy as np
from numba import njit, int32, float64


@njit((float64[:], int32))
def Foo(a, n):
    return np.broadcast_to([a], n)

Foo(1., 6)

The last part of the traceback is:

Traceback end

^^^^^
                                              File "/home/gmarkall/numbadev/numba/numba/core/typed_passes.py", line 93, in type_inference_stage
                                                errs = infer.propagate(raise_errors=raise_errors)
                                                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                              File "/home/gmarkall/numbadev/numba/numba/core/typeinfer.py", line 1091, in propagate
                                                raise errors[0]
                                            numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
                                            No implementation of function Function(<intrinsic np_array>) found for signature:
                                             
                                             >>> np_array(list(array(float64, 1d, A))<iv=None>, none)
                                             
                                            There are 2 candidate implementations:
                                                  - Of which 2 did not match due to:
                                                  Intrinsic in function 'np_array': File: numba/np/arrayobj.py: Line 5396.
                                                    With argument(s): '(list(array(float64, 1d, A))<iv=None>, none)':
                                                   Rejected as the implementation raised a specific error:
                                                     TypingError: array(float64, 1d, A) not allowed in a homogeneous sequence
                                                       Traceback (most recent call last):
                                                         File "/home/gmarkall/numbadev/numba/numba/core/types/functions.py", line 308, in get_call_type
                                                           sig = temp.apply(nolitargs, nolitkws)
                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/core/typing/templates.py", line 351, in apply
                                                           sig = generic(args, kws)
                                                                 ^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/core/typing/templates.py", line 965, in generic
                                                           result = self._definition_func(self.context, *args, **kws)
                                                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/np/arrayobj.py", line 5399, in np_array
                                                           ret = np_array_typer(typingctx, obj, dtype)
                                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/np/arrayobj.py", line 5386, in np_array_typer
                                                           ndim, seq_dtype = _parse_nested_sequence(typingctx, object)
                                                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/core/typing/npydecl.py", line 484, in _parse_nested_sequence
                                                           n, dtype = _parse_nested_sequence(context, typ.dtype)
                                                                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                                         File "/home/gmarkall/numbadev/numba/numba/core/typing/npydecl.py", line 482, in _parse_nested_sequence
                                                           raise TypingError("%s not allowed in a homogeneous sequence" % typ)
                                                       numba.core.errors.TypingError: array(float64, 1d, A) not allowed in a homogeneous sequence
                                              raised from /home/gmarkall/numbadev/numba/numba/core/typing/npydecl.py:482
                                            
                                            During: resolving callee type: Function(<intrinsic np_array>)
                                            During: typing of call at /home/gmarkall/numbadev/numba/numba/np/arrayobj.py (5433)
                                            
                                            
                                            File "../../numba/numba/np/arrayobj.py", line 5433:
                                                def impl(object, dtype=None):
                                                    return np_array(object, dtype)
                                                    ^
                                   raised from /home/gmarkall/numbadev/numba/numba/core/typeinfer.py:1091
                                 
                                 During: resolving callee type: Function(<built-in function array>)
                                 During: typing of call at /home/gmarkall/numbadev/numba/numba/np/arraymath.py (4312)
                                 
                                 
                                 File "../../numba/numba/np/arraymath.py", line 4312:
                                             def impl(a, dtype=None):
                                                 return np.array(a)
                                                 ^
                        raised from /home/gmarkall/numbadev/numba/numba/core/typeinfer.py:1091
                      
                      During: resolving callee type: Function(<built-in function asarray>)
                      During: typing of call at /home/gmarkall/numbadev/numba/numba/np/arrayobj.py (1457)
                      
                      
                      File "../../numba/numba/np/arrayobj.py", line 1457:
                      def _default_broadcast_to_impl(array, shape):
                          array = np.asarray(array)
                          ^
             raised from /home/gmarkall/numbadev/numba/numba/core/typeinfer.py:1091
           
           During: resolving callee type: Function(<function broadcast_to at 0x77079a6bdf80>)
           During: typing of call at /home/gmarkall/numbadev/numba/numba/np/arrayobj.py (1470)
           
           
           File "../../numba/numba/np/arrayobj.py", line 1470:
                   def impl(array, shape):
                       return np.broadcast_to(array, (shape,))
                       ^
  raised from /home/gmarkall/numbadev/numba/numba/core/typeinfer.py:1091

During: resolving callee type: Function(<function broadcast_to at 0x77079a6bdf80>)
During: typing of call at /home/gmarkall/numbadev/issues/9522/repro.py (7)


File "repro.py", line 7:
def Foo(a, n):
    return np.broadcast_to([a], n)
    ^

@gmarkall gmarkall added bug - failure to compile Bugs: failed to compile valid code needtriage labels Apr 3, 2024
@gmarkall
Copy link
Member

gmarkall commented Apr 3, 2024

Labelling as a bug for now, but I think a bit of discussion in the triage meeting will help establish the right directions to take for looking further into this bug / this collection of related issues.

@gmarkall
Copy link
Member

gmarkall commented Apr 9, 2024

After discussion in the triage meeting - the issue is that broadcasting a list is not supported - if you replace the list that's the first argument of broadcast_to with a tuple, does that work for your use case?

@gmarkall gmarkall added feature_request question Notes an issue as a question and removed needtriage bug - failure to compile Bugs: failed to compile valid code labels Apr 9, 2024
@guilhermeleobas
Copy link
Collaborator

@JulVandenBroeck, are you trying to broadcast a set of arrays? If so, can you try np.broadcast_arrays, instead? np.broadcast_to expects the first argument to be an array-like, that's why you're seeing the error.

@JulVandenBroeck
Copy link
Author

JulVandenBroeck commented Apr 9, 2024

After discussion in the triage meeting - the issue is that broadcasting a list is not supported - if you replace the list that's the first argument of broadcast_to with a tuple, does that work for your use case?

Thanks for the info! Using a tuple gives the same error, and so does an ndarray. It finds the appropriate candidate implementations but fails during the native lowering step.

@JulVandenBroeck, are you trying to broadcast a set of arrays? If so, can you try np.broadcast_arrays, instead? np.broadcast_to expects the first argument to be an array-like, that's why you're seeing the error.

No, I want to broadcast a single array to a certain shape: in my example an array with shape (1,) to shape (5,). I used [a] as the first argument, which is an array-like. From the traceback, I deduce that Numba finds the correct implementation but fails to compile. I personally believe it has nothing to do with Numpy.

@JulVandenBroeck
Copy link
Author

I decided to switch to a structref, which solved all my issues (for the moment being :) )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature_request question Notes an issue as a question
Projects
None yet
Development

No branches or pull requests

3 participants