[pythran] Re: question about multiple None default arguments

  • From: Serge Guelton <serge.guelton@xxxxxxxxxxxxxxxxxxx>
  • To: pythran@xxxxxxxxxxxxx
  • Date: Wed, 30 Dec 2020 13:23:05 +0100

On Mon, Dec 28, 2020 at 05:13:29PM +0100, Jochen S wrote:

I have an issue defining a function signature with multiple default arguments
and I don't quite understand what I'm doing wrong.
I want to implement the interface for np.fft.fft(x, n=None, axis=-1, 
norm=None)
in particular I want the ability to pass None to n and norm (to reflect the
python interface).

The include/numpy/fft/fft.hpp  looks like this (essentially I followed some of
the other examples):

#ifndef PYTHONIC_INCLUDE_NUMPY_FFT_FFT_HPP
#define PYTHONIC_INCLUDE_NUMPY_FFT_FFT_HPP

#include "pythonic/include/utils/functor.hpp"
#include "pythonic/include/types/ndarray.hpp"

PYTHONIC_NS_BEGIN

namespace numpy
{
  namespace fft
  {

    template <class T, class pS>
    types::ndarray<std::complex<T>,
            types::array<long, std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, long n = -1, long axis =
-1,
          types::str const &norm = {});

    template <class T, class pS>
    types::ndarray<std::complex<T>,
            types::array<long, std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, types::none_type n, long
axis ,
          types::str const &norm );

    template <class T, class pS>
    types::ndarray<std::complex<T>,
            types::array<long, std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, long n, long axis ,
          types::none_type norm);

    template <class T, class pS>
    types::ndarray<std::complex<T>,
            types::array<long, std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, types::none_type n, long
axis ,
          types::none_type norm );

    NUMPY_EXPR_TO_NDARRAY0_DECL(fft);
    DEFINE_FUNCTOR(pythonic::numpy::fft, fft);
  }
}
PYTHONIC_NS_END


#endif

And the interface in tables is defined as:

            "fft": FunctionIntr(args=("a", "n", "axis", "norm"),
                                defaults=( None, -1, None), global_effects=
True),
 
However if I try to compile an example which sets the n argument (but not the
norm kwarg)
to None e.g.

#pythran export test_fft(complex128[][], int)
def test_fft(x, a):
    return np.fft.fft(x, axis=a, n=None)      

I get a compile error with the first error (let me know if the full error is
needed), adding norm=None  however fixes it:

Let's try to match this error with your code:

no match for call to 
({anonymous}::pythonic::numpy::fft::functor::fft)(
  
{anonymous}::pythonic::types::ndarray<std::complex<double>,{anonymous}::pythonic::types::pshape<long
 int, long int> >,
  {anonymous}::pythonic::types::none_type,
  long int)

The overload you defined are:

    template <class T, class pS>
    types::ndarray<std::complex<T>, types::array<long, 
std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, long n = -1, long axis = 
-1, types::str const &norm = {});

^ this one doesn't match, as its second argument is an int, not none_type ^

    template <class T, class pS>
    types::ndarray<std::complex<T>, types::array<long, 
std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, types::none_type n, long 
axis , types::str const &norm );

^ this one doesn't match because you don't provide a default value for norm, 
otherwise it's fine ^

    template <class T, class pS>
    types::ndarray<std::complex<T>, types::array<long, 
std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, long n, long axis , 
types::none_type norm);

^ this one doesn't match because second argument is long ^

    template <class T, class pS>
    types::ndarray<std::complex<T>, types::array<long, 
std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, types::none_type n, long 
axis , types::none_type norm );

^ this one doesn't match because you don't provide a default value for norm, 
otherwise it's fine ^

The surprising part is that pythran doens't expand all the default values. What
you could do is change the last signature to

    template <class T, class pS>
    types::ndarray<std::complex<T>, types::array<long, 
std::tuple_size<pS>::value>>
    fft(types::ndarray<std::complex<T>, pS> const &a, types::none_type n, long 
axis , types::none_type norm=types::none_type{});

That should do the trick.

Other related posts: