[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