Compare commits

...
16 Commits
Author SHA1 Message Date
conrad bc2e8d5fcc patch bump 2026-07-23 23:23:18 +10:00
conrad c8b3ac8df1 fix speed regression for diagmat(glue_times) 2026-07-21 14:58:50 +10:00
conrad fef5c5954d fix speed regression for diagvec(glue_times) 2026-07-21 14:24:50 +10:00
conrad 9ce600b03b patch bump 2026-07-09 14:34:39 +10:00
conrad 37744f9a3c fix: unwrap the given object 2026-07-09 13:56:55 +10:00
conrad 1954f4a1d8 minor cleanup 2026-07-08 11:31:26 +10:00
conrad 9d731a6565 workaround for false positive warnings in GCC 15 2026-07-06 12:52:44 +10:00
conrad c7ffb88d54 more efficient handling of aliasing 2026-07-02 22:34:59 +10:00
conrad fe2930b966 fix: unwrap the given object 2026-07-02 21:23:15 +10:00
conrad 25aca17550 remove redundant code 2026-07-01 15:04:22 +10:00
conrad 23f652e542 simplification + speedup 2026-07-01 14:45:17 +10:00
conrad c6f4af01d8 more efficient handling of aliasing 2026-06-29 23:12:20 +10:00
conrad 1441e9f1a0 fix for handling .is_alias() 2026-06-29 23:07:24 +10:00
conrad f41149d528 more efficient handling of aliasing 2026-06-29 12:51:40 +10:00
conrad 3d7fd53b53 fill only non-integer matrices with NaN 2026-06-26 12:27:57 +10:00
conrad 340a1b3592 expand Mat::fixed with .row() and .col() specialisations 2026-06-25 12:04:18 +10:00
32 changed files with 381 additions and 195 deletions
+6
View File
@@ -938,6 +938,12 @@ class Mat<eT>::fixed : public Mat<eT>
arma_warn_unused arma_inline eT* memptr();
arma_warn_unused arma_inline const eT* memptr() const;
arma_inline subview_row<eT> row(const uword row_num);
arma_inline const subview_row<eT> row(const uword row_num) const;
arma_inline subview_col<eT> col(const uword col_num);
arma_inline const subview_col<eT> col(const uword col_num) const;
arma_warn_unused arma_inline bool is_vec() const;
inline const Mat<eT>& fill(const eT val);
+60
View File
@@ -10746,6 +10746,66 @@ Mat<eT>::fixed<fixed_n_rows, fixed_n_cols>::memptr() const
template<typename eT>
template<uword fixed_n_rows, uword fixed_n_cols>
arma_inline
subview_row<eT>
Mat<eT>::fixed<fixed_n_rows, fixed_n_cols>::row(const uword row_num)
{
arma_debug_sigprint();
arma_conform_check_bounds( row_num >= fixed_n_rows, "Mat::row(): index out of bounds" );
return subview_row<eT>(*this, row_num);
}
template<typename eT>
template<uword fixed_n_rows, uword fixed_n_cols>
arma_inline
const subview_row<eT>
Mat<eT>::fixed<fixed_n_rows, fixed_n_cols>::row(const uword row_num) const
{
arma_debug_sigprint();
arma_conform_check_bounds( row_num >= fixed_n_rows, "Mat::row(): index out of bounds" );
return subview_row<eT>(*this, row_num);
}
template<typename eT>
template<uword fixed_n_rows, uword fixed_n_cols>
arma_inline
subview_col<eT>
Mat<eT>::fixed<fixed_n_rows, fixed_n_cols>::col(const uword col_num)
{
arma_debug_sigprint();
arma_conform_check_bounds( col_num >= fixed_n_cols, "Mat::col(): index out of bounds" );
return subview_col<eT>(*this, col_num);
}
template<typename eT>
template<uword fixed_n_rows, uword fixed_n_cols>
arma_inline
const subview_col<eT>
Mat<eT>::fixed<fixed_n_rows, fixed_n_cols>::col(const uword col_num) const
{
arma_debug_sigprint();
arma_conform_check_bounds( col_num >= fixed_n_cols, "Mat::col(): index out of bounds" );
return subview_col<eT>(*this, col_num);
}
template<typename eT>
template<uword fixed_n_rows, uword fixed_n_cols>
arma_inline
-2
View File
@@ -52,8 +52,6 @@ struct SpBase
{
arma_inline const derived& get_ref() const;
arma_inline bool is_alias(const SpMat<elem_type>& X) const;
arma_warn_unused inline const SpOp<derived,spop_htrans> t() const; //!< Hermitian transpose
arma_warn_unused inline const SpOp<derived,spop_htrans> ht() const; //!< Hermitian transpose
arma_warn_unused inline const SpOp<derived,spop_strans> st() const; //!< simple transpose
-10
View File
@@ -31,16 +31,6 @@ SpBase<elem_type,derived>::get_ref() const
template<typename elem_type, typename derived>
arma_inline
bool
SpBase<elem_type,derived>::is_alias(const SpMat<elem_type>& X) const
{
return (*this).get_ref().is_alias(X);
}
template<typename elem_type, typename derived>
inline
const SpOp<derived, spop_htrans>
+2 -1
View File
@@ -37,7 +37,8 @@ struct SpGlue : public SpBase< typename T1::elem_type, SpGlue<T1, T2, spglue_typ
inline SpGlue(const T1& in_A, const T2& in_B, const elem_type in_aux);
inline ~SpGlue();
arma_inline bool is_alias(const SpMat<elem_type>& X) const;
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
const T1& A; //!< first operand; must be derived from SpBase
const T2& B; //!< second operand; must be derived from SpBase
+2 -1
View File
@@ -54,9 +54,10 @@ SpGlue<T1,T2,spglue_type>::~SpGlue()
template<typename T1, typename T2, typename spglue_type>
template<typename eT2>
arma_inline
bool
SpGlue<T1,T2,spglue_type>::is_alias(const SpMat<typename T1::elem_type>& X) const
SpGlue<T1,T2,spglue_type>::is_alias(const SpMat<eT2>& X) const
{
return (A.is_alias(X) || B.is_alias(X));
}
+2 -1
View File
@@ -649,7 +649,8 @@ class SpMat : public SpBase< eT, SpMat<eT> >
template<typename eT2, typename T1, typename Functor> inline void init_xform_mt(const SpBase<eT2,T1>& x, const Functor& func);
//! don't use this unless you're writing internal Armadillo code
arma_inline bool is_alias(const SpMat<eT>& X) const;
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
protected:
+5 -2
View File
@@ -6015,11 +6015,14 @@ SpMat<eT>::init_xform_mt(const SpBase<eT2,T1>& A, const Functor& func)
template<typename eT>
template<typename eT2>
arma_inline
bool
SpMat<eT>::is_alias(const SpMat<eT>& X) const
SpMat<eT>::is_alias(const SpMat<eT2>& X) const
{
return (&X == this);
arma_debug_sigprint();
return (is_same_type<eT,eT2>::yes) && (void_ptr(this) == void_ptr(&X));
}
+2 -1
View File
@@ -38,7 +38,8 @@ struct SpOp : public SpBase< typename T1::elem_type, SpOp<T1, op_type> >
inline SpOp(const T1& in_m, const uword in_aux_uword_a, const uword in_aux_uword_b);
inline ~SpOp();
arma_inline bool is_alias(const SpMat<elem_type>& X) const;
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
const T1& m; //!< the operand; must be derived from SpBase
elem_type aux; //!< auxiliary data, using the element type as used by T1
+2 -1
View File
@@ -64,9 +64,10 @@ SpOp<T1, op_type>::~SpOp()
template<typename T1, typename op_type>
template<typename eT2>
arma_inline
bool
SpOp<T1, op_type>::is_alias(const SpMat<typename T1::elem_type>& X) const
SpOp<T1, op_type>::is_alias(const SpMat<eT2>& X) const
{
return m.is_alias(X);
}
+2 -1
View File
@@ -323,7 +323,8 @@ class SpSubview : public SpBase< eT, SpSubview<eT> >
inline const_row_iterator end_row(const uword row_num) const;
//! don't use this unless you're writing internal Armadillo code
arma_inline bool is_alias(const SpMat<eT>& X) const;
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
private:
@@ -89,6 +89,8 @@ class SpSubview_col_list : public SpBase< eT, SpSubview_col_list<eT,T1> >
inline static void schur_inplace(SpMat<eT>& out, const SpSubview_col_list& in);
inline static void div_inplace(SpMat<eT>& out, const SpSubview_col_list& in);
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
friend class SpMat<eT>;
};
@@ -714,4 +714,15 @@ SpSubview_col_list<eT,T1>::div_inplace(SpMat<eT>& out, const SpSubview_col_list&
template<typename eT, typename T1>
template<typename eT2>
arma_inline
bool
SpSubview_col_list<eT,T1>::is_alias(const SpMat<eT2>& X) const
{
return m.is_alias(X);
}
//! @}
+2 -1
View File
@@ -1786,9 +1786,10 @@ SpSubview<eT>::end_row(const uword row_num) const
template<typename eT>
template<typename eT2>
arma_inline
bool
SpSubview<eT>::is_alias(const SpMat<eT>& X) const
SpSubview<eT>::is_alias(const SpMat<eT2>& X) const
{
return m.is_alias(X);
}
+1 -1
View File
@@ -23,7 +23,7 @@
#define ARMA_VERSION_MAJOR 15
#define ARMA_VERSION_MINOR 4
#define ARMA_VERSION_PATCH 0
#define ARMA_VERSION_PATCH 2
#define ARMA_VERSION_NAME "Medium Roast Agave"
+1 -1
View File
@@ -1865,7 +1865,7 @@ diskio::load_csv_ascii(Mat<eT>& x, std::istream& f, std::string& err_msg, const
try { x.zeros(f_n_rows, f_n_cols); } catch(...) { err_msg = "not enough memory"; return false; }
if(strict) { x.fill(Datum<eT>::nan); } // take into account that each row may have a unique number of columns
if(strict && is_real<eT>::yes) { x.fill(Datum<eT>::nan); } // take into account that each row may have a unique number of columns
const bool use_mp = (arma_config::openmp) && (f_n_rows >= 2) && (f_n_cols >= 64);
+5 -5
View File
@@ -22,9 +22,8 @@
struct memory
{
template<typename eT> arma_malloc inline static eT* acquire(const uword n_elem);
template<typename eT> arma_inline static void release(eT* mem);
template<typename eT> arma_inline static eT* acquire(const uword n_elem);
template<typename eT> arma_inline static void release( eT* mem );
template<typename eT> arma_inline static bool is_aligned(const eT* mem);
template<typename eT> arma_inline static void mark_as_aligned( eT*& mem);
@@ -33,9 +32,10 @@ struct memory
// NOTE: arma_inline is used as a partial workaround for bugs in GCC 15:
// NOTE: false positive warnings from -Wmismatched-new-delete and -Wmaybe-uninitialized
template<typename eT>
arma_malloc
inline
arma_inline
eT*
memory::acquire(const uword n_elem)
{
+1 -1
View File
@@ -94,7 +94,7 @@ arma_inline
bool
mtSpOp<out_eT, T1, op_type>::is_alias(const SpMat<eT2>& X) const
{
return (void_ptr(&X) == void_ptr(&m));
return m.is_alias(X);
}
@@ -52,6 +52,9 @@ struct mtSpReduceOp : public SpBase< out_eT, mtSpReduceOp<out_eT, T1, op_type> >
inline mtSpReduceOp(const T1& in_m, const uword in_aux_uword_a, const uword in_aux_uword_b);
inline ~mtSpReduceOp();
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
const T1& m; //!< the operand; must be derived from SpBase
uword aux_uword_a; //!< auxiliary data, uword format
uword aux_uword_b; //!< auxiliary data, uword format
@@ -52,4 +52,15 @@ mtSpReduceOp<out_eT, T1, op_type>::~mtSpReduceOp()
template<typename out_eT, typename T1, typename op_type>
template<typename eT2>
arma_inline
bool
mtSpReduceOp<out_eT, T1, op_type>::is_alias(const SpMat<eT2>& X) const
{
return m.is_alias(X);
}
//! @}
@@ -27,12 +27,20 @@ struct op_diagmat
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op<T1,op_diagmat>& X);
template<typename T1>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_diagmat>& X);
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Proxy<T1>& P);
//
template<typename T1, typename T2>
inline static void apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagmat>& X);
template<typename T1, typename T2>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagmat>& X);
template<typename T1, typename T2>
inline static void apply_times(Mat<typename T1::elem_type>& out, const T1& X, const T2& Y, const typename arma_not_cx<typename T1::elem_type>::result* junk = nullptr);
@@ -48,6 +56,9 @@ struct op_diagmat2
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op<T1,op_diagmat2>& X);
template<typename T1>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_diagmat2>& X);
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Proxy<T1>& P, const uword row_offset, const uword col_offset);
};
+74 -32
View File
@@ -104,6 +104,20 @@ op_diagmat::apply(Mat<typename T1::elem_type>& out, const Op<T1, op_diagmat>& X)
template<typename T1>
inline
void
op_diagmat::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1, op_diagmat>& X)
{
arma_debug_sigprint();
const Proxy<T1> P(X.m);
op_diagmat::apply(out, P);
}
template<typename T1>
inline
void
@@ -160,6 +174,31 @@ op_diagmat::apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_ti
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
if(X.m.is_alias(out))
{
Mat<eT> tmp;
op_diagmat::apply_times(tmp, X.m.A, X.m.B);
out.steal_mem(tmp);
}
else
{
op_diagmat::apply_times(out, X.m.A, X.m.B);
}
}
template<typename T1, typename T2>
inline
void
op_diagmat::apply(Mat_noalias<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagmat>& X)
{
arma_debug_sigprint();
op_diagmat::apply_times(out, X.m.A, X.m.B);
}
@@ -168,7 +207,7 @@ op_diagmat::apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_ti
template<typename T1, typename T2>
inline
void
op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, const T2& Y, const typename arma_not_cx<typename T1::elem_type>::result* junk)
op_diagmat::apply_times(Mat<typename T1::elem_type>& out, const T1& X, const T2& Y, const typename arma_not_cx<typename T1::elem_type>::result* junk)
{
arma_debug_sigprint();
arma_ignore(junk);
@@ -204,9 +243,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -222,9 +261,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -240,9 +279,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -258,20 +297,15 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
}
// if we got to this point, the multiplication results in a matrix
const bool is_alias = (UA.is_alias(actual_out) || UB.is_alias(actual_out));
Mat<eT> tmp;
Mat<eT>& out = (is_alias) ? tmp : actual_out;
if( (partial_unwrap<T1>::do_trans == false) && (partial_unwrap<T2>::do_trans == false) )
{
@@ -384,8 +418,6 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
out.at(k,k) = (use_alpha) ? eT(alpha * acc) : eT(acc);
}
}
if(is_alias) { actual_out.steal_mem(tmp); }
}
@@ -393,7 +425,7 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
template<typename T1, typename T2>
inline
void
op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, const T2& Y, const typename arma_cx_only<typename T1::elem_type>::result* junk)
op_diagmat::apply_times(Mat<typename T1::elem_type>& out, const T1& X, const T2& Y, const typename arma_cx_only<typename T1::elem_type>::result* junk)
{
arma_debug_sigprint();
arma_ignore(junk);
@@ -430,9 +462,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -448,9 +480,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -466,9 +498,9 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
@@ -484,20 +516,15 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
const eT* C_mem = C.memptr();
const uword N = C.n_elem;
actual_out.zeros(N,N);
out.zeros(N,N);
for(uword i=0; i<N; ++i) { actual_out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
for(uword i=0; i<N; ++i) { out.at(i,i) = (use_alpha) ? eT(alpha * C_mem[i]) : eT(C_mem[i]); }
return;
}
}
// if we got to this point, the multiplication results in a matrix
const bool is_alias = (UA.is_alias(actual_out) || UB.is_alias(actual_out));
Mat<eT> tmp;
Mat<eT>& out = (is_alias) ? tmp : actual_out;
if( (partial_unwrap<T1>::do_trans == false) && (partial_unwrap<T2>::do_trans == false) )
{
@@ -659,8 +686,6 @@ op_diagmat::apply_times(Mat<typename T1::elem_type>& actual_out, const T1& X, co
out.at(k,k) = (use_alpha) ? eT(alpha * acc) : eT(acc);
}
}
if(is_alias) { actual_out.steal_mem(tmp); }
}
@@ -701,6 +726,23 @@ op_diagmat2::apply(Mat<typename T1::elem_type>& out, const Op<T1, op_diagmat2>&
template<typename T1>
inline
void
op_diagmat2::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1, op_diagmat2>& X)
{
arma_debug_sigprint();
const uword row_offset = X.aux_uword_a;
const uword col_offset = X.aux_uword_b;
const Proxy<T1> P(X.m);
op_diagmat2::apply(out, P, row_offset, col_offset);
}
template<typename T1>
inline
void
+17 -3
View File
@@ -27,14 +27,25 @@ struct op_diagvec
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op<T1,op_diagvec>& X);
template<typename T1>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_diagvec>& X);
template<typename T1>
inline static void apply_proxy(Mat<typename T1::elem_type>& out, const Proxy<T1>& P);
template<typename T1, typename T2>
inline static void apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X, const typename arma_not_cx<typename T1::elem_type>::result* junk = nullptr);
//
template<typename T1, typename T2>
inline static void apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X, const typename arma_cx_only<typename T1::elem_type>::result* junk = nullptr);
inline static void apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X);
template<typename T1, typename T2>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X);
template<typename T1, typename T2>
inline static void apply_glue_times(Mat<typename T1::elem_type>& out, const Glue<T1,T2,glue_times>& X, const typename arma_not_cx<typename T1::elem_type>::result* junk = nullptr);
template<typename T1, typename T2>
inline static void apply_glue_times(Mat<typename T1::elem_type>& out, const Glue<T1,T2,glue_times>& X, const typename arma_cx_only<typename T1::elem_type>::result* junk = nullptr);
};
@@ -45,6 +56,9 @@ struct op_diagvec2
template<typename T1>
inline static void apply(Mat<typename T1::elem_type>& out, const Op<T1,op_diagvec2>& X);
template<typename T1>
inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_diagvec2>& X);
template<typename T1>
inline static void apply_proxy(Mat<typename T1::elem_type>& out, const Proxy<T1>& P, const uword row_offset, const uword col_offset);
};
+79 -22
View File
@@ -48,6 +48,20 @@ op_diagvec::apply(Mat<typename T1::elem_type>& out, const Op<T1, op_diagvec>& X)
template<typename T1>
inline
void
op_diagvec::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1, op_diagvec>& X)
{
arma_debug_sigprint();
const Proxy<T1> P(X.m);
op_diagvec::apply_proxy(out, P);
}
template<typename T1>
inline
void
@@ -87,31 +101,63 @@ op_diagvec::apply_proxy(Mat<typename T1::elem_type>& out, const Proxy<T1>& P)
template<typename T1, typename T2>
inline
void
op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X, const typename arma_not_cx<typename T1::elem_type>::result* junk)
op_diagvec::apply(Mat<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
if(X.m.is_alias(out))
{
Mat<eT> tmp;
op_diagvec::apply_glue_times(tmp, X.m);
out.steal_mem(tmp);
}
else
{
op_diagvec::apply_glue_times(out, X.m);
}
}
template<typename T1, typename T2>
inline
void
op_diagvec::apply(Mat_noalias<typename T1::elem_type>& out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X)
{
arma_debug_sigprint();
op_diagvec::apply_glue_times(out, X.m);
}
template<typename T1, typename T2>
inline
void
op_diagvec::apply_glue_times(Mat<typename T1::elem_type>& out, const Glue<T1,T2,glue_times>& X, const typename arma_not_cx<typename T1::elem_type>::result* junk)
{
arma_debug_sigprint();
arma_ignore(junk);
typedef typename T1::elem_type eT;
const partial_unwrap<T1> UA(X.m.A);
const partial_unwrap<T2> UB(X.m.B);
const partial_unwrap<T1> UA(X.A);
const partial_unwrap<T2> UB(X.B);
const typename partial_unwrap<T1>::stored_type& A = UA.M;
const typename partial_unwrap<T2>::stored_type& B = UB.M;
arma_conform_assert_trans_mul_size< partial_unwrap<T1>::do_trans, partial_unwrap<T2>::do_trans >(A.n_rows, A.n_cols, B.n_rows, B.n_cols, "matrix multiplication");
if( (A.n_elem == 0) || (B.n_elem == 0) ) { actual_out.reset(); return; }
if( (A.n_elem == 0) || (B.n_elem == 0) ) { out.reset(); return; }
constexpr bool use_alpha = partial_unwrap<T1>::do_times || partial_unwrap<T2>::do_times;
const eT alpha = use_alpha ? (UA.get_val() * UB.get_val()) : eT(0);
const bool is_alias = (UA.is_alias(actual_out) || UB.is_alias(actual_out));
Mat<eT> tmp;
Mat<eT>& out = (is_alias) ? tmp : actual_out;
const uword A_n_rows = A.n_rows;
const uword A_n_cols = A.n_cols;
@@ -237,8 +283,6 @@ op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,
out_mem[k] = (use_alpha) ? eT(alpha * acc) : eT(acc);
}
}
if(is_alias) { actual_out.steal_mem(tmp); }
}
@@ -246,7 +290,7 @@ op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,
template<typename T1, typename T2>
inline
void
op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,glue_times>, op_diagvec>& X, const typename arma_cx_only<typename T1::elem_type>::result* junk)
op_diagvec::apply_glue_times(Mat<typename T1::elem_type>& out, const Glue<T1,T2,glue_times>& X, const typename arma_cx_only<typename T1::elem_type>::result* junk)
{
arma_debug_sigprint();
arma_ignore(junk);
@@ -254,24 +298,19 @@ op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,
typedef typename T1::pod_type T;
typedef typename T1::elem_type eT;
const partial_unwrap<T1> UA(X.m.A);
const partial_unwrap<T2> UB(X.m.B);
const partial_unwrap<T1> UA(X.A);
const partial_unwrap<T2> UB(X.B);
const typename partial_unwrap<T1>::stored_type& A = UA.M;
const typename partial_unwrap<T2>::stored_type& B = UB.M;
arma_conform_assert_trans_mul_size< partial_unwrap<T1>::do_trans, partial_unwrap<T2>::do_trans >(A.n_rows, A.n_cols, B.n_rows, B.n_cols, "matrix multiplication");
if( (A.n_elem == 0) || (B.n_elem == 0) ) { actual_out.reset(); return; }
if( (A.n_elem == 0) || (B.n_elem == 0) ) { out.reset(); return; }
constexpr bool use_alpha = partial_unwrap<T1>::do_times || partial_unwrap<T2>::do_times;
const eT alpha = use_alpha ? (UA.get_val() * UB.get_val()) : eT(0);
const bool is_alias = (UA.is_alias(actual_out) || UB.is_alias(actual_out));
Mat<eT> tmp;
Mat<eT>& out = (is_alias) ? tmp : actual_out;
const uword A_n_rows = A.n_rows;
const uword A_n_cols = A.n_cols;
@@ -446,8 +485,6 @@ op_diagvec::apply(Mat<typename T1::elem_type>& actual_out, const Op< Glue<T1,T2,
out_mem[k] = (use_alpha) ? eT(alpha * acc) : eT(acc);
}
}
if(is_alias) { actual_out.steal_mem(tmp); }
}
@@ -491,6 +528,26 @@ op_diagvec2::apply(Mat<typename T1::elem_type>& out, const Op<T1, op_diagvec2>&
template<typename T1>
inline
void
op_diagvec2::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1, op_diagvec2>& X)
{
arma_debug_sigprint();
const uword a = X.aux_uword_a;
const uword b = X.aux_uword_b;
const uword row_offset = (b > 0) ? a : 0;
const uword col_offset = (b == 0) ? a : 0;
const Proxy<T1> P(X.m);
op_diagvec2::apply_proxy(out, P, row_offset, col_offset);
}
template<typename T1>
inline
void
@@ -28,6 +28,8 @@ struct op_repelem
template<typename obj> inline static void apply_noalias(Mat<typename obj::elem_type>& out, const obj& X, const uword copies_per_row, const uword copies_per_col);
template<typename T1> inline static void apply(Mat<typename T1::elem_type>& out, const Op<T1,op_repelem>& in);
template<typename T1> inline static void apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_repelem>& in);
};
@@ -100,4 +100,21 @@ op_repelem::apply(Mat<typename T1::elem_type>& out, const Op<T1,op_repelem>& in)
template<typename T1>
inline
void
op_repelem::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op_repelem>& in)
{
arma_debug_sigprint();
const uword copies_per_row = in.aux_uword_a;
const uword copies_per_col = in.aux_uword_b;
const quasi_unwrap<T1> U(in.m);
op_repelem::apply_noalias(out, U.M, copies_per_row, copies_per_col);
}
//! @}
@@ -34,8 +34,6 @@ struct op_vectorise_col
template<typename T1> inline static void apply_direct(Mat_noalias<typename T1::elem_type>& out, const T1& expr);
template<typename eT> inline static void apply_subview(Mat<eT>& out, const subview<eT>& sv);
template<typename T1> inline static void apply_proxy(Mat<typename T1::elem_type>& out, const Proxy<T1>& P);
};
+12 -106
View File
@@ -80,39 +80,12 @@ op_vectorise_col::apply_direct(Mat<typename T1::elem_type>& out, const T1& expr)
}
}
else
if( (quasi_unwrap<T1>::has_orig_mem) || (is_Mat<typename Proxy<T1>::stored_type>::value) || (arma_config::openmp && Proxy<T1>::use_mp) )
{
const quasi_unwrap<T1> U(expr);
Mat<eT> tmp = expr;
if(U.is_alias(out))
{
Mat<eT> tmp(U.M.memptr(), U.M.n_elem, 1);
out.steal_mem(tmp);
}
else
{
out.set_size(U.M.n_elem, 1);
arrayops::copy(out.memptr(), U.M.memptr(), U.M.n_elem);
}
}
else
{
const Proxy<T1> P(expr);
tmp.set_size(tmp.n_elem, 1);
if(P.is_alias(out))
{
Mat<eT> tmp;
op_vectorise_col::apply_proxy(tmp, P);
out.steal_mem(tmp);
}
else
{
op_vectorise_col::apply_proxy(out, P);
}
out.steal_mem(tmp);
}
}
@@ -133,12 +106,17 @@ op_vectorise_col::apply(Mat_noalias<typename T1::elem_type>& out, const Op<T1,op
template<typename T1>
inline
void
op_vectorise_col::apply_direct(Mat_noalias<typename T1::elem_type>& out, const T1& expr)
op_vectorise_col::apply_direct(Mat_noalias<typename T1::elem_type>& actual_out, const T1& expr)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
Mat<eT>& out = actual_out;
// no special handling for T1 = Mat, as that currently can't happen;
// the Mat class uses the Mat_noalias type only for delayed expressions
if(is_subview<T1>::value)
{
const subview<eT>& sv = reinterpret_cast< const subview<eT>& >(expr);
@@ -146,19 +124,12 @@ op_vectorise_col::apply_direct(Mat_noalias<typename T1::elem_type>& out, const T
op_vectorise_col::apply_subview(out, sv);
}
else
if( (quasi_unwrap<T1>::has_orig_mem) || (is_Mat<typename Proxy<T1>::stored_type>::value) || (arma_config::openmp && Proxy<T1>::use_mp) )
{
const quasi_unwrap<T1> U(expr);
Mat<eT> tmp = expr;
out.set_size(U.M.n_elem, 1);
tmp.set_size(tmp.n_elem, 1);
arrayops::copy(out.memptr(), U.M.memptr(), U.M.n_elem);
}
else
{
const Proxy<T1> P(expr);
op_vectorise_col::apply_proxy(out, P);
out.steal_mem(tmp);
}
}
@@ -190,71 +161,6 @@ op_vectorise_col::apply_subview(Mat<eT>& out, const subview<eT>& sv)
template<typename T1>
inline
void
op_vectorise_col::apply_proxy(Mat<typename T1::elem_type>& out, const Proxy<T1>& P)
{
arma_debug_sigprint();
typedef typename T1::elem_type eT;
const uword N = P.get_n_elem();
out.set_size(N, 1);
if(N == 0) { return; }
eT* outmem = out.memptr();
if(Proxy<T1>::use_at == false)
{
// TODO: add handling of aligned access ?
typename Proxy<T1>::ea_type A = P.get_ea();
uword i,j;
for(i=0, j=1; j < N; i+=2, j+=2)
{
const eT tmp_i = A[i];
const eT tmp_j = A[j];
outmem[i] = tmp_i;
outmem[j] = tmp_j;
}
if(i < N)
{
outmem[i] = A[i];
}
}
else
{
const uword n_rows = P.get_n_rows();
const uword n_cols = P.get_n_cols();
if(n_rows == 1)
{
for(uword i=0; i < n_cols; ++i)
{
outmem[i] = P.at(0,i);
}
}
else
{
for(uword col=0; col < n_cols; ++col)
for(uword row=0; row < n_rows; ++row)
{
*outmem = P.at(row,col);
outmem++;
}
}
}
}
template<typename T1>
inline
void
@@ -107,6 +107,9 @@ class spdiagview : public SpBase< eT, spdiagview<eT> >
inline static void extract(SpMat<eT>& out, const spdiagview& in);
inline static void extract( Mat<eT>& out, const spdiagview& in);
template<typename eT2>
arma_inline bool is_alias(const SpMat<eT2>& X) const;
friend class SpMat<eT>;
};
@@ -1076,4 +1076,15 @@ spdiagview<eT>::randn()
template<typename eT>
template<typename eT2>
arma_inline
bool
spdiagview<eT>::is_alias(const SpMat<eT2>& X) const
{
return m.is_alias(X);
}
//! @}
@@ -26,6 +26,9 @@ struct spop_diagmat
template<typename T1>
inline static void apply(SpMat<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat>& in);
template<typename T1>
inline static void apply(SpMat_noalias<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat>& in);
template<typename T1>
inline static void apply_noalias(SpMat<typename T1::elem_type>& out, const SpBase<typename T1::elem_type, T1>& expr);
@@ -40,7 +43,6 @@ struct spop_diagmat
template<typename T1, typename T2>
inline static void apply_noalias(SpMat<typename T1::elem_type>& out, const SpGlue<T1,T2,spglue_times>& expr);
};
@@ -51,6 +53,9 @@ struct spop_diagmat2
template<typename T1>
inline static void apply(SpMat<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat2>& in);
template<typename T1>
inline static void apply(SpMat_noalias<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat2>& in);
template<typename eT>
inline static void apply_noalias(SpMat<eT>& out, const SpMat<eT>& X, const uword row_offset, const uword col_offset);
};
@@ -46,6 +46,18 @@ spop_diagmat::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1, spop_diag
template<typename T1>
inline
void
spop_diagmat::apply(SpMat_noalias<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat>& in)
{
arma_debug_sigprint();
spop_diagmat::apply_noalias(out, in.m);
}
template<typename T1>
inline
void
@@ -374,6 +386,23 @@ spop_diagmat2::apply(SpMat<typename T1::elem_type>& out, const SpOp<T1, spop_dia
template<typename T1>
inline
void
spop_diagmat2::apply(SpMat_noalias<typename T1::elem_type>& out, const SpOp<T1, spop_diagmat2>& in)
{
arma_debug_sigprint();
const uword row_offset = in.aux_uword_a;
const uword col_offset = in.aux_uword_b;
const unwrap_spmat<T1> U(in.m);
spop_diagmat2::apply_noalias(out, U.M, row_offset, col_offset);
}
template<typename eT>
inline
void