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

Feature/pythran numpy 2 #2202

Merged
merged 10 commits into from
Apr 30, 2024
Merged
2 changes: 1 addition & 1 deletion pythran/conversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ def to_ast(value):
if any(value is t for t in (bool, int, float)):
return builtin_folding(value)
elif isinstance(value, np.generic):
return to_ast(value.item())
raise ToNotEval()
elif isinstance(value, (numbers.Number, str, bool, type(None))):
iinfo = np.iinfo(int)
if isinstance(value, int) and not (iinfo.min <= value <= iinfo.max):
Expand Down
22 changes: 19 additions & 3 deletions pythran/pythonic/include/numpy/sign.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#ifndef PYTHONIC_INCLUDE_NUMPY_SIGN_HPP
#define PYTHONIC_INCLUDE_NUMPY_SIGN_HPP

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

#include <xsimd/xsimd.hpp>
Expand All @@ -11,10 +11,26 @@ PYTHONIC_NS_BEGIN

namespace numpy
{
namespace details
{
#if PyArray_RUNTIME_VERSION < NPY_2_0_API_VERSION
template <typename T>
std::complex<T> sign(std::complex<T> v)
{
return xsimd::select(v == 0, v, v / xsimd::abs(v));
}
#endif
template <typename T>
T sign(T v)
{
return xsimd::sign(v);
}

} // namespace details
#define NUMPY_NARY_FUNC_NAME sign
#define NUMPY_NARY_FUNC_SYM xsimd::sign
#define NUMPY_NARY_FUNC_SYM details::sign
#include "pythonic/include/types/numpy_nary_expr.hpp"
}
} // namespace numpy
PYTHONIC_NS_END

#endif
6 changes: 3 additions & 3 deletions pythran/pythonic/numpy/sign.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

#include "pythonic/include/numpy/sign.hpp"

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

PYTHONIC_NS_BEGIN

namespace numpy
{
#define NUMPY_NARY_FUNC_NAME sign
#define NUMPY_NARY_FUNC_SYM xsimd::sign
#define NUMPY_NARY_FUNC_SYM details::sign
#include "pythonic/types/numpy_nary_expr.hpp"
}
} // namespace numpy
PYTHONIC_NS_END

#endif
39 changes: 31 additions & 8 deletions pythran/tables.py
Original file line number Diff line number Diff line change
Expand Up @@ -2547,8 +2547,8 @@ def partialsum(seq):
]


