414 lines
12 KiB
C++
414 lines
12 KiB
C++
// Copyright (C) 2008 Davis E. King (davis@dlib.net)
|
|
// License: Boost Software License See LICENSE.txt for the full license.
|
|
#ifndef DLIB_MATRIx_ASSIGn_FWD_
|
|
#define DLIB_MATRIx_ASSIGn_FWD_
|
|
|
|
// GCC 4.8 gives false alarms about some variables being uninitialized. Disable these
|
|
// false warnings.
|
|
#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
|
#endif
|
|
|
|
#include "../enable_if.h"
|
|
#include "matrix_data_layout.h"
|
|
#include "../algs.h"
|
|
|
|
namespace dlib
|
|
{
|
|
|
|
/*
|
|
The point of the matrix_assign() functions is to contain all the various
|
|
optimizations that help the matrix assign a matrix_exp to an actual matrix
|
|
object quickly.
|
|
*/
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
namespace ma
|
|
{
|
|
// This template here controls how big a compile time sized matrix needs
|
|
// to be for it to get passed into the optimized versions of the
|
|
// matrix_assign() function. So small matrices are evaluated with a simple
|
|
// loop like the ones in this file and bigger matrices may get sent to BLAS
|
|
// routines or some other kind of optimized thing.
|
|
template < typename EXP, typename enable = void >
|
|
struct is_small_matrix { static const bool value = false; };
|
|
template < typename EXP >
|
|
struct is_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
|
|
EXP::NR<=17 && EXP::NC<=17 && (EXP::cost <= 70)>::type> { static const bool value = true; };
|
|
|
|
// I wouldn't use this mul object to do the multiply but visual studio 7.1 wouldn't
|
|
// compile otherwise.
|
|
template <long a, long b>
|
|
struct mul { const static long value = a*b; };
|
|
|
|
template < typename EXP, typename enable = void >
|
|
struct is_very_small_matrix { static const bool value = false; };
|
|
template < typename EXP >
|
|
struct is_very_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
|
|
(mul<EXP::NR,EXP::NC>::value <= 16) && (EXP::cost <= 70)>::type> { static const bool value = true; };
|
|
|
|
|
|
template < typename EXP, typename enable = void >
|
|
struct has_column_major_layout { static const bool value = false; };
|
|
template < typename EXP >
|
|
struct has_column_major_layout<EXP, typename enable_if<is_same_type<typename EXP::layout_type, column_major_layout> >::type >
|
|
{ static const bool value = true; };
|
|
|
|
|
|
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename EXP
|
|
>
|
|
class matrix_exp;
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename EXP1, typename EXP2>
|
|
inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
|
|
matrix_assign_default (
|
|
EXP1& dest,
|
|
const EXP2& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) = src(r,c);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename EXP1, typename EXP2>
|
|
inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
|
|
matrix_assign_default (
|
|
EXP1& dest,
|
|
const EXP2& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) = src(r,c);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename EXP1, typename EXP2>
|
|
inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
|
|
matrix_assign_default (
|
|
EXP1& dest,
|
|
const EXP2& src,
|
|
typename EXP2::type alpha,
|
|
bool add_to
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- if (add_to == false) then
|
|
- #dest == alpha*src
|
|
- else
|
|
- #dest == dest + alpha*src
|
|
!*/
|
|
{
|
|
if (add_to)
|
|
{
|
|
if (alpha == static_cast<typename EXP2::type>(1))
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) += src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else if (alpha == static_cast<typename EXP2::type>(-1))
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) -= src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) += alpha*src(r,c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (alpha == static_cast<typename EXP2::type>(1))
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) = src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
dest(r,c) = alpha*src(r,c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <typename EXP1, typename EXP2>
|
|
inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
|
|
matrix_assign_default (
|
|
EXP1& dest,
|
|
const EXP2& src,
|
|
typename EXP2::type alpha,
|
|
bool add_to
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- if (add_to == false) then
|
|
- #dest == alpha*src
|
|
- else
|
|
- #dest == dest + alpha*src
|
|
!*/
|
|
{
|
|
if (add_to)
|
|
{
|
|
if (alpha == static_cast<typename EXP2::type>(1))
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) += src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else if (alpha == static_cast<typename EXP2::type>(-1))
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) -= src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) += alpha*src(r,c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (alpha == static_cast<typename EXP2::type>(1))
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) = src(r,c);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (long c = 0; c < src.nc(); ++c)
|
|
{
|
|
for (long r = 0; r < src.nr(); ++r)
|
|
{
|
|
dest(r,c) = alpha*src(r,c);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename matrix_dest_type,
|
|
typename src_exp
|
|
>
|
|
void matrix_assign_big (
|
|
matrix_dest_type& dest,
|
|
const matrix_exp<src_exp>& src
|
|
)
|
|
{
|
|
matrix_assign_default(dest,src);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename matrix_dest_type,
|
|
typename src_exp
|
|
>
|
|
inline typename disable_if<ma::is_small_matrix<src_exp> >::type matrix_assign (
|
|
matrix_dest_type& dest,
|
|
const matrix_exp<src_exp>& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
// Call src.ref() here so that the derived type of the matrix_exp shows
|
|
// up so we can overload matrix_assign_big() based on various matrix expression
|
|
// types.
|
|
matrix_assign_big(dest,src.ref());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
// this code is here to perform an unrolled version of the matrix_assign() function
|
|
template < typename DEST, typename SRC, long NR, long NC,
|
|
long R = 0, long C = 0, bool base_case = (R==NR) >
|
|
struct matrix_unroll_helper
|
|
{
|
|
inline static void go ( DEST& dest, const SRC& src)
|
|
{
|
|
dest(R,C) = src(R,C);
|
|
matrix_unroll_helper<DEST,SRC,NR,NC, R + (C+1)/NC, (C+1)%NC>::go(dest,src);
|
|
}
|
|
};
|
|
|
|
template < typename DEST, typename SRC, long NR, long NC, long R, long C >
|
|
struct matrix_unroll_helper<DEST,SRC,NR,NC,R,C,true>
|
|
{ inline static void go ( DEST& , const SRC& ) {} };
|
|
|
|
template <typename DEST, typename SRC>
|
|
inline void matrix_assign_unrolled (
|
|
DEST& dest,
|
|
const SRC& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
COMPILE_TIME_ASSERT(SRC::NR*SRC::NC != 0);
|
|
matrix_unroll_helper<DEST,SRC, SRC::NR, SRC::NC>::go(dest,src);
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename matrix_dest_type,
|
|
typename src_exp
|
|
>
|
|
inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==false >::type matrix_assign (
|
|
matrix_dest_type& dest,
|
|
const matrix_exp<src_exp>& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
matrix_assign_default(dest,src.ref());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
template <
|
|
typename matrix_dest_type,
|
|
typename src_exp
|
|
>
|
|
inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==true >::type matrix_assign (
|
|
matrix_dest_type& dest,
|
|
const matrix_exp<src_exp>& src
|
|
)
|
|
/*!
|
|
requires
|
|
- src.destructively_aliases(dest) == false
|
|
- dest.nr() == src.nr()
|
|
- dest.nc() == src.nc()
|
|
ensures
|
|
- #dest == src
|
|
!*/
|
|
{
|
|
matrix_assign_unrolled(dest,src.ref());
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------------------
|
|
|
|
}
|
|
|
|
#if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))
|
|
#pragma GCC diagnostic pop
|
|
#endif
|
|
|
|
#endif // DLIB_MATRIx_ASSIGn_FWD_
|
|
|
|
|