diff armadillo-3.900.4/include/armadillo_bits/fn_eig.hpp @ 49:1ec0e2823891

Switch to using subrepo copies of qm-dsp, nnls-chroma, vamp-plugin-sdk; update Armadillo version; assume build without external BLAS/LAPACK
author Chris Cannam
date Thu, 13 Jun 2013 10:25:24 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/armadillo-3.900.4/include/armadillo_bits/fn_eig.hpp	Thu Jun 13 10:25:24 2013 +0100
@@ -0,0 +1,327 @@
+// Copyright (C) 2008-2012 NICTA (www.nicta.com.au)
+// Copyright (C) 2008-2012 Conrad Sanderson
+// Copyright (C) 2009 Edmund Highcock
+// Copyright (C) 2011 Stanislav Funiak
+// 
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+//! \addtogroup fn_eig
+//! @{
+
+
+//
+// symmetric/hermitian matrices
+//
+
+
+//! Eigenvalues of real/complex symmetric/hermitian matrix X
+template<typename T1>
+inline
+bool
+eig_sym
+  (
+         Col<typename T1::pod_type>&     eigval,
+  const Base<typename T1::elem_type,T1>& X,
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  // unwrap_check not used as T1::elem_type and T1::pod_type may not be the same.
+  // furthermore, it doesn't matter if X is an alias of eigval, as auxlib::eig_sym() makes a copy of X
+  
+  const bool status = auxlib::eig_sym(eigval, X);
+  
+  if(status == false)
+    {
+    eigval.reset();
+    arma_bad("eig_sym(): failed to converge", false);
+    }
+  
+  return status;
+  }
+
+
+
+//! Eigenvalues of real/complex symmetric/hermitian matrix X
+template<typename T1>
+inline
+Col<typename T1::pod_type>
+eig_sym
+  (
+  const Base<typename T1::elem_type,T1>& X,
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  Col<typename T1::pod_type> out;
+  const bool status = auxlib::eig_sym(out, X);
+
+  if(status == false)
+    {
+    out.reset();
+    arma_bad("eig_sym(): failed to converge");
+    }
+  
+  return out;
+  }
+
+
+
+//! Eigenvalues and eigenvectors of real/complex symmetric/hermitian matrix X
+template<typename T1> 
+inline
+bool
+eig_sym
+  (
+         Col<typename T1::pod_type>&     eigval,
+         Mat<typename T1::elem_type>&    eigvec,
+  const Base<typename T1::elem_type,T1>& X,
+  const char* method =                   "",
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  arma_debug_check( void_ptr(&eigval) == void_ptr(&eigvec), "eig_sym(): eigval is an alias of eigvec" );
+  
+  bool use_divide_and_conquer = false;
+  
+  const char sig = method[0];
+  
+  switch(sig)
+    {
+    case '\0':
+    case 's':
+      break;
+      
+    case 'd':
+      use_divide_and_conquer = true;
+      break;
+    
+    default:
+      {
+      arma_stop("eig_sym(): unknown method specified");
+      return false;
+      }
+    }
+  
+  const bool status = (use_divide_and_conquer == false) ? auxlib::eig_sym(eigval, eigvec, X) : auxlib::eig_sym_dc(eigval, eigvec, X);
+  
+  if(status == false)
+    {
+    eigval.reset();
+    eigvec.reset();
+    arma_bad("eig_sym(): failed to converge", false);
+    }
+  
+  return status;
+  }
+
+
+
+//
+// general matrices
+//
+
+
+
+//! Eigenvalues and eigenvectors (both left and right) of general real/complex square matrix X
+template<typename T1>
+inline
+bool
+eig_gen
+  (
+         Col< std::complex<typename T1::pod_type> >& eigval, 
+         Mat<typename T1::elem_type>&                l_eigvec,
+         Mat<typename T1::elem_type>&                r_eigvec,
+  const Base<typename T1::elem_type,T1>&             X,
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  arma_debug_check
+    (
+    ((&l_eigvec) == (&r_eigvec)),
+    "eig_gen(): l_eigvec is an alias of r_eigvec"
+    );
+  
+  arma_debug_check
+    (
+      (
+      (((void*)(&eigval)) == ((void*)(&l_eigvec)))
+      ||
+      (((void*)(&eigval)) == ((void*)(&r_eigvec)))
+      ),
+    "eig_gen(): eigval is an alias of l_eigvec or r_eigvec"
+    );
+  
+  const bool status = auxlib::eig_gen(eigval, l_eigvec, r_eigvec, X, 'b');
+  
+  if(status == false)
+    {
+    eigval.reset();
+    l_eigvec.reset();
+    r_eigvec.reset();
+    arma_bad("eig_gen(): failed to converge", false);
+    }
+  
+  return status;
+  }
+
+
+
+//! Eigenvalues and eigenvectors of general real square matrix X.
+//! Optional argument 'side' specifies which eigenvectors should be computed:
+//! 'r' for right (default) and 'l' for left.
+template<typename eT, typename T1>
+inline
+bool
+eig_gen
+  (
+        Col< std::complex<eT> >& eigval, 
+        Mat< std::complex<eT> >& eigvec,
+  const Base<eT, T1>&            X, 
+  const char                     side = 'r',
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  //std::cout << "real" << std::endl;
+  
+  arma_debug_check( ( ((void*)(&eigval)) == ((void*)(&eigvec)) ), "eig_gen(): eigval is an alias of eigvec" );
+  
+  Mat<eT> dummy_eigvec;
+  Mat<eT> tmp_eigvec;
+  
+  bool status;
+  
+  switch(side)
+    {
+    case 'r':
+      status = auxlib::eig_gen(eigval, dummy_eigvec, tmp_eigvec, X, side);
+      break;
+    
+    case 'l':
+      status = auxlib::eig_gen(eigval, tmp_eigvec, dummy_eigvec, X, side);
+      break;
+      
+    default:
+      arma_stop("eig_gen(): parameter 'side' is invalid");
+      status = false;
+    }
+  
+  if(status == false)
+    {
+    eigval.reset();
+    eigvec.reset();
+    arma_bad("eig_gen(): failed to converge", false);
+    }
+  else
+    {
+    const uword n = eigval.n_elem;
+    
+    if(n > 0)
+      {
+      eigvec.set_size(n,n);
+      
+      for(uword j=0; j<n; ++j)
+        {
+        if( (j < n-1) && (eigval[j] == std::conj(eigval[j+1])) )
+          {
+          // eigvec.col(j)   = Mat< std::complex<eT> >( tmp_eigvec.col(j),  tmp_eigvec.col(j+1) );
+          // eigvec.col(j+1) = Mat< std::complex<eT> >( tmp_eigvec.col(j), -tmp_eigvec.col(j+1) );
+          
+          for(uword i=0; i<n; ++i)
+            {
+            eigvec.at(i,j)   = std::complex<eT>( tmp_eigvec.at(i,j),  tmp_eigvec.at(i,j+1) );
+            eigvec.at(i,j+1) = std::complex<eT>( tmp_eigvec.at(i,j), -tmp_eigvec.at(i,j+1) );
+            }
+          
+          ++j;
+          }
+        else
+          {
+          // eigvec.col(i) = tmp_eigvec.col(i);
+          
+          for(uword i=0; i<n; ++i)
+            {
+            eigvec.at(i,j) = std::complex<eT>(tmp_eigvec.at(i,j), eT(0));
+            }
+          
+          }
+        }
+      }
+    }
+  
+  return status;
+  }
+
+
+
+//! Eigenvalues and eigenvectors of general complex square matrix X
+//! Optional argument 'side' specifies which eigenvectors should be computed:
+//! 'r' for right (default) and 'l' for left.
+template<typename T, typename T1>
+inline
+bool
+eig_gen
+  (
+         Col<std::complex<T> >&    eigval, 
+         Mat<std::complex<T> >&    eigvec,
+  const Base<std::complex<T>, T1>& X, 
+  const char                       side = 'r',
+  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
+  )
+  {
+  arma_extra_debug_sigprint();
+  arma_ignore(junk);
+  
+  //std::cout << "complex" << std::endl;
+  
+  arma_debug_check( ( ((void*)(&eigval)) == ((void*)(&eigvec)) ), "eig_gen(): eigval is an alias of eigvec" );
+  
+  Mat< std::complex<T> > dummy_eigvec;
+  
+  bool status;
+  
+  switch(side)
+    {
+    case 'r':
+      status = auxlib::eig_gen(eigval, dummy_eigvec, eigvec, X, side);
+      break;
+    
+    case 'l':
+      status = auxlib::eig_gen(eigval, eigvec, dummy_eigvec, X, side);
+      break;
+      
+    default:
+      arma_stop("eig_gen(): parameter 'side' is invalid");
+      status = false;
+    }
+  
+  if(status == false)
+    {
+    eigval.reset();
+    eigvec.reset();
+    arma_bad("eig_gen(): failed to converge", false);
+    }
+  
+  return status;
+  }
+
+
+
+//! @}
+