This is gsl-ref.info, produced by makeinfo version 4.2 from
gsl-ref.texi.

INFO-DIR-SECTION Scientific software
START-INFO-DIR-ENTRY
* gsl-ref: (gsl-ref).                   GNU Scientific Library - Reference
END-INFO-DIR-ENTRY


File: gsl-ref.info,  Node: Cholesky Decomposition,  Next: Tridiagonal Decomposition of Real Symmetric Matrices,  Prev: Singular Value Decomposition,  Up: Linear Algebra

Cholesky Decomposition
======================

   A symmetric, positive definite square matrix A has a Cholesky
decomposition into a product of a lower triangular matrix L and its
transpose L^T,

     A = L L^T

This is sometimes referred to as taking the square-root of a matrix. The
Cholesky decomposition can only be carried out when all the eigenvalues
of the matrix are positive.  This decomposition can be used to convert
the linear system A x = b into a pair of triangular systems (L y = b,
L^T x = y), which can be solved by forward and back-substitution.

 - Function: int gsl_linalg_cholesky_decomp (gsl_matrix * A)
     This function factorizes the positive-definite square matrix A
     into the Cholesky decomposition A = L L^T. On output the diagonal
     and lower triangular part of the input matrix A contain the matrix
     L. The upper triangular part of the input matrix contains L^T, the
     diagonal terms being identical for both L and L^T.  If the matrix
     is not positive-definite then the decomposition will fail,
     returning the error code `GSL_EDOM'.

 - Function: int gsl_linalg_cholesky_solve (const gsl_matrix *
          CHOLESKY, const gsl_vector * B, gsl_vector * X)
     This function solves the system A x = b using the Cholesky
     decomposition of A into the matrix CHOLESKY given by
     `gsl_linalg_cholesky_decomp'.

 - Function: int gsl_linalg_cholesky_svx (const gsl_matrix * CHOLESKY,
          gsl_vector * X)
     This function solves the system A x = b in-place using the
     Cholesky decomposition of A into the matrix CHOLESKY given by
     `gsl_linalg_cholesky_decomp'. On input X should contain the
     right-hand side b, which is replaced by the solution on output.


File: gsl-ref.info,  Node: Tridiagonal Decomposition of Real Symmetric Matrices,  Next: Tridiagonal Decomposition of Hermitian Matrices,  Prev: Cholesky Decomposition,  Up: Linear Algebra

Tridiagonal Decomposition of Real Symmetric Matrices
====================================================

   A symmetric matrix A can be factorized by similarity transformations
into the form,

     A = Q T Q^T

where Q is an orthogonal matrix and T is a symmetric tridiagonal matrix.

 - Function: int gsl_linalg_symmtd_decomp (gsl_matrix * A, gsl_vector *
          TAU)
     This function factorizes the symmetric square matrix A into the
     symmetric tridiagonal decomposition Q T Q^T.  On output the
     diagonal and subdiagonal part of the input matrix A contain the
     tridiagonal matrix T.  The remaining lower triangular part of the
     input matrix contains the Householder vectors which, together with
     the Householder coefficients TAU, encode the orthogonal matrix Q.
     This storage scheme is the same as used by LAPACK.  The upper
     triangular part of A is not referenced.

 - Function: int gsl_linalg_symmtd_unpack (const gsl_matrix * A, const
          gsl_vector * TAU, gsl_matrix * Q, gsl_vector * DIAG,
          gsl_vector * SUBDIAG)
     This function unpacks the encoded symmetric tridiagonal
     decomposition (A, TAU) obtained from `gsl_linalg_symmtd_decomp'
     into the orthogonal matrix Q, the vector of diagonal elements DIAG
     and the vector of subdiagonal elements SUBDIAG.

 - Function: int gsl_linalg_symmtd_unpack_T (const gsl_matrix * A,
          gsl_vector * DIAG, gsl_vector * SUBDIAG)
     This function unpacks the diagonal and subdiagonal of the encoded
     symmetric tridiagonal decomposition (A, TAU) obtained from
     `gsl_linalg_symmtd_decomp' into the vectors DIAG and SUBDIAG.


File: gsl-ref.info,  Node: Tridiagonal Decomposition of Hermitian Matrices,  Next: Bidiagonalization,  Prev: Tridiagonal Decomposition of Real Symmetric Matrices,  Up: Linear Algebra

Tridiagonal Decomposition of Hermitian Matrices
===============================================

   A hermitian matrix A can be factorized by similarity transformations
into the form,

     A = U T U^T

where U is an unitary matrix and T is a real symmetric tridiagonal
matrix.

 - Function: int gsl_linalg_hermtd_decomp (gsl_matrix_complex * A,
          gsl_vector_complex * TAU)
     This function factorizes the hermitian matrix A into the symmetric
     tridiagonal decomposition U T U^T.  On output the real parts of
     the diagonal and subdiagonal part of the input matrix A contain
     the tridiagonal matrix T.  The remaining lower triangular part of
     the input matrix contains the Householder vectors which, together
     with the Householder coefficients TAU, encode the orthogonal matrix
     Q. This storage scheme is the same as used by LAPACK.  The upper
     triangular part of A and imaginary parts of the diagonal are not
     referenced.

 - Function: int gsl_linalg_hermtd_unpack (const gsl_matrix_complex *
          A, const gsl_vector_complex * TAU, gsl_matrix_complex * Q,
          gsl_vector * DIAG, gsl_vector * SUBDIAG)
     This function unpacks the encoded tridiagonal decomposition (A,
     TAU) obtained from `gsl_linalg_hermtd_decomp' into the unitary
     matrix U, the real vector of diagonal elements DIAG and the real
     vector of subdiagonal elements SUBDIAG.

 - Function: int gsl_linalg_hermtd_unpack_T (const gsl_matrix_complex *
          A, gsl_vector * DIAG, gsl_vector * SUBDIAG)
     This function unpacks the diagonal and subdiagonal of the encoded
     tridiagonal decomposition (A, TAU) obtained from
     `gsl_linalg_hermtd_decomp' into the real vectors DIAG and SUBDIAG.


File: gsl-ref.info,  Node: Bidiagonalization,  Next: Householder solver for linear systems,  Prev: Tridiagonal Decomposition of Hermitian Matrices,  Up: Linear Algebra

Bidiagonalization
=================

   A general matrix A can be factorized by similarity transformations
into the form,

     A = U B V^T

where U and V are orthogonal matrices and B is a N-by-N bidiagonal
matrix with non-zero entries only on the diagonal and superdiagonal.
The size of U is M-by-N and the size of V is N-by-N.

 - Function: int gsl_linalg_bidiag_decomp (gsl_matrix * A, gsl_vector *
          TAU_U, gsl_vector * TAU_V)
     This function factorizes the M-by-N matrix A into bidiagonal form
     U B V^T.  The diagonal and superdiagonal of the matrix B are
     stored in the diagonal and superdiagonal of A.  The orthogonal
     matrices U and V are stored as compressed Householder vectors in
     the remaining elements of A.  The Householder coefficients are
     stored in the vectors TAU_U and TAU_V.  The length of TAU_U must
     equal the number of elements in the diagonal of A and the length
     of TAU_V should be one element shorter.

 - Function: int gsl_linalg_bidiag_unpack (const gsl_matrix * A, const
          gsl_vector * TAU_U, gsl_matrix * U, const gsl_vector * TAU_V,
          gsl_matrix * V, gsl_vector * DIAG, gsl_vector * SUPERDIAG)
     This function unpacks the bidiagonal decomposition of A given by
     `gsl_linalg_bidiag_decomp', (A, TAU_U, TAU_V) into the separate
     orthogonal matrices U, V and the diagonal vector DIAG and
     superdiagonal SUPERDIAG.

 - Function: int gsl_linalg_bidiag_unpack2 (gsl_matrix * A, gsl_vector
          * TAU_U, gsl_vector * TAU_V, gsl_matrix * V)
     This function unpacks the bidiagonal decomposition of A given by
     `gsl_linalg_bidiag_decomp', (A, TAU_U, TAU_V) into the separate
     orthogonal matrices U, V and the diagonal vector DIAG and
     superdiagonal SUPERDIAG.  The matrix U is stored in-place in A.

 - Function: int gsl_linalg_bidiag_unpack_B (const gsl_matrix * A,
          gsl_vector * DIAG, gsl_vector * SUPERDIAG)
     This function unpacks the diagonal and superdiagonal of the
     bidiagonal decomposition of A given by `gsl_linalg_bidiag_decomp',
     into the diagonal vector DIAG and superdiagonal vector SUPERDIAG.


