Chris@49: // Copyright (C) 2008-2012 NICTA (www.nicta.com.au) Chris@49: // Copyright (C) 2008-2012 Conrad Sanderson Chris@49: // Chris@49: // This Source Code Form is subject to the terms of the Mozilla Public Chris@49: // License, v. 2.0. If a copy of the MPL was not distributed with this Chris@49: // file, You can obtain one at http://mozilla.org/MPL/2.0/. Chris@49: Chris@49: Chris@49: //! \addtogroup fn_norm Chris@49: //! @{ Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_1(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: T acc = T(0); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: T acc1 = T(0); Chris@49: T acc2 = T(0); Chris@49: Chris@49: uword i,j; Chris@49: for(i=0, j=1; j Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_2 Chris@49: ( Chris@49: const Proxy& P, Chris@49: const typename arma_not_cx::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: T acc = T(0); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: T acc1 = T(0); Chris@49: T acc2 = T(0); Chris@49: Chris@49: uword i,j; Chris@49: Chris@49: for(i=0, j=1; j Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_2 Chris@49: ( Chris@49: const Proxy& P, Chris@49: const typename arma_cx_only::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: T acc = T(0); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: for(uword i=0; i Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_k Chris@49: ( Chris@49: const Proxy& P, Chris@49: const int k Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: T acc = T(0); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: uword i,j; Chris@49: Chris@49: for(i=0, j=1; j Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_max(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: T max_val = (N != 1) ? priv::most_neg() : std::abs(P[0]); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: uword i,j; Chris@49: for(i=0, j=1; j Chris@49: arma_hot Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_vec_norm_min(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const uword N = P.get_n_elem(); Chris@49: Chris@49: T min_val = (N != 1) ? priv::most_pos() : std::abs(P[0]); Chris@49: Chris@49: if(Proxy::prefer_at_accessor == false) Chris@49: { Chris@49: typename Proxy::ea_type A = P.get_ea(); Chris@49: Chris@49: uword i,j; Chris@49: for(i=0, j=1; j tmp_i) { min_val = tmp_i; } Chris@49: if(min_val > tmp_j) { min_val = tmp_j; } Chris@49: } Chris@49: Chris@49: if(i < N) Chris@49: { Chris@49: const T tmp_i = std::abs(A[i]); Chris@49: Chris@49: if(min_val > tmp_i) { min_val = tmp_i; } Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: const uword n_rows = P.get_n_rows(); Chris@49: const uword n_cols = P.get_n_cols(); Chris@49: Chris@49: if(n_rows != 1) Chris@49: { Chris@49: for(uword col=0; col < n_cols; ++col) Chris@49: for(uword row=0; row < n_rows; ++row) Chris@49: { Chris@49: const T tmp = std::abs(P.at(row,col)); Chris@49: Chris@49: if(min_val > tmp) { min_val = tmp; } Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: for(uword col=0; col < n_cols; ++col) Chris@49: { Chris@49: const T tmp = std::abs(P.at(0,col)); Chris@49: Chris@49: if(min_val > tmp) { min_val = tmp; } Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: return min_val; Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_mat_norm_1(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: // TODO: this can be sped up with a dedicated implementation Chris@49: return as_scalar( max( sum(abs(P.Q), 0), 1) ); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_mat_norm_2(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: // TODO: is the SVD based approach only valid for square matrices? Chris@49: Chris@49: Col S; Chris@49: svd(S, P.Q); Chris@49: Chris@49: return (S.n_elem > 0) ? max(S) : T(0); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_mat_norm_inf(const Proxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: // TODO: this can be sped up with a dedicated implementation Chris@49: return as_scalar( max( sum(abs(P.Q), 1), 0) ); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: arma_warn_unused Chris@49: typename enable_if2< is_arma_type::value, typename T1::pod_type >::result Chris@49: norm Chris@49: ( Chris@49: const T1& X, Chris@49: const uword k, Chris@49: const typename arma_real_or_cx_only::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const Proxy P(X); Chris@49: Chris@49: if(P.get_n_elem() == 0) Chris@49: { Chris@49: return T(0); Chris@49: } Chris@49: Chris@49: const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1); Chris@49: Chris@49: if(is_vec == true) Chris@49: { Chris@49: switch(k) Chris@49: { Chris@49: case 1: Chris@49: return arma_vec_norm_1(P); Chris@49: break; Chris@49: Chris@49: case 2: Chris@49: return arma_vec_norm_2(P); Chris@49: break; Chris@49: Chris@49: default: Chris@49: { Chris@49: arma_debug_check( (k == 0), "norm(): k must be greater than zero" ); Chris@49: return arma_vec_norm_k(P, int(k)); Chris@49: } Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: switch(k) Chris@49: { Chris@49: case 1: Chris@49: return arma_mat_norm_1(P); Chris@49: break; Chris@49: Chris@49: case 2: Chris@49: return arma_mat_norm_2(P); Chris@49: break; Chris@49: Chris@49: default: Chris@49: arma_stop("norm(): unsupported matrix norm type"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: arma_warn_unused Chris@49: typename enable_if2< is_arma_type::value, typename T1::pod_type >::result Chris@49: norm Chris@49: ( Chris@49: const T1& X, Chris@49: const char* method, Chris@49: const typename arma_real_or_cx_only::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const Proxy P(X); Chris@49: Chris@49: if(P.get_n_elem() == 0) Chris@49: { Chris@49: return T(0); Chris@49: } Chris@49: Chris@49: const char sig = method[0]; Chris@49: const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1); Chris@49: Chris@49: if(is_vec == true) Chris@49: { Chris@49: if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // max norm Chris@49: { Chris@49: return arma_vec_norm_max(P); Chris@49: } Chris@49: else Chris@49: if(sig == '-') // min norm Chris@49: { Chris@49: return arma_vec_norm_min(P); Chris@49: } Chris@49: else Chris@49: if( (sig == 'f') || (sig == 'F') ) Chris@49: { Chris@49: return arma_vec_norm_2(P); Chris@49: } Chris@49: else Chris@49: { Chris@49: arma_stop("norm(): unsupported vector norm type"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // inf norm Chris@49: { Chris@49: return arma_mat_norm_inf(P); Chris@49: } Chris@49: else Chris@49: if( (sig == 'f') || (sig == 'F') ) Chris@49: { Chris@49: return arma_vec_norm_2(P); Chris@49: } Chris@49: else Chris@49: { Chris@49: arma_stop("norm(): unsupported matrix norm type"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // Chris@49: // norms for sparse matrices Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_mat_norm_1(const SpProxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: // TODO: this can be sped up with a dedicated implementation Chris@49: return as_scalar( max( sum(abs(P.Q), 0), 1) ); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: // template Chris@49: // inline Chris@49: // typename T1::pod_type Chris@49: // arma_mat_norm_2(const SpProxy& P) Chris@49: // { Chris@49: // arma_extra_debug_sigprint(); Chris@49: // Chris@49: // // TODO: norm = sqrt( largest eigenvalue of (A^H)*A ), where ^H is the conjugate transpose Chris@49: // // TODO: can use ARPACK or directly implement the Arnoldi iteration Chris@49: // // http://math.stackexchange.com/questions/4368/computing-the-largest-eigenvalue-of-a-very-large-sparse-matrix Chris@49: // } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: typename T1::pod_type Chris@49: arma_mat_norm_inf(const SpProxy& P) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: Chris@49: // TODO: this can be sped up with a dedicated implementation Chris@49: return as_scalar( max( sum(abs(P.Q), 1), 0) ); Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: arma_warn_unused Chris@49: typename enable_if2< is_arma_sparse_type::value, typename T1::pod_type >::result Chris@49: norm Chris@49: ( Chris@49: const T1& X, Chris@49: const uword k, Chris@49: const typename arma_real_or_cx_only::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::elem_type eT; Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const SpProxy P(X); Chris@49: Chris@49: if(P.get_n_nonzero() == 0) Chris@49: { Chris@49: return T(0); Chris@49: } Chris@49: Chris@49: const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1); Chris@49: Chris@49: if(is_vec == true) Chris@49: { Chris@49: const unwrap_spmat::stored_type> tmp(P.Q); Chris@49: const SpMat& A = tmp.M; Chris@49: Chris@49: // create a fake dense vector to allow reuse of code for dense vectors Chris@49: Col fake_vector( access::rwp(A.values), A.n_nonzero, false ); Chris@49: Chris@49: const Proxy< Col > P_fake_vector(fake_vector); Chris@49: Chris@49: switch(k) Chris@49: { Chris@49: case 1: Chris@49: return arma_vec_norm_1(P_fake_vector); Chris@49: break; Chris@49: Chris@49: case 2: Chris@49: return arma_vec_norm_2(P_fake_vector); Chris@49: break; Chris@49: Chris@49: default: Chris@49: { Chris@49: arma_debug_check( (k == 0), "norm(): k must be greater than zero" ); Chris@49: return arma_vec_norm_k(P_fake_vector, int(k)); Chris@49: } Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: switch(k) Chris@49: { Chris@49: case 1: Chris@49: return arma_mat_norm_1(P); Chris@49: break; Chris@49: Chris@49: // case 2: Chris@49: // return arma_mat_norm_2(P); Chris@49: // break; Chris@49: Chris@49: default: Chris@49: arma_stop("norm(): unsupported or unimplemented norm type for sparse matrices"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: template Chris@49: inline Chris@49: arma_warn_unused Chris@49: typename enable_if2< is_arma_sparse_type::value, typename T1::pod_type >::result Chris@49: norm Chris@49: ( Chris@49: const T1& X, Chris@49: const char* method, Chris@49: const typename arma_real_or_cx_only::result* junk = 0 Chris@49: ) Chris@49: { Chris@49: arma_extra_debug_sigprint(); Chris@49: arma_ignore(junk); Chris@49: Chris@49: typedef typename T1::elem_type eT; Chris@49: typedef typename T1::pod_type T; Chris@49: Chris@49: const SpProxy P(X); Chris@49: Chris@49: if(P.get_n_nonzero() == 0) Chris@49: { Chris@49: return T(0); Chris@49: } Chris@49: Chris@49: Chris@49: const unwrap_spmat::stored_type> tmp(P.Q); Chris@49: const SpMat& A = tmp.M; Chris@49: Chris@49: // create a fake dense vector to allow reuse of code for dense vectors Chris@49: Col fake_vector( access::rwp(A.values), A.n_nonzero, false ); Chris@49: Chris@49: const Proxy< Col > P_fake_vector(fake_vector); Chris@49: Chris@49: Chris@49: const char sig = method[0]; Chris@49: const bool is_vec = (P.get_n_rows() == 1) || (P.get_n_cols() == 1); Chris@49: Chris@49: if(is_vec == true) Chris@49: { Chris@49: if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // max norm Chris@49: { Chris@49: return arma_vec_norm_max(P_fake_vector); Chris@49: } Chris@49: else Chris@49: if(sig == '-') // min norm Chris@49: { Chris@49: const T val = arma_vec_norm_min(P_fake_vector); Chris@49: Chris@49: if( P.get_n_nonzero() < P.get_n_elem() ) Chris@49: { Chris@49: return (std::min)(T(0), val); Chris@49: } Chris@49: else Chris@49: { Chris@49: return val; Chris@49: } Chris@49: } Chris@49: else Chris@49: if( (sig == 'f') || (sig == 'F') ) Chris@49: { Chris@49: return arma_vec_norm_2(P_fake_vector); Chris@49: } Chris@49: else Chris@49: { Chris@49: arma_stop("norm(): unsupported vector norm type"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: else Chris@49: { Chris@49: if( (sig == 'i') || (sig == 'I') || (sig == '+') ) // inf norm Chris@49: { Chris@49: return arma_mat_norm_inf(P); Chris@49: } Chris@49: else Chris@49: if( (sig == 'f') || (sig == 'F') ) Chris@49: { Chris@49: return arma_vec_norm_2(P_fake_vector); Chris@49: } Chris@49: else Chris@49: { Chris@49: arma_stop("norm(): unsupported matrix norm type"); Chris@49: return T(0); Chris@49: } Chris@49: } Chris@49: } Chris@49: Chris@49: Chris@49: Chris@49: //! @}