Commit 395a0c89 authored by Martin Reinecke's avatar Martin Reinecke

change normalization parameters

parent d77cdeb5
...@@ -5,7 +5,7 @@ import pypocketfft ...@@ -5,7 +5,7 @@ import pypocketfft
from time import time from time import time
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
nthreads=0 nthreads=1
def _l2error(a,b): def _l2error(a,b):
return np.sqrt(np.sum(np.abs(a-b)**2)/np.sum(np.abs(a)**2)) return np.sqrt(np.sum(np.abs(a-b)**2)/np.sum(np.abs(a)**2))
...@@ -26,7 +26,7 @@ def bench_nd_fftn(ndim, nmax, ntry, tp, nrepeat, filename=""): ...@@ -26,7 +26,7 @@ def bench_nd_fftn(ndim, nmax, ntry, tp, nrepeat, filename=""):
b=pypocketfft.fftn(a,nthreads=nthreads) b=pypocketfft.fftn(a,nthreads=nthreads)
t1=time() t1=time()
tmin_pp = min(tmin_pp,t1-t0) tmin_pp = min(tmin_pp,t1-t0)
a2=pypocketfft.ifftn(b,fct=1./a.size) a2=pypocketfft.ifftn(b,inorm=2)
assert(_l2error(a,a2)<(2.5e-15 if tp=='c16' else 6e-7)) assert(_l2error(a,a2)<(2.5e-15 if tp=='c16' else 6e-7))
res.append(tmin_pp/tmin_np) res.append(tmin_pp/tmin_np)
plt.title("t(pypocketfft / numpy 1.17), {}D, {}, max_extent={}".format(ndim, str(tp), nmax)) plt.title("t(pypocketfft / numpy 1.17), {}D, {}, max_extent={}".format(ndim, str(tp), nmax))
......
...@@ -34,11 +34,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -34,11 +34,11 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define POCKETFFT_HDRONLY_H #define POCKETFFT_HDRONLY_H
#ifndef __cplusplus #ifndef __cplusplus
#error This file is C++ and requires a C++ compiler #error This file is C++ and requires a C++ compiler.
#endif #endif
#if !(__cplusplus >= 201103L || _MSVC_LANG+0L >= 201103L) #if !(__cplusplus >= 201103L || _MSVC_LANG+0L >= 201103L)
#error This file requires at least C++11 support #error This file requires at least C++11 support.
#endif #endif
#include <cmath> #include <cmath>
...@@ -48,9 +48,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -48,9 +48,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <complex> #include <complex>
#if defined(_WIN32)
#include <malloc.h>
#endif
#ifdef POCKETFFT_OPENMP #ifdef POCKETFFT_OPENMP
#include <omp.h> #include <omp.h>
#endif #endif
...@@ -83,7 +80,7 @@ constexpr bool FORWARD = true, ...@@ -83,7 +80,7 @@ constexpr bool FORWARD = true,
#ifndef POCKETFFT_NO_VECTORS #ifndef POCKETFFT_NO_VECTORS
#define POCKETFFT_NO_VECTORS #define POCKETFFT_NO_VECTORS
#if defined(__INTEL_COMPILER) #if defined(__INTEL_COMPILER)
// do nothing. This is necessary because this compiler also sets __GNUC__ // do nothing. This is necessary because this compiler also sets __GNUC__.
#elif defined(__clang__) #elif defined(__clang__)
#if __clang__>=5 #if __clang__>=5
#undef POCKETFFT_NO_VECTORS #undef POCKETFFT_NO_VECTORS
...@@ -141,27 +138,19 @@ template<typename T> class arr ...@@ -141,27 +138,19 @@ template<typename T> class arr
} }
static void dealloc(T *ptr) static void dealloc(T *ptr)
{ free(ptr); } { free(ptr); }
#elif defined(_WIN32) #else // portable emulation
static T *ralloc(size_t num) static T *ralloc(size_t num)
{ {
if (num==0) return nullptr; if (num==0) return nullptr;
void *res = _aligned_malloc(num*sizeof(T), 64); void *ptr = malloc(num*sizeof(T)+64);
if (!res) throw bad_alloc(); if (!ptr) throw bad_alloc();
return reinterpret_cast<T *>(res); T *res = reinterpret_cast<T *>
((reinterpret_cast<size_t>(ptr) & ~(size_t(63))) + 64);
(reinterpret_cast<void**>(res))[-1] = ptr;
return res;
} }
static void dealloc(T *ptr) static void dealloc(T *ptr)
{ _aligned_free(ptr); } { if (ptr) free((reinterpret_cast<void**>(ptr))[-1]); }
#else
static T *ralloc(size_t num)
{
if (num==0) return nullptr;
void *res(nullptr);
if (posix_memalign(&res, 64, num*sizeof(T))!=0)
throw bad_alloc();
return reinterpret_cast<T *>(res);
}
static void dealloc(T *ptr)
{ free(ptr); }
#endif #endif
public: public:
......
...@@ -27,12 +27,16 @@ using namespace pocketfft; ...@@ -27,12 +27,16 @@ using namespace pocketfft;
namespace py = pybind11; namespace py = pybind11;
// Only instantiate long double transforms if they offer more precision
using ldbl_t = typename std::conditional<
sizeof(long double)==sizeof(double), double, long double>::type;
auto c64 = py::dtype("complex64"); auto c64 = py::dtype("complex64");
auto c128 = py::dtype("complex128"); auto c128 = py::dtype("complex128");
auto c256 = py::dtype("complex256"); auto clong = py::dtype("longcomplex");
auto f32 = py::dtype("float32"); auto f32 = py::dtype("float32");
auto f64 = py::dtype("float64"); auto f64 = py::dtype("float64");
auto f128 = py::dtype("float128"); auto flong = py::dtype("longfloat");
shape_t copy_shape(const py::array &arr) shape_t copy_shape(const py::array &arr)
{ {
...@@ -72,11 +76,29 @@ shape_t makeaxes(const py::array &in, py::object axes) ...@@ -72,11 +76,29 @@ shape_t makeaxes(const py::array &in, py::object axes)
auto dtype = arr.dtype(); \ auto dtype = arr.dtype(); \
if (dtype.is(T1)) return func<double> args; \ if (dtype.is(T1)) return func<double> args; \
if (dtype.is(T2)) return func<float> args; \ if (dtype.is(T2)) return func<float> args; \
if (dtype.is(T3)) return func<long double> args; \ if (dtype.is(T3)) return func<ldbl_t> args; \
throw runtime_error("unsupported data type"); throw runtime_error("unsupported data type");
template<typename T> T norm_fct(int inorm, size_t N)
{
if (inorm==0) return T(1);
if (inorm==2) return T(1/ldbl_t(N));
if (inorm==1) return T(1/sqrt(ldbl_t(N)));
throw invalid_argument("invalid value for inorm (must be 0, 1, or 2)");
}
template<typename T> T norm_fct(int inorm, const shape_t &shape,
const shape_t &axes)
{
if (inorm==0) return T(1);
size_t N(1);
for (auto a: axes)
N *= shape[a];
return norm_fct<T>(inorm, N);
}
template<typename T> py::array xfftn_internal(const py::array &in, template<typename T> py::array xfftn_internal(const py::array &in,
const shape_t &axes, long double fct, bool inplace, bool fwd, size_t nthreads) const shape_t &axes, int inorm, bool inplace, bool fwd, size_t nthreads)
{ {
auto dims(copy_shape(in)); auto dims(copy_shape(in));
py::array res = inplace ? in : py::array_t<complex<T>>(dims); py::array res = inplace ? in : py::array_t<complex<T>>(dims);
...@@ -86,28 +108,29 @@ template<typename T> py::array xfftn_internal(const py::array &in, ...@@ -86,28 +108,29 @@ template<typename T> py::array xfftn_internal(const py::array &in,
auto d_out=reinterpret_cast<complex<T> *>(res.mutable_data()); auto d_out=reinterpret_cast<complex<T> *>(res.mutable_data());
{ {
py::gil_scoped_release release; py::gil_scoped_release release;
c2c(dims, s_in, s_out, axes, fwd, d_in, d_out, T(fct), nthreads); T fct = norm_fct<T>(inorm, dims, axes);
c2c(dims, s_in, s_out, axes, fwd, d_in, d_out, fct, nthreads);
} }
return res; return res;
} }
py::array xfftn(const py::array &a, py::object axes, double fct, bool inplace, py::array xfftn(const py::array &a, py::object axes, int inorm,
bool fwd, size_t nthreads) bool inplace, bool fwd, size_t nthreads)
{ {
DISPATCH(a, c128, c64, c256, xfftn_internal, (a, makeaxes(a, axes), fct, DISPATCH(a, c128, c64, clong, xfftn_internal, (a, makeaxes(a, axes), inorm,
inplace, fwd, nthreads)) inplace, fwd, nthreads))
} }
py::array fftn(const py::array &a, py::object axes, double fct, bool inplace, py::array fftn(const py::array &a, py::object axes, int inorm,
size_t nthreads) bool inplace, size_t nthreads)
{ return xfftn(a, axes, fct, inplace, true, nthreads); } { return xfftn(a, axes, inorm, inplace, true, nthreads); }
py::array ifftn(const py::array &a, py::object axes, double fct, bool inplace, py::array ifftn(const py::array &a, py::object axes, int inorm,
size_t nthreads) bool inplace, size_t nthreads)
{ return xfftn(a, axes, fct, inplace, false, nthreads); } { return xfftn(a, axes, inorm, inplace, false, nthreads); }
template<typename T> py::array rfftn_internal(const py::array &in, template<typename T> py::array rfftn_internal(const py::array &in,
py::object axes_, long double fct, size_t nthreads) py::object axes_, int inorm, size_t nthreads)
{ {
auto axes = makeaxes(in, axes_); auto axes = makeaxes(in, axes_);
auto dims_in(copy_shape(in)), dims_out(dims_in); auto dims_in(copy_shape(in)), dims_out(dims_in);
...@@ -119,19 +142,20 @@ template<typename T> py::array rfftn_internal(const py::array &in, ...@@ -119,19 +142,20 @@ template<typename T> py::array rfftn_internal(const py::array &in,
auto d_out=reinterpret_cast<complex<T> *>(res.mutable_data()); auto d_out=reinterpret_cast<complex<T> *>(res.mutable_data());
{ {
py::gil_scoped_release release; py::gil_scoped_release release;
r2c(dims_in, s_in, s_out, axes, d_in, d_out, T(fct), nthreads); T fct = norm_fct<T>(inorm, dims_in, axes);
r2c(dims_in, s_in, s_out, axes, d_in, d_out, fct, nthreads);
} }
return res; return res;
} }
py::array rfftn(const py::array &in, py::object axes_, double fct, py::array rfftn(const py::array &in, py::object axes_, int inorm,
size_t nthreads) size_t nthreads)
{ {
DISPATCH(in, f64, f32, f128, rfftn_internal, (in, axes_, fct, nthreads)) DISPATCH(in, f64, f32, flong, rfftn_internal, (in, axes_, inorm, nthreads))
} }
template<typename T> py::array xrfft_scipy(const py::array &in, template<typename T> py::array xrfft_scipy(const py::array &in,
size_t axis, long double fct, bool inplace, bool fwd, size_t nthreads) size_t axis, int inorm, bool inplace, bool fwd, size_t nthreads)
{ {
auto dims(copy_shape(in)); auto dims(copy_shape(in));
py::array res = inplace ? in : py::array_t<T>(dims); py::array res = inplace ? in : py::array_t<T>(dims);
...@@ -141,26 +165,27 @@ template<typename T> py::array xrfft_scipy(const py::array &in, ...@@ -141,26 +165,27 @@ template<typename T> py::array xrfft_scipy(const py::array &in,
auto d_out=reinterpret_cast<T *>(res.mutable_data()); auto d_out=reinterpret_cast<T *>(res.mutable_data());
{ {
py::gil_scoped_release release; py::gil_scoped_release release;
r2r_fftpack(dims, s_in, s_out, axis, fwd, d_in, d_out, T(fct), nthreads); T fct = norm_fct<T>(inorm, dims[axis]);
r2r_fftpack(dims, s_in, s_out, axis, fwd, d_in, d_out, fct, nthreads);
} }
return res; return res;
} }
py::array rfft_scipy(const py::array &in, size_t axis, double fct, bool inplace, py::array rfft_scipy(const py::array &in, size_t axis, int inorm,
size_t nthreads) bool inplace, size_t nthreads)
{ {
DISPATCH(in, f64, f32, f128, xrfft_scipy, (in, axis, fct, inplace, true, DISPATCH(in, f64, f32, flong, xrfft_scipy, (in, axis, inorm, inplace, true,
nthreads)) nthreads))
} }
py::array irfft_scipy(const py::array &in, size_t axis, double fct, py::array irfft_scipy(const py::array &in, size_t axis, int inorm,
bool inplace, size_t nthreads) bool inplace, size_t nthreads)
{ {
DISPATCH(in, f64, f32, f128, xrfft_scipy, (in, axis, fct, inplace, false, DISPATCH(in, f64, f32, flong, xrfft_scipy, (in, axis, inorm, inplace, false,
nthreads)) nthreads))
} }
template<typename T> py::array irfftn_internal(const py::array &in, template<typename T> py::array irfftn_internal(const py::array &in,
py::object axes_, size_t lastsize, long double fct, size_t nthreads) py::object axes_, size_t lastsize, int inorm, size_t nthreads)
{ {
auto axes = makeaxes(in, axes_); auto axes = makeaxes(in, axes_);
size_t axis = axes.back(); size_t axis = axes.back();
...@@ -176,20 +201,21 @@ template<typename T> py::array irfftn_internal(const py::array &in, ...@@ -176,20 +201,21 @@ template<typename T> py::array irfftn_internal(const py::array &in,
auto d_out=reinterpret_cast<T *>(res.mutable_data()); auto d_out=reinterpret_cast<T *>(res.mutable_data());
{ {
py::gil_scoped_release release; py::gil_scoped_release release;
c2r(dims_out, s_in, s_out, axes, d_in, d_out, T(fct), nthreads); T fct = norm_fct<T>(inorm, dims_out, axes);
c2r(dims_out, s_in, s_out, axes, d_in, d_out, fct, nthreads);
} }
return res; return res;
} }
py::array irfftn(const py::array &in, py::object axes_, size_t lastsize, py::array irfftn(const py::array &in, py::object axes_, size_t lastsize,
double fct, size_t nthreads) int inorm, size_t nthreads)
{ {
DISPATCH(in, c128, c64, c256, irfftn_internal, (in, axes_, lastsize, fct, DISPATCH(in, c128, c64, clong, irfftn_internal, (in, axes_, lastsize, inorm,
nthreads)) nthreads))
} }
template<typename T> py::array hartley_internal(const py::array &in, template<typename T> py::array hartley_internal(const py::array &in,
py::object axes_, long double fct, bool inplace, size_t nthreads) py::object axes_, int inorm, bool inplace, size_t nthreads)
{ {
auto dims(copy_shape(in)); auto dims(copy_shape(in));
py::array res = inplace ? in : py::array_t<T>(dims); py::array res = inplace ? in : py::array_t<T>(dims);
...@@ -200,15 +226,16 @@ template<typename T> py::array hartley_internal(const py::array &in, ...@@ -200,15 +226,16 @@ template<typename T> py::array hartley_internal(const py::array &in,
auto d_out=reinterpret_cast<T *>(res.mutable_data()); auto d_out=reinterpret_cast<T *>(res.mutable_data());
{ {
py::gil_scoped_release release; py::gil_scoped_release release;
r2r_hartley(dims, s_in, s_out, axes, d_in, d_out, T(fct), nthreads); T fct = norm_fct<T>(inorm, dims, axes);
r2r_hartley(dims, s_in, s_out, axes, d_in, d_out, fct, nthreads);
} }
return res; return res;
} }
py::array hartley(const py::array &in, py::object axes_, double fct, py::array hartley(const py::array &in, py::object axes_, int inorm,
bool inplace, size_t nthreads) bool inplace, size_t nthreads)
{ {
DISPATCH(in, f64, f32, f128, hartley_internal, (in, axes_, fct, inplace, DISPATCH(in, f64, f32, flong, hartley_internal, (in, axes_, inorm, inplace,
nthreads)) nthreads))
} }
...@@ -261,13 +288,13 @@ template<typename T>py::array complex2hartley(const py::array &in, ...@@ -261,13 +288,13 @@ template<typename T>py::array complex2hartley(const py::array &in,
py::array mycomplex2hartley(const py::array &in, py::array mycomplex2hartley(const py::array &in,
const py::array &tmp, py::object axes_, bool inplace) const py::array &tmp, py::object axes_, bool inplace)
{ {
DISPATCH(in, f64, f32, f128, complex2hartley, (in, tmp, axes_, inplace)) DISPATCH(in, f64, f32, flong, complex2hartley, (in, tmp, axes_, inplace))
} }
py::array hartley2(const py::array &in, py::object axes_, double fct, py::array hartley2(const py::array &in, py::object axes_, int inorm,
bool inplace, size_t nthreads) bool inplace, size_t nthreads)
{ {
return mycomplex2hartley(in, rfftn(in, axes_, fct, nthreads), axes_, return mycomplex2hartley(in, rfftn(in, axes_, inorm, nthreads), axes_,
inplace); inplace);
} }
...@@ -293,8 +320,12 @@ a : numpy.ndarray (np.complex64 or np.complex128) ...@@ -293,8 +320,12 @@ a : numpy.ndarray (np.complex64 or np.complex128)
axes : list of integers axes : list of integers
The axes along which the FFT is carried out. The axes along which the FFT is carried out.
If not set, all axes will be transformed. If not set, all axes will be transformed.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the product of the lengths of the transformed axes.
inplace : bool inplace : bool
if False, returns the result in a new array and leaves the input unchanged. if False, returns the result in a new array and leaves the input unchanged.
if True, stores the result in the input array and returns a handle to it. if True, stores the result in the input array and returns a handle to it.
...@@ -317,8 +348,12 @@ a : numpy.ndarray (np.complex64 or np.complex128) ...@@ -317,8 +348,12 @@ a : numpy.ndarray (np.complex64 or np.complex128)
axes : list of integers axes : list of integers
The axes along which the FFT is carried out. The axes along which the FFT is carried out.
If not set, all axes will be transformed. If not set, all axes will be transformed.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the product of the lengths of the transformed axes.
inplace : bool inplace : bool
if False, returns the result in a new array and leaves the input unchanged. if False, returns the result in a new array and leaves the input unchanged.
if True, stores the result in the input array and returns a handle to it. if True, stores the result in the input array and returns a handle to it.
...@@ -341,8 +376,12 @@ a : numpy.ndarray (np.float32 or np.float64) ...@@ -341,8 +376,12 @@ a : numpy.ndarray (np.float32 or np.float64)
axes : list of integers axes : list of integers
The axes along which the FFT is carried out. The axes along which the FFT is carried out.
If not set, all axes will be transformed in ascending order. If not set, all axes will be transformed in ascending order.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the product of the lengths of the transformed input axes.
nthreads : int nthreads : int
Number of threads to use. If 0, use the system default (typically governed Number of threads to use. If 0, use the system default (typically governed
by the `OMP_NUM_THREADS` environment variable). by the `OMP_NUM_THREADS` environment variable).
...@@ -363,8 +402,12 @@ a : numpy.ndarray (np.float32 or np.float64) ...@@ -363,8 +402,12 @@ a : numpy.ndarray (np.float32 or np.float64)
The input data The input data
axis : int axis : int
The axis along which the FFT is carried out. The axis along which the FFT is carried out.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the length of `axis`.
inplace : bool inplace : bool
if False, returns the result in a new array and leaves the input unchanged. if False, returns the result in a new array and leaves the input unchanged.
if True, stores the result in the input array and returns a handle to it. if True, stores the result in the input array and returns a handle to it.
...@@ -391,8 +434,12 @@ axes : list of integers ...@@ -391,8 +434,12 @@ axes : list of integers
If not set, all axes will be transformed in ascending order. If not set, all axes will be transformed in ascending order.
lastsize : the output size of the last axis to be transformed. lastsize : the output size of the last axis to be transformed.
If the corresponding input axis has size n, this can be 2*n-2 or 2*n-1. If the corresponding input axis has size n, this can be 2*n-2 or 2*n-1.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the product of the lengths of the transformed output axes.
nthreads : int nthreads : int
Number of threads to use. If 0, use the system default (typically governed Number of threads to use. If 0, use the system default (typically governed
by the `OMP_NUM_THREADS` environment variable). by the `OMP_NUM_THREADS` environment variable).
...@@ -414,8 +461,12 @@ a : numpy.ndarray (np.float32 or np.float64) ...@@ -414,8 +461,12 @@ a : numpy.ndarray (np.float32 or np.float64)
FFTPACK half-complex order, i.e. `a[0].re, a[1].re, a[1].im, a[2].re ...`. FFTPACK half-complex order, i.e. `a[0].re, a[1].re, a[1].im, a[2].re ...`.
axis : int axis : int
The axis along which the FFT is carried out. The axis along which the FFT is carried out.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the length of `axis`.
inplace : bool inplace : bool
if False, returns the result in a new array and leaves the input unchanged. if False, returns the result in a new array and leaves the input unchanged.
if True, stores the result in the input array and returns a handle to it. if True, stores the result in the input array and returns a handle to it.
...@@ -441,8 +492,12 @@ a : numpy.ndarray (np.float32 or np.float64) ...@@ -441,8 +492,12 @@ a : numpy.ndarray (np.float32 or np.float64)
axes : list of integers axes : list of integers
The axes along which the transform is carried out. The axes along which the transform is carried out.
If not set, all axes will be transformed. If not set, all axes will be transformed.
fct : float inorm : int
Normalization factor Normalization type
0 : no normalization
1 : divide by sqrt(N)
2 : divide by N
where N is the product of the lengths of the transformed axes.
inplace : bool inplace : bool
if False, returns the result in a new array and leaves the input unchanged. if False, returns the result in a new array and leaves the input unchanged.
if True, stores the result in the input array and returns a handle to it. if True, stores the result in the input array and returns a handle to it.
...@@ -463,21 +518,21 @@ PYBIND11_MODULE(pypocketfft, m) ...@@ -463,21 +518,21 @@ PYBIND11_MODULE(pypocketfft, m)
using namespace pybind11::literals; using namespace pybind11::literals;
m.doc() = pypocketfft_DS; m.doc() = pypocketfft_DS;
m.def("fftn",&fftn, fftn_DS, "a"_a, "axes"_a=py::none(), "fct"_a=1., m.def("fftn",&fftn, fftn_DS, "a"_a, "axes"_a=py::none(), "inorm"_a=0,
"inplace"_a=false, "nthreads"_a=1); "inplace"_a=false, "nthreads"_a=1);
m.def("ifftn",&ifftn, ifftn_DS, "a"_a, "axes"_a=py::none(), "fct"_a=1., m.def("ifftn",&ifftn, ifftn_DS, "a"_a, "axes"_a=py::none(), "inorm"_a=0,
"inplace"_a=false, "nthreads"_a=1); "inplace"_a=false, "nthreads"_a=1);
m.def("rfftn",&rfftn, rfftn_DS, "a"_a, "axes"_a=py::none(), "fct"_a=1., m.def("rfftn",&rfftn, rfftn_DS, "a"_a, "axes"_a=py::none(), "inorm"_a=0,
"nthreads"_a=1); "nthreads"_a=1);
m.def("rfft_scipy",&rfft_scipy, rfft_scipy_DS, "a"_a, "axis"_a, "fct"_a=1., m.def("rfft_scipy",&rfft_scipy, rfft_scipy_DS, "a"_a, "axis"_a, "inorm"_a=0,
"inplace"_a=false, "nthreads"_a=1); "inplace"_a=false, "nthreads"_a=1);
m.def("irfftn",&irfftn, irfftn_DS, "a"_a, "axes"_a=py::none(), "lastsize"_a=0, m.def("irfftn",&irfftn, irfftn_DS, "a"_a, "axes"_a=py::none(), "lastsize"_a=0,
"fct"_a=1., "nthreads"_a=1); "inorm"_a=0, "nthreads"_a=1);
m.def("irfft_scipy",&irfft_scipy, irfft_scipy_DS, "a"_a, "axis"_a, "fct"_a=1., m.def("irfft_scipy",&irfft_scipy, irfft_scipy_DS, "a"_a, "axis"_a,
"inplace"_a=false, "nthreads"_a=1); "inorm"_a=0, "inplace"_a=false, "nthreads"_a=1);
m.def("hartley",&hartley, hartley_DS, "a"_a, "axes"_a=py::none(), "fct"_a=1., m.def("hartley",&hartley, hartley_DS, "a"_a, "axes"_a=py::none(), "inorm"_a=0,
"inplace"_a=false, "nthreads"_a=1); "inplace"_a=false, "nthreads"_a=1);
m.def("hartley2",&hartley2, "a"_a, "axes"_a=py::none(), "fct"_a=1., m.def("hartley2",&hartley2, "a"_a, "axes"_a=py::none(), "inorm"_a=0,
"inplace"_a=false, "nthreads"_a=1); "inplace"_a=false, "nthreads"_a=1);
m.def("complex2hartley",&mycomplex2hartley, "in"_a, "tmp"_a, "axes"_a, m.def("complex2hartley",&mycomplex2hartley, "in"_a, "tmp"_a, "axes"_a,
"inplace"_a=false); "inplace"_a=false);
......
...@@ -21,34 +21,33 @@ def test(): ...@@ -21,34 +21,33 @@ def test():
nax = np.random.randint(1,ndim+1) nax = np.random.randint(1,ndim+1)
axes = axes[:nax] axes = axes[:nax]
lastsize = shape[axes[-1]] lastsize = shape[axes[-1]]
fct = 1./np.prod(np.take(shape, axes))
a=np.random.rand(*shape)-0.5 + 1j*np.random.rand(*shape)-0.5j a=np.random.rand(*shape)-0.5 + 1j*np.random.rand(*shape)-0.5j
b=pypocketfft.ifftn(pypocketfft.fftn(a,axes=axes,nthreads=nthreads),axes=axes,fct=fct,nthreads=nthreads) b=pypocketfft.ifftn(pypocketfft.fftn(a,axes=axes,nthreads=nthreads),axes=axes,inorm=2,nthreads=nthreads)
err = _l2error(a,b) err = _l2error(a,b)
if err > cmaxerr: if err > cmaxerr:
cmaxerr = err cmaxerr = err
print("cmaxerr:", cmaxerr, shape, axes) print("cmaxerr:", cmaxerr, shape, axes)
b=pypocketfft.irfftn(pypocketfft.rfftn(a.real,axes=axes,nthreads=nthreads),axes=axes,fct=fct,lastsize=lastsize,nthreads=nthreads) b=pypocketfft.irfftn(pypocketfft.rfftn(a.real,axes=axes,nthreads=nthreads),axes=axes,inorm=2,lastsize=lastsize,nthreads=nthreads)
err = _l2error(a.real,b) err = _l2error(a.real,b)