File: gsl-ref.info,  Node: Householder solver for linear systems,  Next: Tridiagonal Systems,  Prev: Bidiagonalization,  Up: Linear Algebra

Householder solver for linear systems
=====================================

 - Function: int gsl_linalg_HH_solve (gsl_matrix * A, const gsl_vector
          * B, gsl_vector * X)
     This function solves the system A x = b directly using Householder
     transformations. On output the solution is stored in X and B is
     not modified. The matrix A is destroyed by the Householder
     transformations.

 - Function: int gsl_linalg_HH_svx (gsl_matrix * A, gsl_vector * X)
     This function solves the system A x = b in-place using Householder
     transformations.  On input X should contain the right-hand side b,
     which is replaced by the solution on output.  The matrix A is
     destroyed by the Householder transformations.


File: gsl-ref.info,  Node: Tridiagonal Systems,  Next: Linear Algebra Examples,  Prev: Householder solver for linear systems,  Up: Linear Algebra

Tridiagonal Systems
===================

 - Function: int gsl_linalg_solve_symm_tridiag (const gsl_vector *
          DIAG, const gsl_vector * E, const gsl_vector * B, gsl_vector
          * X)
     This function solves the general N-by-N system A x = b where A is
     symmetric tridiagonal.  The form of A for the 4-by-4 case is shown
     below,

          A = ( d_0 e_0         )
              ( e_0 d_1 e_1     )
              (     e_1 d_2 e_2 )
              (         e_2 d_3 )


 - Function: int gsl_linalg_solve_symm_cyc_tridiag (const gsl_vector *
          DIAG, const gsl_vector * E, const gsl_vector * B, gsl_vector
          * X)
     This function solves the general N-by-N system A x = b where A is
     symmetric cyclic tridiagonal.  The form of A for the 4-by-4 case
     is shown below,

          A = ( d_0 e_0     e_3 )
              ( e_0 d_1 e_1     )
              (     e_1 d_2 e_2 )
              ( e_3     e_2 d_3 )



File: gsl-ref.info,  Node: Linear Algebra Examples,  Next: Linear Algebra References and Further Reading,  Prev: Tridiagonal Systems,  Up: Linear Algebra

Examples
========

   The following program solves the linear system A x = b. The system
to be solved is,

     [ 0.18 0.60 0.57 0.96 ] [x0]   [1.0]
     [ 0.41 0.24 0.99 0.58 ] [x1] = [2.0]
     [ 0.14 0.30 0.97 0.66 ] [x2]   [3.0]
     [ 0.51 0.13 0.19 0.85 ] [x3]   [4.0]

and the solution is found using LU decomposition of the matrix A.

     #include <stdio.h>
     #include <gsl/gsl_linalg.h>
     
     int
     main (void)
     {
       double a_data[] = { 0.18, 0.60, 0.57, 0.96,
                           0.41, 0.24, 0.99, 0.58,
                           0.14, 0.30, 0.97, 0.66,
                           0.51, 0.13, 0.19, 0.85 };
     
       double b_data[] = { 1.0, 2.0, 3.0, 4.0 };
     
       gsl_matrix_view m
         = gsl_matrix_view_array(a_data, 4, 4);
     
       gsl_vector_view b
         = gsl_vector_view_array(b_data, 4);
     
       gsl_vector *x = gsl_vector_alloc (4);
     
       int s;
     
       gsl_permutation * p = gsl_permutation_alloc (4);
     
       gsl_linalg_LU_decomp (&m.matrix, p, &s);
     
       gsl_linalg_LU_solve (&m.matrix, p, &b.vector, x);
     
       printf ("x = \n");
       gsl_vector_fprintf(stdout, x, "%g");
     
       gsl_permutation_free (p);
       return 0;
     }

