inline
bool
glue_solve_tri::apply(Mat<eT>& out, const Base<eT,T1>& A_expr, const Base<eT,T2>& B_expr, const uword flags)
  {
  arma_extra_debug_sigprint();
  
  const bool fast        = bool(flags & solve_opts::flag_fast       );
  const bool equilibrate = bool(flags & solve_opts::flag_equilibrate);
  const bool no_approx   = bool(flags & solve_opts::flag_no_approx  );
  const bool triu        = bool(flags & solve_opts::flag_triu       );
  const bool tril        = bool(flags & solve_opts::flag_tril       );
  
  arma_extra_debug_print("glue_solve_tri::apply(): enabled flags:");
  
  if(fast       )  { arma_extra_debug_print("fast");        }
  if(equilibrate)  { arma_extra_debug_print("equilibrate"); }
  if(no_approx  )  { arma_extra_debug_print("no_approx");   }
  if(triu       )  { arma_extra_debug_print("triu");        }
  if(tril       )  { arma_extra_debug_print("tril");        }
  
  bool status = false;
  
  if(equilibrate)  { arma_debug_warn("solve(): option 'equilibrate' ignored for triangular matrices"); }
  
  const unwrap_check<T1> U(A_expr.get_ref(), out);
  const Mat<eT>& A     = U.M;
  
  arma_debug_check( (A.is_square() == false), "solve(): matrix marked as triangular must be square sized" );
  
  const uword layout = (triu) ? uword(0) : uword(1);
  
  status = auxlib::solve_tri(out, A, B_expr.get_ref(), layout);  // A is not modified
  
  if( (status == false) && (no_approx == false) )
    {
    arma_extra_debug_print("glue_solve_tri::apply(): solving rank deficient system");
    
    arma_debug_warn("solve(): system seems singular; attempting approx solution");
    
    Mat<eT> triA = (triu) ? trimatu( A_expr.get_ref() ) : trimatl( A_expr.get_ref() );
    
    status = auxlib::solve_approx_svd(out, triA, B_expr.get_ref());  // triA is overwritten
    }
  
  
  if(status == false)  { out.reset(); }
  
  return status;
  }
Пример #2
0
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_debug_warn("eig_sym(): decomposition failed");
    }
  
  return status;
  }
Пример #3
0
inline
bool
syl
  (
        Mat <typename T1::elem_type>   & out,
  const Base<typename T1::elem_type,T1>& in_A,
  const Base<typename T1::elem_type,T2>& in_B,
  const Base<typename T1::elem_type,T3>& in_C,
  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename T1::elem_type eT;
  
  const unwrap_check<T1> tmp_A(in_A.get_ref(), out);
  const unwrap_check<T2> tmp_B(in_B.get_ref(), out);
  const unwrap_check<T3> tmp_C(in_C.get_ref(), out);
  
  const Mat<eT>& A = tmp_A.M;
  const Mat<eT>& B = tmp_B.M;
  const Mat<eT>& C = tmp_C.M;
  
  const bool status = auxlib::syl(out, A, B, C);
  
  if(status == false)
    {
    out.soft_reset();
    arma_debug_warn("syl(): solution not found");
    }
  
  return status;
  }
Пример #4
0
inline
bool
schur
  (
         Mat<typename T1::elem_type>&    S,
  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);
  
  typedef typename T1::elem_type eT;
  
  Mat<eT> U;
  
  const bool status = auxlib::schur(U, S, X.get_ref(), false);
  
  if(status == false)
    {
    S.reset();
    arma_debug_warn("schur(): decomposition failed");
    }
  
  return status;
  }
Пример #5
0
inline
typename enable_if2< is_supported_blas_type<typename T1::pod_type>::value, bool >::result
eig_pair
  (
         Col< std::complex<typename T1::pod_type> >& eigvals,
  const Base< typename T1::elem_type, T1 >&          A_expr,
  const Base< typename T1::elem_type, T2 >&          B_expr
  )
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::pod_type T;
  
  Mat< std::complex<T> > eigvecs;
  
  const bool status = auxlib::eig_pair(eigvals, eigvecs, false, A_expr.get_ref(), B_expr.get_ref());
  
  if(status == false)
    {
    eigvals.reset();
    arma_debug_warn("eig_pair(): decomposition failed");
    }
  
  return status;
  }
