-
-
Notifications
You must be signed in to change notification settings - Fork 198
Feature/20 fft #2686
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
Merged
Merged
Feature/20 fft #2686
Changes from all commits
Commits
Show all changes
23 commits
Select commit
Hold shift + click to select a range
61b1588
prim version of fft, inv_fft, with tests
bob-carpenter e35b762
fft expression template args
bob-carpenter ff0248c
generic type guards for fft and inv_fft
bob-carpenter faa7416
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
bob-carpenter 9b0028d
autodiff tests for fft (failing due to finite diffs)
bob-carpenter cf71d62
failing fft test example
bob-carpenter c843aac
forward 2D FFT with tests, but low precision match to numpy
bob-carpenter 81d190e
2D FFT and inverse passing tests
bob-carpenter 27de0ab
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
bob-carpenter e5e04f7
fwd fft tested
bob-carpenter b345c51
fft funs passing tests, fixes #20
bob-carpenter f023e83
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot 4b45aba
fft doc
bob-carpenter 95f033b
new tests for ffts and fixed doc
bob-carpenter 1954e96
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot 1389297
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
bob-carpenter f73c6fa
Merge branch 'develop' of https://github.com/stan-dev/math into featu…
bob-carpenter 6b3e712
elide test if tolerance is inf; fft test rev only
bob-carpenter cb26922
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot f2e4dba
fft done w/o analytic rev mode
bob-carpenter a1a4cd2
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot 593e5ec
requested fixes to testing; fixes #20
bob-carpenter cc813b4
[Jenkins] auto-formatting by clang-format version 10.0.0-4ubuntu1
stan-buildbot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| #ifndef STAN_MATH_PRIM_FUN_FFT_HPP | ||
| #define STAN_MATH_PRIM_FUN_FFT_HPP | ||
|
|
||
| #include <stan/math/prim/meta.hpp> | ||
| #include <stan/math/prim/fun/Eigen.hpp> | ||
| #include <unsupported/Eigen/FFT> | ||
| #include <Eigen/Dense> | ||
| #include <complex> | ||
| #include <type_traits> | ||
| #include <vector> | ||
|
|
||
| namespace stan { | ||
| namespace math { | ||
|
|
||
| /** | ||
| * Return the discrete Fourier transform of the specified complex | ||
| * vector. | ||
| * | ||
| * Given an input complex vector `x[0:N-1]` of size `N`, the discrete | ||
| * Fourier transform computes entries of the resulting complex | ||
| * vector `y[0:N-1]` by | ||
| * | ||
| * ``` | ||
| * y[n] = SUM_{i < N} x[i] * exp(-n * i * 2 * pi * sqrt(-1) / N) | ||
| * ``` | ||
| * | ||
| * If the input is of size zero, the result is a size zero vector. | ||
| * | ||
| * @tparam V type of complex vector argument | ||
| * @param[in] x vector to transform | ||
| * @return discrete Fourier transform of `x` | ||
| */ | ||
| template <typename V, require_eigen_vector_vt<is_complex, V>* = nullptr> | ||
| inline Eigen::Matrix<scalar_type_t<V>, -1, 1> fft(const V& x) { | ||
| // copy because fft() requires Eigen::Matrix type | ||
| Eigen::Matrix<scalar_type_t<V>, -1, 1> xv = x; | ||
| if (xv.size() <= 1) | ||
| return xv; | ||
| Eigen::FFT<base_type_t<V>> fft; | ||
| return fft.fwd(xv); | ||
| } | ||
|
|
||
| /** | ||
| * Return the inverse discrete Fourier transform of the specified | ||
| * complex vector. | ||
| * | ||
| * Given an input complex vector `y[0:N-1]` of size `N`, the inverse | ||
| * discrete Fourier transform computes entries of the resulting | ||
| * complex vector `x[0:N-1]` by | ||
| * | ||
| * ``` | ||
| * x[n] = SUM_{i < N} y[i] * exp(n * i * 2 * pi * sqrt(-1) / N) | ||
| * ``` | ||
| * | ||
| * If the input is of size zero, the result is a size zero vector. | ||
| * The only difference between the discrete DFT and its inverse is | ||
| * the sign of the exponent. | ||
| * | ||
| * @tparam V type of complex vector argument | ||
| * @param[in] y vector to inverse transform | ||
| * @return inverse discrete Fourier transform of `y` | ||
| */ | ||
| template <typename V, require_eigen_vector_vt<is_complex, V>* = nullptr> | ||
| inline Eigen::Matrix<scalar_type_t<V>, -1, 1> inv_fft(const V& y) { | ||
| // copy because fft() requires Eigen::Matrix type | ||
| Eigen::Matrix<scalar_type_t<V>, -1, 1> yv = y; | ||
| if (y.size() <= 1) | ||
| return yv; | ||
| Eigen::FFT<base_type_t<V>> fft; | ||
| return fft.inv(yv); | ||
| } | ||
|
|
||
| /** | ||
| * Return the two-dimensional discrete Fourier transform of the | ||
| * specified complex matrix. The 2D discrete Fourier transform first | ||
| * runs the discrete Fourier transform on the each row, then on each | ||
| * column of the result. | ||
| * | ||
| * @tparam M type of complex matrix argument | ||
| * @param[in] x matrix to transform | ||
| * @return discrete 2D Fourier transform of `x` | ||
| */ | ||
| template <typename M, require_eigen_dense_dynamic_vt<is_complex, M>* = nullptr> | ||
| inline Eigen::Matrix<scalar_type_t<M>, -1, -1> fft2(const M& x) { | ||
| Eigen::Matrix<scalar_type_t<M>, -1, -1> y(x.rows(), x.cols()); | ||
| for (int i = 0; i < y.rows(); ++i) | ||
| y.row(i) = fft(x.row(i)); | ||
| for (int j = 0; j < y.cols(); ++j) | ||
| y.col(j) = fft(y.col(j)); | ||
| return y; | ||
| } | ||
|
|
||
| /** | ||
| * Return the two-dimensional inverse discrete Fourier transform of | ||
| * the specified complex matrix. The 2D inverse discrete Fourier | ||
| * transform first runs the 1D inverse Fourier transform on the | ||
| * columns, and then on the resulting rows. The composition of the | ||
| * FFT and inverse FFT (or vice-versa) is the identity. | ||
| * | ||
| * @tparam M type of complex matrix argument | ||
| * @param[in] y matrix to inverse trnasform | ||
| * @return inverse discrete 2D Fourier transform of `y` | ||
| */ | ||
| template <typename M, require_eigen_dense_dynamic_vt<is_complex, M>* = nullptr> | ||
| inline Eigen::Matrix<scalar_type_t<M>, -1, -1> inv_fft2(const M& y) { | ||
| Eigen::Matrix<scalar_type_t<M>, -1, -1> x(y.rows(), y.cols()); | ||
| for (int j = 0; j < x.cols(); ++j) | ||
| x.col(j) = inv_fft(y.col(j)); | ||
| for (int i = 0; i < x.rows(); ++i) | ||
| x.row(i) = inv_fft(x.row(i)); | ||
| return x; | ||
| } | ||
|
|
||
| } // namespace math | ||
| } // namespace stan | ||
|
|
||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,177 @@ | ||
| #include <test/unit/math/test_ad.hpp> | ||
|
|
||
| void expect_fft(const Eigen::VectorXcd& x) { | ||
| stan::test::ad_tolerances tols = stan::test::reverse_only_ad_tolerances(); | ||
| for (int m = 0; m < x.rows(); ++m) { | ||
| auto g = [m](const auto& x) { | ||
| using stan::math::fft; | ||
| return fft(x)(m); | ||
| }; | ||
| stan::test::expect_ad(tols, g, x); | ||
| } | ||
| } | ||
|
|
||
| TEST(mathMixFun, fft) { | ||
| using cvec_t = Eigen::VectorXcd; | ||
|
|
||
| cvec_t x0(0); | ||
| expect_fft(x0); | ||
|
|
||
| cvec_t x1(1); | ||
| x1[0] = {1, 2}; | ||
| expect_fft(x1); | ||
|
|
||
| cvec_t x2(2); | ||
| x2[0] = {1, 2}; | ||
| x2[1] = {-1.3, 2.9}; | ||
| expect_fft(x2); | ||
|
|
||
| Eigen::VectorXcd x3(3); | ||
| x3[0] = {1, -1.3}; | ||
| x3[1] = {2.9, 14.7}; | ||
| x3[2] = {-12.9, -4.8}; | ||
| expect_fft(x3); | ||
|
|
||
| Eigen::VectorXcd x4(4); | ||
| x4[0] = {1, -1.3}; | ||
| x4[1] = {-2.9, 14.7}; | ||
| x4[2] = {-12.9, -4.8}; | ||
| x4[3] = {8.398, 9.387}; | ||
| expect_fft(x4); | ||
| } | ||
|
|
||
| void expect_inv_fft(const Eigen::VectorXcd& x) { | ||
| stan::test::ad_tolerances tols = stan::test::reverse_only_ad_tolerances(); | ||
| for (int m = 0; m < x.rows(); ++m) { | ||
| auto g = [m](const auto& x) { | ||
| using stan::math::inv_fft; | ||
| return inv_fft(x)(m); | ||
| }; | ||
| stan::test::expect_ad(tols, g, x); | ||
| } | ||
| } | ||
|
|
||
| TEST(mathMixFun, invFft) { | ||
| using cvec_t = Eigen::VectorXcd; | ||
|
|
||
| cvec_t x0(0); | ||
| expect_inv_fft(x0); | ||
|
|
||
| cvec_t x1(1); | ||
| x1[0] = {1, 2}; | ||
| expect_inv_fft(x1); | ||
|
|
||
| cvec_t x2(2); | ||
| x2[0] = {1, 2}; | ||
| x2[1] = {-1.3, 2.9}; | ||
| expect_inv_fft(x2); | ||
|
|
||
| Eigen::VectorXcd x3(3); | ||
| x3[0] = {1, -1.3}; | ||
| x3[1] = {2.9, 14.7}; | ||
| x3[2] = {-12.9, -4.8}; | ||
| expect_inv_fft(x3); | ||
|
|
||
| Eigen::VectorXcd x4(4); | ||
| x4[0] = {1, -1.3}; | ||
| x4[1] = {-2.9, 14.7}; | ||
| x4[2] = {-12.9, -4.8}; | ||
| x4[3] = {8.398, 9.387}; | ||
| expect_inv_fft(x4); | ||
| } | ||
|
|
||
| void expect_fft2(const Eigen::MatrixXcd& x) { | ||
| stan::test::ad_tolerances tols = stan::test::reverse_only_ad_tolerances(); | ||
| for (int n = 0; n < x.cols(); ++n) { | ||
| for (int m = 0; m < x.rows(); ++m) { | ||
| auto g = [m, n](const auto& x) { | ||
| using stan::math::fft2; | ||
| return fft2(x)(m, n); | ||
| }; | ||
| stan::test::expect_ad(tols, g, x); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| TEST(mathMixFun, fft2) { | ||
| using cmat_t = Eigen::MatrixXcd; | ||
|
|
||
| cmat_t x00(0, 0); | ||
| expect_fft2(x00); | ||
|
|
||
| cmat_t x11(1, 1); | ||
| x11(0, 0) = {1, 2}; | ||
| expect_fft2(x11); | ||
|
|
||
| cmat_t x21(2, 1); | ||
| x21(0, 0) = {1, 2}; | ||
| x21(1, 0) = {-1.3, 2.9}; | ||
| expect_fft2(x21); | ||
|
|
||
| cmat_t x22(2, 2); | ||
| x22(0, 0) = {3, 9}; | ||
| x22(0, 1) = {-13.2, 8.345}; | ||
| x22(1, 0) = {-4.23, 7.566}; | ||
| x22(1, 1) = {1, -12.9}; | ||
| expect_fft2(x22); | ||
|
|
||
| cmat_t x33(3, 3); | ||
| x33(0, 0) = {3, 9}; | ||
| x33(0, 1) = {-13.2, 8.345}; | ||
| x33(0, 2) = {4.333, -1.9}; | ||
| x33(1, 0) = {-4.23, 7.566}; | ||
| x33(1, 1) = {1, -12.9}; | ||
| x33(1, 2) = {-1.01, -4.01}; | ||
| x33(2, 0) = {3.87, 5.89}; | ||
| x33(2, 1) = {-2.875, -2.999}; | ||
| x33(2, 2) = {12.98, 14.5555}; | ||
| expect_fft2(x33); | ||
| } | ||
|
|
||
| void expect_inv_fft2(const Eigen::MatrixXcd& x) { | ||
| stan::test::ad_tolerances tols = stan::test::reverse_only_ad_tolerances(); | ||
| for (int n = 0; n < x.cols(); ++n) { | ||
| for (int m = 0; m < x.rows(); ++m) { | ||
| auto g = [m, n](const auto& x) { | ||
| using stan::math::inv_fft2; | ||
| return inv_fft2(x)(m, n); | ||
| }; | ||
| stan::test::expect_ad(tols, g, x); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| TEST(mathMixFun, inv_fft2) { | ||
| using cmat_t = Eigen::MatrixXcd; | ||
|
|
||
| cmat_t x00(0, 0); | ||
| expect_inv_fft2(x00); | ||
|
|
||
| cmat_t x11(1, 1); | ||
| x11(0, 0) = {1, 2}; | ||
| expect_inv_fft2(x11); | ||
|
|
||
| cmat_t x21(2, 1); | ||
| x21(0, 0) = {1, 2}; | ||
| x21(1, 0) = {-1.3, 2.9}; | ||
| expect_inv_fft2(x21); | ||
|
|
||
| cmat_t x22(2, 2); | ||
| x22(0, 0) = {3, 9}; | ||
| x22(0, 1) = {-13.2, 8.345}; | ||
| x22(1, 0) = {-4.23, 7.566}; | ||
| x22(1, 1) = {1, -12.9}; | ||
| expect_inv_fft2(x22); | ||
|
|
||
| cmat_t x33(3, 3); | ||
| x33(0, 0) = {3, 9}; | ||
| x33(0, 1) = {-13.2, 8.345}; | ||
| x33(0, 2) = {4.333, -1.9}; | ||
| x33(1, 0) = {-4.23, 7.566}; | ||
| x33(1, 1) = {1, -12.9}; | ||
| x33(1, 2) = {-1.01, -4.01}; | ||
| x33(2, 0) = {3.87, 5.89}; | ||
| x33(2, 1) = {-2.875, -2.999}; | ||
| x33(2, 2) = {12.98, 14.5555}; | ||
| expect_inv_fft2(x33); | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.