Here is the output from the program,

     x = -4.05205
     -12.6056
     1.66091
     8.69377

This can be verified by multiplying the solution x by the original
matrix A using GNU OCTAVE,
     octave> A = [ 0.18, 0.60, 0.57, 0.96;
                   0.41, 0.24, 0.99, 0.58;
                   0.14, 0.30, 0.97, 0.66;
                   0.51, 0.13, 0.19, 0.85 ];
     
     octave> x = [ -4.05205; -12.6056; 1.66091; 8.69377];
     
     octave> A * x
     ans =
     
       1.0000
       2.0000
       3.0000
       4.0000

This reproduces the original right-hand side vector, b, in accordance
with the equation A x = b.


File: gsl-ref.info,  Node: Linear Algebra References and Further Reading,  Prev: Linear Algebra Examples,  Up: Linear Algebra

References and Further Reading
==============================

Further information on the algorithms described in this section can be
found in the following book,

     G. H. Golub, C. F. Van Loan, `Matrix Computations' (3rd Ed, 1996),
     Johns Hopkins University Press, ISBN 0-8018-5414-8.

The LAPACK library is described in,

     `LAPACK Users' Guide' (Third Edition, 1999), Published by SIAM,
     ISBN 0-89871-447-8.

     <http://www.netlib.org/lapack>

The LAPACK source code can be found at the website above, along with an
online copy of the users guide.

The Modified Golub-Reinsch algorithm is described in the following
paper,

     T.F. Chan, "An Improved Algorithm for Computing the Singular Value
     Decomposition", `ACM Transactions on Mathematical Software', 8
     (1982), pp 72-83.

The Jacobi algorithm for singular value decomposition is described in
the following papers,

     J.C.Nash, "A one-sided transformation method for the singular value
     decomposition and algebraic eigenproblem", `Computer Journal',
     Volume 18, Number 1 (1973), p 74--76

     James Demmel, Kresimir Veselic, "Jacobi's Method is more accurate
     than QR", `Lapack Working Note 15' (LAWN-15), October 1989.
     Available from netlib, <http://www.netlib.org/lapack/> in the
     `lawns' or `lawnspdf' directories.


File: gsl-ref.info,  Node: Eigensystems,  Next: Fast Fourier Transforms,  Prev: Linear Algebra,  Up: Top

Eigensystems
************

   This chapter describes functions for computing eigenvalues and
eigenvectors of matrices.  There are routines for real symmetric and
complex hermitian matrices, and eigenvalues can be computed with or
without eigenvectors.  The algorithms used are symmetric
bidiagonalization followed by QR reduction.

   These routines are intended for "small" systems where simple
algorithms are acceptable.  Anyone interested finding eigenvalues and
eigenvectors of large matrices will want to use the sophisticated
routines found in LAPACK. The Fortran version of LAPACK is recommended
as the standard package for linear algebra.

   The functions described in this chapter are declared in the header