Пример #6
0
inline
bool
schur
  (
         Mat<typename T1::elem_type>&    U,
         Mat<typename T1::elem_type>&    S,
  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( void_ptr(&U) == void_ptr(&S), "schur(): 'U' is an alias of 'S'" );
  
  const bool status = auxlib::schur(U, S, X.get_ref(), true);
  
  if(status == false)
    {
    U.reset();
    S.reset();
    arma_debug_warn("schur(): decomposition failed");
    }
  
  return status;
  }
Пример #7
0
inline
typename enable_if2< is_supported_blas_type<typename T1::pod_type>::value, bool >::result
eig_pair
  (
         Col< std::complex<typename T1::pod_type> >& eigvals,
         Mat< std::complex<typename T1::pod_type> >& eigvecs,
  const Base< typename T1::elem_type, T1 >&          A_expr,
  const Base< typename T1::elem_type, T2 >&          B_expr
  )
  {
  arma_extra_debug_sigprint();
  
  arma_debug_check( (void_ptr(&eigvals) == void_ptr(&eigvecs)), "eig_pair(): parameter 'eigval' is an alias of parameter 'eigvec'" );
  
  const bool status = auxlib::eig_pair(eigvals, eigvecs, true, A_expr.get_ref(), B_expr.get_ref());
  
  if(status == false)
    {
    eigvals.reset();
    eigvecs.reset();
    arma_debug_warn("eig_pair(): decomposition failed");
    }
  
  return status;
  }
Пример #8
0
inline
bool
qr_econ
  (
         Mat<typename T1::elem_type>&    Q,
         Mat<typename T1::elem_type>&    R,
  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( (&Q == &R), "qr_econ(): Q and R are the same object");
  
  const bool status = auxlib::qr_econ(Q, R, X);
  
  if(status == false)
    {
    Q.soft_reset();
    R.soft_reset();
    arma_debug_warn("qr_econ(): decomposition failed");
    }
  
  return status;
  }
Пример #9
0
inline
bool
hess
  (
         Mat<typename T1::elem_type>&    H,
  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);
  
  typedef typename T1::elem_type eT;
  
  Col<eT> tao;
  
  const bool status = auxlib::hess(H, X.get_ref(), tao);
  
  if(H.n_rows > 2)
    {
    for(uword i=0; i < H.n_rows-2; ++i)
      {
      H(span(i+2, H.n_rows-1), i).zeros();
      }
    }
  
  if(status == false)
    {
    H.soft_reset();
    arma_debug_warn("hess(): decomposition failed");
    }
  
  return status;
  }
Пример #10
0
inline
bool
eigs_sym
  (
           Col<typename T1::pod_type >&    eigval,
           Mat<typename T1::elem_type>&    eigvec,
  const SpBase<typename T1::elem_type,T1>& X,
  const uword                              n_eigvals,
  const char*                              form = "lm",
  const typename T1::elem_type             tol  = 0.0,
  const typename arma_real_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  arma_debug_check( void_ptr(&eigval) == void_ptr(&eigvec), "eigs_sym(): paramater 'eigval' is an alias of parameter 'eigvec'" );
  
  const bool status = sp_auxlib::eigs_sym(eigval, eigvec, X, n_eigvals, form, tol);
  
  if(status == false)
    {
    eigval.reset();
    arma_debug_warn("eigs_sym(): decomposition failed");
    }
  
  return status;
  }
Пример #11
0
inline
bool
lu
  (
         Mat<typename T1::elem_type>&    L,
         Mat<typename T1::elem_type>&    U, 
         Mat<typename T1::elem_type>&    P,
  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 == &U) || (&L == &P) || (&U == &P) ), "lu(): two or more output objects are the same object");
  
  const bool status = auxlib::lu(L, U, P, X);
  
  if(status == false)
    {
    L.reset();
    U.reset();
    P.reset();
    arma_debug_warn("lu(): decomposition failed");
    }
  
  return status;
  }
