[arrayfire] 184/408: FEAT / TEST: Adding support for inplace fft
Ghislain Vaillant
ghisvail-guest at moszumanska.debian.org
Mon Sep 21 19:11:53 UTC 2015
This is an automated email from the git hooks/post-receive script.
ghisvail-guest pushed a commit to branch debian/sid
in repository arrayfire.
commit 61968d6faaa95a8465338ec213080b6904ebe3a4
Author: Pavan Yalamanchili <pavan at arrayfire.com>
Date: Tue Aug 4 16:34:44 2015 -0400
FEAT / TEST: Adding support for inplace fft
---
include/af/signal.h | 163 +++++++++++++++++++++++++++++++++++++++++++-
src/api/c/fft.cpp | 62 +++++++++++++++++
src/api/cpp/fft.cpp | 36 ++++++++++
src/backend/cpu/copy.cpp | 25 +++++++
src/backend/cpu/copy.hpp | 3 +
src/backend/cuda/copy.cu | 7 ++
src/backend/cuda/copy.hpp | 3 +
src/backend/opencl/copy.cpp | 7 ++
src/backend/opencl/copy.hpp | 3 +
test/fft.cpp | 102 +++++++++++++++++++++++++++
10 files changed, 410 insertions(+), 1 deletion(-)
diff --git a/include/af/signal.h b/include/af/signal.h
index eb9fb94..8ddf71f 100644
--- a/include/af/signal.h
+++ b/include/af/signal.h
@@ -76,7 +76,7 @@ AFAPI array fft2Norm(const array& in, const double norm_factor, const dim_t odim
/**
C++ Interface for fast fourier transform on three dimensional data
- \param[in] in is the input array
+ \param[in] in is the input array and the output of 1D fourier transform on exit
\param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
\param[in] odim0 is the length of output data along first dimension - used to either truncate/pad the input
\param[in] odim1 is the length of output data along second dimension - used to either truncate/pad the input
@@ -90,6 +90,44 @@ AFAPI array fft3Norm(const array& in, const double norm_factor, const dim_t odim
/**
C++ Interface for fast fourier transform on one dimensional data
+ \param[inout] in is the input array on entry and the output of 1D forward fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_fft
+ */
+AFAPI void fftInPlace(const array& in, const double norm_factor = 1);
+
+/**
+ C++ Interface for fast fourier transform on two dimensional data
+
+ \param[inout] in is the input array on entry and the output of 2D forward fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return the transformed array
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_fft2
+ */
+AFAPI void fft2InPlace(const array& in, const double norm_factor = 1);
+
+/**
+ C++ Interface for fast fourier transform on three dimensional data
+
+ \param[inout] in is the input array on entry and the output of 3D forward fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return the transformed array
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_fft3
+ */
+AFAPI void fft3InPlace(const array& in, const double norm_factor = 1);
+
+/**
+ C++ Interface for fast fourier transform on one dimensional data
+
This version of fft function uses a default norm_factor parameter that is calculated internally
based on the input data.
@@ -211,6 +249,44 @@ AFAPI array ifft2Norm(const array& in, const double norm_factor, const dim_t odi
AFAPI array ifft3Norm(const array& in, const double norm_factor, const dim_t odim0=0, const dim_t odim1=0, const dim_t odim2=0);
/**
+ C++ Interface for fast fourier transform on one dimensional data
+
+ \param[inout] in is the input array on entry and the output of 1D inverse fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_ifft
+ */
+AFAPI void ifftInPlace(const array& in, const double norm_factor = 1);
+
+/**
+ C++ Interface for fast fourier transform on two dimensional data
+
+ \param[inout] in is the input array on entry and the output of 2D inverse fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return the transformed array
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_ifft2
+ */
+AFAPI void ifft2InPlace(const array& in, const double norm_factor = 1);
+
+/**
+ C++ Interface for fast fourier transform on three dimensional data
+
+ \param[inout] in is the input array on entry and the output of 3D inverse fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return the transformed array
+
+ \note The input \p in must be complex
+
+ \ingroup signal_func_ifft3
+ */
+AFAPI void ifft3InPlace(const array& in, const double norm_factor = 1);
+
+/**
C++ Interface for inverse fast fourier transform on one dimensional data
This version of fft function uses a default norm_factor parameter that is calculated internally
@@ -518,6 +594,20 @@ AFAPI af_err af_approx2(af_array *out, const af_array in, const af_array pos0, c
AFAPI af_err af_fft(af_array *out, const af_array in, const double norm_factor, const dim_t odim0);
/**
+ C Interface for fast fourier transform on one dimensional data
+
+ \param[inout] in is the input array on entry and the output of 1D forward fourier transform at exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the fft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p in must be a complex array
+
+ \ingroup signal_func_fft
+*/
+AFAPI af_err af_fft_inplace(af_array in, const double norm_factor);
+
+/**
C Interface for fast fourier transform on two dimensional data
\param[out] out is the transformed array
@@ -533,6 +623,20 @@ AFAPI af_err af_fft(af_array *out, const af_array in, const double norm_factor,
AFAPI af_err af_fft2(af_array *out, const af_array in, const double norm_factor, const dim_t odim0, const dim_t odim1);
/**
+ C Interface for fast fourier transform on two dimensional data
+
+ \param[inout] in is the input array on entry and the output of 2D forward fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the fft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p in must be a complex array
+
+ \ingroup signal_func_fft2
+ */
+AFAPI af_err af_fft2_inplace(af_array in, const double norm_factor);
+
+/**
C Interface for fast fourier transform on three dimensional data
\param[out] out is the transformed array
@@ -549,6 +653,20 @@ AFAPI af_err af_fft2(af_array *out, const af_array in, const double norm_factor,
AFAPI af_err af_fft3(af_array *out, const af_array in, const double norm_factor, const dim_t odim0, const dim_t odim1, const dim_t odim2);
/**
+ C Interface for fast fourier transform on three dimensional data
+
+ \param[inout] in is the input array on entry and the output of 3D forward fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the fft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p must be a complex array
+
+ \ingroup signal_func_fft3
+ */
+AFAPI af_err af_fft3_inplace(af_array in, const double norm_factor);
+
+/**
C Interface for inverse fast fourier transform on one dimensional data
\param[out] out is the transformed array
@@ -563,6 +681,20 @@ AFAPI af_err af_fft3(af_array *out, const af_array in, const double norm_factor,
AFAPI af_err af_ifft(af_array *out, const af_array in, const double norm_factor, const dim_t odim0);
/**
+ C Interface for fast fourier transform on one dimensional data
+
+ \param[inout] in is the input array on entry and the output of 1D inverse fourier transform at exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the ifft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p in must be a complex array
+
+ \ingroup signal_func_ifft
+*/
+AFAPI af_err af_ifft_inplace(af_array in, const double norm_factor);
+
+/**
C Interface for inverse fast fourier transform on two dimensional data
\param[out] out is the transformed array
@@ -578,6 +710,20 @@ AFAPI af_err af_ifft(af_array *out, const af_array in, const double norm_factor,
AFAPI af_err af_ifft2(af_array *out, const af_array in, const double norm_factor, const dim_t odim0, const dim_t odim1);
/**
+ C Interface for fast fourier transform on two dimensional data
+
+ \param[inout] in is the input array on entry and the output of 2D inverse fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the ifft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p in must be a complex array
+
+ \ingroup signal_func_ifft2
+*/
+AFAPI af_err af_ifft2_inplace(af_array in, const double norm_factor);
+
+/**
C Interface for inverse fast fourier transform on three dimensional data
\param[out] out is the transformed array
@@ -594,6 +740,21 @@ AFAPI af_err af_ifft2(af_array *out, const af_array in, const double norm_factor
AFAPI af_err af_ifft3(af_array *out, const af_array in, const double norm_factor, const dim_t odim0, const dim_t odim1, const dim_t odim2);
/**
+ C Interface for fast fourier transform on three dimensional data
+
+ \param[inout] in is the input array on entry and the output of 3D inverse fourier transform on exit
+ \param[in] norm_factor is the normalization factor with which the input is scaled before the transformation is applied
+ \return \ref AF_SUCCESS if the ifft transform is successful,
+ otherwise an appropriate error code is returned.
+
+ \note The input \p must be a complex array
+
+ \ingroup signal_func_ifft3
+*/
+AFAPI af_err af_ifft3_inplace(af_array in, const double norm_factor);
+
+
+/**
C Interface for convolution on one dimensional data
\param[out] out is convolved array
diff --git a/src/api/c/fft.cpp b/src/api/c/fft.cpp
index e7f361f..9a2a4d0 100644
--- a/src/api/c/fft.cpp
+++ b/src/api/c/fft.cpp
@@ -14,6 +14,7 @@
#include <err_common.hpp>
#include <backend.hpp>
#include <fft.hpp>
+#include <copy.hpp>
using af::dim4;
using namespace detail;
@@ -113,3 +114,64 @@ af_err af_ifft3(af_array *out, const af_array in, const double norm_factor, cons
const dim_t pad[3] = {pad0, pad1, pad2};
return ifft<3>(out, in, norm_factor, (pad0>0&&pad1>0&&pad2>0?3:0), pad);
}
+
+template<typename T, int rank, bool direction>
+static void fft_inplace(const af_array in, const double norm_factor)
+{
+ Array<T> &input = getWritableArray<T>(in);
+ fft_inplace<T, rank, direction>(input);
+ if (norm_factor != 1) {
+ multiply_inplace<T>(input, norm_factor);
+ }
+}
+
+template<int rank, bool direction>
+static af_err fft_inplace(af_array in, const double norm_factor)
+{
+ try {
+ ArrayInfo info = getInfo(in);
+ af_dtype type = info.getType();
+ af::dim4 dims = info.dims();
+
+ DIM_ASSERT(1, (dims.ndims()>=rank));
+
+ switch(type) {
+ case c32: fft_inplace<cfloat , rank, direction>(in, norm_factor); break;
+ case c64: fft_inplace<cdouble, rank, direction>(in, norm_factor); break;
+ default: TYPE_ERROR(1, type);
+ }
+ }
+ CATCHALL;
+
+ return AF_SUCCESS;
+}
+
+af_err af_fft_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<1, true>(in, norm_factor);
+}
+
+af_err af_fft2_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<2, true>(in, norm_factor);
+}
+
+af_err af_fft3_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<3, true>(in, norm_factor);
+}
+
+af_err af_ifft_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<1, false>(in, norm_factor);
+}
+
+af_err af_ifft2_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<2, false>(in, norm_factor);
+}
+
+af_err af_ifft3_inplace(af_array in, const double norm_factor)
+{
+ return fft_inplace<3, false>(in, norm_factor);
+}
diff --git a/src/api/cpp/fft.cpp b/src/api/cpp/fft.cpp
index dbc4406..6d8c3c9 100644
--- a/src/api/cpp/fft.cpp
+++ b/src/api/cpp/fft.cpp
@@ -144,4 +144,40 @@ array idft(const array& in)
return idft(in, 1.0, dim4(0,0,0,0));
}
+void fftInPlace(const array& in, const double norm_factor)
+{
+ AF_THROW(af_fft_inplace(in.get(), norm_factor));
+}
+
+void fft2InPlace(const array& in, const double norm_factor)
+{
+ AF_THROW(af_fft2_inplace(in.get(), norm_factor));
+}
+
+void fft3InPlace(const array& in, const double norm_factor)
+{
+ AF_THROW(af_fft3_inplace(in.get(), norm_factor));
+}
+
+void ifftInPlace(const array& in, const double norm_factor)
+{
+ const dim4 dims = in.dims();
+ double norm = norm_factor *(1.0 / dims[0]);
+ AF_THROW(af_ifft_inplace(in.get(), norm));
+}
+
+void ifft2InPlace(const array& in, const double norm_factor)
+{
+ const dim4 dims = in.dims();
+ double norm = norm_factor *(1.0 / (dims[0] * dims[1]));
+ AF_THROW(af_ifft2_inplace(in.get(), norm));
+}
+
+void ifft3InPlace(const array& in, const double norm_factor)
+{
+ const dim4 dims = in.dims();
+ double norm = norm_factor *(1.0 / (dims[0] * dims[1] * dims[2]));
+ AF_THROW(af_ifft3_inplace(in.get(), norm));
+}
+
}
diff --git a/src/backend/cpu/copy.cpp b/src/backend/cpu/copy.cpp
index eb50e79..1900145 100644
--- a/src/backend/cpu/copy.cpp
+++ b/src/backend/cpu/copy.cpp
@@ -63,6 +63,30 @@ namespace cpu
return out;
}
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val)
+ {
+ dim4 idims = in.dims();
+ dim4 istrides = in.strides();
+ T *iptr = in.get();
+
+ for (dim_t l = 0; l < idims[3]; l++) {
+ dim_t off3 = l * istrides[3];
+
+ for (dim_t k = 0; k < idims[2]; k++) {
+ dim_t off2 = off3 + k * istrides[2];
+
+ for (dim_t j = 0; j < idims[1]; j++) {
+ dim_t off1 = off2 + j * istrides[1];
+
+ for (dim_t i = 0; i < idims[0]; i++) {
+ iptr[off1 + i] *= val;
+ }
+ }
+ }
+ }
+ }
+
template<typename inType, typename outType>
static void copy(Array<outType> &dst, const Array<inType> &src, outType default_value, double factor)
{
@@ -132,6 +156,7 @@ namespace cpu
#define INSTANTIATE(T) \
template void copyData<T> (T *data, const Array<T> &from); \
template Array<T> copyArray<T>(const Array<T> &A); \
+ template void multiply_inplace<T> (Array<T> &in, double norm); \
INSTANTIATE(float )
INSTANTIATE(double )
diff --git a/src/backend/cpu/copy.hpp b/src/backend/cpu/copy.hpp
index 4178461..e9b91f6 100644
--- a/src/backend/cpu/copy.hpp
+++ b/src/backend/cpu/copy.hpp
@@ -26,4 +26,7 @@ namespace cpu
template<typename inType, typename outType>
Array<outType> padArray(Array<inType> const &in, dim4 const &dims,
outType default_value=outType(0), double factor=1.0);
+
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val);
}
diff --git a/src/backend/cuda/copy.cu b/src/backend/cuda/copy.cu
index c58b1cb..0358bfa 100644
--- a/src/backend/cuda/copy.cu
+++ b/src/backend/cuda/copy.cu
@@ -73,6 +73,12 @@ namespace cuda
return ret;
}
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val)
+ {
+ kernel::copy<T, T>(in, in, in.ndims(), scalar<T>(0), val);
+ }
+
template<typename inType, typename outType>
struct copyWrapper {
void operator()(Array<outType> &out, Array<inType> const &in)
@@ -109,6 +115,7 @@ namespace cuda
#define INSTANTIATE(T) \
template void copyData<T> (T *data, const Array<T> &from); \
template Array<T> copyArray<T>(const Array<T> &A); \
+ template void multiply_inplace<T> (Array<T> &in, double norm); \
INSTANTIATE(float)
INSTANTIATE(double)
diff --git a/src/backend/cuda/copy.hpp b/src/backend/cuda/copy.hpp
index 02e672a..f71504a 100644
--- a/src/backend/cuda/copy.hpp
+++ b/src/backend/cuda/copy.hpp
@@ -26,4 +26,7 @@ namespace cuda
template<typename inType, typename outType>
Array<outType> padArray(Array<inType> const &in, dim4 const &dims,
outType default_value, double factor=1.0);
+
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val);
}
diff --git a/src/backend/opencl/copy.cpp b/src/backend/opencl/copy.cpp
index 37b33df..370b072 100644
--- a/src/backend/opencl/copy.cpp
+++ b/src/backend/opencl/copy.cpp
@@ -79,6 +79,12 @@ namespace opencl
return ret;
}
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val)
+ {
+ kernel::copy<T, T, true>(in, in, in.ndims(), scalar<T>(0), val);
+ }
+
template<typename inType, typename outType>
struct copyWrapper {
void operator()(Array<outType> &out, Array<inType> const &in)
@@ -123,6 +129,7 @@ namespace opencl
#define INSTANTIATE(T) \
template void copyData<T> (T *data, const Array<T> &from); \
template Array<T> copyArray<T>(const Array<T> &A); \
+ template void multiply_inplace<T> (Array<T> &in, double norm); \
INSTANTIATE(float)
INSTANTIATE(double)
diff --git a/src/backend/opencl/copy.hpp b/src/backend/opencl/copy.hpp
index 3ad0d0a..818cfa4 100644
--- a/src/backend/opencl/copy.hpp
+++ b/src/backend/opencl/copy.hpp
@@ -26,4 +26,7 @@ namespace opencl
template<typename inType, typename outType>
Array<outType> padArray(Array<inType> const &in, dim4 const &dims,
outType default_value, double factor=1.0);
+
+ template<typename T>
+ void multiply_inplace(Array<T> &in, double val);
}
diff --git a/test/fft.cpp b/test/fft.cpp
index c2e5fcb..84f0e23 100644
--- a/test/fft.cpp
+++ b/test/fft.cpp
@@ -580,3 +580,105 @@ TEST(fft3, GFOR)
delete[] h_b;
delete[] h_c;
}
+
+TEST(fft, InPlace)
+{
+ af::array a = af::randu(1024, 1024, c32);
+ af::array b = af::fft(a);
+ af::fftInPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
+
+TEST(ifft, InPlace)
+{
+ af::array a = af::randu(1024, 1024, c32);
+ af::array b = af::ifft(a);
+ af::ifftInPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
+
+TEST(fft2, InPlace)
+{
+ af::array a = af::randu(1024, 1024, c32);
+ af::array b = af::fft2(a);
+ af::fft2InPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
+
+TEST(ifft2, InPlace)
+{
+ af::array a = af::randu(1024, 1024, c32);
+ af::array b = af::ifft2(a);
+ af::ifft2InPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
+
+TEST(fft3, InPlace)
+{
+ af::array a = af::randu(32, 32, 32, c32);
+ af::array b = af::fft3(a);
+ af::fft3InPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
+
+TEST(ifft3, InPlace)
+{
+ af::array a = af::randu(32, 32, 32, c32);
+ af::array b = af::ifft3(a);
+ af::ifft3InPlace(a);
+
+ std::vector<af::cfloat> ha(a.elements());
+ std::vector<af::cfloat> hb(b.elements());
+
+ a.host(&ha[0]);
+ b.host(&hb[0]);
+
+ for (int i = 0; i < (int)a.elements(); i++) {
+ ASSERT_EQ(ha[i], hb[i]);
+ }
+}
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-science/packages/arrayfire.git
More information about the debian-science-commits
mailing list