file `gsl_eigen.h'.

* Menu:

* Real Symmetric Matrices::
* Complex Hermitian Matrices::
* Sorting Eigenvalues and Eigenvectors::
* Eigenvalue and Eigenvector Examples::
* Eigenvalue and Eigenvector References::


File: gsl-ref.info,  Node: Real Symmetric Matrices,  Next: Complex Hermitian Matrices,  Up: Eigensystems

Real Symmetric Matrices
=======================

 - Function: gsl_eigen_symm_workspace * gsl_eigen_symm_alloc (const
          size_t N)
     This function allocates a workspace for computing eigenvalues of
     N-by-N real symmetric matrices.  The size of the workspace is
     O(2n).

 - Function: void gsl_eigen_symm_free (gsl_eigen_symm_workspace * W)
     This function frees the memory associated with the workspace W.

 - Function: int gsl_eigen_symm (gsl_matrix * A, gsl_vector * EVAL,
          gsl_eigen_symm_workspace * W)
     This function computes the eigenvalues of the real symmetric matrix
     A.  Additional workspace of the appropriate size must be provided
     in W.  The diagonal and lower triangular part of A are destroyed
     during the computation, but the strict upper triangular part is
     not referenced.  The eigenvalues are stored in the vector EVAL and
     are unordered.

 - Function: gsl_eigen_symmv_workspace * gsl_eigen_symmv_alloc (const
          size_t N)
     This function allocates a workspace for computing eigenvalues and
     eigenvectors of N-by-N real symmetric matrices.  The size of the
     workspace is O(4n).

 - Function: void gsl_eigen_symmv_free (gsl_eigen_symmv_workspace * W)
     This function frees the memory associated with the workspace W.

 - Function: int gsl_eigen_symmv (gsl_matrix * A, gsl_vector * EVAL,
          gsl_matrix * EVEC, gsl_eigen_symmv_workspace * W)
     This function computes the eigenvalues and eigenvectors of the real
     symmetric matrix A.  Additional workspace of the appropriate size
     must be provided in W.  The diagonal and lower triangular part of
     A are destroyed during the computation, but the strict upper
     triangular part is not referenced.  The eigenvalues are stored in
     the vector EVAL and are unordered.  The corresponding eigenvectors
     are stored in the columns of the matrix EVEC.  For example, the
     eigenvector in the first column corresponds to the first
     eigenvalue.  The eigenvectors are guaranteed to be mutually
     orthogonal and normalised to unit magnitude.


File: gsl-ref.info,  Node: Complex Hermitian Matrices,  Next: Sorting Eigenvalues and Eigenvectors,  Prev: Real Symmetric Matrices,  Up: Eigensystems

Complex Hermitian Matrices
==========================

 - Function: gsl_eigen_herm_workspace * gsl_eigen_herm_alloc (const
          size_t N)
     This function allocates a workspace for computing eigenvalues of
     N-by-N complex hermitian matrices.  The size of the workspace is
     O(3n).

 - Function: void gsl_eigen_herm_free (gsl_eigen_herm_workspace * W)
     This function frees the memory associated with the workspace W.

 - Function: int gsl_eigen_herm (gsl_matrix_complex * A, gsl_vector *
          EVAL, gsl_eigen_herm_workspace * W)
     This function computes the eigenvalues of the complex hermitian
     matrix A.  Additional workspace of the appropriate size must be
     provided in W.  The diagonal and lower triangular part of A are
     destroyed during the computation, but the strict upper triangular
     part is not referenced.  The imaginary parts of the diagonal are
     assumed to be zero and are not referenced. The eigenvalues are
     stored in the vector EVAL and are unordered.

 - Function: gsl_eigen_hermv_workspace * gsl_eigen_hermv_alloc (const
          size_t N)
     This function allocates a workspace for computing eigenvalues and
     eigenvectors of N-by-N complex hermitian matrices.  The size of
     the workspace is O(5n).

 - Function: void gsl_eigen_hermv_free (gsl_eigen_hermv_workspace * W)
     This function frees the memory associated with the workspace W.

 - Function: int gsl_eigen_hermv (gsl_matrix_complex * A, gsl_vector *
          EVAL, gsl_matrix_complex * EVEC, gsl_eigen_hermv_workspace *
          W)
     This function computes the eigenvalues and eigenvectors of the
     complex hermitian matrix A.  Additional workspace of the
     appropriate size must be provided in W.  The diagonal and lower
     triangular part of A are destroyed during the computation, but the
     strict upper triangular part is not referenced. The imaginary
     parts of the diagonal are assumed to be zero and are not
     referenced.  The eigenvalues are stored in the vector EVAL and are
     unordered.  The corresponding complex eigenvectors are stored in
     the columns of the matrix EVEC.  For example, the eigenvector in
     the first column corresponds to the first eigenvalue.  The
     eigenvectors are guaranteed to be mutually orthogonal and
     normalised to unit magnitude.


File: gsl-ref.info,  Node: Sorting Eigenvalues and Eigenvectors,  Next: Eigenvalue and Eigenvector Examples,  Prev: Complex Hermitian Matrices,  Up: Eigensystems

Sorting Eigenvalues and Eigenvectors
====================================

 - Function: int gsl_eigen_symmv_sort (gsl_vector * EVAL, gsl_matrix *
          EVEC, gsl_eigen_sort_t SORT_TYPE)
     This function simultaneously sorts the eigenvalues stored in the
     vector EVAL and the corresponding real eigenvectors stored in the
     columns of the matrix EVEC into ascending or descending order
     according to the value of the parameter SORT_TYPE,

    `GSL_EIGEN_SORT_VAL_ASC'
          ascending order in numerical value

    `GSL_EIGEN_SORT_VAL_DESC'
          descending order in numerical value

    `GSL_EIGEN_SORT_ABS_ASC'
          ascending order in magnitude

    `GSL_EIGEN_SORT_ABS_DESC'
          descending order in magnitude


 - Function: int gsl_eigen_hermv_sort (gsl_vector * EVAL,
          gsl_matrix_complex * EVEC, gsl_eigen_sort_t SORT_TYPE)
     This function simultaneously sorts the eigenvalues stored in the
     vector EVAL and the corresponding complex eigenvectors stored in
     the columns of the matrix EVEC into ascending or descending order
     according to the value of the parameter SORT_TYPE as shown above.


File: gsl-ref.info,  Node: Eigenvalue and Eigenvector Examples,  Next: Eigenvalue and Eigenvector References,  Prev: Sorting Eigenvalues and Eigenvectors,  Up: Eigensystems

Examples
========

   The following program computes the eigenvalues and eigenvectors of
the 4-th order Hilbert matrix, H(i,j) = 1/(i + j + 1).

     #include <stdio.h>
     #include <gsl/gsl_math.h>
     #include <gsl/gsl_eigen.h>
     
     int
     main (void)
     {
       double data[] = { 1.0  , 1/2.0, 1/3.0, 1/4.0,
                         1/2.0, 1/3.0, 1/4.0, 1/5.0,
                         1/3.0, 1/4.0, 1/5.0, 1/6.0,
                         1/4.0, 1/5.0, 1/6.0, 1/7.0 };
     
       gsl_matrix_view m
         = gsl_matrix_view_array(data, 4, 4);
     
       gsl_vector *eval = gsl_vector_alloc (4);
       gsl_matrix *evec = gsl_matrix_alloc (4, 4);
     
       gsl_eigen_symmv_workspace * w =
         gsl_eigen_symmv_alloc (4);
     
       gsl_eigen_symmv (&m.matrix, eval, evec, w);
     
       gsl_eigen_symmv_free(w);
     
       gsl_eigen_symmv_sort (eval, evec,
                             GSL_EIGEN_SORT_ABS_ASC);
     
       {
         int i;
     
         for (i = 0; i < 4; i++)
           {
             double eval_i
                = gsl_vector_get(eval, i);
             gsl_vector_view evec_i
                = gsl_matrix_column(evec, i);
     
             printf("eigenvalue = %g\n", eval_i);
             printf("eigenvector = \n");
             gsl_vector_fprintf(stdout,
                                &evec_i.vector, "%g");
           }
       }
     
       return 0;
     }

Here is the beginning of the output from the program,

     $ ./a.out
     eigenvalue = 9.67023e-05
     eigenvector =
     -0.0291933
     0.328712
     -0.791411
     0.514553
     ...

This can be compared with the corresponding output from GNU OCTAVE,

     octave> [v,d] = eig(hilb(4));
     octave> diag(d)
     ans =
     
        9.6702e-05
        6.7383e-03
        1.6914e-01
        1.5002e+00
     
     octave> v
     v =
     
        0.029193   0.179186  -0.582076   0.792608
       -0.328712  -0.741918   0.370502   0.451923
        0.791411   0.100228   0.509579   0.322416
       -0.514553   0.638283   0.514048   0.252161

Note that the eigenvectors can differ by a change of sign, since the
sign of an eigenvector is arbitrary.


File: gsl-ref.info,  Node: Eigenvalue and Eigenvector References,  Prev: Eigenvalue and Eigenvector Examples,  Up: Eigensystems

References and Further Reading
==============================

Further information on the algorithms described in this section can be
found in the following book,

     G. H. Golub, C. F. Van Loan, `Matrix Computations' (3rd Ed, 1996),
     Johns Hopkins University Press, ISBN 0-8018-5414-8.