Пример #12
0
inline
bool
op_logmat_cx::helper(Mat<eT>& A, const uword m)
  {
  arma_extra_debug_sigprint();
  
  const vec indices = regspace<vec>(1,m-1);
  
  mat tmp(m,m,fill::zeros);
  
  tmp.diag(-1) = indices / sqrt(square(2.0*indices) - 1.0);
  tmp.diag(+1) = indices / sqrt(square(2.0*indices) - 1.0);
  
  vec eigval;
  mat eigvec;
  
  const bool eig_ok = eig_sym(eigval, eigvec, tmp);
  
  if(eig_ok == false)  { arma_debug_warn("logmat(): eig_sym() failed"); return false; }
  
  const vec nodes   = (eigval + 1.0) / 2.0;
  const vec weights = square(eigvec.row(0).t());
  
  const uword N = A.n_rows;
  
  Mat<eT> B(N,N,fill::zeros);
  
  Mat<eT> X;
  
  for(uword i=0; i < m; ++i)
    {
    // B += weights(i) * solve( (nodes(i)*A + eye< Mat<eT> >(N,N)), A );
    
    //const bool solve_ok = solve( X, (nodes(i)*A + eye< Mat<eT> >(N,N)), A, solve_opts::fast );
    const bool solve_ok = solve( X, trimatu(nodes(i)*A + eye< Mat<eT> >(N,N)), A );
    
    if(solve_ok == false)  { arma_debug_warn("logmat(): solve() failed"); return false; }
    
    B += weights(i) * X;
    }
  
  A = B;
  
  return true;
  }
Пример #13
0
inline
void
op_sqrtmat::apply(Mat< std::complex<typename T1::elem_type> >& out, const mtOp<std::complex<typename T1::elem_type>,T1,op_sqrtmat>& in)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_sqrtmat::apply_direct(out, in.m);
  
  if(status == false)
    {
    arma_debug_warn("sqrtmat(): given matrix seems singular; may not have a square root");
    }
  }
inline
void
running_stat<eT>::operator() (const std::complex< typename running_stat<eT>::T >& sample)
  {
  arma_extra_debug_sigprint();
  
  if( arma_isfinite(sample) == false )
    {
    arma_debug_warn("running_stat: sample ignored as it is non-finite" );
    return;
    }
  
  running_stat_aux::update_stats(*this, sample);
  }
Пример #15
0
inline
typename enable_if2< (is_supported_blas_type<typename T1::elem_type>::value && is_cx<typename T1::elem_type>::yes), bool >::result
sqrtmat(Mat<typename T1::elem_type>& Y, const Base<typename T1::elem_type,T1>& X)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_sqrtmat_cx::apply_direct(Y, X.get_ref());
  
  if(status == false)
    {
    arma_debug_warn("sqrtmat(): given matrix seems singular; may not have a square root");
    }
  
  return status;
  }
Пример #16
0
inline
typename enable_if2< is_real<typename T1::pod_type>::value, bool >::result
null(Mat<typename T1::elem_type>& out, const Base<typename T1::elem_type, T1>& X, const typename T1::pod_type tol = 0.0)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_null::apply_direct(out, X.get_ref(), tol);
  
  if(status == false)
    {
    arma_debug_warn("null(): svd failed");
    }
  
  return status;
  }
Пример #17
0
inline
typename enable_if2< is_supported_blas_type<typename T1::elem_type>::value, bool >::result
expmat_sym(Mat<typename T1::elem_type>& Y, const Base<typename T1::elem_type,T1>& X)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_expmat_sym::apply_direct(Y, X.get_ref());
  
  if(status == false)
    {
    Y.reset();
    arma_debug_warn("expmat_sym(): transformation failed");
    }
  
  return status;
  }
Пример #18
0
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 =                   "dc",
  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename T1::elem_type eT;
  
  const char sig = (method != NULL) ? method[0] : char(0);
  
  arma_debug_check( ((sig != 's') && (sig != 'd')),         "eig_sym(): unknown method specified"                             );
  arma_debug_check( void_ptr(&eigval) == void_ptr(&eigvec), "eig_sym(): parameter 'eigval' is an alias of parameter 'eigvec'" );
  
  const Proxy<T1> P(X.get_ref());
  
  const bool is_alias = P.is_alias(eigvec);
  
  Mat<eT>  eigvec_tmp;
  Mat<eT>& eigvec_out = (is_alias == false) ? eigvec : eigvec_tmp;
  
  bool status = false;
  
  if(sig == 'd')       { status = auxlib::eig_sym_dc(eigval, eigvec_out, P.Q); }
  
  if(status == false)  { status = auxlib::eig_sym(eigval, eigvec_out, P.Q);    }
  
  if(status == false)
    {
    eigval.reset();
    eigvec.reset();
    arma_debug_warn("eig_sym(): decomposition failed");
    }
  else
    {
    if(is_alias)  { eigvec.steal_mem(eigvec_tmp); }
    }
  
  return status;
  }
Пример #19
0
inline
typename
enable_if2
  <
  is_supported_blas_type<typename T1::elem_type>::value,
  bool
  >::result
