-
Notifications
You must be signed in to change notification settings - Fork 1
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
Real to complex #21
Real to complex #21
Changes from 7 commits
4c3ee6a
95b09d1
ab2fe9e
350a421
f9ecb7a
e02dd98
8dcb6c1
5b1b809
e8a0160
295744e
0f7e425
9cd754e
53e9caf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
#include <boost/math/fft/multiprecision_complex.hpp> | ||
|
||
#include <boost/math/fft/algorithms.hpp> | ||
#include <boost/math/fft/real_algorithms.hpp> | ||
#include <boost/math/fft/dft_api.hpp> | ||
|
||
namespace boost { namespace math { namespace fft { | ||
|
@@ -138,11 +139,101 @@ | |
std::size_t my_size{}; | ||
}; | ||
|
||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the bsl rfft backend needs to be implemented |
||
template<class T, class allocator_t = std::allocator<T> > | ||
class bsl_rfft_backend | ||
{ | ||
public: | ||
using value_type = T; | ||
using allocator_type = allocator_t; | ||
|
||
// the provided root of unity is used instead of exp(-i 2 pi/n) | ||
constexpr bsl_rfft_backend(std::size_t n, const allocator_type& in_alloc = allocator_type{}): | ||
alloc{in_alloc}, | ||
my_size{n} | ||
{ | ||
} | ||
|
||
~bsl_rfft_backend() | ||
{ | ||
} | ||
|
||
void resize(std::size_t new_size) | ||
{ | ||
my_size = new_size; | ||
} | ||
|
||
constexpr std::size_t size() const { return my_size; } | ||
constexpr std::size_t unique_complex_size() const { return my_size/2 + 1;} | ||
|
||
void real_to_halfcomplex(const value_type* in, value_type* out) const | ||
{ | ||
const long N = static_cast<long>(size()); | ||
// select the implementation according to the DFT size | ||
switch(N) | ||
{ | ||
case 0: | ||
return; | ||
case 1: | ||
out[0]=in[0]; | ||
return; | ||
case 2: | ||
detail::real_dft_2(in,out,1); | ||
return; | ||
} | ||
if( detail::is_power2(N)) | ||
{ | ||
detail::real_dft_power2(in,in+N,out,1); | ||
}else | ||
{ | ||
detail::real_dft_composite(in,in+N,out,1,alloc); | ||
} | ||
//if(detail::is_prime(N)) | ||
//{ | ||
// detail::real_dft_prime_rader(in,in+N,out,sign,alloc); | ||
//} | ||
} | ||
void halfcomplex_to_real(const value_type* in, value_type* out) const | ||
{ | ||
const long N = static_cast<long>(size()); | ||
// select the implementation according to the DFT size | ||
switch(N) | ||
{ | ||
case 0: | ||
return; | ||
case 1: | ||
out[0]=in[0]; | ||
return; | ||
case 2: | ||
detail::real_inverse_dft_2(in,out,1); | ||
return; | ||
} | ||
if( detail::is_power2(N)) | ||
{ | ||
detail::real_inverse_dft_power2(in,in+N,out,1); | ||
}else | ||
{ | ||
//detail::real_inverse_dft_composite(in,in+N,out,1,alloc); | ||
} | ||
//if(detail::is_prime(N)) | ||
//{ | ||
// detail::real_inverse_dft_prime_rader(in,in+N,out,sign,alloc); | ||
//} | ||
} | ||
|
||
private: | ||
allocator_type alloc; | ||
std::size_t my_size{}; | ||
}; | ||
|
||
} // namespace detail | ||
|
||
template<class RingType = std::complex<double>, class Allocator_t = std::allocator<RingType> > | ||
using bsl_dft = detail::complex_dft<detail::bsl_backend,RingType,Allocator_t>; | ||
|
||
template<class T = double, class Allocator_t = std::allocator<T> > | ||
using bsl_rfft = detail::real_dft<detail::bsl_rfft_backend,T,Allocator_t>; | ||
|
||
template<class RingType = std::complex<double>, class Allocator_t = std::allocator<RingType> > | ||
using bsl_algebraic_dft = detail::algebraic_dft<detail::bsl_backend,RingType,Allocator_t>; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -574,28 +574,14 @@ | |
// -> size(out) >= N | ||
{ | ||
const std::size_t N = size(); | ||
vector_t<real_value_type> tmp(out,out+N); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The algorithm that we use for rfft for powers of 2, comes naturally in-place if we use the halfcomplex representation used by FFTW. |
||
out[0]=tmp[0]; | ||
for(unsigned int i=1,j=1;j<N;++i,j+=2) | ||
{ | ||
out[j] = tmp[i]; | ||
if(j+1<N) | ||
out[j+1] = tmp[N-i]; | ||
} | ||
for(unsigned int i=1,j=N-1;i<j;++i,--j) | ||
out[j] = -out[j]; | ||
} | ||
void unpack_halfcomplex(real_value_type* out) const | ||
// precondition: | ||
// -> size(out) >= N | ||
{ | ||
const std::size_t N = size(); | ||
vector_t<real_value_type> tmp(out,out+N); | ||
out[0]=tmp[0]; | ||
for(unsigned int i=1,j=1;j<N;++i,j+=2) | ||
{ | ||
out[i] = tmp[j]; | ||
if(j+1<N) | ||
out[N-i] = tmp[j+1]; | ||
} | ||
pack_halfcomplex(out); | ||
} | ||
|
||
public: | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -174,6 +174,34 @@ namespace fft { namespace detail { | |
gsl_fft_halfcomplex_wavetable *halfcomplex_wtable; | ||
gsl_fft_real_workspace *real_wspace; | ||
|
||
void pack_halfcomplex(real_value_type* out) const | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The algorithm that we use for rfft for powers of 2, comes naturally in-place if we use the halfcomplex representation used by FFTW. Hence we have to pack and unpack the halfcomplex returned by GSL to make it compatible with our representation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wow, I appreciate your comments about what's going on in the code. It's a bit unrelated to this comment, but I noticed that we could replace |
||
// precondition: | ||
// -> size(out) >= N | ||
{ | ||
const std::size_t N = size(); | ||
vector_t<real_value_type> tmp(out,out+N); | ||
out[0]=tmp[0]; | ||
for(unsigned int i=1,j=1;j<N;++i,j+=2) | ||
{ | ||
out[j] = tmp[i]; | ||
if(j+1<N) | ||
out[j+1] = -tmp[N-i]; | ||
} | ||
} | ||
void unpack_halfcomplex(real_value_type* out) const | ||
// precondition: | ||
// -> size(out) >= N | ||
{ | ||
const std::size_t N = size(); | ||
vector_t<real_value_type> tmp(out,out+N); | ||
out[0]=tmp[0]; | ||
for(unsigned int i=1,j=1;j<N;++i,j+=2) | ||
{ | ||
out[i] = tmp[j]; | ||
if(j+1<N) | ||
out[N-i] = -tmp[j+1]; | ||
} | ||
} | ||
template<plan_type p> | ||
void execute(const real_value_type* in, | ||
real_value_type* out, | ||
|
@@ -189,6 +217,7 @@ namespace fft { namespace detail { | |
} | ||
gsl_fft_real_transform( | ||
out,1, N, real_wtable, real_wspace); | ||
unpack_halfcomplex(out); | ||
} | ||
template<plan_type p> | ||
void execute(const real_value_type* in, | ||
|
@@ -203,6 +232,7 @@ namespace fft { namespace detail { | |
// undefined-behavior | ||
std::copy(in,in+N,out); | ||
} | ||
pack_halfcomplex(out); | ||
gsl_fft_halfcomplex_transform( | ||
out,1, N, halfcomplex_wtable, real_wspace); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
According to the GSL documentation, the rfft can be deduced from the decimation-in-time (DIT) complex fft.
The default complex fft for powers of 2 is implemented as Decimation-in-frequency (DIF), i wrote another complex fft as DIT to test the algorithm before writing the rfft.