The LAPACK library is described in,

     `LAPACK Users' Guide' (Third Edition, 1999), Published by SIAM,
     ISBN 0-89871-447-8.

     <http://www.netlib.org/lapack>

The LAPACK source code can be found at the website above along with an
online copy of the users guide.


File: gsl-ref.info,  Node: Fast Fourier Transforms,  Next: Numerical Integration,  Prev: Eigensystems,  Up: Top

Fast Fourier Transforms (FFTs)
******************************

   This chapter describes functions for performing Fast Fourier
Transforms (FFTs).  The library includes radix-2 routines (for lengths
which are a power of two) and mixed-radix routines (which work for any
length).  For efficiency there are separate versions of the routines
for real data and for complex data.  The mixed-radix routines are a
reimplementation of the FFTPACK library by Paul Swarztrauber.  Fortran
code for FFTPACK is available on Netlib (FFTPACK also includes some
routines for sine and cosine transforms but these are currently not
available in GSL).  For details and derivations of the underlying
algorithms consult the document `GSL FFT Algorithms' (*note FFT
References and Further Reading::)

* Menu:

* Mathematical Definitions::
* Overview of complex data FFTs::
* Radix-2 FFT routines for complex data::
* Mixed-radix FFT routines for complex data::
* Overview of real data FFTs::
* Radix-2 FFT routines for real data::
* Mixed-radix FFT routines for real data::
* FFT References and Further Reading::


File: gsl-ref.info,  Node: Mathematical Definitions,  Next: Overview of complex data FFTs,  Up: Fast Fourier Transforms

Mathematical Definitions
========================

   Fast Fourier Transforms are efficient algorithms for calculating the
discrete fourier transform (DFT),

     x_j = \sum_{k=0}^{N-1} z_k \exp(-2\pi i j k / N)

   The DFT usually arises as an approximation to the continuous fourier
transform when functions are sampled at discrete intervals in space or
time.  The naive evaluation of the discrete fourier transform is a
matrix-vector multiplication W\vec{z}. A general matrix-vector
multiplication takes O(N^2) operations for N data-points.  Fast fourier
transform algorithms use a divide-and-conquer strategy to factorize the
matrix W into smaller sub-matrices, corresponding to the integer
factors of the length N.  If N can be factorized into a product of
integers f_1 f_2 ... f_n then the DFT can be computed in O(N \sum f_i)
operations.  For a radix-2 FFT this gives an operation count of O(N
\log_2 N).

   All the FFT functions offer three types of transform: forwards,
inverse and backwards, based on the same mathematical definitions.  The
definition of the "forward fourier transform", x = FFT(z), is,

     x_j = \sum_{k=0}^{N-1} z_k \exp(-2\pi i j k / N)

and the definition of the "inverse fourier transform", x = IFFT(z), is,

     z_j = {1 \over N} \sum_{k=0}^{N-1} x_k \exp(2\pi i j k / N).

The factor of 1/N makes this a true inverse.  For example, a call to
`gsl_fft_complex_forward' followed by a call to
`gsl_fft_complex_inverse' should return the original data (within
numerical errors).

   In general there are two possible choices for the sign of the
exponential in the transform/ inverse-transform pair. GSL follows the
same convention as FFTPACK, using a negative exponential for the forward
transform.  The advantage of this convention is that the inverse
transform recreates the original function with simple fourier
synthesis.  Numerical Recipes uses the opposite convention, a positive
exponential in the forward transform.

   The "backwards FFT" is simply our terminology for an unscaled
version of the inverse FFT,

     z^{backwards}_j = \sum_{k=0}^{N-1} x_k \exp(2\pi i j k / N).

When the overall scale of the result is unimportant it is often
convenient to use the backwards FFT instead of the inverse to save
unnecessary divisions.


File: gsl-ref.info,  Node: Overview of complex data FFTs,  Next: Radix-2 FFT routines for complex data,  Prev: Mathematical Definitions,  Up: Fast Fourier Transforms

Overview of complex data FFTs
=============================

   The inputs and outputs for the complex FFT routines are "packed
arrays" of floating point numbers.  In a packed array the real and
imaginary parts of each complex number are placed in alternate
neighboring elements.  For example, the following definition of a packed
array of length 6,

     gsl_complex_packed_array data[6];

can be used to hold an array of three complex numbers, `z[3]', in the
following way,

     data[0] = Re(z[0])
     data[1] = Im(z[0])
     data[2] = Re(z[1])
     data[3] = Im(z[1])
     data[4] = Re(z[2])
     data[5] = Im(z[2])

A "stride" parameter allows the user to perform transforms on the
elements `z[stride*i]' instead of `z[i]'.  A stride greater than 1 can
be used to take an in-place FFT of the column of a matrix. A stride of
1 accesses the array without any additional spacing between elements.

   The array indices have the same ordering as those in the definition
of the DFT -- i.e. there are no index transformations or permutations of
the data.

   For physical applications it is important to remember that the index
