/*******************************************************
* Copyright (c) 2014, ArrayFire
* All rights reserved.
*
* This file is distributed under 3-clause BSD license.
* The complete license agreement can be obtained at:
* http://arrayfire.com/licenses/BSD-3-Clause
********************************************************/
#include
#include
#include
#include "error.hpp"
using af::array;
using af::dim4;
namespace af {
array fftNorm(const array& in, const double norm_factor, const dim_t odim0) {
af_array out = 0;
AF_THROW(af_fft(&out, in.get(), norm_factor, odim0));
return array(out);
}
array fft2Norm(const array& in, const double norm_factor, const dim_t odim0,
const dim_t odim1) {
af_array out = 0;
AF_THROW(af_fft2(&out, in.get(), norm_factor, odim0, odim1));
return array(out);
}
array fft3Norm(const array& in, const double norm_factor, const dim_t odim0,
const dim_t odim1, const dim_t odim2) {
af_array out = 0;
AF_THROW(af_fft3(&out, in.get(), norm_factor, odim0, odim1, odim2));
return array(out);
}
array fft(const array& in, const dim_t odim0) {
return fftNorm(in, 1.0, odim0);
}
array fft2(const array& in, const dim_t odim0, const dim_t odim1) {
return fft2Norm(in, 1.0, odim0, odim1);
}
array fft3(const array& in, const dim_t odim0, const dim_t odim1,
const dim_t odim2) {
return fft3Norm(in, 1.0, odim0, odim1, odim2);
}
// NOLINTNEXTLINE(performance-unnecessary-value-param)
array dft(const array& in, const double norm_factor, const dim4 outDims) {
array temp;
switch (in.dims().ndims()) {
case 1: temp = fftNorm(in, norm_factor, outDims[0]); break;
case 2: temp = fft2Norm(in, norm_factor, outDims[0], outDims[1]); break;
case 3:
temp =
fft3Norm(in, norm_factor, outDims[0], outDims[1], outDims[2]);
break;
default: AF_THROW(AF_ERR_NOT_SUPPORTED);
}
return temp;
}
// NOLINTNEXTLINE(performance-unnecessary-value-param)
array dft(const array& in, const dim4 outDims) { return dft(in, 1.0, outDims); }
array dft(const array& in) { return dft(in, 1.0, dim4(0, 0, 0, 0)); }
array ifftNorm(const array& in, const double norm_factor, const dim_t odim0) {
af_array out = 0;
AF_THROW(af_ifft(&out, in.get(), norm_factor, odim0));
return array(out);
}
array ifft2Norm(const array& in, const double norm_factor, const dim_t odim0,
const dim_t odim1) {
af_array out = 0;
AF_THROW(af_ifft2(&out, in.get(), norm_factor, odim0, odim1));
return array(out);
}
array ifft3Norm(const array& in, const double norm_factor, const dim_t odim0,
const dim_t odim1, const dim_t odim2) {
af_array out = 0;
AF_THROW(af_ifft3(&out, in.get(), norm_factor, odim0, odim1, odim2));
return array(out);
}
array ifft(const array& in, const dim_t odim0) {
const dim4 dims = in.dims();
dim_t dim0 = odim0 == 0 ? dims[0] : odim0;
double norm_factor = 1.0 / static_cast(dim0);
return ifftNorm(in, norm_factor, odim0);
}
array ifft2(const array& in, const dim_t odim0, const dim_t odim1) {
const dim4 dims = in.dims();
dim_t dim0 = odim0 == 0 ? dims[0] : odim0;
dim_t dim1 = odim1 == 0 ? dims[1] : odim1;
double norm_factor = 1.0 / static_cast(dim0 * dim1);
return ifft2Norm(in, norm_factor, odim0, odim1);
}
array ifft3(const array& in, const dim_t odim0, const dim_t odim1,
const dim_t odim2) {
const dim4 dims = in.dims();
dim_t dim0 = odim0 == 0 ? dims[0] : odim0;
dim_t dim1 = odim1 == 0 ? dims[1] : odim1;
dim_t dim2 = odim2 == 0 ? dims[2] : odim2;
double norm_factor = 1.0 / static_cast(dim0 * dim1 * dim2);
return ifft3Norm(in, norm_factor, odim0, odim1, odim2);
}
// NOLINTNEXTLINE(performance-unnecessary-value-param)
array idft(const array& in, const double norm_factor, const dim4 outDims) {
array temp;
switch (in.dims().ndims()) {
case 1: temp = ifftNorm(in, norm_factor, outDims[0]); break;
case 2:
temp = ifft2Norm(in, norm_factor, outDims[0], outDims[1]);
break;
case 3:
temp =
ifft3Norm(in, norm_factor, outDims[0], outDims[1], outDims[2]);
break;
default: AF_THROW(AF_ERR_NOT_SUPPORTED);
}
return temp;
}
// NOLINTNEXTLINE(performance-unnecessary-value-param)
array idft(const array& in, const dim4 outDims) {
return idft(in, 1.0, outDims);
}
array idft(const array& in) { return idft(in, 1.0, dim4(0, 0, 0, 0)); }
void fftInPlace(array& in, const double norm_factor) {
AF_THROW(af_fft_inplace(in.get(), norm_factor));
}
void fft2InPlace(array& in, const double norm_factor) {
AF_THROW(af_fft2_inplace(in.get(), norm_factor));
}
void fft3InPlace(array& in, const double norm_factor) {
AF_THROW(af_fft3_inplace(in.get(), norm_factor));
}
void ifftInPlace(array& in, const double norm_factor) {
const dim4 dims = in.dims();
double norm = norm_factor * (1.0 / static_cast(dims[0]));
AF_THROW(af_ifft_inplace(in.get(), norm));
}
void ifft2InPlace(array& in, const double norm_factor) {
const dim4 dims = in.dims();
double norm = norm_factor * (1.0 / static_cast(dims[0] * dims[1]));
AF_THROW(af_ifft2_inplace(in.get(), norm));
}
void ifft3InPlace(array& in, const double norm_factor) {
const dim4 dims = in.dims();
double norm =
norm_factor * (1.0 / static_cast(dims[0] * dims[1] * dims[2]));
AF_THROW(af_ifft3_inplace(in.get(), norm));
}
template
AFAPI array fftR2C(const array& in, const dim4& dims,
const double norm_factor) {
af_array res;
AF_THROW(af_fft_r2c(&res, in.get(), norm_factor == 0 ? 1.0 : norm_factor,
dims[0]));
return array(res);
}
template
AFAPI array fftR2C(const array& in, const dim4& dims,
const double norm_factor) {
af_array res;
AF_THROW(af_fft2_r2c(&res, in.get(), norm_factor == 0 ? 1.0 : norm_factor,
dims[0], dims[1]));
return array(res);
}
template
AFAPI array fftR2C(const array& in, const dim4& dims,
const double norm_factor) {
af_array res;
AF_THROW(af_fft3_r2c(&res, in.get(), norm_factor == 0 ? 1.0 : norm_factor,
dims[0], dims[1], dims[2]));
return array(res);
}
inline dim_t getOrigDim(dim_t d, bool is_odd) {
return 2 * (d - 1) + (is_odd ? 1 : 0);
}
template
AFAPI array fftC2R(const array& in, const bool is_odd,
const double norm_factor) {
double norm = norm_factor;
if (norm == 0) {
dim4 idims = in.dims();
dim_t dim0 = getOrigDim(idims[0], is_odd);
norm = 1.0 / static_cast(dim0);
}
af_array res;
AF_THROW(af_fft_c2r(&res, in.get(), norm, is_odd));
return array(res);
}
template
AFAPI array fftC2R(const array& in, const bool is_odd,
const double norm_factor) {
double norm = norm_factor;
if (norm == 0) {
dim4 idims = in.dims();
dim_t dim0 = getOrigDim(idims[0], is_odd);
dim_t dim1 = idims[1];
norm = 1.0 / static_cast(dim0 * dim1);
}
af_array res;
AF_THROW(af_fft2_c2r(&res, in.get(), norm, is_odd));
return array(res);
}
template
AFAPI array fftC2R(const array& in, const bool is_odd,
const double norm_factor) {
double norm = norm_factor;
if (norm == 0) {
dim4 idims = in.dims();
dim_t dim0 = getOrigDim(idims[0], is_odd);
dim_t dim1 = idims[1];
dim_t dim2 = idims[2];
norm = 1.0 / static_cast(dim0 * dim1 * dim2);
}
af_array res;
AF_THROW(af_fft3_c2r(&res, in.get(), norm, is_odd));
return array(res);
}
#define FFT_REAL(rank) \
template \
AFAPI array fftR2C(const array& in, const double norm_factor) { \
return fftR2C(in, in.dims(), norm_factor); \
}
FFT_REAL(1)
FFT_REAL(2)
FFT_REAL(3)
void setFFTPlanCacheSize(size_t cacheSize) {
AF_THROW(af_set_fft_plan_cache_size(cacheSize));
}
} // namespace af