def expand_numpy_2_args(args, defaults=None):
if numpy.__version__[0] < '2':
def expand_numpy_2_args(args, defaults=None, force=False):
if force or numpy.__version__[0] < '2':
if defaults is not None:
return {'args': args, 'defaults': defaults}
else:
Expand Down Expand Up @@ -2941,7 +2941,9 @@ def expand_numpy_2_args(args, defaults=None):
),
"alltrue": ConstFunctionIntr(
signature=_numpy_unary_op_bool_axis_signature,
return_range=interval.bool_values
return_range=interval.bool_values,
args=("a", "axis"),
defaults=(None,)
),
"amax": ConstFunctionIntr(signature=_numpy_unary_op_axis_signature),
"amin": ConstFunctionIntr(signature=_numpy_unary_op_axis_signature),
Expand Down Expand Up @@ -3687,7 +3689,9 @@ def expand_numpy_2_args(args, defaults=None):
signature=_numpy_unary_op_cumsum_axis_signature
),
"cumproduct": ConstFunctionIntr(
signature=_numpy_unary_op_cumsum_axis_signature
signature=_numpy_unary_op_cumsum_axis_signature,
args=("a", "axis", "dtype", "out"),
defaults=(None, None, None),
),
"cumsum": ConstMethodIntr(
signature=_numpy_unary_op_cumsum_axis_signature
Expand Down Expand Up @@ -3883,7 +3887,10 @@ def expand_numpy_2_args(args, defaults=None):
signature=_numpy_binary_op_signature
),
"prod": ConstMethodIntr(),
"product": ConstFunctionIntr(),
"product": ConstFunctionIntr(
args=("a", "axis", "dtype", "out"),
defaults=(None, None, None),
),
"ptp": ConstMethodIntr(),
"put": MethodIntr(),
"putmask": FunctionIntr(),
Expand Down Expand Up @@ -3954,7 +3961,7 @@ def expand_numpy_2_args(args, defaults=None):
"rand": FunctionIntr(global_effects=True,
**expand_numpy_2_args(args=())),
"ranf": FunctionIntr(global_effects=True,
**expand_numpy_2_args(args=('size',))),
**expand_numpy_2_args(args=('size',), force=True)),
"randint": FunctionIntr(global_effects=True,
**expand_numpy_2_args(args=("low", "high", "size"),
defaults=(None, None))),
Expand All @@ -3970,7 +3977,7 @@ def expand_numpy_2_args(args, defaults=None):
**expand_numpy_2_args(args=('scale', 'size',),
defaults=(1.0, None,))),
"sample": FunctionIntr(global_effects=True,
**expand_numpy_2_args(args=('size',))),
**expand_numpy_2_args(args=('size',), force=True)),
"seed": FunctionIntr(global_effects=True),
"shuffle": FunctionIntr(global_effects=True),
"standard_exponential": FunctionIntr(global_effects=True,
Expand Down Expand Up @@ -4017,7 +4024,10 @@ def expand_numpy_2_args(args, defaults=None):
"sin": ConstFunctionIntr(signature=_numpy_unary_op_float_signature),
"sinh": ConstFunctionIntr(signature=_numpy_unary_op_float_signature),
"size": ConstFunctionIntr(return_range=interval.positive_values),
"sometrue": ConstFunctionIntr(),
"sometrue": ConstFunctionIntr(
args=("a", "axis"),
defaults=(None,)
),
"sort": ConstFunctionIntr(),
"sort_complex": ConstFunctionIntr(),
"spacing": ConstFunctionIntr(),
Expand Down Expand Up @@ -4569,6 +4579,8 @@ def expand_numpy_2_args(args, defaults=None):
except ImportError:
pass

def looks_like_a_forward_function(spec):
return not spec.args and spec.varargs == 'args' and spec.varkw == 'kwargs'

# populate argument description through introspection
def save_arguments(module_name, elements):
Expand All @@ -4592,8 +4604,19 @@ def save_arguments(module_name, elements):
except:
continue

# some function are actually forward function, detect those
# and accept to use our description instead.
if looks_like_a_forward_function(spec):
assert signature.args.args, "{} require an explicit description".format(elem)
continue

args = [ast.Name(arg, ast.Param(), None, None)
for arg in spec.args]

# pop 'self' if we have a bound method
if inspect.ismethod(obj):
args = args[1:]

defaults = list(spec.defaults or [])
args += [ast.Name(arg, ast.Param(), None, None)
for arg in spec.kwonlyargs]
Expand Down
22 changes: 11 additions & 11 deletions pythran/tests/notebooks/export.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -418,20 +418,20 @@
"name": "stdout",
"output_type": "stream",
"text": [
"(1.5, -1.5)\n",
"(1.5, -1.5)\n",
"(1.5, -1.5)\n"
"1.5 -1.5\n",
"1.5 -1.5\n",
"1.5 -1.5\n"
]
}
],
"source": [
"import numpy as np\n",
"x64 = dtype(np.complex64(1.5 + -1.5j))\n",
"print(x64)\n",
"x128 = dtype(np.complex128(1.5 + -1.5j))\n",
"print(x128)\n",
"x256 = dtype(np.complex256(1.5 + -1.5j))\n",
"print(x256)"
"x64r, x64i = dtype(np.complex64(1.5 + -1.5j))\n",
"print(x64r, x64i)\n",
"x128r, x128i = dtype(np.complex128(1.5 + -1.5j))\n",
"print(x128r, x128i)\n",
"x256r, x264i = dtype(np.complex256(1.5 + -1.5j))\n",
"print(x256r, x264i)"
]
},
{
Expand Down Expand Up @@ -969,9 +969,9 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
"version": "3.12.2"
}
},
"nbformat": 4,
"nbformat_minor": 2
"nbformat_minor": 4
}
32 changes: 14 additions & 18 deletions pythran/tests/notebooks/ufunc.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,15 @@
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4.0"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
"name": "stdout",
"output_type": "stream",
"text": [
"4.0\n"
]
}
],
"source": [
"incr(3)"
"print(incr(3))"
]
},
{
Expand Down Expand Up @@ -229,18 +226,17 @@
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(-1, 0)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
"name": "stdout",
"output_type": "stream",
"text": [
"-1\n",
"0\n"
]
}
],
"source": [
"decr(np.int32(0)), decr(np.uint32(0))"
"print(decr(np.int32(0)))\n",
"print(decr(np.uint32(0)))"
]
}
],
Expand Down
4 changes: 3 additions & 1 deletion pythran/tests/test_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@ def test_complex_broadcast_scalar0(self):
complex_broadcast_scalar0=[complex])