appearing in the DFT does not correspond directly to a physical
frequency.  If the time-step of the DFT is \Delta then the
frequency-domain includes both positive and negative frequencies,
ranging from -1/(2\Delta) through 0 to +1/(2\Delta).  The positive
frequencies are stored from the beginning of the array up to the
middle, and the negative frequencies are stored backwards from the end
of the array.

   Here is a table which shows the layout of the array DATA, and the
correspondence between the time-domain data z, and the frequency-domain
data x.

     index    z               x = FFT(z)
     
     0        z(t = 0)        x(f = 0)
     1        z(t = 1)        x(f = 1/(N Delta))
     2        z(t = 2)        x(f = 2/(N Delta))
     .        ........        ..................
     N/2      z(t = N/2)      x(f = +1/(2 Delta),
                                    -1/(2 Delta))
     .        ........        ..................
     N-3      z(t = N-3)      x(f = -3/(N Delta))
     N-2      z(t = N-2)      x(f = -2/(N Delta))
     N-1      z(t = N-1)      x(f = -1/(N Delta))

When N is even the location N/2 contains the most positive and negative
frequencies +1/(2 \Delta), -1/(2 \Delta)) which are equivalent.  If N
is odd then general structure of the table above still applies, but N/2
does not appear.


File: gsl-ref.info,  Node: Radix-2 FFT routines for complex data,  Next: Mixed-radix FFT routines for complex data,  Prev: Overview of complex data FFTs,  Up: Fast Fourier Transforms

Radix-2 FFT routines for complex data
=====================================

   The radix-2 algorithms described in this section are simple and
compact, although not necessarily the most efficient.  They use the
Cooley-Tukey algorithm to compute in-place complex FFTs for lengths
which are a power of 2 -- no additional storage is required.  The
corresponding self-sorting mixed-radix routines offer better
performance at the expense of requiring additional working space.

   All these functions are declared in the header file
`gsl_fft_complex.h'.

 - Function: int gsl_fft_complex_radix2_forward
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_transform
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_backward
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_inverse
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
     These functions compute forward, backward and inverse FFTs of
     length N with stride STRIDE, on the packed complex array DATA
     using an in-place radix-2 decimation-in-time algorithm.  The
     length of the transform N is restricted to powers of two.

     The functions return a value of `GSL_SUCCESS' if no errors were
     detected, or `GSL_EDOM' if the length of the data N is not a power
     of two.

 - Function: int gsl_fft_complex_radix2_dif_forward
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_dif_transform
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_dif_backward
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
 - Function: int gsl_fft_complex_radix2_dif_inverse
          (gsl_complex_packed_array DATA[], size_t STRIDE, size_t N)
     These are decimation-in-frequency versions of the radix-2 FFT
     functions.


   Here is an example program which computes the FFT of a short pulse
in a sample of length 128.  To make the resulting fourier transform
real the pulse is defined for equal positive and negative times (-10
... 10), where the negative times wrap around the end of the array.

     #include <stdio.h>
     #include <math.h>
     #include <gsl/gsl_errno.h>
     #include <gsl/gsl_fft_complex.h>
     
     #define REAL(z,i) ((z)[2*(i)])
     #define IMAG(z,i) ((z)[2*(i)+1])
     
     int
     main (void)
     {
       int i;
       double data[2*128];
     
       for (i = 0; i < 128; i++)
         {
            REAL(data,i) = 0.0;
            IMAG(data,i) = 0.0;
         }
     
       REAL(data,0) = 1.0;
     
       for (i = 1; i <= 10; i++)
         {
            REAL(data,i) = REAL(data,128-i) = 1.0;
         }
     
       for (i = 0; i < 128; i++)
         {
           printf ("%d %e %e\n", i,
                   REAL(data,i), IMAG(data,i));
         }
       printf ("\n");
     
       gsl_fft_complex_radix2_forward (data, 1, 128);
     
       for (i = 0; i < 128; i++)
         {
           printf ("%d %e %e\n", i,
                   REAL(data,i)/sqrt(128),
                   IMAG(data,i)/sqrt(128));
         }
     
       return 0;
     }

Note that we have assumed that the program is using the default error
handler (which calls `abort' for any errors).  If you are not using a
safe error handler you would need to check the return status of
`gsl_fft_complex_radix2_forward'.

   The transformed data is rescaled by 1/\sqrt N so that it fits on the
same plot as the input.  Only the real part is shown, by the choice of
the input data the imaginary part is zero.  Allowing for the
wrap-around of negative times at t=128, and working in units of k/N,
the DFT approximates the continuum fourier transform, giving a
modulated \sin function.


File: gsl-ref.info,  Node: Mixed-radix FFT routines for complex data,  Next: Overview of real data FFTs,  Prev: Radix-2 FFT routines for complex data,  Up: Fast Fourier Transforms

Mixed-radix FFT routines for complex data
=========================================

   This section describes mixed-radix FFT algorithms for complex data.
The mixed-radix functions work for FFTs of any length.  They are a
reimplementation of the Fortran FFTPACK library by Paul Swarztrauber.
The theory is explained in the review article `Self-sorting Mixed-radix
FFTs' by Clive Temperton.  The routines here use the same indexing
scheme and basic algorithms as FFTPACK.

   The mixed-radix algorithm is based on sub-transform modules - highly
optimized small length FFTs which are combined to create larger FFTs.
There are efficient modules for factors of 2, 3, 4, 5, 6 and 7.  The
modules for the composite factors of 4 and 6 are faster than combining
the modules for 2*2 and 2*3.

   For factors which are not implemented as modules there is a
