LCOV - code coverage report
Current view: top level - include/math/ft - mftT.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 4.5 % 44 2
Test Date: 2026-08-30 22:23:37 Functions: 33.3 % 3 1

            Line data    Source code
       1              : /** \file mftT.hpp
       2              :  * \brief The Matrix Fourier Transform interface
       3              :  * \ingroup ft_files
       4              :  * \author Jared R. Males (jaredmales@gmail.com)
       5              :  *
       6              :  */
       7              : 
       8              : //***********************************************************************//
       9              : // Copyright 2024-2025 Jared R. Males (jaredmales@gmail.com)
      10              : //
      11              : // This file is part of mxlib.
      12              : //
      13              : // mxlib is free software: you can redistribute it and/or modify
      14              : // it under the terms of the GNU General Public License as published by
      15              : // the Free Software Foundation, either version 3 of the License, or
      16              : // (at your option) any later version.
      17              : //
      18              : // mxlib is distributed in the hope that it will be useful,
      19              : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      20              : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      21              : // GNU General Public License for more details.
      22              : //
      23              : // You should have received a copy of the GNU General Public License
      24              : // along with mxlib.  If not, see <http://www.gnu.org/licenses/>.
      25              : //***********************************************************************//
      26              : 
      27              : #ifndef mftT_hpp
      28              : #define mftT_hpp
      29              : 
      30              : #pragma GCC system_header
      31              : #include <Eigen/Dense>
      32              : 
      33              : #include "fftwTemplates.hpp"
      34              : #include "ftTypes.hpp"
      35              : #include "../../math/constants.hpp"
      36              : 
      37              : /** \addtogroup mft
      38              :  *
      39              :  * The Matrix Fourier Transform is the <a href="https://en.wikipedia.org/wiki/DFT_matrix">
      40              :  * matrix-multiplication implementation of the
      41              :  * Discrete Fourier Transform</a>.  It is slower than the FFT given the same size matrix, e.g.
      42              :  * <a href="https://pages.hmc.edu/ruye/e161/lectures/fourier/node11.html">in 2D</a>
      43              :  * \f$O(N^3)\f$ vs \f$O(N^2\ln(N))\f$.  However, compared to zero-padding,
      44              :  * it can provide advantages in both speed
      45              :  * and memory required for problems where oversampling is needed but only over a small region
      46              :  * of the output.
      47              :  */
      48              : namespace mx
      49              : {
      50              : namespace math
      51              : {
      52              : namespace ft
      53              : {
      54              : 
      55              : template <typename _inputT, typename _outputT, size_t _rank, int _cudaGPU = 0>
      56              : class mftT;
      57              : 
      58              : /// Matrix Fourier Transforms
      59              : /** Calculates the Discrete Fourier Transform (DFT) using matrix multiplication.  This
      60              :  *  is normally much less efficient than the FFT, but for large oversampling (padding)
      61              :  *  the Matrix FT (MFT) will be much more space efficient and faster at the cost of
      62              :  *  "field of view".
      63              :  *
      64              :  *  This interface is modeled after the \ref fftT<_inputT, _outputT, _rank, 0> "fftT" interface to fftw, and is interoperable with it.
      65              :  *  That means that using, e.g., mftT (unshifted, not-oversampled) for the forward transform
      66              :  *  and \ref fftT<_inputT, _outputT, _rank, 0> "fftT" for the backward
      67              :  *  transform is equivalent to using one or the other for both. Note that
      68              :  *  the MFT is normalized as in fftw, so by 1/N on the forward and by 1 on the backward.
      69              :  *
      70              :  *  Oversampling is optionally included in the transform, which is equivalent to zero padding
      71              :  *  in terms of increased resolution \cite soummer_2007.
      72              :  *  The cost is that the output domain is truncated by the oversampling factor.  I.e. if we
      73              :  *  oversample by a factor of 10, only 1/10th of the output transform is available.
      74              :  *
      75              :  *  The output can be shifted as part of the MFT calculation, which is implemented similarly
      76              :  *  to <a href="https://www.mathworks.com/matlabcentral/fileexchange/18401-efficient-subpixel-image-registration-by-cross-correlation">
      77              :  *  this matlab code</a>.
      78              :  *
      79              :  *  Note that when either oversampling or shifting is done on a forward (backward) transform,
      80              :  *  a subsequent backward (forward) transform will not in general be the inverse.
      81              :  *
      82              :  *  \tparam inputT is the input type of the transform, only complex types are suppored by mftT
      83              :  *  \tparam outputT is the output type of the transform, only complex types are suppored by mftT
      84              :  *  \tparam _rank is the rank of the transform. Currently only rank 2 is implemented.
      85              :  *
      86              :  *  \ingroup mft
      87              :  */
      88              : template <typename _inputT, typename _outputT, size_t _rank>
      89              : class mftT<_inputT, _outputT, _rank, 0>
      90              : {
      91              :     typedef _inputT inputT;
      92              :     typedef _outputT outputT;
      93              : 
      94              :     typedef typename fftwTypeSpec<inputT, outputT>::realT realT;
      95              : 
      96              :     typedef typename fftwTypeSpec<_inputT, _outputT>::complexT complexT;
      97              : 
      98              :     static const size_t rank = _rank;
      99              : 
     100              :     typedef Eigen::Array<inputT, -1, -1> eigenArrayInT;
     101              :     typedef Eigen::Array<outputT, -1, -1> eigenArrayOutT;
     102              : 
     103              :     typedef Eigen::Matrix<complexT, -1, -1> eigenMatrixT;
     104              : 
     105              :   protected:
     106              :     dir m_dir{ dir::forward }; /**< Direction of this MFT, either dir::forward (default)
     107              :                                      or dir::backward */
     108              : 
     109              :     int m_szX{ 0 }; ///< Size of the x dimension
     110              :     int m_szY{ 0 }; ///< Size of the y dimension
     111              :     int m_szZ{ 0 }; ///< size of the z dimension
     112              : 
     113              :     float m_osFac{ 1 }; ///< The oversampling factor
     114              : 
     115              :     realT m_xOff{ 0 }; ///< The offset in the rows direction for the center of the DFT.
     116              :     realT m_yOff{ 0 }; ///< The offset in the columns direction for the center of the DFT.
     117              :   public:
     118              :     eigenMatrixT m_dftR; ///< DFT matrix for the rows
     119              :     eigenMatrixT m_dftC; ///< DFT matrix for the columnss
     120              : 
     121              :   public:
     122              :     /// Default c'tor
     123              :     mftT();
     124              : 
     125              :     /// Constructor for rank 1 MFT.
     126              :     template <size_t crank = _rank>
     127              :     mftT( int nx,                   ///< [in] the desired size of the MFT
     128              :           dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
     129              :                                                          (default) or dir::backward */
     130              :           realT xOff = 0,           /**< [in] [optional] the x offset of the center of the
     131              :                                                          transformed array. Default 0.*/
     132              :           realT osFac = 1.0,        /**< [in] [optional] the oversampling factor.  Default 1. */
     133              :           typename std::enable_if<crank == 1>::type * = 0 ) = delete;
     134              : 
     135              :     /// Constructor for rank 2 MFT.
     136              :     template <size_t crank = _rank>
     137              :     mftT( int nx,                   ///< [in] the desired x size of the MFT
     138              :           int ny,                   ///< [in] the desired y size of the MFT
     139              :           dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
     140              :                                                          (default) or dir::backward */
     141              :           realT xOff = 0,           /**< [in] [optional] the x offset of the center of the
     142              :                                                          transformed array. Default 0.*/
     143              :           realT yOff = 0,           /**< [in] [optional] the y offset of the center of the
     144              :                                                          transformed array  Default 0.*/
     145              :           realT osFac = 1.0,        /**< [in] [optional] the oversampling factor.  Default 1. */
     146              :           typename std::enable_if<crank == 2>::type * = 0 );
     147              : 
     148              :     /// Constructor for rank 3 MFT.
     149              :     template <size_t crank = _rank>
     150              :     mftT( int nx,                   ///< [in] the desired x size of the MFT
     151              :           int ny,                   ///< [in] the desired y size of the MFT
     152              :           int nz,                   ///< [in] the desired z size of the MFT
     153              :           dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
     154              :                                                          (default) or dir::backward */
     155              :           realT xOff = 0,           /**< [in] [optional] the x offset of the center of the
     156              :                                                          transformed array. Default 0.*/
     157              :           realT yOff = 0,           /**< [in] [optional] the y offset of the center of the
     158              :                                                          transformed array  Default 0.*/
     159              :           realT zOff = 0,           /**< [in] [optional] the z offset of the center of the
     160              :                                                          transformed array  Default 0.*/
     161              :           realT osFac = 1.0,        /**< [in] [optional] the oversampling factor.  Default 1. */
     162              :           typename std::enable_if<crank == 3>::type * = 0 ) = delete;
     163              : 
     164              :     /// Planning routine for rank 2 transforms.
     165              :     template <size_t crank = _rank>
     166              :     void plan( int nx,                   ///< [in] the desired x size of the MFT
     167              :                int ny,                   ///< [in] the desired y size of the MFT
     168              :                dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
     169              :                                                               (default) or dir::backward */
     170              :                realT xOff = 0,           /**< [in] [optional] the x offset of the center of the
     171              :                                                               transformed array. Default 0.*/
     172              :                realT yOff = 0,           /**< [in] [optional] the y offset of the center of the
     173              :                                                               transformed array  Default 0.*/
     174              :                realT osFac = 1.0,        /**< [in] [optional] the oversampling factor.  Default 1. */
     175              :                typename std::enable_if<crank == 2>::type * = 0 );
     176              : 
     177              :     /// Conduct the MFT
     178              :     void operator()( eigenArrayOutT &out, /**< [out] the output of the DFT */
     179              :                      const eigenArrayInT &in /**< [in] the input to the DFT */ ) const;
     180              : };
     181              : 
     182              : template <typename inputT, typename outputT, size_t rank>
     183           12 : mftT<inputT, outputT, rank, 0>::mftT()
     184              : {
     185           12 : }
     186              : 
     187              : template <typename inputT, typename outputT, size_t rank>
     188              : template <size_t crank>
     189              : mftT<inputT, outputT, rank, 0>::mftT(
     190              :     int nx, int ny, dir ndir, realT xoff, realT yoff, realT osFac, typename std::enable_if<crank == 2>::type * )
     191              : {
     192              :     plan( nx, ny, ndir, xoff, yoff, osFac );
     193              : }
     194              : 
     195              : template <typename inputT, typename outputT, size_t rank>
     196              : template <size_t crank>
     197            0 : void mftT<inputT, outputT, rank, 0>::plan(
     198              :     int nx, int ny, dir ndir, realT xOff, realT yOff, realT osFac, typename std::enable_if<crank == 2>::type * )
     199              : {
     200            0 :     if(m_szX == nx && m_szY == ny && m_dir == ndir && m_xOff == xOff && m_yOff == yOff && m_osFac == osFac)
     201              :     {
     202            0 :         return;
     203              :     }
     204              : 
     205            0 :     m_szX = nx;
     206            0 :     m_szY = ny;
     207            0 :     m_dir = ndir;
     208            0 :     m_xOff = xOff;
     209            0 :     m_yOff = yOff;
     210            0 :     m_osFac = osFac;
     211              : 
     212            0 :     if( m_szX != m_szY )
     213              :     {
     214            0 :         throw std::invalid_argument( "MFT of non-square size is not implemented. nx must equal ny." );
     215              :     }
     216              : 
     217              :     // These should depend on szX too.
     218            0 :     m_dftR.resize( m_szX, m_szX );
     219            0 :     m_dftC.resize( m_szX, m_szX );
     220              : 
     221              :     // There is probably an osNx and an osNy?
     222            0 :     realT osN = m_szX * m_osFac;
     223              : 
     224            0 :     if( m_dir == dir::forward )
     225              :     {
     226            0 :         realT sign = -1;
     227            0 :         realT norm = 1.0 / ( m_szX * m_szY );
     228              : 
     229            0 :         for( int cc = 0; cc < m_szY; ++cc )
     230              :         {
     231            0 :             realT ccx = cc;
     232              : 
     233            0 :             for( int rr = 0; rr < m_szX; ++rr )
     234              :             {
     235            0 :                 realT x = ( rr - m_xOff ) * ccx / osN;
     236              : 
     237            0 :                 m_dftR( rr, cc ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
     238              : 
     239            0 :                 realT rrx = rr;
     240              : 
     241            0 :                 x = rrx * ( cc - m_yOff ) / osN;
     242              : 
     243            0 :                 m_dftC( rr, cc ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
     244              :             }
     245              :         }
     246              :     }
     247              :     else
     248              :     {
     249            0 :         realT sign = +1;
     250            0 :         realT norm = 1.0;
     251              : 
     252            0 :         for( int cc = 0; cc < m_szY; ++cc )
     253              :         {
     254            0 :             realT ccx = cc;
     255            0 :             if( ccx > m_szY / 2 )
     256            0 :                 ccx = -1 * ( m_szY - ccx );
     257              : 
     258            0 :             for( int rr = 0; rr < m_szX; ++rr )
     259              :             {
     260            0 :                 realT rrx = rr;
     261            0 :                 if( rrx > m_szX / 2 )
     262            0 :                     rrx = -1 * ( m_szX - rrx );
     263              : 
     264            0 :                 realT x = rrx * ( cc - m_xOff ) / osN;
     265              : 
     266            0 :                 m_dftR( cc, rr ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
     267              : 
     268            0 :                 x = ( rr - m_yOff ) * ccx / osN;
     269              : 
     270            0 :                 m_dftC( cc, rr ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
     271              :             }
     272              :         }
     273              :     }
     274              : }
     275              : 
     276              : template <typename inputT, typename outputT, size_t rank>
     277            0 : void mftT<inputT, outputT, rank, 0>::operator()( eigenArrayOutT &out, const eigenArrayInT &in ) const
     278              : {
     279            0 :     out = ( m_dftR * in.matrix() * m_dftC ).array();
     280            0 : }
     281              : 
     282              : } // namespace ft
     283              : } // namespace math
     284              : } // namespace mx
     285              : 
     286              : #endif // mdft_hpp
        

Generated by: LCOV version 2.0-1