def test_complex_broadcast_scalar1(self):
self.run_test('def complex_broadcast_scalar1(x): return x + 1.5, 1.3 +x, 3.1 - x, x - 3.7, x * 5.4, 7.6 * x',
self.run_test('def complex_broadcast_scalar1(x):\n'
' from numpy import float32 as f32\n'
' return x + f32(1.5), f32(1.3) + x, f32(3.1) - x, x - f32(3.7), x * f32(5.4), f32(7.6) * x',
np.complex64(5.1 + 3j),
complex_broadcast_scalar1=[np.complex64])

Expand Down
6 changes: 6 additions & 0 deletions pythran/tests/test_numpy_fft.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@ def test_rfft_2(self):
self.run_test("def test_rfft_2(x,n): from numpy.fft import rfft ; return rfft(x,n)", numpy.arange(0,8.),9, test_rfft_2=[NDArray[float,:],int])
def test_rfft_3(self):
self.run_test("def test_rfft_3(x,n): from numpy.fft import rfft ; return rfft(x,n)", numpy.arange(0,8.),7, test_rfft_3=[NDArray[float,:],int])

@unittest.skipIf(LooseVersion(numpy.__version__) >= '2', "see https://github.com/numpy/numpy/issues/26349")
def test_rfft_4(self):
self.run_test("def test_rfft_4(x,n): from numpy.fft import rfft ; return rfft(x,n)", numpy.arange(0,8.),6, test_rfft_4=[NDArray[float,:],int])

def test_rfft_5(self):
self.run_test("def test_rfft_5(x,n): from numpy.fft import rfft ; return rfft(x,n)", numpy.arange(0,8.),10, test_rfft_5=[NDArray[float,:],int])

Expand Down Expand Up @@ -254,8 +257,11 @@ def test_ihfft_2(self):
self.run_test("def test_ihfft_2(x,n): from numpy.fft import ihfft ; return ihfft(x,n)", numpy.arange(0,8.),9, test_ihfft_2=[NDArray[float,:],int])
def test_ihfft_3(self):
self.run_test("def test_ihfft_3(x,n): from numpy.fft import ihfft ; return ihfft(x,n)", numpy.arange(0,8.),7, test_ihfft_3=[NDArray[float,:],int])

@unittest.skipIf(LooseVersion(numpy.__version__) >= '2', "see https://github.com/numpy/numpy/issues/26349")
def test_ihfft_4(self):
self.run_test("def test_ihfft_4(x,n): from numpy.fft import ihfft ; return ihfft(x,n)", numpy.arange(0,8.),6, test_ihfft_4=[NDArray[float,:],int])

def test_ihfft_5(self):
self.run_test("def test_ihfft_5(x,n): from numpy.fft import ihfft ; return ihfft(x,n)", numpy.arange(0,8.),10, test_ihfft_5=[NDArray[float,:],int])

Expand Down
42 changes: 24 additions & 18 deletions pythran/tests/test_numpy_func0.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ def test_nansum0(self):
self.run_test("def np_nansum0(a): import numpy as np ; return np.nansum(a)" , numpy.array([[1, 2], [3, numpy.nan]]), np_nansum0=[NDArray[float,:,:]])

def test_nansum1(self):
self.run_test("def np_nansum1(a): import numpy as np ; return np.nansum(a)" , numpy.array([[1, 2], [numpy.NINF, numpy.nan]]), np_nansum1=[NDArray[float,:,:]])
self.run_test("def np_nansum1(a): import numpy as np ; return np.nansum(a)",
numpy.array([[1, 2], [-numpy.inf, numpy.nan]]), np_nansum1=[NDArray[float,:,:]])

def test_nansum2(self):
self.run_test("def np_nansum2(a): import numpy as np ; return np.nansum(a)", [1., numpy.nan], np_nansum2=[List[float]])
Expand All @@ -126,7 +127,8 @@ def test_nanmin0(self):
self.run_test("def np_nanmin0(a): import numpy as np ; return np.nanmin(a)" , numpy.array([[1, 2], [3, numpy.nan]]), np_nanmin0=[NDArray[float,:,:]])

def test_nanmin1(self):
self.run_test("def np_nanmin1(a): import numpy as np ; return np.nanmin(a)" , numpy.array([[1, 2], [numpy.NINF, numpy.nan]]), np_nanmin1=[NDArray[float,:,:]])
self.run_test("def np_nanmin1(a): import numpy as np ; return np.nanmin(a)",
numpy.array([[1, 2], [-numpy.inf, numpy.nan]]), np_nanmin1=[NDArray[float,:,:]])

def test_nanmin2(self):
self.run_test("def np_nanmin2(a): import numpy as np ; return np.nanmin(a)" , numpy.array([[numpy.nan, numpy.nan], [numpy.nan, numpy.nan]]), np_nanmin2=[NDArray[float,:,:]])
Expand Down Expand Up @@ -389,14 +391,15 @@ def test_lexsort1(self):
def test_lexsort2(self):
self.run_test("def np_lexsort2(a): from numpy import lexsort ; return lexsort((a+1,a-1))", numpy.array([1,5,1,4,3,4,4]), np_lexsort2=[NDArray[int,:]])

def test_issctype0(self):
self.run_test("def np_issctype0(): from numpy import issctype, int32 ; a = int32 ; return issctype(a)", np_issctype0=[])
if hasattr(numpy, 'issctype'): # no longer supported in numpy 2.x
def test_issctype0(self):
self.run_test("def np_issctype0(): from numpy import issctype, int32 ; a = int32 ; return issctype(a)", np_issctype0=[])

def test_issctype1(self):
self.run_test("def np_issctype1(): from numpy import issctype ; a = list ; return issctype(a)", np_issctype1=[])
def test_issctype1(self):
self.run_test("def np_issctype1(): from numpy import issctype ; a = list ; return issctype(a)", np_issctype1=[])

def test_issctype2(self):
self.run_test("def np_issctype2(a): from numpy import issctype ; return issctype(a)", 3.1, np_issctype2=[float])
def test_issctype2(self):
self.run_test("def np_issctype2(a): from numpy import issctype ; return issctype(a)", 3.1, np_issctype2=[float])

def test_isscalar0(self):
self.run_test("def np_isscalar0(a): from numpy import isscalar ; return isscalar(a)", 3.1, np_isscalar0=[float])
Expand Down Expand Up @@ -570,11 +573,13 @@ def test_place0(self):
def test_place1(self):
self.run_test("def np_place1(x): from numpy import place ; place(x, x>1, [57, 58]); return x", numpy.arange(6).reshape((2,3)), np_place1=[NDArray[int,:,:]])

def test_product(self):
self.run_test("def np_product(x):\n from numpy import product\n return product(x)", numpy.arange(1, 10), np_product=[NDArray[int,:]])
if hasattr(numpy, 'product'):
def test_product(self):
self.run_test("def np_product(x):\n from numpy import product\n return product(x)", numpy.arange(1, 10), np_product=[NDArray[int,:]])

def test_ptp0(self):
self.run_test("def np_ptp0(x): return x.ptp()", numpy.arange(4).reshape((2,2)), np_ptp0=[NDArray[int,:,:]])
if hasattr(numpy.ndarray((1)), 'ptp'):
def test_ptp0(self):
self.run_test("def np_ptp0(x): return x.ptp()", numpy.arange(4).reshape((2,2)), np_ptp0=[NDArray[int,:,:]])

def test_ptp1(self):
self.run_test("def np_ptp1(x): from numpy import ptp ; return ptp(x,0)", numpy.arange(4).reshape((2,2)), np_ptp1=[NDArray[int,:,:]])
Expand Down Expand Up @@ -758,14 +763,15 @@ def test_select1(self):
def test_select0(self):
self.run_test("def np_select0(x): from numpy import select; condlist = [x<3, x>5]; choicelist = [x, x**2]; return select(condlist, choicelist)", numpy.arange(10), np_select0=[NDArray[int,:]])

def test_sometrue0(self):
self.run_test("def np_sometrue0(a): from numpy import sometrue ; return sometrue(a)", numpy.array([[True, False], [True, True]]), np_sometrue0=[NDArray[bool,:,:]])
if hasattr(numpy, 'sometrue'):
def test_sometrue0(self):
self.run_test("def np_sometrue0(a): from numpy import sometrue ; return sometrue(a)", numpy.array([[True, False], [True, True]]), np_sometrue0=[NDArray[bool,:,:]])

def test_sometrue1(self):
self.run_test("def np_sometrue1(a): from numpy import sometrue ; return sometrue(a, 0)", numpy.array([[True, False], [False, False]]), np_sometrue1=[NDArray[bool,:,:]])
def test_sometrue1(self):
self.run_test("def np_sometrue1(a): from numpy import sometrue ; return sometrue(a, 0)", numpy.array([[True, False], [False, False]]), np_sometrue1=[NDArray[bool,:,:]])

def test_sometrue2(self):
self.run_test("def np_sometrue2(a): from numpy import sometrue ; return sometrue(a)", [-1, 0, 5], np_sometrue2=[List[int]])
def test_sometrue2(self):
self.run_test("def np_sometrue2(a): from numpy import sometrue ; return sometrue(a)", [-1, 0, 5], np_sometrue2=[List[int]])

def test_sort0(self):
self.run_test("def np_sort0(a): from numpy import sort ; return sort(a)", numpy.array([[1,6],[7,5]]), np_sort0=[NDArray[int,:,:]])
Expand Down
Loading
Loading