fall-back to a general length-n module which uses Singleton's method for
efficiently computing a DFT. This module is O(n^2), and slower than a
dedicated module would be but works for any length n.  Of course,
lengths which use the general length-n module will still be factorized
as much as possible.  For example, a length of 143 will be factorized
into 11*13.  Large prime factors are the worst case scenario, e.g. as
found in n=2*3*99991, and should be avoided because their O(n^2)
scaling will dominate the run-time (consult the document `GSL FFT
Algorithms' included in the GSL distribution if you encounter this
problem).

   The mixed-radix initialization function
`gsl_fft_complex_wavetable_alloc' returns the list of factors chosen by
the library for a given length N.  It can be used to check how well the
length has been factorized, and estimate the run-time.  To a first
approximation the run-time scales as N \sum f_i, where the f_i are the
factors of N.  For programs under user control you may wish to issue a
warning that the transform will be slow when the length is poorly
factorized.  If you frequently encounter data lengths which cannot be
factorized using the existing small-prime modules consult `GSL FFT
Algorithms' for details on adding support for other factors.

   All these functions are declared in the header file
`gsl_fft_complex.h'.

 - Function: gsl_fft_complex_wavetable *
          gsl_fft_complex_wavetable_alloc (size_t N)
     This function prepares a trigonometric lookup table for a complex
     FFT of length N. The function returns a pointer to the newly
     allocated `gsl_fft_complex_wavetable' if no errors were detected,
     and a null pointer in the case of error.  The length N is
     factorized into a product of subtransforms, and the factors and
     their trigonometric coefficients are stored in the wavetable. The
     trigonometric coefficients are computed using direct calls to
     `sin' and `cos', for accuracy.  Recursion relations could be used
     to compute the lookup table faster, but if an application performs
     many FFTs of the same length then this computation is a one-off
     overhead which does not affect the final throughput.

     The wavetable structure can be used repeatedly for any transform
     of the same length.  The table is not modified by calls to any of
     the other FFT functions.  The same wavetable can be used for both
     forward and backward (or inverse) transforms of a given length.

 - Function: void gsl_fft_complex_wavetable_free
          (gsl_fft_complex_wavetable * WAVETABLE)
     This function frees the memory associated with the wavetable
     WAVETABLE.  The wavetable can be freed if no further FFTs of the
     same length will be needed.

These functions operate on a `gsl_fft_complex_wavetable' structure
which contains internal parameters for the FFT.  It is not necessary to
set any of the components directly but it can sometimes be useful to
examine them.  For example, the chosen factorization of the FFT length
is given and can be used to provide an estimate of the run-time or
numerical error.

   The wavetable structure is declared in the header file
`gsl_fft_complex.h'.

 - Data Type: gsl_fft_complex_wavetable
     This is a structure that holds the factorization and trigonometric
     lookup tables for the mixed radix fft algorithm.  It has the
     following components:

    `size_t n'
          This is the number of complex data points

    `size_t nf'
          This is the number of factors that the length `n' was
          decomposed into.

    `size_t factor[64]'
          This is the array of factors.  Only the first `nf' elements
          are used.

    `gsl_complex * trig'
          This is a pointer to a preallocated trigonometric lookup
          table of `n' complex elements.

    `gsl_complex * twiddle[64]'
          This is an array of pointers into `trig', giving the twiddle
          factors for each pass.

The mixed radix algorithms require an additional working space to hold
the intermediate steps of the transform.

 - Function: gsl_fft_complex_workspace *
          gsl_fft_complex_workspace_alloc (size_t N)
     This function allocates a workspace for a complex transform of
     length N.

 - Function: void gsl_fft_complex_workspace_free
          (gsl_fft_complex_workspace * WORKSPACE)
     This function frees the memory associated with the workspace
     WORKSPACE. The workspace can be freed if no further FFTs of the
     same length will be needed.

The following functions compute the transform,

 - Function: int gsl_fft_complex_forward (gsl_complex_packed_array
          DATA[], size_t STRIDE, size_t N, const
          gsl_fft_complex_wavetable * WAVETABLE,
          gsl_fft_complex_workspace * WORK)
 - Function: int gsl_fft_complex_transform (gsl_complex_packed_array
          DATA[], size_t STRIDE, size_t N, const
          gsl_fft_complex_wavetable * WAVETABLE,
          gsl_fft_complex_workspace * WORK)
 - Function: int gsl_fft_complex_backward (gsl_complex_packed_array
          DATA[], size_t STRIDE, size_t N, const
          gsl_fft_complex_wavetable * WAVETABLE,
          gsl_fft_complex_workspace * WORK)
 - Function: int gsl_fft_complex_inverse (gsl_complex_packed_array
          DATA[], size_t STRIDE, size_t N, const
          gsl_fft_complex_wavetable * WAVETABLE,
          gsl_fft_complex_workspace * WORK)
     These functions compute forward, backward and inverse FFTs of
     length N with stride STRIDE, on the packed complex array DATA,
     using a mixed radix decimation-in-frequency algorithm.  There is
     no restriction on the length N.  Efficient modules are provided
     for subtransforms of length 2, 3, 4, 5, 6 and 7.  Any remaining
     factors are computed with a slow, O(n^2), general-n module. The
     caller must supply a WAVETABLE containing the trigonometric lookup
     tables and a workspace WORK.

     The functions return a value of `0' if no errors were detected. The
     following `gsl_errno' conditions are defined for these functions:

    `GSL_EDOM'
          The length of the data N is not a positive integer (i.e. N is
          zero).

    `GSL_EINVAL'
          The length of the data N and the length used to compute the
          given WAVETABLE do not match.

   Here is an example program which computes the FFT of a short pulse
in a sample of length 630 (=2*3*3*5*7) using the mixed-radix algorithm.

     #include <stdio.h>
     #include <math.h>
     #include <gsl/gsl_errno.h>
     #include <gsl/gsl_fft_complex.h>
     
     #define REAL(z,i) ((z)[2*(i)])
     #define IMAG(z,i) ((z)[2*(i)+1])
     
     int
     main (void)
     {
       int i;
       const int n = 630;
       double data[2*n];
     
       gsl_fft_complex_wavetable * wavetable;
       gsl_fft_complex_workspace * workspace;
     
       for (i = 0; i < n; i++)
         {
           REAL(data,i) = 0.0;
           IMAG(data,i) = 0.0;
         }
     
       data[0].real = 1.0;
     
       for (i = 1; i <= 10; i++)
         {
           REAL(data,i) = REAL(data,n-i) = 1.0;
         }
     
       for (i = 0; i < n; i++)
         {
           printf ("%d: %e %e\n", i, REAL(data,i),
                                     IMAG(data,i));
         }
       printf ("\n");
     
       wavetable = gsl_fft_complex_wavetable_alloc (n);
       workspace = gsl_fft_complex_workspace_alloc (n);
     
       for (i = 0; i < wavetable->nf; i++)
         {
            printf("# factor %d: %d\n", i,
                   wavetable->factor[i]);
         }
     
       gsl_fft_complex_forward (data, 1, n,
                                wavetable, workspace);
     
       for (i = 0; i < n; i++)
         {
           printf ("%d: %e %e\n", i, REAL(data,i),
                                     IMAG(data,i));
         }
     
       gsl_fft_complex_wavetable_free (wavetable);
       gsl_fft_complex_workspace_free (workspace);
       return 0;
     }

Note that we have assumed that the program is using the default `gsl'
error handler (which calls `abort' for any errors).  If you are not
using a safe error handler you would need to check the return status of
all the `gsl' routines.


File: gsl-ref.info,  Node: Overview of real data FFTs,  Next: Radix-2 FFT routines for real data,  Prev: Mixed-radix FFT routines for complex data,  Up: Fast Fourier Transforms

Overview of real data FFTs
==========================

   The functions for real data are similar to those for complex data.
However, there is an important difference between forward and inverse
transforms.  The fourier transform of a real sequence is not real.  It
is a complex sequence with a special symmetry:

     z_k = z_{N-k}^*

A sequence with this symmetry is called "conjugate-complex" or
"half-complex".  This different structure requires different storage
layouts for the forward transform (from real to half-complex) and
inverse transform (from half-complex back to real).  As a consequence
the routines are divided into two sets: functions in `gsl_fft_real'
which operate on real sequences and functions in `gsl_fft_halfcomplex'
which operate on half-complex sequences.

   Functions in `gsl_fft_real' compute the frequency coefficients of a
real sequence.  The half-complex coefficients c of a real sequence x
are given by fourier analysis,

     c_k = \sum_{j=0}^{N-1} x_k \exp(-2 \pi i j k /N)

Functions in `gsl_fft_halfcomplex' compute inverse or backwards
transforms.  They reconstruct real sequences by fourier synthesis from
their half-complex frequency coefficients, c,

     x_j = {1 \over N} \sum_{k=0}^{N-1} c_k \exp(2 \pi i j k /N)

The symmetry of the half-complex sequence implies that only half of the
complex numbers in the output need to be stored.  The remaining half can
be reconstructed using the half-complex symmetry condition. (This works
for all lengths, even and odd.  When the length is even the middle
value, where k=N/2, is also real).  Thus only N real numbers are
required to store the half-complex sequence, and the transform of a real
sequence can be stored in the same size array as the original data.

   The precise storage arrangements depend on the algorithm, and are
different for radix-2 and mixed-radix routines.  The radix-2 function
operates in-place, which constrain the locations where each element can
be stored.  The restriction forces real and imaginary parts to be stored
far apart.  The mixed-radix algorithm does not have this restriction,
and it stores the real and imaginary parts of a given term in
neighboring locations.  This is desirable for better locality of memory
accesses.


File: gsl-ref.info,  Node: Radix-2 FFT routines for real data,  Next: Mixed-radix FFT routines for real data,  Prev: Overview of real data FFTs,  Up: Fast Fourier Transforms

Radix-2 FFT routines for real data
==================================

   This section describes radix-2 FFT algorithms for real data.  They
use the Cooley-Tukey algorithm to compute in-place FFTs for lengths
which are a power of 2.

   The radix-2 FFT functions for real data are declared in the header
files `gsl_fft_real.h'

 - Function: int gsl_fft_real_radix2_transform (double DATA[], size_t
          STRIDE, size_t N)
     This function computes an in-place radix-2 FFT of length N and
     stride STRIDE on the real array DATA.  The output is a
     half-complex sequence, which is stored in-place.  The arrangement
     of the half-complex terms uses the following scheme: for k < N/2
     the real part of the k-th term is stored in location k, and the
     corresponding imaginary part is stored in location N-k.  Terms
     with k > N/2 can be reconstructed using the symmetry z_k =
     z^*_{N-k}.  The terms for k=0 and k=N/2 are both purely real, and
     count as a special case.  Their real parts are stored in locations
     0 and N/2 respectively, while their imaginary parts which are zero
     are not stored.

     The following table shows the correspondence between the output
     DATA and the equivalent results obtained by considering the input
     data as a complex sequence with zero imaginary part,

          complex[0].real    =    data[0]
          complex[0].imag    =    0
          complex[1].real    =    data[1]
          complex[1].imag    =    data[N-1]
          ...............         ................
          complex[k].real    =    data[k]
          complex[k].imag    =    data[N-k]
          ...............         ................
          complex[N/2].real  =    data[N/2]
          complex[N/2].real  =    0
          ...............         ................
          complex[k'].real   =    data[k]        k' = N - k
          complex[k'].imag   =   -data[N-k]
          ...............         ................
          complex[N-1].real  =    data[1]
          complex[N-1].imag  =   -data[N-1]

   The radix-2 FFT functions for halfcomplex data are declared in the
header file `gsl_fft_halfcomplex.h'.

 - Function: int gsl_fft_halfcomplex_radix2_inverse (double DATA[],
          size_t STRIDE, size_t N)
 - Function: int gsl_fft_halfcomplex_radix2_backward (double DATA[],
          size_t STRIDE, size_t N)
     These functions compute the inverse or backwards in-place radix-2
     FFT of length N and stride STRIDE on the half-complex sequence
     DATA stored according the output scheme used by
     `gsl_fft_real_radix2'.  The result is a real array stored in
     natural order.