roots(Mat< std::complex<typename T1::pod_type> >& out, const Base<typename T1::elem_type, T1>& X)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_roots::apply_direct(out, X.get_ref());
  
  if(status == false)  { arma_debug_warn("roots(): eigen decomposition failed"); }
  
  return status;
  }
Пример #20
0
arma_warn_unused
inline
typename enable_if2< is_supported_blas_type<typename T1::elem_type>::value, typename T1::elem_type >::result
det
  (
  const Op<T1,op_inv>& X
  )
  {
  arma_extra_debug_sigprint();
  
  typedef typename T1::elem_type eT;
  
  const eT tmp = det(X.m);
  
  if(tmp == eT(0))  { arma_debug_warn("det(): denominator is zero" ); }
  
  return eT(1) / tmp;
  }
Пример #21
0
inline
typename
enable_if2
  <
  is_real<typename T1::elem_type>::value,
  bool
  >::result
wishrnd(Mat<typename T1::elem_type>& W, const Base<typename T1::elem_type, T1>& S, typename T1::elem_type df)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_wishrnd::apply_direct(W, S.get_ref(), df, uword(1));
  
  if(status == false)
    {
    arma_debug_warn("wishrnd(): given matrix is not symmetric positive definite");
    return false;
    }
  
  return true;
  }
Пример #22
0
inline
arma_warn_unused
typename T1::elem_type
det
  (
  const Op<T1,op_inv>& X,
  const bool slow = false,
  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename T1::elem_type eT;
  
  const eT tmp = det(X.m, slow);
  
  arma_debug_warn( (tmp == eT(0)), "det(): warning: denominator is zero" );
  
  return eT(1) / tmp;
  }
Пример #23
0
arma_warn_unused
inline
typename
enable_if2
  <
  is_real<typename T1::elem_type>::value,
  bool
  >::result
mvnrnd(Mat<typename T1::elem_type>& out, const Base<typename T1::elem_type, T1>& M, const Base<typename T1::elem_type, T2>& C, const uword N)
  {
  arma_extra_debug_sigprint();
  
  const bool status = glue_mvnrnd::apply_direct(out, M.get_ref(), C.get_ref(), N);
  
  if(status == false)
    {
    arma_debug_warn("mvnrnd(): given covariance matrix is not symmetric positive semi-definite");
    return false;
    }
  
  return true;
  }
Пример #24
0
inline
typename
enable_if2
  <
  is_real<typename T1::pod_type>::value,
  bool
  >::result
expmat(Mat<typename T1::elem_type>& B, const Base<typename T1::elem_type,T1>& A)
  {
  arma_extra_debug_sigprint();
  
  const bool status = op_expmat::apply_direct(B, A);
  
  if(status == false)
    {
    arma_debug_warn("expmat(): given matrix appears ill-conditioned");
    B.reset();
    return false;
    }
  
  return true;
  }
arma_hot
inline
void
running_stat_vec<obj_type>::operator() (const Base<typename running_stat_vec<obj_type>::T, T1>& X)
  {
  arma_extra_debug_sigprint();
  
  const quasi_unwrap<T1> tmp(X.get_ref());
  const Mat<T>& sample = tmp.M;
  
  if( sample.is_empty() )
    {
    return;
    }
  
  if( sample.is_finite() == false )
    {
    arma_debug_warn("running_stat_vec: sample ignored as it has non-finite elements");
    return;
    }
  
  running_stat_vec_aux::update_stats(*this, sample);
  }
Пример #26
0
inline
bool
spsolve
  (
           Mat<typename T1::elem_type>&     out,
  const SpBase<typename T1::elem_type, T1>& A,
  const   Base<typename T1::elem_type, T2>& B,
  const char*                          solver   = "superlu",
  const spsolve_opts_base&             settings = spsolve_opts_none(),
  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  const bool status = spsolve_helper(out, A.get_ref(), B.get_ref(), solver, settings);
  
  if(status == false)
    {
    arma_debug_warn("spsolve(): solution not found");
    }
  
  return status;
  }
