// SPDX-License-Identifier: Apache-2.0 // // Copyright 2008-2016 Conrad Sanderson (http://conradsanderson.id.au) // Copyright 2008-2016 National ICT Australia (NICTA) // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ------------------------------------------------------------------------ //! \addtogroup op_norm //! @{ template inline typename T1::pod_type op_norm::vec_norm_1(const Proxy& P, const typename arma_not_cx::result* junk) { arma_extra_debug_sigprint(); arma_ignore(junk); const bool use_direct_mem = (is_Mat::stored_type>::value) || (is_subview_col::stored_type>::value) || (arma_config::openmp && Proxy::use_mp); if(use_direct_mem) { const quasi_unwrap::stored_type> tmp(P.Q); return op_norm::vec_norm_1_direct_std(tmp.M); } typedef typename T1::pod_type T; T acc = T(0); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); const uword N = P.get_n_elem(); T acc1 = T(0); T acc2 = T(0); uword i,j; for(i=0, j=1; j inline typename T1::pod_type op_norm::vec_norm_1(const Proxy& P, const typename arma_cx_only::result* junk) { arma_extra_debug_sigprint(); arma_ignore(junk); typedef typename T1::elem_type eT; typedef typename T1::pod_type T; T acc = T(0); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); const uword N = P.get_n_elem(); for(uword i=0; i& X = A[i]; const T a = X.real(); const T b = X.imag(); acc += std::sqrt( (a*a) + (b*b) ); } } else { const uword n_rows = P.get_n_rows(); const uword n_cols = P.get_n_cols(); if(n_rows == 1) { for(uword col=0; col& X = P.at(0,col); const T a = X.real(); const T b = X.imag(); acc += std::sqrt( (a*a) + (b*b) ); } } else { for(uword col=0; col& X = P.at(row,col); const T a = X.real(); const T b = X.imag(); acc += std::sqrt( (a*a) + (b*b) ); } } } if( (acc != T(0)) && arma_isfinite(acc) ) { return acc; } else { arma_extra_debug_print("op_norm::vec_norm_1(): detected possible underflow or overflow"); const quasi_unwrap::stored_type> R(P.Q); const uword N = R.M.n_elem; const eT* R_mem = R.M.memptr(); T max_val = priv::most_neg(); for(uword i=0; i& X = R_mem[i]; const T a = std::abs(X.real()); const T b = std::abs(X.imag()); if(a > max_val) { max_val = a; } if(b > max_val) { max_val = b; } } if(max_val == T(0)) { return T(0); } T alt_acc = T(0); for(uword i=0; i& X = R_mem[i]; const T a = X.real() / max_val; const T b = X.imag() / max_val; alt_acc += std::sqrt( (a*a) + (b*b) ); } return ( alt_acc * max_val ); } } template inline eT op_norm::vec_norm_1_direct_std(const Mat& X) { arma_extra_debug_sigprint(); const uword N = X.n_elem; const eT* A = X.memptr(); if(N < uword(32)) { return op_norm::vec_norm_1_direct_mem(N,A); } else { #if defined(ARMA_USE_ATLAS) { return atlas::cblas_asum(N,A); } #elif defined(ARMA_USE_BLAS) { return blas::asum(N,A); } #else { return op_norm::vec_norm_1_direct_mem(N,A); } #endif } } template inline eT op_norm::vec_norm_1_direct_mem(const uword N, const eT* A) { arma_extra_debug_sigprint(); #if (defined(ARMA_SIMPLE_LOOPS) || defined(__FAST_MATH__)) { eT acc1 = eT(0); if(memory::is_aligned(A)) { memory::mark_as_aligned(A); for(uword i=0; i inline typename T1::pod_type op_norm::vec_norm_2(const Proxy& P, const typename arma_not_cx::result* junk) { arma_extra_debug_sigprint(); arma_ignore(junk); const bool use_direct_mem = (is_Mat::stored_type>::value) || (is_subview_col::stored_type>::value) || (arma_config::openmp && Proxy::use_mp); if(use_direct_mem) { const quasi_unwrap::stored_type> tmp(P.Q); return op_norm::vec_norm_2_direct_std(tmp.M); } typedef typename T1::pod_type T; T acc = T(0); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); const uword N = P.get_n_elem(); T acc1 = T(0); T acc2 = T(0); uword i,j; for(i=0, j=1; j::stored_type> tmp(P.Q); return op_norm::vec_norm_2_direct_robust(tmp.M); } } template inline typename T1::pod_type op_norm::vec_norm_2(const Proxy& P, const typename arma_cx_only::result* junk) { arma_extra_debug_sigprint(); arma_ignore(junk); typedef typename T1::elem_type eT; typedef typename T1::pod_type T; T acc = T(0); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); const uword N = P.get_n_elem(); for(uword i=0; i& X = A[i]; const T a = X.real(); const T b = X.imag(); acc += (a*a) + (b*b); } } else { const uword n_rows = P.get_n_rows(); const uword n_cols = P.get_n_cols(); if(n_rows == 1) { for(uword col=0; col& X = P.at(0,col); const T a = X.real(); const T b = X.imag(); acc += (a*a) + (b*b); } } else { for(uword col=0; col& X = P.at(row,col); const T a = X.real(); const T b = X.imag(); acc += (a*a) + (b*b); } } } const T sqrt_acc = std::sqrt(acc); if( (sqrt_acc != T(0)) && arma_isfinite(sqrt_acc) ) { return sqrt_acc; } else { arma_extra_debug_print("op_norm::vec_norm_2(): detected possible underflow or overflow"); const quasi_unwrap::stored_type> R(P.Q); const uword N = R.M.n_elem; const eT* R_mem = R.M.memptr(); T max_val = priv::most_neg(); for(uword i=0; i max_val) { max_val = val_i; } } if(max_val == T(0)) { return T(0); } T alt_acc = T(0); for(uword i=0; i inline eT op_norm::vec_norm_2_direct_std(const Mat& X) { arma_extra_debug_sigprint(); const uword N = X.n_elem; const eT* A = X.memptr(); eT result; if(N < uword(32)) { result = op_norm::vec_norm_2_direct_mem(N,A); } else { #if defined(ARMA_USE_ATLAS) { result = atlas::cblas_nrm2(N,A); } #elif defined(ARMA_USE_BLAS) { result = blas::nrm2(N,A); } #else { result = op_norm::vec_norm_2_direct_mem(N,A); } #endif } if( (result != eT(0)) && arma_isfinite(result) ) { return result; } else { arma_extra_debug_print("op_norm::vec_norm_2_direct_std(): detected possible underflow or overflow"); return op_norm::vec_norm_2_direct_robust(X); } } template inline eT op_norm::vec_norm_2_direct_mem(const uword N, const eT* A) { arma_extra_debug_sigprint(); eT acc; #if (defined(ARMA_SIMPLE_LOOPS) || defined(__FAST_MATH__)) { eT acc1 = eT(0); if(memory::is_aligned(A)) { memory::mark_as_aligned(A); for(uword i=0; i inline eT op_norm::vec_norm_2_direct_robust(const Mat& X) { arma_extra_debug_sigprint(); const uword N = X.n_elem; const eT* A = X.memptr(); eT max_val = priv::most_neg(); uword j; for(j=1; j max_val) { max_val = val_i; } if(val_j > max_val) { max_val = val_j; } } if((j-1) < N) { const eT val_i = std::abs(*A); if(val_i > max_val) { max_val = val_i; } } if(max_val == eT(0)) { return eT(0); } const eT* B = X.memptr(); eT acc1 = eT(0); eT acc2 = eT(0); for(j=1; j inline typename T1::pod_type op_norm::vec_norm_k(const Proxy& P, const int k) { arma_extra_debug_sigprint(); typedef typename T1::pod_type T; T acc = T(0); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); const uword N = P.get_n_elem(); for(uword i=0; i inline typename T1::pod_type op_norm::vec_norm_max(const Proxy& P) { arma_extra_debug_sigprint(); typedef typename T1::pod_type T; const uword N = P.get_n_elem(); T max_val = (N != 1) ? priv::most_neg() : std::abs(P[0]); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); uword i,j; for(i=0, j=1; j inline typename T1::pod_type op_norm::vec_norm_min(const Proxy& P) { arma_extra_debug_sigprint(); typedef typename T1::pod_type T; const uword N = P.get_n_elem(); T min_val = (N != 1) ? priv::most_pos() : std::abs(P[0]); if(Proxy::use_at == false) { typename Proxy::ea_type A = P.get_ea(); uword i,j; for(i=0, j=1; j tmp_i) { min_val = tmp_i; } if(min_val > tmp_j) { min_val = tmp_j; } } if(i < N) { const T tmp_i = std::abs(A[i]); if(min_val > tmp_i) { min_val = tmp_i; } } } else { const uword n_rows = P.get_n_rows(); const uword n_cols = P.get_n_cols(); if(n_rows != 1) { for(uword col=0; col < n_cols; ++col) for(uword row=0; row < n_rows; ++row) { const T tmp = std::abs(P.at(row,col)); if(min_val > tmp) { min_val = tmp; } } } else { for(uword col=0; col < n_cols; ++col) { const T tmp = std::abs(P.at(0,col)); if(min_val > tmp) { min_val = tmp; } } } } return min_val; } template inline typename get_pod_type::result op_norm::mat_norm_1(const Mat& X) { arma_extra_debug_sigprint(); // TODO: this can be sped up with a dedicated implementation return as_scalar( max( sum(abs(X), 0), 1) ); } template inline typename get_pod_type::result op_norm::mat_norm_2(const Mat& X) { arma_extra_debug_sigprint(); typedef typename get_pod_type::result T; if(X.internal_has_nonfinite()) { arma_debug_warn_level(1, "norm(): given matrix has non-finite elements"); } Col S; svd(S, X); return (S.n_elem > 0) ? S[0] : T(0); } template inline typename get_pod_type::result op_norm::mat_norm_inf(const Mat& X) { arma_extra_debug_sigprint(); // TODO: this can be sped up with a dedicated implementation return as_scalar( max( sum(abs(X), 1), 0) ); } //! @}