Commit 7a479f80 authored by Davis King's avatar Davis King

Added a bunch of overloads to catch operations on diagonal matrices

and use more efficient code paths for them.  For example, inv(diagm(d))
turns into diagm(reciprocal(d)).

--HG--
extra : convert_revision : svn%3Afdd8eb12-d10e-0410-9acb-85c331704f74/trunk%403915
parent d031d605
......@@ -183,6 +183,23 @@ namespace dlib
is_matrix<T>::value == 1 if T is a matrix type else 0
*/
// ----------------------------------------------------------------------------------------
template <
typename EXP
>
class matrix_diag_exp : public matrix_exp<EXP>
{
/*!
This is a matrix expression type used to represent diagonal matrices.
That is, square matrices with all off diagonal elements equal to 0.
!*/
protected:
matrix_diag_exp() {}
matrix_diag_exp(const matrix_diag_exp& item ):matrix_exp<EXP>(item) {}
};
// ----------------------------------------------------------------------------------------
}
......
......@@ -971,6 +971,64 @@ convergence:
const matrix_exp<EXP>& m
) { return inv_helper<EXP,matrix_exp<EXP>::NR>::inv(m); }
// ----------------------------------------------------------------------------------------
template <typename M>
struct op_diag_inv
{
template <typename EXP>
op_diag_inv( const matrix_exp<EXP>& m_) : m(m_){}
const static long cost = 1;
const static long NR = (M::NC&&M::NR)? (tmax<M::NR,M::NC>::value) : (0);
const static long NC = NR;
typedef typename M::type type;
typedef const type const_ret_type;
typedef typename M::mem_manager_type mem_manager_type;
typedef typename M::layout_type layout_type;
// hold the matrix by value
const matrix<type,NR,1,mem_manager_type,layout_type> m;
const_ret_type apply ( long r, long c) const
{
if (r==c)
return m(r);
else
return 0;
}
long nr () const { return m.size(); }
long nc () const { return m.size(); }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
};
template <
typename EXP
>
const matrix_diag_op<op_diag_inv<EXP> > inv (
const matrix_diag_exp<EXP>& m
)
{
typedef op_diag_inv<EXP> op;
return matrix_diag_op<op>(op(reciprocal(diag(m))));
}
template <
typename EXP
>
const matrix_diag_op<op_diag_inv<EXP> > pinv (
const matrix_diag_exp<EXP>& m
)
{
typedef op_diag_inv<EXP> op;
return matrix_diag_op<op>(op(reciprocal(diag(m))));
}
// ----------------------------------------------------------------------------------------
template <typename EXP>
......
......@@ -84,6 +84,84 @@ namespace dlib
) const { return op.nc(); }
const OP op;
};
// ----------------------------------------------------------------------------------------
template <typename OP >
class matrix_diag_op;
template < typename OP >
struct matrix_traits<matrix_diag_op<OP> >
{
typedef typename OP::type type;
typedef typename OP::const_ret_type const_ret_type;
typedef typename OP::mem_manager_type mem_manager_type;
typedef typename OP::layout_type layout_type;
const static long NR = OP::NR;
const static long NC = OP::NC;
const static long cost = OP::cost;
};
template <
typename OP
>
class matrix_diag_op : public matrix_diag_exp<matrix_diag_op<OP> >
{
/*!
WHAT THIS OBJECT REPRESENTS
The matrix_diag_op is simply a tool for reducing the amount of boilerplate
you need to write when creating matrix expressions.
!*/
public:
typedef typename matrix_traits<matrix_diag_op>::type type;
typedef typename matrix_traits<matrix_diag_op>::const_ret_type const_ret_type;
typedef typename matrix_traits<matrix_diag_op>::mem_manager_type mem_manager_type;
typedef typename matrix_traits<matrix_diag_op>::layout_type layout_type;
const static long NR = matrix_traits<matrix_diag_op>::NR;
const static long NC = matrix_traits<matrix_diag_op>::NC;
const static long cost = matrix_traits<matrix_diag_op>::cost;
private:
// This constructor exists simply for the purpose of causing a compile time error if
// someone tries to create an instance of this object with the wrong kind of object.
template <typename T1>
matrix_diag_op (T1);
public:
matrix_diag_op (
const OP& op_
) :
op(op_)
{}
const_ret_type operator() (
long r,
long c
) const { return op.apply(r,c); }
const_ret_type operator() ( long i ) const
{ return matrix_exp<matrix_diag_op>::operator()(i); }
template <typename U>
bool aliases (
const matrix_exp<U>& item
) const { return op.aliases(item); }
template <typename U>
bool destructively_aliases (
const matrix_exp<U>& item
) const { return op.destructively_aliases(item); }
long nr (
) const { return op.nr(); }
long nc (
) const { return op.nc(); }
const OP op;
};
......
......@@ -1004,7 +1004,7 @@ namespace dlib
template <
typename EXP
>
const matrix_op<op_diagm<EXP> > diagm (
const matrix_diag_op<op_diagm<EXP> > diagm (
const matrix_exp<EXP>& m
)
{
......@@ -1017,7 +1017,7 @@ namespace dlib
<< "\n\tm.nc(): " << m.nc()
);
typedef op_diagm<EXP> op;
return matrix_op<op>(op(m.ref()));
return matrix_diag_op<op>(op(m.ref()));
}
// ----------------------------------------------------------------------------------------
......@@ -1893,6 +1893,37 @@ namespace dlib
return matrix_op<op>(op());
}
// ----------------------------------------------------------------------------------------
template <typename M>
struct op_add_diag
{
op_add_diag( const M& m_, const typename M::type& value_) : m(m_), value(value_){}
const M& m;
const typename M::type value;
const static long cost = M::cost+1;
const static long NR = M::NR;
const static long NC = M::NC;
typedef typename M::type type;
typedef const typename M::type const_ret_type;
typedef typename M::mem_manager_type mem_manager_type;
typedef typename M::layout_type layout_type;
const_ret_type apply ( long r, long c) const
{
if (r==c)
return m(r,c)+value;
else
return m(r,c);
}
long nr () const { return m.nr(); }
long nc () const { return m.nc(); }
template <typename U> bool aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.destructively_aliases(item); }
};
// ----------------------------------------------------------------------------------------
template <
......@@ -1920,7 +1951,7 @@ namespace dlib
template <
typename T
>
const matrix_op<op_identity_matrix_2<T> > identity_matrix (
const matrix_diag_op<op_identity_matrix_2<T> > identity_matrix (
const long& size
)
{
......@@ -1930,7 +1961,193 @@ namespace dlib
<< "\n\tsize: " << size
);
typedef op_identity_matrix_2<T> op;
return matrix_op<op>(op(size));
return matrix_diag_op<op>(op(size));
}
// ----------------------------------------------------------------------------------------
template <
typename EXP,
typename T
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<EXP>& lhs,
const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(lhs.ref(),1));
}
// ----------------------------------------------------------------------------------------
template <
typename EXP,
typename T
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& lhs,
const matrix_exp<EXP>& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(rhs.ref(),1));
}
// ----------------------------------------------------------------------------------------
template <
typename T,
long N
>
struct op_const_diag_matrix : does_not_alias
{
op_const_diag_matrix(const long& size_, const T& value_) : size(size_),value(value_) {}
const long size;
const T value;
const static long cost = 1;
const static long NR = N;
const static long NC = N;
typedef memory_manager<char>::kernel_1a mem_manager_type;
typedef row_major_layout layout_type;
typedef T type;
typedef const T const_ret_type;
const_ret_type apply (long r, long c) const
{
if (r == c)
return value;
else
return 0;
}
long nr() const { return size; }
long nc() const { return size; }
};
template <
typename T,
typename U
>
const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (
const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m,
const U& value
)
{
typedef op_const_diag_matrix<T,0> op;
return matrix_diag_op<op>(op(m.nr(), value));
}
template <
typename T,
typename U
>
const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,0> > >::type operator* (
const U& value,
const matrix_exp<matrix_diag_op<op_identity_matrix_2<T> > >& m
)
{
typedef op_const_diag_matrix<T,0> op;
return matrix_diag_op<op>(op(m.nr(), value));
}
// ----------------------------------------------------------------------------------------
template <
typename EXP,
typename T,
long N
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<EXP>& lhs,
const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(lhs.ref(),rhs.ref().op.value));
}
template <
typename EXP,
typename T,
long N
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<matrix_diag_op<op_const_diag_matrix<T,N> > >& lhs,
const matrix_exp<EXP>& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(rhs.ref(),lhs.ref().op.value));
}
// ----------------------------------------------------------------------------------------
......@@ -1958,13 +2175,105 @@ namespace dlib
typename T,
long N
>
const matrix_op<op_identity_matrix<T,N> > identity_matrix (
const matrix_diag_op<op_identity_matrix<T,N> > identity_matrix (
)
{
COMPILE_TIME_ASSERT(N > 0);
typedef op_identity_matrix<T,N> op;
return matrix_op<op>(op());
return matrix_diag_op<op>(op());
}
template <
typename T,
typename U,
long N
>
const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (
const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m,
const U& value
)
{
typedef op_const_diag_matrix<T,N> op;
return matrix_diag_op<op>(op(m.nr(), value));
}
template <
typename T,
typename U,
long N
>
const typename disable_if<is_matrix<U>, matrix_diag_op<op_const_diag_matrix<T,N> > >::type operator* (
const U& value,
const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& m
)
{
typedef op_const_diag_matrix<T,N> op;
return matrix_diag_op<op>(op(m.nr(), value));
}
// ----------------------------------------------------------------------------------------
template <
typename EXP,
typename T,
long N
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& lhs,
const matrix_exp<EXP>& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(rhs.ref(),1));
}
template <
typename EXP,
typename T,
long N
>
const matrix_op<op_add_diag<EXP> > operator+ (
const matrix_exp<EXP>& lhs,
const matrix_exp<matrix_diag_op<op_identity_matrix<T,N> > >& rhs
)
{
// both matrices must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<T,typename EXP::type>::value == true));
// You can only add matrices together if they both have the same number of rows and columns.
DLIB_ASSERT(lhs.nc() == rhs.nc() &&
lhs.nr() == rhs.nr(),
"\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
<< "\n\tYou are trying to add two incompatible matrices together"
<< "\n\tlhs.nr(): " << lhs.nr()
<< "\n\tlhs.nc(): " << lhs.nc()
<< "\n\trhs.nr(): " << rhs.nr()
<< "\n\trhs.nc(): " << rhs.nc()
<< "\n\t&lhs: " << &lhs
<< "\n\t&rhs: " << &rhs
);
typedef op_add_diag<EXP> op;
return matrix_op<op>(op(lhs.ref(),1));
}
// ----------------------------------------------------------------------------------------
......@@ -2597,12 +2906,71 @@ namespace dlib
>
const matrix_op<op_scale_columns<EXP1,EXP2> > operator* (
const matrix_exp<EXP1>& m,
const matrix_exp<matrix_op<op_diagm<EXP2> > >& v
const matrix_exp<matrix_diag_op<op_diagm<EXP2> > >& v
)
{
return scale_columns(m,v.ref().op.m);
}
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2>
struct op_scale_columns_diag
{
op_scale_columns_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
const M1& m1;
const M2& m2;
const static long cost = M1::cost + M2::cost + 1;
typedef typename M1::type type;
typedef const typename M1::type const_ret_type;
typedef typename M1::mem_manager_type mem_manager_type;
typedef typename M1::layout_type layout_type;
const static long NR = M1::NR;
const static long NC = M1::NC;
const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(c,c); }
long nr () const { return m1.nr(); }
long nc () const { return m1.nc(); }
template <typename U> bool aliases ( const matrix_exp<U>& item) const
{ return m1.aliases(item) || m2.aliases(item) ; }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
{ return m1.destructively_aliases(item) || m2.aliases(item); }
};
// turn expressions of the form mat*diagonal_matrix into scale_columns(mat, d)
template <
typename EXP1,
typename EXP2
>
const matrix_op<op_scale_columns_diag<EXP1,EXP2> > operator* (
const matrix_exp<EXP1>& m,
const matrix_diag_exp<EXP2>& d
)
{
// Both arguments to this function must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
// figure out the compile time known length of d
const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);
// the length of d must match the number of columns in m
COMPILE_TIME_ASSERT(EXP1::NC == v_len || EXP1::NC == 0 || v_len == 0);
DLIB_ASSERT(m.nc() == d.nr(),
"\tconst matrix_exp operator*(m, d)"
<< "\n\tmatrix dimensions don't match"
<< "\n\tm.nr(): " << m.nr()
<< "\n\tm.nc(): " << m.nc()
<< "\n\td.nr(): " << d.nr()
<< "\n\td.nc(): " << d.nc()
);
typedef op_scale_columns_diag<EXP1,EXP2> op;
return matrix_op<op>(op(m.ref(),d.ref()));
}
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2>
......@@ -2671,13 +3039,72 @@ namespace dlib
typename EXP2
>
const matrix_op<op_scale_rows<EXP1,EXP2> > operator* (
const matrix_exp<matrix_op<op_diagm<EXP2> > >& v,
const matrix_exp<matrix_diag_op<op_diagm<EXP2> > >& v,
const matrix_exp<EXP1>& m
)
{
return scale_rows(m,v.ref().op.m);
}
// ----------------------------------------------------------------------------------------
template <typename M1, typename M2>
struct op_scale_rows_diag
{
op_scale_rows_diag(const M1& m1_, const M2& m2_) : m1(m1_), m2(m2_) {}
const M1& m1;
const M2& m2;
const static long cost = M1::cost + M2::cost + 1;
typedef typename M1::type type;
typedef const typename M1::type const_ret_type;
typedef typename M1::mem_manager_type mem_manager_type;
typedef typename M1::layout_type layout_type;
const static long NR = M1::NR;
const static long NC = M1::NC;
const_ret_type apply ( long r, long c) const { return m1(r,c)*m2(r,r); }
long nr () const { return m1.nr(); }
long nc () const { return m1.nc(); }
template <typename U> bool aliases ( const matrix_exp<U>& item) const
{ return m1.aliases(item) || m2.aliases(item) ; }
template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
{ return m1.destructively_aliases(item) || m2.aliases(item); }
};
// turn expressions of the form diagonal_matrix*mat into scale_rows(mat, d)
template <
typename EXP1,
typename EXP2
>
const matrix_op<op_scale_rows_diag<EXP1,EXP2> > operator* (
const matrix_diag_exp<EXP2>& d,
const matrix_exp<EXP1>& m
)
{
// Both arguments to this function must contain the same type of element
COMPILE_TIME_ASSERT((is_same_type<typename EXP1::type,typename EXP2::type>::value == true));
// figure out the compile time known length of d
const long v_len = ((EXP2::NR)*(EXP2::NC) == 0)? 0 : (tmax<EXP2::NR,EXP2::NC>::value);
// the length of d must match the number of rows in m
COMPILE_TIME_ASSERT(EXP1::NR == v_len || EXP1::NR == 0 || v_len == 0);
DLIB_ASSERT(d.nc() == m.nr(),
"\tconst matrix_exp operator*(d, m)"
<< "\n\tThe dimensions of the d and m matrices don't match."
<< "\n\tm.nr(): " << m.nr()
<< "\n\tm.nc(): " << m.nc()
<< "\n\td.nr(): " << d.nr()
<< "\n\td.nc(): " << d.nc()
);
typedef op_scale_rows_diag<EXP1,EXP2> op;
return matrix_op<op>(op(m.ref(),d.ref()));
}
// ----------------------------------------------------------------------------------------
struct sort_columns_sort_helper
......
......@@ -369,6 +369,141 @@ namespace
m = trans(m)+1;
DLIB_TEST(m == m2);
}
{
matrix<double> d(3,1), di(3,1);
matrix<double> m(3,3);
m = 1,2,3,
4,5,6,
7,8,9;
d = 1,2,3;
di = 1, 1/2.0, 1/3.0;
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(pinv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m);
DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di)));
DLIB_TEST(inv(diagm(d)) + m == tmp(diagm(di)) + m);
DLIB_TEST(m + inv(diagm(d)) == tmp(diagm(di)) + m);
DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
}
{
matrix<double,3,1> d(3,1), di(3,1);
matrix<double,3,3> m(3,3);
m = 1,2,3,
4,5,6,
7,8,9;
d = 1,2,3;
di = 1, 1/2.0, 1/3.0;
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m);
DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di)));
DLIB_TEST(inv(diagm(d)) + m == tmp(diagm(di)) + m);
DLIB_TEST(m + inv(diagm(d)) == tmp(diagm(di)) + m);
DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
}
{
matrix<double,1,3> d(1,3), di(1,3);
matrix<double,3,3> m(3,3);
m = 1,2,3,
4,5,6,
7,8,9;
d = 1,2,3;
di = 1, 1/2.0, 1/3.0;
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m);
DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di)));
DLIB_TEST(inv(diagm(d)) + m == tmp(diagm(di)) + m);
DLIB_TEST(m + inv(diagm(d)) == tmp(diagm(di)) + m);
DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
}
{
matrix<double,1,0> d(1,3), di(1,3);
matrix<double,0,3> m(3,3);
m = 1,2,3,
4,5,6,
7,8,9;
d = 1,2,3;
di = 1, 1/2.0, 1/3.0;
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d)) == diagm(di));
DLIB_TEST(inv(diagm(d))*m == tmp(diagm(di))*m);
DLIB_TEST(m*inv(diagm(d)) == m*tmp(diagm(di)));
DLIB_TEST(inv(diagm(d)) + m == tmp(diagm(di)) + m);
DLIB_TEST(m + inv(diagm(d)) == tmp(diagm(di)) + m);
DLIB_TEST((m + identity_matrix<double>(3) == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>() == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((m + 2*identity_matrix<double>(3) == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + 2*identity_matrix<double,3>() == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((m + identity_matrix<double>(3)*2 == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((m + identity_matrix<double,3>()*2 == m + 2*tmp(identity_matrix<double,3>())));
DLIB_TEST((identity_matrix<double>(3) + m == m + tmp(identity_matrix<double>(3))));
DLIB_TEST((identity_matrix<double,3>() + m == m + tmp(identity_matrix<double,3>())));
DLIB_TEST((2*identity_matrix<double>(3) + m == m + 2*tmp(identity_matrix<double>(3))));
DLIB_TEST((2*identity_matrix<double,3>() + m == m + 2*tmp(identity_matrix<double,3>())));
}
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment