From 1ccc7dbd73ed1013fd651dacf8d3a7090eb69062 Mon Sep 17 00:00:00 2001 From: conrad Date: Thu, 14 Aug 2025 19:43:08 +1000 Subject: [PATCH] fallback to generic method if symmetric/hermitian optimisation failed --- include/armadillo_bits/fn_cond_rcond.hpp | 10 ++- include/armadillo_bits/op_cond_bones.hpp | 8 +- include/armadillo_bits/op_cond_meat.hpp | 93 ++++++++++++++---------- 3 files changed, 67 insertions(+), 44 deletions(-) diff --git a/include/armadillo_bits/fn_cond_rcond.hpp b/include/armadillo_bits/fn_cond_rcond.hpp index 1ef1e1b2..6455c663 100644 --- a/include/armadillo_bits/fn_cond_rcond.hpp +++ b/include/armadillo_bits/fn_cond_rcond.hpp @@ -29,7 +29,15 @@ cond(const Base& X) { arma_debug_sigprint(); - return op_cond::apply(X.get_ref()); + typedef typename T1::pod_type T; + + T out = T(0); + + const bool status = op_cond::apply(out, X.get_ref()); + + if(status == false) { arma_stop_runtime_error("cond(): failed"); return Datum::nan; } + + return out; } diff --git a/include/armadillo_bits/op_cond_bones.hpp b/include/armadillo_bits/op_cond_bones.hpp index e494a8d8..5b123338 100644 --- a/include/armadillo_bits/op_cond_bones.hpp +++ b/include/armadillo_bits/op_cond_bones.hpp @@ -23,11 +23,11 @@ struct op_cond : public traits_op_default { - template static inline typename T1::pod_type apply(const Base& X); + template static inline bool apply(typename T1::pod_type& out, const Base& X); - template static inline typename get_pod_type::result apply_diag(const Mat& A); - template static inline typename get_pod_type::result apply_sym ( Mat& A); - template static inline typename get_pod_type::result apply_gen ( Mat& A); + template static inline bool apply_diag(typename get_pod_type::result& out, const Mat& A); + template static inline bool apply_sym (typename get_pod_type::result& out, Mat& A); + template static inline bool apply_gen (typename get_pod_type::result& out, Mat& A); }; diff --git a/include/armadillo_bits/op_cond_meat.hpp b/include/armadillo_bits/op_cond_meat.hpp index 6ef475be..a272b09d 100644 --- a/include/armadillo_bits/op_cond_meat.hpp +++ b/include/armadillo_bits/op_cond_meat.hpp @@ -23,8 +23,8 @@ template inline -typename T1::pod_type -op_cond::apply(const Base& X) +bool +op_cond::apply(typename T1::pod_type& out, const Base& X) { arma_debug_sigprint(); @@ -33,31 +33,55 @@ op_cond::apply(const Base& X) Mat A(X.get_ref()); - if(A.n_elem == 0) { return T(0); } + if(A.n_elem == 0) { out = T(0); return true; } if(is_op_diagmat::value || A.is_diagmat()) { arma_debug_print("op_cond::apply(): diag optimisation"); - return op_cond::apply_diag(A); + return op_cond::apply_diag(out, A); } - if(sym_helper::is_approx_sym(A)) + bool do_sym = false; + + const bool is_sym_size_ok = (A.n_rows == A.n_cols) && (A.n_rows > (is_cx::yes ? uword(20) : uword(40))); // for consistency with op_pinv + + if( (is_sym_size_ok) && (arma_config::optimise_sym) ) + { + do_sym = is_sym_expr::eval(X.get_ref()); + + if(do_sym == false) { do_sym = sym_helper::is_approx_sym(A); } + } + + if(do_sym) { arma_debug_print("op_cond: symmetric/hermitian optimisation"); - return op_cond::apply_sym(A); + const bool status = op_cond::apply_sym(out, A); + + if(status) + { + return true; + } + else + { + arma_debug_print("op_cond: symmetric/hermitian optimisation failed"); + + A = X.get_ref(); + + // fallthrough + } } - return op_cond::apply_gen(A); + return op_cond::apply_gen(out, A); } template inline -typename get_pod_type::result -op_cond::apply_diag(const Mat& A) +bool +op_cond::apply_diag(typename get_pod_type::result& out, const Mat& A) { arma_debug_sigprint(); @@ -72,28 +96,25 @@ op_cond::apply_diag(const Mat& A) { const T abs_val = std::abs(A.at(i,i)); - if(arma_isnan(abs_val)) - { - arma_warn(3, "cond(): failed"); - - return Datum::nan; - } + if(arma_isnan(abs_val)) { out = Datum::nan; return false; } abs_min = (abs_val < abs_min) ? abs_val : abs_min; abs_max = (abs_val > abs_max) ? abs_val : abs_max; } - if((abs_min == T(0)) || (abs_max == T(0))) { return Datum::inf; } + if((abs_min == T(0)) || (abs_max == T(0))) { out = Datum::inf; return true; } - return T(abs_max / abs_min); + out = T(abs_max / abs_min); + + return true; } template inline -typename get_pod_type::result -op_cond::apply_sym(Mat& A) +bool +op_cond::apply_sym(typename get_pod_type::result& out, Mat& A) { arma_debug_sigprint(); @@ -103,14 +124,9 @@ op_cond::apply_sym(Mat& A) const bool status = auxlib::eig_sym(eigval, A); - if(status == false) - { - arma_warn(3, "cond(): failed"); - - return Datum::nan; - } + if(status == false) { out = Datum::nan; return false; } - if(eigval.n_elem == 0) { return T(0); } + if(eigval.n_elem == 0) { out = T(0); return true; } const T* eigval_mem = eigval.memptr(); @@ -125,17 +141,19 @@ op_cond::apply_sym(Mat& A) abs_max = (abs_val > abs_max) ? abs_val : abs_max; } - if((abs_min == T(0)) || (abs_max == T(0))) { return Datum::inf; } + if((abs_min == T(0)) || (abs_max == T(0))) { out = Datum::inf; return true; } - return T(abs_max / abs_min); + out = T(abs_max / abs_min); + + return true; } template inline -typename get_pod_type::result -op_cond::apply_gen(Mat& A) +bool +op_cond::apply_gen(typename get_pod_type::result& out, Mat& A) { arma_debug_sigprint(); @@ -145,21 +163,18 @@ op_cond::apply_gen(Mat& A) const bool status = auxlib::svd_dc(S, A); - if(status == false) - { - arma_warn(3, "cond(): failed"); - - return Datum::nan; - } + if(status == false) { out = Datum::nan; return false; } - if(S.n_elem == 0) { return T(0); } + if(S.n_elem == 0) { out = T(0); return true; } const T S_max = S[0]; const T S_min = S[S.n_elem-1]; - if((S_max == T(0)) || (S_min == T(0))) { return Datum::inf; } + if((S_max == T(0)) || (S_min == T(0))) { out = Datum::inf; return true; } - return T(S_max / S_min); + out = T(S_max / S_min); + + return true; }