Пример #27
0
inline
bool
hess
  (
         Mat<typename T1::elem_type>&    U,
         Mat<typename T1::elem_type>&    H,
  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( void_ptr(&U) == void_ptr(&H), "hess(): 'U' is an alias of 'H'" );
  
  typedef typename T1::elem_type eT;
  
  Col<eT> tao;
  
  const bool status = auxlib::hess(H, X.get_ref(), tao);
  
  if(H.n_rows == 0)
    {
    U.reset();
    }
  else
  if(H.n_rows == 1)
    {
    U.ones(1, 1);
    }
  else
  if(H.n_rows == 2)
    {
    U.eye(2, 2);
    }
  else
    {
    U.eye(size(H));
    
    Col<eT> v;
    
    for(uword i=0; i < H.n_rows-2; ++i)
      {
      // TODO: generate v in a more efficient manner; 
      // TODO: the .ones() operation is an overkill, as most of v is overwritten afterwards
      
      v.ones(H.n_rows-i-1);
      
      v(span(1, H.n_rows-i-2)) = H(span(i+2, H.n_rows-1), i);
      
      U(span::all, span(i+1, H.n_rows-1)) -= tao(i) * (U(span::all, span(i+1, H.n_rows-1)) * v * v.t());
      }
    
    U(span::all, H.n_rows-1) = U(span::all, H.n_rows-1) * (eT(1) - tao(H.n_rows-2));
    
    for(uword i=0; i < H.n_rows-2; ++i)
      {
      H(span(i+2, H.n_rows-1), i).zeros();
      }
    }
  
  if(status == false)
    {
    U.soft_reset();
    H.soft_reset();
    arma_debug_warn("hess(): decomposition failed");
    }
  
  return status;
  }
Пример #28
0
inline
bool
spsolve_helper
  (
           Mat<typename T1::elem_type>&     out,
  const SpBase<typename T1::elem_type, T1>& A,
  const   Base<typename T1::elem_type, T2>& B,
  const char*                          solver,
  const spsolve_opts_base&             settings,
  const typename arma_blas_type_only<typename T1::elem_type>::result* junk = 0
  )
  {
  arma_extra_debug_sigprint();
  arma_ignore(junk);
  
  typedef typename T1::elem_type eT;
  
  const char sig = (solver != NULL) ? solver[0] : char(0);
  
  arma_debug_check( ((sig != 'l') && (sig != 's')), "spsolve(): unknown solver" );
  
  bool status = false;
  
  if(sig == 's')  // SuperLU solver
    {
    const superlu_opts& opts = (settings.id == 1) ? static_cast<const superlu_opts&>(settings) : superlu_opts();
    
    arma_debug_check( ( (opts.pivot_thresh < double(0)) || (opts.pivot_thresh > double(1)) ), "spsolve(): pivot_thresh out of bounds" );
    
    status = sp_auxlib::spsolve(out, A.get_ref(), B.get_ref(), opts);
    }
  else
  if(sig == 'l')  // brutal LAPACK solver
    {
    if(settings.id != 0)  { arma_debug_warn("spsolve(): ignoring settings not applicable to LAPACK based solver"); }
    
    Mat<eT> AA;
    
    bool conversion_ok = false;
    
    try
      {
      Mat<eT> tmp(A.get_ref());  // conversion from sparse to dense can throw std::bad_alloc
      
      AA.steal_mem(tmp);
      
      conversion_ok = true;
      }
    catch(std::bad_alloc&)
      {
      arma_debug_warn("spsolve(): not enough memory to use LAPACK based solver");
      }
    
    if(conversion_ok)
      {
      arma_debug_check( (AA.n_rows != AA.n_cols), "spsolve(): matrix A must be square sized" );
      
      status = auxlib::solve(out, AA, B.get_ref(), true);
      }
    }
  
  if(status == false)  { out.reset(); }
  
  return status;
  }
Пример #29
0
inline
bool
op_logmat_cx::apply_common(Mat< std::complex<T> >& out, Mat< std::complex<T> >& S, const uword n_iters)
  {
  arma_extra_debug_sigprint();
  
  typedef typename std::complex<T> eT;
  
  Mat<eT> U;
  
  const bool schur_ok = auxlib::schur(U,S);
  
  if(schur_ok == false)  { arma_extra_debug_print("logmat(): schur decomposition failed"); return false; }
  
//double theta[] = { 1.10e-5, 1.82e-3, 1.62e-2,               5.39e-2,               1.14e-1,               1.87e-1,               2.64e-1              };
  double theta[] = { 0.0,     0.0,     1.6206284795015624e-2, 5.3873532631381171e-2, 1.1352802267628681e-1, 1.8662860613541288e-1, 2.642960831111435e-1 };
  // theta[0] and theta[1] not really used
  
  const uword N = S.n_rows;
  
  uword p = 0;
  uword m = 6;
  
  uword iter = 0;
  
  while(iter < n_iters)
    {
    const T tau = norm( (S - eye< Mat<eT> >(N,N)), 1 );
    
    if(tau <= theta[6])
      {
      p++;
      
      uword j1 = 0;
      uword j2 = 0;
      
      for(uword i=2; i<=6; ++i)  { if( tau      <= theta[i])  { j1 = i; break; } }
      for(uword i=2; i<=6; ++i)  { if((tau/2.0) <= theta[i])  { j2 = i; break; } }
      
      // sanity check, for development purposes only
      arma_debug_check( (j2 > j1), "internal error: op_logmat::apply_direct(): j2 > j1" );
      
      if( ((j1 - j2) <= 1) || (p == 2) )  { m = j1; break; }
      }
    
    const bool sqrtmat_ok = op_sqrtmat_cx::apply_direct(S,S);
    
    if(sqrtmat_ok == false)  { arma_extra_debug_print("logmat(): sqrtmat() failed"); return false; }
    
    iter++;
    }
  
  if(iter >= n_iters)  { arma_debug_warn("logmat(): reached max iterations without full convergence"); }
  
  S.diag() -= eT(1);
  
  if(m >= 1)
    {
    const bool helper_ok = op_logmat_cx::helper(S,m);
    
    if(helper_ok == false)  { return false; }
    }
  
  out = U * S * U.t();
  
  out *= eT(eop_aux::pow(double(2), double(iter)));
  
  return true;
  }
inline
bool
glue_solve_gen::apply(Mat<eT>& out, const Base<eT,T1>& A_expr, const Base<eT,T2>& B_expr, const uword flags)
  {
  arma_extra_debug_sigprint();
  
  typedef typename get_pod_type<eT>::result T;
  
  const bool fast        = bool(flags & solve_opts::flag_fast       );
  const bool equilibrate = bool(flags & solve_opts::flag_equilibrate);
  const bool no_approx   = bool(flags & solve_opts::flag_no_approx  );
  
  arma_extra_debug_print("glue_solve_gen::apply(): enabled flags:");
  
  if(fast       )  { arma_extra_debug_print("fast");        }
  if(equilibrate)  { arma_extra_debug_print("equilibrate"); }
  if(no_approx  )  { arma_extra_debug_print("no_approx");   }
  
  T    rcond  = T(0);
  bool status = false;
  
  Mat<eT> A = A_expr.get_ref();
  
  if(A.n_rows == A.n_cols)
    {
    arma_extra_debug_print("glue_solve_gen::apply(): detected square system");
    
    if(fast)
      {
      arma_extra_debug_print("glue_solve_gen::apply(): (fast)");
      
      if(equilibrate)  { arma_debug_warn("solve(): option 'equilibrate' ignored, as option 'fast' is enabled"); }
      
      status = auxlib::solve_square_fast(out, A, B_expr.get_ref());  // A is overwritten
      }
    else
      {
      arma_extra_debug_print("glue_solve_gen::apply(): (refine)");
      
      status = auxlib::solve_square_refine(out, rcond, A, B_expr, equilibrate);  // A is overwritten
      }
    
    if( (status == false) && (no_approx == false) )
      {
      arma_extra_debug_print("glue_solve_gen::apply(): solving rank deficient system");
      
      if(rcond > T(0))
        {
        arma_debug_warn("solve(): system seems singular (rcond: ", rcond, "); attempting approx solution");
        }
      else
        {
        arma_debug_warn("solve(): system seems singular; attempting approx solution");
        }
      
      Mat<eT> AA = A_expr.get_ref();
      status = auxlib::solve_approx_svd(out, AA, B_expr.get_ref());  // AA is overwritten
      }
    }
  else
    {
    arma_extra_debug_print("glue_solve_gen::apply(): detected non-square system");
    
    if(equilibrate)  { arma_debug_warn( "solve(): option 'equilibrate' ignored for non-square matrix" ); }
    
    if(fast)
      {
      status = auxlib::solve_approx_fast(out, A, B_expr.get_ref());  // A is overwritten
      
      if(status == false)
        {
        Mat<eT> AA = A_expr.get_ref();
        
        status = auxlib::solve_approx_svd(out, AA, B_expr.get_ref());  // AA is overwritten
        }
      }
    else
      {
      status = auxlib::solve_approx_svd(out, A, B_expr.get_ref());  // A is overwritten
      }
    }
  
  
  if(status == false)  { out.reset(); }
  
  return status;
  }