1 // Copyright (C) 2008  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_MATRIx_ASSIGn_FWD_
4 #define DLIB_MATRIx_ASSIGn_FWD_
5 
6 // GCC 4.8 gives false alarms about some variables being uninitialized.  Disable these
7 // false warnings.
8 #if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))
9 #pragma GCC diagnostic push
10 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
11 #endif
12 
13 #include "../enable_if.h"
14 #include "matrix_data_layout.h"
15 #include "../algs.h"
16 
17 namespace dlib
18 {
19 
20     /*
21         The point of the matrix_assign() functions is to contain all the various
22         optimizations that help the matrix assign a matrix_exp to an actual matrix
23         object quickly.
24     */
25 
26 // ----------------------------------------------------------------------------------------
27 
28     namespace ma
29     {
30         // This template here controls how big a compile time sized matrix needs
31         // to be for it to get passed into the optimized versions of the
32         // matrix_assign() function.  So small matrices are evaluated with a simple
33         // loop like the ones in this file and bigger matrices may get sent to BLAS
34         // routines or some other kind of optimized thing.
35         template < typename EXP, typename enable = void >
36         struct is_small_matrix { static const bool value = false; };
37         template < typename EXP >
38         struct is_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
39         EXP::NR<=17 && EXP::NC<=17 && (EXP::cost <= 70)>::type> { static const bool value = true; };
40 
41         // I wouldn't use this mul object to do the multiply but visual studio 7.1 wouldn't
42         // compile otherwise.
43         template <long a, long b>
44         struct mul { const static long value = a*b; };
45 
46         template < typename EXP, typename enable = void >
47         struct is_very_small_matrix { static const bool value = false; };
48         template < typename EXP >
49         struct is_very_small_matrix<EXP, typename enable_if_c<EXP::NR>=1 && EXP::NC>=1 &&
50         (mul<EXP::NR,EXP::NC>::value <= 16) && (EXP::cost <= 70)>::type> { static const bool value = true; };
51 
52 
53         template < typename EXP, typename enable = void >
54         struct has_column_major_layout { static const bool value = false; };
55         template < typename EXP >
56         struct has_column_major_layout<EXP, typename enable_if<is_same_type<typename EXP::layout_type, column_major_layout> >::type >
57         { static const bool value = true; };
58 
59 
60 
61     }
62 
63 // ----------------------------------------------------------------------------------------
64 
65     template <
66         typename EXP
67         >
68     class matrix_exp;
69 
70 // ----------------------------------------------------------------------------------------
71 
72     template <typename EXP1, typename EXP2>
73     inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
74     matrix_assign_default (
75         EXP1& dest,
76         const EXP2& src
77     )
78     /*!
79         requires
80             - src.destructively_aliases(dest) == false
81             - dest.nr() == src.nr()
82             - dest.nc() == src.nc()
83         ensures
84             - #dest == src
85     !*/
86     {
87         for (long r = 0; r < src.nr(); ++r)
88         {
89             for (long c = 0; c < src.nc(); ++c)
90             {
91                 dest(r,c) = src(r,c);
92             }
93         }
94     }
95 
96 // ----------------------------------------------------------------------------------------
97 
98     template <typename EXP1, typename EXP2>
99     inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
100     matrix_assign_default (
101         EXP1& dest,
102         const EXP2& src
103     )
104     /*!
105         requires
106             - src.destructively_aliases(dest) == false
107             - dest.nr() == src.nr()
108             - dest.nc() == src.nc()
109         ensures
110             - #dest == src
111     !*/
112     {
113         for (long c = 0; c < src.nc(); ++c)
114         {
115             for (long r = 0; r < src.nr(); ++r)
116             {
117                 dest(r,c) = src(r,c);
118             }
119         }
120     }
121 
122 // ----------------------------------------------------------------------------------------
123 
124     template <typename EXP1, typename EXP2>
125     inline typename disable_if<ma::has_column_major_layout<EXP1> >::type
126     matrix_assign_default (
127         EXP1& dest,
128         const EXP2& src,
129         typename EXP2::type alpha,
130         bool add_to
131     )
132     /*!
133         requires
134             - src.destructively_aliases(dest) == false
135             - dest.nr() == src.nr()
136             - dest.nc() == src.nc()
137         ensures
138             - if (add_to == false) then
139                 - #dest == alpha*src
140             - else
141                 - #dest == dest + alpha*src
142     !*/
143     {
144         if (add_to)
145         {
146             if (alpha == static_cast<typename EXP2::type>(1))
147             {
148                 for (long r = 0; r < src.nr(); ++r)
149                 {
150                     for (long c = 0; c < src.nc(); ++c)
151                     {
152                         dest(r,c) += src(r,c);
153                     }
154                 }
155             }
156             else if (alpha == static_cast<typename EXP2::type>(-1))
157             {
158                 for (long r = 0; r < src.nr(); ++r)
159                 {
160                     for (long c = 0; c < src.nc(); ++c)
161                     {
162                         dest(r,c) -= src(r,c);
163                     }
164                 }
165             }
166             else
167             {
168                 for (long r = 0; r < src.nr(); ++r)
169                 {
170                     for (long c = 0; c < src.nc(); ++c)
171                     {
172                         dest(r,c) += alpha*src(r,c);
173                     }
174                 }
175             }
176         }
177         else
178         {
179             if (alpha == static_cast<typename EXP2::type>(1))
180             {
181                 for (long r = 0; r < src.nr(); ++r)
182                 {
183                     for (long c = 0; c < src.nc(); ++c)
184                     {
185                         dest(r,c) = src(r,c);
186                     }
187                 }
188             }
189             else
190             {
191                 for (long r = 0; r < src.nr(); ++r)
192                 {
193                     for (long c = 0; c < src.nc(); ++c)
194                     {
195                         dest(r,c) = alpha*src(r,c);
196                     }
197                 }
198             }
199         }
200     }
201 
202 // ----------------------------------------------------------------------------------------
203 
204     template <typename EXP1, typename EXP2>
205     inline typename enable_if<ma::has_column_major_layout<EXP1> >::type
206     matrix_assign_default (
207         EXP1& dest,
208         const EXP2& src,
209         typename EXP2::type alpha,
210         bool add_to
211     )
212     /*!
213         requires
214             - src.destructively_aliases(dest) == false
215             - dest.nr() == src.nr()
216             - dest.nc() == src.nc()
217         ensures
218             - if (add_to == false) then
219                 - #dest == alpha*src
220             - else
221                 - #dest == dest + alpha*src
222     !*/
223     {
224         if (add_to)
225         {
226             if (alpha == static_cast<typename EXP2::type>(1))
227             {
228                 for (long c = 0; c < src.nc(); ++c)
229                 {
230                     for (long r = 0; r < src.nr(); ++r)
231                     {
232                         dest(r,c) += src(r,c);
233                     }
234                 }
235             }
236             else if (alpha == static_cast<typename EXP2::type>(-1))
237             {
238                 for (long c = 0; c < src.nc(); ++c)
239                 {
240                     for (long r = 0; r < src.nr(); ++r)
241                     {
242                         dest(r,c) -= src(r,c);
243                     }
244                 }
245             }
246             else
247             {
248                 for (long c = 0; c < src.nc(); ++c)
249                 {
250                     for (long r = 0; r < src.nr(); ++r)
251                     {
252                         dest(r,c) += alpha*src(r,c);
253                     }
254                 }
255             }
256         }
257         else
258         {
259             if (alpha == static_cast<typename EXP2::type>(1))
260             {
261                 for (long c = 0; c < src.nc(); ++c)
262                 {
263                     for (long r = 0; r < src.nr(); ++r)
264                     {
265                         dest(r,c) = src(r,c);
266                     }
267                 }
268             }
269             else
270             {
271                 for (long c = 0; c < src.nc(); ++c)
272                 {
273                     for (long r = 0; r < src.nr(); ++r)
274                     {
275                         dest(r,c) = alpha*src(r,c);
276                     }
277                 }
278             }
279         }
280     }
281 
282 // ----------------------------------------------------------------------------------------
283 
284     template <
285         typename matrix_dest_type,
286         typename src_exp
287         >
288     void matrix_assign_big (
289         matrix_dest_type& dest,
290         const matrix_exp<src_exp>& src
291     )
292     {
293         matrix_assign_default(dest,src);
294     }
295 
296 // ----------------------------------------------------------------------------------------
297 
298     template <
299         typename matrix_dest_type,
300         typename src_exp
301         >
302     inline typename disable_if<ma::is_small_matrix<src_exp> >::type matrix_assign (
303         matrix_dest_type& dest,
304         const matrix_exp<src_exp>& src
305     )
306     /*!
307         requires
308             - src.destructively_aliases(dest) == false
309             - dest.nr() == src.nr()
310             - dest.nc() == src.nc()
311         ensures
312             - #dest == src
313     !*/
314     {
315         // Call src.ref() here so that the derived type of the matrix_exp shows
316         // up so we can overload matrix_assign_big() based on various matrix expression
317         // types.
318         matrix_assign_big(dest,src.ref());
319     }
320 
321 // ----------------------------------------------------------------------------------------
322 // ----------------------------------------------------------------------------------------
323 
324 // this code is here to perform an unrolled version of the matrix_assign() function
325     template < typename DEST, typename SRC, long NR, long NC,
326     long R = 0, long C = 0, bool base_case = (R==NR) >
327     struct matrix_unroll_helper
328     {
329         inline static void go ( DEST& dest, const SRC& src)
330         {
331             dest(R,C) = src(R,C);
332             matrix_unroll_helper<DEST,SRC,NR,NC, R + (C+1)/NC,  (C+1)%NC>::go(dest,src);
333         }
334     };
335 
336     template < typename DEST, typename SRC, long NR, long NC, long R, long C >
337     struct matrix_unroll_helper<DEST,SRC,NR,NC,R,C,true>
338     { inline static void go ( DEST& , const SRC& ) {} };
339 
340     template <typename DEST, typename SRC>
341     inline void matrix_assign_unrolled (
342         DEST& dest,
343         const SRC& src
344     )
345     /*!
346         requires
347             - src.destructively_aliases(dest) == false
348             - dest.nr() == src.nr()
349             - dest.nc() == src.nc()
350         ensures
351             - #dest == src
352     !*/
353     {
354         COMPILE_TIME_ASSERT(SRC::NR*SRC::NC != 0);
355         matrix_unroll_helper<DEST,SRC, SRC::NR, SRC::NC>::go(dest,src);
356     }
357 
358 // ----------------------------------------------------------------------------------------
359 // ----------------------------------------------------------------------------------------
360 
361     template <
362         typename matrix_dest_type,
363         typename src_exp
364         >
365     inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==false >::type matrix_assign (
366         matrix_dest_type& dest,
367         const matrix_exp<src_exp>& src
368     )
369     /*!
370         requires
371             - src.destructively_aliases(dest) == false
372             - dest.nr() == src.nr()
373             - dest.nc() == src.nc()
374         ensures
375             - #dest == src
376     !*/
377     {
378         matrix_assign_default(dest,src.ref());
379     }
380 
381 // ----------------------------------------------------------------------------------------
382 
383     template <
384         typename matrix_dest_type,
385         typename src_exp
386         >
387     inline typename enable_if_c<ma::is_small_matrix<src_exp>::value && ma::is_very_small_matrix<src_exp>::value==true >::type matrix_assign (
388         matrix_dest_type& dest,
389         const matrix_exp<src_exp>& src
390     )
391     /*!
392         requires
393             - src.destructively_aliases(dest) == false
394             - dest.nr() == src.nr()
395             - dest.nc() == src.nc()
396         ensures
397             - #dest == src
398     !*/
399     {
400         matrix_assign_unrolled(dest,src.ref());
401     }
402 
403 // ----------------------------------------------------------------------------------------
404 
405 }
406 
407 #if defined(__GNUC__) && ((__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) || (__GNUC__ > 4))
408 #pragma GCC diagnostic pop
409 #endif
410 
411 #endif // DLIB_MATRIx_ASSIGn_FWD_
412 
413 
414