Compare commits

...
9 Commits
12 changed files with 238 additions and 42 deletions
+1 -1
View File
@@ -9655,7 +9655,7 @@ vec b = diff(a);
</li>
<br>
<li>
<b>Caveat:</b> <a href="#norm">norm()</a> is preferred for calculating the 2-norm, as it reduces the incidence of numerical underflows and overflows
<b>Caveat:</b> to obtain the Euclidean norm, use the more robust <a href="#norm">norm(x)</a> instead of <i>sqrt(dot(x,x))</i>
</li>
<br>
<li>
+1 -1
View File
@@ -957,7 +957,7 @@ Base_extra_yes<elem_type,derived>::is_sympd(typename get_pod_type<elem_type>::re
typedef typename get_pod_type<elem_type>::result T;
arma_conform_check( ((tol >= T(0)) == false), "is_sympd(): parameter 'tol' must be > 0" );
arma_conform_check( ((tol >= T(0)) == false), "is_sympd(): parameter 'tol' must be >= 0" );
Mat<elem_type> X = static_cast<const derived&>(*this);
+4 -4
View File
@@ -2544,7 +2544,7 @@ Mat<eT>::Mat(const subview_elem1<eT,T1>& X, const arma_vec_indicator&, const uhw
{
arma_debug_sigprint_this(this);
(*this).operator=(X);
subview_elem1<eT,T1>::extract_noalias(*this, X);
}
@@ -2563,7 +2563,7 @@ Mat<eT>::Mat(const subview_elem1<eT,T1>& X)
{
arma_debug_sigprint_this(this);
(*this).operator=(X);
subview_elem1<eT,T1>::extract_noalias(*this, X);
}
@@ -2672,7 +2672,7 @@ Mat<eT>::Mat(const subview_elem2<eT,T1,T2>& X, const arma_vec_indicator&, const
{
arma_debug_sigprint_this(this);
(*this).operator=(X);
subview_elem2<eT,T1,T2>::extract_noalias(*this, X);
}
@@ -2691,7 +2691,7 @@ Mat<eT>::Mat(const subview_elem2<eT,T1,T2>& X)
{
arma_debug_sigprint_this(this);
(*this).operator=(X);
subview_elem2<eT,T1,T2>::extract_noalias(*this, X);
}
+3 -3
View File
@@ -1537,7 +1537,7 @@ struct Proxy_xtrans_default< Op<T1, op_htrans> >
arma_inline aligned_ea_type get_aligned_ea() const { return Q; }
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return void_ptr(&(U.M)) == void_ptr(&X); }
arma_inline bool is_alias(const Mat<eT2>& X) const { return U.is_alias(X); }
template<typename eT2>
arma_inline bool has_overlap(const subview<eT2>& X) const { return is_alias(X.m); }
@@ -1578,7 +1578,7 @@ struct Proxy_xtrans_default< Op<T1, op_strans> >
arma_inline aligned_ea_type get_aligned_ea() const { return Q; }
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return void_ptr(&(U.M)) == void_ptr(&X); }
arma_inline bool is_alias(const Mat<eT2>& X) const { return U.is_alias(X); }
template<typename eT2>
arma_inline bool has_overlap(const subview<eT2>& X) const { return is_alias(X.m); }
@@ -2441,7 +2441,7 @@ struct Proxy_vectorise_col_mat< Op<T1, op_vectorise_col> >
arma_inline aligned_ea_type get_aligned_ea() const { return Q; }
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return ( void_ptr(&X) == void_ptr(&(U.M)) ); }
arma_inline bool is_alias(const Mat<eT2>& X) const { return U.is_alias(X); }
template<typename eT2>
arma_inline bool has_overlap(const subview<eT2>& X) const { return is_alias(X.m); }
+1 -1
View File
@@ -23,7 +23,7 @@
#define ARMA_VERSION_MAJOR 15
#define ARMA_VERSION_MINOR 2
#define ARMA_VERSION_PATCH 6
#define ARMA_VERSION_PATCH 7
#define ARMA_VERSION_NAME "Medium Roast Deluxe"
+17 -2
View File
@@ -94,7 +94,9 @@ field<oT>::field(const subview_field<oT>& X)
{
arma_debug_sigprint_this(this);
(*this).operator=(X);
init(X.n_rows, X.n_cols, X.n_slices);
subview_field<oT>::extract(*this, X);
}
@@ -107,7 +109,20 @@ field<oT>::operator=(const subview_field<oT>& X)
{
arma_debug_sigprint();
subview_field<oT>::extract(*this, X);
const bool alias = (this == &(X.f));
if(alias == false)
{
(*this).init(X.n_rows, X.n_cols, X.n_slices);
subview_field<oT>::extract(*this, X);
}
else
{
field<oT> tmp(X);
(*this).operator=(std::move(tmp));
}
return *this;
}
@@ -90,6 +90,8 @@ class subview_elem1 : public Base< eT, subview_elem1<eT,T1> >
template<typename T2> inline void operator%= (const Base<eT,T2>& x);
template<typename T2> inline void operator/= (const Base<eT,T2>& x);
inline static void extract_noalias(Mat<eT>& out, const subview_elem1& in);
inline static void extract(Mat<eT>& out, const subview_elem1& in);
template<typename op_type> inline static void mat_inplace_op(Mat<eT>& out, const subview_elem1& in);
+53 -4
View File
@@ -759,6 +759,55 @@ subview_elem1<eT,T1>::operator/= (const Base<eT,T2>& x)
template<typename eT, typename T1>
inline
void
subview_elem1<eT,T1>::extract_noalias(Mat<eT>& out, const subview_elem1<eT,T1>& in)
{
arma_debug_sigprint();
const quasi_unwrap<T1> tmp1(in.a.get_ref());
const umat& aa = tmp1.M;
if(resolves_to_vector<T1>::no)
{
arma_conform_check( ( (aa.is_vec() == false) && (aa.is_empty() == false) ), "Mat::elem(): given object must be a vector" );
}
const uword* aa_mem = aa.memptr();
const uword aa_n_elem = aa.n_elem;
const eT* m_mem = in.m.memptr();
const uword m_n_elem = in.m.n_elem;
out.set_size(aa_n_elem, 1);
eT* out_mem = out.memptr();
uword i,j;
for(i=0, j=1; j<aa_n_elem; i+=2, j+=2)
{
const uword ii = aa_mem[i];
const uword jj = aa_mem[j];
arma_conform_check_bounds( ( (ii >= m_n_elem) || (jj >= m_n_elem) ), "Mat::elem(): index out of bounds" );
out_mem[i] = m_mem[ii];
out_mem[j] = m_mem[jj];
}
if(i < aa_n_elem)
{
const uword ii = aa_mem[i];
arma_conform_check_bounds( (ii >= m_n_elem) , "Mat::elem(): index out of bounds" );
out_mem[i] = m_mem[ii];
}
}
template<typename eT, typename T1>
inline
void
@@ -777,12 +826,12 @@ subview_elem1<eT,T1>::extract(Mat<eT>& actual_out, const subview_elem1<eT,T1>& i
const uword* aa_mem = aa.memptr();
const uword aa_n_elem = aa.n_elem;
const Mat<eT>& m_local = in.m;
const Mat<eT>& m = in.m;
const eT* m_mem = m_local.memptr();
const uword m_n_elem = m_local.n_elem;
const eT* m_mem = m.memptr();
const uword m_n_elem = m.n_elem;
const bool alias = (&actual_out == &m_local);
const bool alias = (&actual_out == &m);
if(alias) { arma_debug_print("subview_elem1::extract(): aliasing detected"); }
@@ -98,6 +98,8 @@ class subview_elem2 : public Base< eT, subview_elem2<eT,T1,T2> >
template<typename expr> inline void operator%= (const SpBase<eT,expr>& x);
template<typename expr> inline void operator/= (const SpBase<eT,expr>& x);
inline static void extract_noalias(Mat<eT>& out, const subview_elem2& in);
inline static void extract(Mat<eT>& out, const subview_elem2& in);
inline static void plus_inplace(Mat<eT>& out, const subview_elem2& in);
+124 -9
View File
@@ -917,6 +917,121 @@ subview_elem2<eT,T1,T2>::operator/= (const SpBase<eT,expr>& x)
template<typename eT, typename T1, typename T2>
inline
void
subview_elem2<eT,T1,T2>::extract_noalias(Mat<eT>& out, const subview_elem2<eT,T1,T2>& in)
{
arma_debug_sigprint();
const Mat<eT>& m = in.m;
const uword m_n_rows = m.n_rows;
const uword m_n_cols = m.n_cols;
if( (in.all_rows == false) && (in.all_cols == false) )
{
const quasi_unwrap<T1> tmp1(in.base_ri.get_ref());
const quasi_unwrap<T2> tmp2(in.base_ci.get_ref());
const umat& ri = tmp1.M;
const umat& ci = tmp2.M;
arma_conform_check
(
( ((ri.is_vec() == false) && (ri.is_empty() == false)) || ((ci.is_vec() == false) && (ci.is_empty() == false)) ),
"Mat::elem(): given object must be a vector"
);
const uword* ri_mem = ri.memptr();
const uword ri_n_elem = ri.n_elem;
const uword* ci_mem = ci.memptr();
const uword ci_n_elem = ci.n_elem;
out.set_size(ri_n_elem, ci_n_elem);
eT* out_mem = out.memptr();
uword out_count = 0;
for(uword ci_count=0; ci_count < ci_n_elem; ++ci_count)
{
const uword col = ci_mem[ci_count];
arma_conform_check_bounds( (col >= m_n_cols), "Mat::elem(): index out of bounds" );
for(uword ri_count=0; ri_count < ri_n_elem; ++ri_count)
{
const uword row = ri_mem[ri_count];
arma_conform_check_bounds( (row >= m_n_rows), "Mat::elem(): index out of bounds" );
out_mem[out_count] = m.at(row,col);
++out_count;
}
}
}
else
if( (in.all_rows == true) && (in.all_cols == false) )
{
const quasi_unwrap<T2> tmp2(in.base_ci.get_ref());
const umat& ci = tmp2.M;
arma_conform_check
(
( (ci.is_vec() == false) && (ci.is_empty() == false) ),
"Mat::elem(): given object must be a vector"
);
const uword* ci_mem = ci.memptr();
const uword ci_n_elem = ci.n_elem;
out.set_size(m_n_rows, ci_n_elem);
for(uword ci_count=0; ci_count < ci_n_elem; ++ci_count)
{
const uword col = ci_mem[ci_count];
arma_conform_check_bounds( (col >= m_n_cols), "Mat::elem(): index out of bounds" );
arrayops::copy( out.colptr(ci_count), m.colptr(col), m_n_rows );
}
}
else
if( (in.all_rows == false) && (in.all_cols == true) )
{
const quasi_unwrap<T1> tmp1(in.base_ri.get_ref());
const umat& ri = tmp1.M;
arma_conform_check
(
( (ri.is_vec() == false) && (ri.is_empty() == false) ),
"Mat::elem(): given object must be a vector"
);
const uword* ri_mem = ri.memptr();
const uword ri_n_elem = ri.n_elem;
out.set_size(ri_n_elem, m_n_cols);
for(uword col=0; col < m_n_cols; ++col)
{
for(uword ri_count=0; ri_count < ri_n_elem; ++ri_count)
{
const uword row = ri_mem[ri_count];
arma_conform_check_bounds( (row >= m_n_rows), "Mat::elem(): index out of bounds" );
out.at(ri_count,col) = m.at(row,col);
}
}
}
}
template<typename eT, typename T1, typename T2>
inline
void
@@ -924,12 +1039,12 @@ subview_elem2<eT,T1,T2>::extract(Mat<eT>& actual_out, const subview_elem2<eT,T1,
{
arma_debug_sigprint();
Mat<eT>& m_local = const_cast< Mat<eT>& >(in.m);
const Mat<eT>& m = in.m;
const uword m_n_rows = m_local.n_rows;
const uword m_n_cols = m_local.n_cols;
const uword m_n_rows = m.n_rows;
const uword m_n_cols = m.n_cols;
const bool alias = (&actual_out == &m_local);
const bool alias = (&actual_out == &m);
if(alias) { arma_debug_print("subview_elem2::extract(): aliasing detected"); }
@@ -973,7 +1088,7 @@ subview_elem2<eT,T1,T2>::extract(Mat<eT>& actual_out, const subview_elem2<eT,T1,
arma_conform_check_bounds( (row >= m_n_rows), "Mat::elem(): index out of bounds" );
out_mem[out_count] = m_local.at(row,col);
out_mem[out_count] = m.at(row,col);
++out_count;
}
}
@@ -981,7 +1096,7 @@ subview_elem2<eT,T1,T2>::extract(Mat<eT>& actual_out, const subview_elem2<eT,T1,
else
if( (in.all_rows == true) && (in.all_cols == false) )
{
const unwrap_check_mixed<T2> tmp2(in.base_ci.get_ref(), m_local);
const unwrap_check_mixed<T2> tmp2(in.base_ci.get_ref(), m);
const umat& ci = tmp2.M;
@@ -1002,13 +1117,13 @@ subview_elem2<eT,T1,T2>::extract(Mat<eT>& actual_out, const subview_elem2<eT,T1,
arma_conform_check_bounds( (col >= m_n_cols), "Mat::elem(): index out of bounds" );
arrayops::copy( out.colptr(ci_count), m_local.colptr(col), m_n_rows );
arrayops::copy( out.colptr(ci_count), m.colptr(col), m_n_rows );
}
}
else
if( (in.all_rows == false) && (in.all_cols == true) )
{
const unwrap_check_mixed<T1> tmp1(in.base_ri.get_ref(), m_local);
const unwrap_check_mixed<T1> tmp1(in.base_ri.get_ref(), m);
const umat& ri = tmp1.M;
@@ -1031,7 +1146,7 @@ subview_elem2<eT,T1,T2>::extract(Mat<eT>& actual_out, const subview_elem2<eT,T1,
arma_conform_check_bounds( (row >= m_n_rows), "Mat::elem(): index out of bounds" );
out.at(ri_count,col) = m_local.at(row,col);
out.at(ri_count,col) = m.at(row,col);
}
}
}
+3 -16
View File
@@ -507,24 +507,17 @@ subview_field<oT>::fill(const oT& x)
template<typename oT>
inline
void
subview_field<oT>::extract(field<oT>& actual_out, const subview_field<oT>& in)
subview_field<oT>::extract(field<oT>& out, const subview_field<oT>& in)
{
arma_debug_sigprint();
//
const bool alias = (&actual_out == &in.f);
field<oT>* tmp = (alias) ? new field<oT> : nullptr;
field<oT>& out = (alias) ? (*tmp) : actual_out;
//
// NOTE: we're assuming that the field has already been set to the correct size and there is no aliasing;
// size setting and alias checking is done by either the field constructor or operator=()
const uword n_rows = in.n_rows;
const uword n_cols = in.n_cols;
const uword n_slices = in.n_slices;
out.set_size(n_rows, n_cols, n_slices);
arma_debug_print(arma_str::format("out.n_rows: %u; out.n_cols: %u; out.n_slices: %u; in.f.n_rows: %u; in.f.n_cols: %u; in.f.n_slices: %u") % out.n_rows % out.n_cols % out.n_slices % in.f.n_rows % in.f.n_cols % in.f.n_slices);
if(n_slices == 1)
@@ -544,12 +537,6 @@ subview_field<oT>::extract(field<oT>& actual_out, const subview_field<oT>& in)
out.at(row,col,slice) = in.at(row,col,slice);
}
}
if(alias)
{
actual_out = out;
delete tmp;
}
}
+27 -1
View File
@@ -38,6 +38,9 @@ struct unwrap_default
}
const Mat<eT> M;
template<typename eT2>
constexpr bool is_alias(const Mat<eT2>&) const { return false; }
};
@@ -55,6 +58,9 @@ struct unwrap_fixed
}
const T1& M;
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return (void_ptr(&M) == void_ptr(&X)); }
};
@@ -94,6 +100,9 @@ struct unwrap< Mat<eT> >
}
const Mat<eT>& M;
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return (is_same_type<eT,eT2>::yes) && (void_ptr(&M) == void_ptr(&X)); }
};
@@ -111,6 +120,9 @@ struct unwrap< Row<eT> >
}
const Row<eT>& M;
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return (is_same_type<eT,eT2>::yes) && (void_ptr(&M) == void_ptr(&X)); }
};
@@ -128,6 +140,9 @@ struct unwrap< Col<eT> >
}
const Col<eT>& M;
template<typename eT2>
arma_inline bool is_alias(const Mat<eT2>& X) const { return (is_same_type<eT,eT2>::yes) && (void_ptr(&M) == void_ptr(&X)); }
};
@@ -145,6 +160,9 @@ struct unwrap< subview_col<eT> >
}
const Col<eT> M;
template<typename eT2>
constexpr bool is_alias(const Mat<eT2>&) const { return false; }
};
@@ -162,6 +180,9 @@ struct unwrap< subview_cols<eT> >
}
const Mat<eT> M;
template<typename eT2>
constexpr bool is_alias(const Mat<eT2>&) const { return false; }
};
@@ -179,6 +200,9 @@ struct unwrap< mtGlue<out_eT, T1, T2, glue_type> >
}
const Mat<out_eT> M;
template<typename eT2>
constexpr bool is_alias(const Mat<eT2>&) const { return false; }
};
@@ -196,6 +220,9 @@ struct unwrap< mtOp<out_eT, T1, op_type> >
}
const Mat<out_eT> M;
template<typename eT2>
constexpr bool is_alias(const Mat<eT2>&) const { return false; }
};
@@ -311,7 +338,6 @@ struct quasi_unwrap< Mat<eT> >
template<typename eT>
struct quasi_unwrap< Row<eT> >
{
inline
quasi_unwrap(const Row<eT>& A)
: M(A)