1 // Copyright (C) 2006  Davis E. King (davis@dlib.net)
2 // License: Boost Software License   See LICENSE.txt for the full license.
3 #ifndef DLIB_MATRIx_
4 #define DLIB_MATRIx_
5 
6 #include "matrix_exp.h"
7 #include "matrix_abstract.h"
8 #include "../algs.h"
9 #include "../serialize.h"
10 #include "../enable_if.h"
11 #include <sstream>
12 #include <algorithm>
13 #include "../memory_manager.h"
14 #include "../is_kind.h"
15 #include "matrix_data_layout.h"
16 #include "matrix_assign_fwd.h"
17 #include "matrix_op.h"
18 #include <utility>
19 #ifdef DLIB_HAS_INITIALIZER_LISTS
20 #include <initializer_list>
21 #endif
22 
23 #ifdef MATLAB_MEX_FILE
24 #include <mex.h>
25 #endif
26 
27 #ifdef _MSC_VER
28 #pragma warning(push)
29 
30 // Disable the following warnings for Visual Studio
31 
32 // This warning is:
33 //    "warning C4355: 'this' : used in base member initializer list"
34 // Which we get from this code but it is not an error so I'm turning this
35 // warning off and then turning it back on at the end of the file.
36 #pragma warning(disable : 4355)
37 
38 // "warning C4723: potential divide by 0" - This warning is triggered in
39 // matrix(const std::initializer_list<T>& l) where the compiler can see that
40 // matrix<> was templated in a way making NR ending up 0, but division by 0 at runtime
41 // is not possible because the division operation is inside "if (NR!=0)" block.
42 #pragma warning(disable : 4723)
43 
44 // "warning C4724: potential mod by 0" - This warning is triggered in
45 // matrix(const std::initializer_list<T>& l) where the compiler can see that
46 // matrix<> was templated in a way making NR ending up 0, but mod by 0 at runtime
47 // is not possible because the mod operation is inside "if (NR!=0)" block.
48 #pragma warning(disable : 4724)
49 
50 #endif
51 
52 namespace dlib
53 {
54 
55 // ----------------------------------------------------------------------------------------
56 
57     // This template will perform the needed loop for element multiplication using whichever
58     // dimension is provided as a compile time constant (if one is at all).
59     template <
60         typename LHS,
61         typename RHS,
62         long lhs_nc = LHS::NC,
63         long rhs_nr = RHS::NR
64         >
65     struct matrix_multiply_helper
66     {
67         typedef typename LHS::type type;
68         template <typename RHS_, typename LHS_>
evalmatrix_multiply_helper69         inline const static type  eval (
70             const RHS_& rhs,
71             const LHS_& lhs,
72             const long r,
73             const long c
74         )
75         {
76             type temp = lhs(r,0)*rhs(0,c);
77             for (long i = 1; i < rhs.nr(); ++i)
78             {
79                 temp += lhs(r,i)*rhs(i,c);
80             }
81             return temp;
82         }
83     };
84 
85     template <
86         typename LHS,
87         typename RHS,
88         long lhs_nc
89         >
90     struct matrix_multiply_helper <LHS,RHS,lhs_nc,0>
91     {
92         typedef typename LHS::type type;
93         template <typename RHS_, typename LHS_>
94         inline const static type  eval (
95             const RHS_& rhs,
96             const LHS_& lhs,
97             const long r,
98             const long c
99         )
100         {
101             type temp = lhs(r,0)*rhs(0,c);
102             for (long i = 1; i < lhs.nc(); ++i)
103             {
104                 temp += lhs(r,i)*rhs(i,c);
105             }
106             return temp;
107         }
108     };
109 
110     template <typename LHS, typename RHS>
111     class matrix_multiply_exp;
112 
113     template <typename LHS, typename RHS>
114     struct matrix_traits<matrix_multiply_exp<LHS,RHS> >
115     {
116         typedef typename LHS::type type;
117         typedef typename LHS::type const_ret_type;
118         typedef typename LHS::mem_manager_type mem_manager_type;
119         typedef typename LHS::layout_type layout_type;
120         const static long NR = LHS::NR;
121         const static long NC = RHS::NC;
122 
123 #ifdef DLIB_USE_BLAS
124         // if there are BLAS functions to be called then we want to make sure we
125         // always evaluate any complex expressions so that the BLAS bindings can happen.
126         const static bool lhs_is_costly = (LHS::cost > 2)&&(RHS::NC != 1 || LHS::cost >= 10000);
127         const static bool rhs_is_costly = (RHS::cost > 2)&&(LHS::NR != 1 || RHS::cost >= 10000);
128 #else
129         const static bool lhs_is_costly = (LHS::cost > 4)&&(RHS::NC != 1);
130         const static bool rhs_is_costly = (RHS::cost > 4)&&(LHS::NR != 1);
131 #endif
132 
133         // Note that if we decide that one of the matrices is too costly we will evaluate it
134         // into a temporary.  Doing this resets its cost back to 1.
135         const static long lhs_cost = ((lhs_is_costly==true)? 1 : (LHS::cost));
136         const static long rhs_cost = ((rhs_is_costly==true)? 1 : (RHS::cost));
137 
138         // The cost of evaluating an element of a matrix multiply is the cost of evaluating elements from
139         // RHS and LHS times the number of rows/columns in the RHS/LHS matrix.  If we don't know the matrix
140         // dimensions then just assume it is really large.
141         const static long cost = ((tmax<LHS::NC,RHS::NR>::value!=0)? ((lhs_cost+rhs_cost)*tmax<LHS::NC,RHS::NR>::value):(10000));
142     };
143 
144     template <typename T, bool is_ref> struct conditional_matrix_temp { typedef typename T::matrix_type type; };
145     template <typename T> struct conditional_matrix_temp<T,true>      { typedef T& type; };
146 
147     template <
148         typename LHS,
149         typename RHS
150         >
151     class matrix_multiply_exp : public matrix_exp<matrix_multiply_exp<LHS,RHS> >
152     {
153         /*!
154             REQUIREMENTS ON LHS AND RHS
155                 - must be matrix_exp objects.
156         !*/
157     public:
158 
159         typedef typename matrix_traits<matrix_multiply_exp>::type type;
160         typedef typename matrix_traits<matrix_multiply_exp>::const_ret_type const_ret_type;
161         typedef typename matrix_traits<matrix_multiply_exp>::mem_manager_type mem_manager_type;
162         const static long NR = matrix_traits<matrix_multiply_exp>::NR;
163         const static long NC = matrix_traits<matrix_multiply_exp>::NC;
164         const static long cost = matrix_traits<matrix_multiply_exp>::cost;
165         typedef typename matrix_traits<matrix_multiply_exp>::layout_type layout_type;
166 
167 
168         const static bool lhs_is_costly = matrix_traits<matrix_multiply_exp>::lhs_is_costly;
169         const static bool rhs_is_costly = matrix_traits<matrix_multiply_exp>::rhs_is_costly;
170         const static bool either_is_costly = lhs_is_costly || rhs_is_costly;
171         const static bool both_are_costly = lhs_is_costly && rhs_is_costly;
172 
173         typedef typename conditional_matrix_temp<const LHS,lhs_is_costly == false>::type LHS_ref_type;
174         typedef typename conditional_matrix_temp<const RHS,rhs_is_costly == false>::type RHS_ref_type;
175 
176         // This constructor exists simply for the purpose of causing a compile time error if
177         // someone tries to create an instance of this object with the wrong kind of objects.
178         template <typename T1, typename T2>
179         matrix_multiply_exp (T1,T2);
180 
181         inline matrix_multiply_exp (
182             const LHS& lhs_,
183             const RHS& rhs_
184         ) :
185             lhs(lhs_),
186             rhs(rhs_)
187         {
188             // You are trying to multiply two incompatible matrices together.  The number of columns
189             // in the matrix on the left must match the number of rows in the matrix on the right.
190             COMPILE_TIME_ASSERT(LHS::NC == RHS::NR || LHS::NC*RHS::NR == 0);
191             DLIB_ASSERT(lhs.nc() == rhs.nr() && lhs.size() > 0 && rhs.size() > 0,
192                 "\tconst matrix_exp operator*(const matrix_exp& lhs, const matrix_exp& rhs)"
193                 << "\n\tYou are trying to multiply two incompatible matrices together"
194                 << "\n\tlhs.nr(): " << lhs.nr()
195                 << "\n\tlhs.nc(): " << lhs.nc()
196                 << "\n\trhs.nr(): " << rhs.nr()
197                 << "\n\trhs.nc(): " << rhs.nc()
198                 << "\n\t&lhs: " << &lhs
199                 << "\n\t&rhs: " << &rhs
200                 );
201 
202             // You can't multiply matrices together if they don't both contain the same type of elements.
203             COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
204         }
205 
206         inline const type operator() (
207             const long r,
208             const long c
209         ) const
210         {
211             return matrix_multiply_helper<LHS,RHS>::eval(rhs,lhs,r,c);
212         }
213 
214         inline const type operator() ( long i ) const
215         { return matrix_exp<matrix_multiply_exp>::operator()(i); }
216 
217         long nr (
218         ) const { return lhs.nr(); }
219 
220         long nc (
221         ) const { return rhs.nc(); }
222 
223         template <typename U>
224         bool aliases (
225             const matrix_exp<U>& item
226         ) const { return lhs.aliases(item) || rhs.aliases(item); }
227 
228         template <typename U>
229         bool destructively_aliases (
230             const matrix_exp<U>& item
231         ) const { return aliases(item); }
232 
233         LHS_ref_type lhs;
234         RHS_ref_type rhs;
235     };
236 
237     template < typename EXP1, typename EXP2 >
238     inline const matrix_multiply_exp<EXP1, EXP2> operator* (
239         const matrix_exp<EXP1>& m1,
240         const matrix_exp<EXP2>& m2
241     )
242     {
243         return matrix_multiply_exp<EXP1, EXP2>(m1.ref(), m2.ref());
244     }
245 
246     template <typename M, bool use_reference = true>
247     class matrix_mul_scal_exp;
248 
249     // -------------------------
250 
251     // Now we declare some overloads that cause any scalar multiplications to percolate
252     // up and outside of any matrix multiplies.  Note that we are using the non-reference containing
253     // mode of the matrix_mul_scal_exp object since we are passing in locally constructed matrix_multiply_exp
254     // objects.  So the matrix_mul_scal_exp object will contain copies of matrix_multiply_exp objects
255     // rather than references to them.  This could result in extra matrix copies if the matrix_multiply_exp
256     // decided it should evaluate any of its arguments.  So we also try to not apply this percolating operation
257     // if the matrix_multiply_exp would contain a fully evaluated copy of the original matrix_mul_scal_exp
258     // expression.
259     //
260     // Also, the reason we want to apply this transformation in the first place is because it (1) makes
261     // the expressions going into matrix multiply expressions simpler and (2) it makes it a lot more
262     // straightforward to bind BLAS calls to matrix expressions involving scalar multiplies.
263     template < typename EXP1, typename EXP2 >
264     inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, matrix_mul_scal_exp<EXP2> >::both_are_costly ,
265                                         matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
266         const matrix_mul_scal_exp<EXP1>& m1,
267         const matrix_mul_scal_exp<EXP2>& m2
268     )
269     {
270         typedef matrix_multiply_exp<EXP1, EXP2> exp1;
271         typedef matrix_mul_scal_exp<exp1,false> exp2;
272         return exp2(exp1(m1.m, m2.m), m1.s*m2.s);
273     }
274 
275     template < typename EXP1, typename EXP2 >
276     inline const typename disable_if_c< matrix_multiply_exp<matrix_mul_scal_exp<EXP1>, EXP2 >::lhs_is_costly ,
277                                       matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
278         const matrix_mul_scal_exp<EXP1>& m1,
279         const matrix_exp<EXP2>& m2
280     )
281     {
282         typedef matrix_multiply_exp<EXP1, EXP2> exp1;
283         typedef matrix_mul_scal_exp<exp1,false> exp2;
284         return exp2(exp1(m1.m, m2.ref()), m1.s);
285     }
286 
287     template < typename EXP1, typename EXP2 >
288     inline const typename disable_if_c< matrix_multiply_exp<EXP1, matrix_mul_scal_exp<EXP2> >::rhs_is_costly ,
289                                       matrix_mul_scal_exp<matrix_multiply_exp<EXP1, EXP2>,false> >::type operator* (
290         const matrix_exp<EXP1>& m1,
291         const matrix_mul_scal_exp<EXP2>& m2
292     )
293     {
294         typedef matrix_multiply_exp<EXP1, EXP2> exp1;
295         typedef matrix_mul_scal_exp<exp1,false> exp2;
296         return exp2(exp1(m1.ref(), m2.m), m2.s);
297     }
298 
299 // ----------------------------------------------------------------------------------------
300 
301     template <typename LHS, typename RHS>
302     class matrix_add_exp;
303 
304     template <typename LHS, typename RHS>
305     struct matrix_traits<matrix_add_exp<LHS,RHS> >
306     {
307         typedef typename LHS::type type;
308         typedef typename LHS::type const_ret_type;
309         typedef typename LHS::mem_manager_type mem_manager_type;
310         typedef typename LHS::layout_type layout_type;
311         const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;
312         const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;
313         const static long cost = LHS::cost+RHS::cost+1;
314     };
315 
316     template <
317         typename LHS,
318         typename RHS
319         >
320     class matrix_add_exp : public matrix_exp<matrix_add_exp<LHS,RHS> >
321     {
322         /*!
323             REQUIREMENTS ON LHS AND RHS
324                 - must be matrix_exp objects.
325         !*/
326     public:
327         typedef typename matrix_traits<matrix_add_exp>::type type;
328         typedef typename matrix_traits<matrix_add_exp>::const_ret_type const_ret_type;
329         typedef typename matrix_traits<matrix_add_exp>::mem_manager_type mem_manager_type;
330         const static long NR = matrix_traits<matrix_add_exp>::NR;
331         const static long NC = matrix_traits<matrix_add_exp>::NC;
332         const static long cost = matrix_traits<matrix_add_exp>::cost;
333         typedef typename matrix_traits<matrix_add_exp>::layout_type layout_type;
334 
335         // This constructor exists simply for the purpose of causing a compile time error if
336         // someone tries to create an instance of this object with the wrong kind of objects.
337         template <typename T1, typename T2>
338         matrix_add_exp (T1,T2);
339 
340         matrix_add_exp (
341             const LHS& lhs_,
342             const RHS& rhs_
343         ) :
344             lhs(lhs_),
345             rhs(rhs_)
346         {
347             // You can only add matrices together if they both have the same number of rows and columns.
348             COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);
349             COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);
350             DLIB_ASSERT(lhs.nc() == rhs.nc() &&
351                    lhs.nr() == rhs.nr(),
352                 "\tconst matrix_exp operator+(const matrix_exp& lhs, const matrix_exp& rhs)"
353                 << "\n\tYou are trying to add two incompatible matrices together"
354                 << "\n\tlhs.nr(): " << lhs.nr()
355                 << "\n\tlhs.nc(): " << lhs.nc()
356                 << "\n\trhs.nr(): " << rhs.nr()
357                 << "\n\trhs.nc(): " << rhs.nc()
358                 << "\n\t&lhs: " << &lhs
359                 << "\n\t&rhs: " << &rhs
360                 );
361 
362             // You can only add matrices together if they both contain the same types of elements.
363             COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
364         }
365 
366         const type operator() (
367             long r,
368             long c
369         ) const { return lhs(r,c) + rhs(r,c); }
370 
371         inline const type operator() ( long i ) const
372         { return matrix_exp<matrix_add_exp>::operator()(i); }
373 
374         template <typename U>
375         bool aliases (
376             const matrix_exp<U>& item
377         ) const { return lhs.aliases(item) || rhs.aliases(item); }
378 
379         template <typename U>
380         bool destructively_aliases (
381             const matrix_exp<U>& item
382         ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }
383 
384         long nr (
385         ) const { return lhs.nr(); }
386 
387         long nc (
388         ) const { return lhs.nc(); }
389 
390         const LHS& lhs;
391         const RHS& rhs;
392     };
393 
394     template <
395         typename EXP1,
396         typename EXP2
397         >
398     inline const matrix_add_exp<EXP1, EXP2> operator+ (
399         const matrix_exp<EXP1>& m1,
400         const matrix_exp<EXP2>& m2
401     )
402     {
403         return matrix_add_exp<EXP1, EXP2>(m1.ref(),m2.ref());
404     }
405 
406 // ----------------------------------------------------------------------------------------
407 
408     template <typename LHS, typename RHS>
409     class matrix_subtract_exp;
410 
411     template <typename LHS, typename RHS>
412     struct matrix_traits<matrix_subtract_exp<LHS,RHS> >
413     {
414         typedef typename LHS::type type;
415         typedef typename LHS::type const_ret_type;
416         typedef typename LHS::mem_manager_type mem_manager_type;
417         typedef typename LHS::layout_type layout_type;
418         const static long NR = (RHS::NR > LHS::NR) ? RHS::NR : LHS::NR;
419         const static long NC = (RHS::NC > LHS::NC) ? RHS::NC : LHS::NC;
420         const static long cost = LHS::cost+RHS::cost+1;
421     };
422 
423     template <
424         typename LHS,
425         typename RHS
426         >
427     class matrix_subtract_exp : public matrix_exp<matrix_subtract_exp<LHS,RHS> >
428     {
429         /*!
430             REQUIREMENTS ON LHS AND RHS
431                 - must be matrix_exp objects.
432         !*/
433     public:
434         typedef typename matrix_traits<matrix_subtract_exp>::type type;
435         typedef typename matrix_traits<matrix_subtract_exp>::const_ret_type const_ret_type;
436         typedef typename matrix_traits<matrix_subtract_exp>::mem_manager_type mem_manager_type;
437         const static long NR = matrix_traits<matrix_subtract_exp>::NR;
438         const static long NC = matrix_traits<matrix_subtract_exp>::NC;
439         const static long cost = matrix_traits<matrix_subtract_exp>::cost;
440         typedef typename matrix_traits<matrix_subtract_exp>::layout_type layout_type;
441 
442 
443         // This constructor exists simply for the purpose of causing a compile time error if
444         // someone tries to create an instance of this object with the wrong kind of objects.
445         template <typename T1, typename T2>
446         matrix_subtract_exp (T1,T2);
447 
448         matrix_subtract_exp (
449             const LHS& lhs_,
450             const RHS& rhs_
451         ) :
452             lhs(lhs_),
453             rhs(rhs_)
454         {
455             // You can only subtract one matrix from another if they both have the same number of rows and columns.
456             COMPILE_TIME_ASSERT(LHS::NR == RHS::NR || LHS::NR == 0 || RHS::NR == 0);
457             COMPILE_TIME_ASSERT(LHS::NC == RHS::NC || LHS::NC == 0 || RHS::NC == 0);
458             DLIB_ASSERT(lhs.nc() == rhs.nc() &&
459                    lhs.nr() == rhs.nr(),
460                 "\tconst matrix_exp operator-(const matrix_exp& lhs, const matrix_exp& rhs)"
461                 << "\n\tYou are trying to subtract two incompatible matrices"
462                 << "\n\tlhs.nr(): " << lhs.nr()
463                 << "\n\tlhs.nc(): " << lhs.nc()
464                 << "\n\trhs.nr(): " << rhs.nr()
465                 << "\n\trhs.nc(): " << rhs.nc()
466                 << "\n\t&lhs: " << &lhs
467                 << "\n\t&rhs: " << &rhs
468                 );
469 
470             // You can only subtract one matrix from another if they both contain elements of the same type.
471             COMPILE_TIME_ASSERT((is_same_type<typename LHS::type, typename RHS::type>::value == true));
472         }
473 
474         const type operator() (
475             long r,
476             long c
477         ) const { return lhs(r,c) - rhs(r,c); }
478 
479         inline const type operator() ( long i ) const
480         { return matrix_exp<matrix_subtract_exp>::operator()(i); }
481 
482         template <typename U>
483         bool aliases (
484             const matrix_exp<U>& item
485         ) const { return lhs.aliases(item) || rhs.aliases(item); }
486 
487         template <typename U>
488         bool destructively_aliases (
489             const matrix_exp<U>& item
490         ) const { return lhs.destructively_aliases(item) || rhs.destructively_aliases(item); }
491 
492         long nr (
493         ) const { return lhs.nr(); }
494 
495         long nc (
496         ) const { return lhs.nc(); }
497 
498         const LHS& lhs;
499         const RHS& rhs;
500     };
501 
502     template <
503         typename EXP1,
504         typename EXP2
505         >
506     inline const matrix_subtract_exp<EXP1, EXP2> operator- (
507         const matrix_exp<EXP1>& m1,
508         const matrix_exp<EXP2>& m2
509     )
510     {
511         return matrix_subtract_exp<EXP1, EXP2>(m1.ref(),m2.ref());
512     }
513 
514 // ----------------------------------------------------------------------------------------
515 
516     template <typename M>
517     class matrix_div_scal_exp;
518 
519     template <typename M>
520     struct matrix_traits<matrix_div_scal_exp<M> >
521     {
522         typedef typename M::type type;
523         typedef typename M::type const_ret_type;
524         typedef typename M::mem_manager_type mem_manager_type;
525         typedef typename M::layout_type layout_type;
526         const static long NR = M::NR;
527         const static long NC = M::NC;
528         const static long cost = M::cost+1;
529     };
530 
531     template <
532         typename M
533         >
534     class matrix_div_scal_exp : public matrix_exp<matrix_div_scal_exp<M> >
535     {
536         /*!
537             REQUIREMENTS ON M
538                 - must be a matrix_exp object.
539         !*/
540     public:
541         typedef typename matrix_traits<matrix_div_scal_exp>::type type;
542         typedef typename matrix_traits<matrix_div_scal_exp>::const_ret_type const_ret_type;
543         typedef typename matrix_traits<matrix_div_scal_exp>::mem_manager_type mem_manager_type;
544         const static long NR = matrix_traits<matrix_div_scal_exp>::NR;
545         const static long NC = matrix_traits<matrix_div_scal_exp>::NC;
546         const static long cost = matrix_traits<matrix_div_scal_exp>::cost;
547         typedef typename matrix_traits<matrix_div_scal_exp>::layout_type layout_type;
548 
549 
550         // This constructor exists simply for the purpose of causing a compile time error if
551         // someone tries to create an instance of this object with the wrong kind of objects.
552         template <typename T1>
553         matrix_div_scal_exp (T1, const type&);
554 
555         matrix_div_scal_exp (
556             const M& m_,
557             const type& s_
558         ) :
559             m(m_),
560             s(s_)
561         {}
562 
563         const type operator() (
564             long r,
565             long c
566         ) const { return m(r,c)/s; }
567 
568         inline const type operator() ( long i ) const
569         { return matrix_exp<matrix_div_scal_exp>::operator()(i); }
570 
571         template <typename U>
572         bool aliases (
573             const matrix_exp<U>& item
574         ) const { return m.aliases(item); }
575 
576         template <typename U>
577         bool destructively_aliases (
578             const matrix_exp<U>& item
579         ) const { return m.destructively_aliases(item); }
580 
581         long nr (
582         ) const { return m.nr(); }
583 
584         long nc (
585         ) const { return m.nc(); }
586 
587         const M& m;
588         const type s;
589     };
590 
591     template <
592         typename EXP,
593         typename S
594         >
595     inline const typename enable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_div_scal_exp<EXP> >::type operator/ (
596         const matrix_exp<EXP>& m,
597         const S& s
598     )
599     {
600         return matrix_div_scal_exp<EXP>(m.ref(),static_cast<typename EXP::type>(s));
601     }
602 
603 // ----------------------------------------------------------------------------------------
604 
605     template <typename M, bool use_reference >
606     struct matrix_traits<matrix_mul_scal_exp<M,use_reference> >
607     {
608         typedef typename M::type type;
609         typedef typename M::type const_ret_type;
610         typedef typename M::mem_manager_type mem_manager_type;
611         typedef typename M::layout_type layout_type;
612         const static long NR = M::NR;
613         const static long NC = M::NC;
614         const static long cost = M::cost+1;
615     };
616 
617     template <typename T, bool is_ref> struct conditional_reference { typedef T type; };
618     template <typename T> struct conditional_reference<T,true>      { typedef T& type; };
619 
620 
621     template <
622         typename M,
623         bool use_reference
624         >
625     class matrix_mul_scal_exp : public matrix_exp<matrix_mul_scal_exp<M,use_reference> >
626     {
627         /*!
628             REQUIREMENTS ON M
629                 - must be a matrix_exp object.
630 
631         !*/
632     public:
633         typedef typename matrix_traits<matrix_mul_scal_exp>::type type;
634         typedef typename matrix_traits<matrix_mul_scal_exp>::const_ret_type const_ret_type;
635         typedef typename matrix_traits<matrix_mul_scal_exp>::mem_manager_type mem_manager_type;
636         const static long NR = matrix_traits<matrix_mul_scal_exp>::NR;
637         const static long NC = matrix_traits<matrix_mul_scal_exp>::NC;
638         const static long cost = matrix_traits<matrix_mul_scal_exp>::cost;
639         typedef typename matrix_traits<matrix_mul_scal_exp>::layout_type layout_type;
640 
641         // You aren't allowed to multiply a matrix of matrices by a scalar.
642         COMPILE_TIME_ASSERT(is_matrix<type>::value == false);
643 
644         // This constructor exists simply for the purpose of causing a compile time error if
645         // someone tries to create an instance of this object with the wrong kind of objects.
646         template <typename T1>
647         matrix_mul_scal_exp (T1, const type&);
648 
649         matrix_mul_scal_exp (
650             const M& m_,
651             const type& s_
652         ) :
653             m(m_),
654             s(s_)
655         {}
656 
657         const type operator() (
658             long r,
659             long c
660         ) const { return m(r,c)*s; }
661 
662         inline const type operator() ( long i ) const
663         { return matrix_exp<matrix_mul_scal_exp>::operator()(i); }
664 
665         template <typename U>
666         bool aliases (
667             const matrix_exp<U>& item
668         ) const { return m.aliases(item); }
669 
670         template <typename U>
671         bool destructively_aliases (
672             const matrix_exp<U>& item
673         ) const { return m.destructively_aliases(item); }
674 
675         long nr (
676         ) const { return m.nr(); }
677 
678         long nc (
679         ) const { return m.nc(); }
680 
681         typedef typename conditional_reference<const M,use_reference>::type M_ref_type;
682 
683         M_ref_type m;
684         const type s;
685     };
686 
687     template <
688         typename EXP,
689         typename S
690         >
691     inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
692         const matrix_exp<EXP>& m,
693         const S& s
694     )
695     {
696         typedef typename EXP::type type;
697         return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));
698     }
699 
700     template <
701         typename EXP,
702         typename S,
703         bool B
704         >
705     inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
706         const matrix_mul_scal_exp<EXP,B>& m,
707         const S& s
708     )
709     {
710         typedef typename EXP::type type;
711         return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);
712     }
713 
714     template <
715         typename EXP,
716         typename S
717         >
718     inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
719         const S& s,
720         const matrix_exp<EXP>& m
721     )
722     {
723         typedef typename EXP::type type;
724         return matrix_mul_scal_exp<EXP>(m.ref(),static_cast<type>(s));
725     }
726 
727     template <
728         typename EXP,
729         typename S,
730         bool B
731         >
732     inline typename disable_if<is_matrix<S>, const matrix_mul_scal_exp<EXP> >::type operator* (
733         const S& s,
734         const matrix_mul_scal_exp<EXP,B>& m
735     )
736     {
737         typedef typename EXP::type type;
738         return matrix_mul_scal_exp<EXP>(m.m,static_cast<type>(s)*m.s);
739     }
740 
741     template <
742         typename EXP ,
743         typename S
744         >
745     inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (
746         const matrix_exp<EXP>& m,
747         const S& s
748     )
749     {
750         typedef typename EXP::type type;
751         const type one = 1;
752         return matrix_mul_scal_exp<EXP>(m.ref(),one/static_cast<type>(s));
753     }
754 
755     template <
756         typename EXP,
757         bool B,
758         typename S
759         >
760     inline const typename disable_if_c<std::numeric_limits<typename EXP::type>::is_integer, matrix_mul_scal_exp<EXP> >::type operator/ (
761         const matrix_mul_scal_exp<EXP,B>& m,
762         const S& s
763     )
764     {
765         typedef typename EXP::type type;
766         return matrix_mul_scal_exp<EXP>(m.m,m.s/static_cast<type>(s));
767     }
768 
769 // ----------------------------------------------------------------------------------------
770 
771     template <typename M>
772     struct op_s_div_m : basic_op_m<M>
773     {
774         typedef typename M::type type;
775 
776         op_s_div_m( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}
777 
778         const type s;
779 
780         const static long cost = M::cost+1;
781         typedef const typename M::type const_ret_type;
782         const_ret_type apply (long r, long c) const
783         {
784             return s/this->m(r,c);
785         }
786     };
787 
788     template <
789         typename EXP,
790         typename S
791         >
792     const typename disable_if<is_matrix<S>, matrix_op<op_s_div_m<EXP> > >::type operator/ (
793         const S& val,
794         const matrix_exp<EXP>& m
795     )
796     {
797         typedef typename EXP::type type;
798 
799         typedef op_s_div_m<EXP> op;
800         return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
801     }
802 
803 // ----------------------------------------------------------------------------------------
804 
805     template <
806         typename EXP
807         >
808     inline const matrix_mul_scal_exp<EXP> operator- (
809         const matrix_exp<EXP>& m
810     )
811     {
812         return matrix_mul_scal_exp<EXP>(m.ref(),-1);
813     }
814 
815     template <
816         typename EXP,
817         bool B
818         >
819     inline const matrix_mul_scal_exp<EXP> operator- (
820         const matrix_mul_scal_exp<EXP,B>& m
821     )
822     {
823         return matrix_mul_scal_exp<EXP>(m.m,-1*m.s);
824     }
825 
826 // ----------------------------------------------------------------------------------------
827 
828     template <typename M>
829     struct op_add_scalar : basic_op_m<M>
830     {
831         typedef typename M::type type;
832 
833         op_add_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}
834 
835         const type s;
836 
837         const static long cost = M::cost+1;
838         typedef const typename M::type const_ret_type;
839         const_ret_type apply (long r, long c) const
840         {
841             return this->m(r,c) + s;
842         }
843     };
844 
845     template <
846         typename EXP,
847         typename T
848         >
849     const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (
850         const matrix_exp<EXP>& m,
851         const T& val
852     )
853     {
854         typedef typename EXP::type type;
855 
856         typedef op_add_scalar<EXP> op;
857         return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
858     }
859 
860     template <
861         typename EXP,
862         typename T
863         >
864     const typename disable_if<is_matrix<T>, matrix_op<op_add_scalar<EXP> > >::type operator+ (
865         const T& val,
866         const matrix_exp<EXP>& m
867     )
868     {
869         typedef typename EXP::type type;
870 
871         typedef op_add_scalar<EXP> op;
872         return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
873     }
874 
875 // ----------------------------------------------------------------------------------------
876 
877     template <typename M>
878     struct op_subl_scalar : basic_op_m<M>
879     {
880         typedef typename M::type type;
881 
882         op_subl_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}
883 
884         const type s;
885 
886         const static long cost = M::cost+1;
887         typedef const typename M::type const_ret_type;
888         const_ret_type apply (long r, long c) const
889         {
890             return s - this->m(r,c) ;
891         }
892     };
893 
894     template <
895         typename EXP,
896         typename T
897         >
898     const typename disable_if<is_matrix<T>, matrix_op<op_subl_scalar<EXP> > >::type operator- (
899         const T& val,
900         const matrix_exp<EXP>& m
901     )
902     {
903         typedef typename EXP::type type;
904 
905         typedef op_subl_scalar<EXP> op;
906         return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
907     }
908 
909 // ----------------------------------------------------------------------------------------
910 
911     template <typename M>
912     struct op_subr_scalar : basic_op_m<M>
913     {
914         typedef typename M::type type;
915 
916         op_subr_scalar( const M& m_, const type& s_) : basic_op_m<M>(m_), s(s_){}
917 
918         const type s;
919 
920         const static long cost = M::cost+1;
921         typedef const typename M::type const_ret_type;
922         const_ret_type apply (long r, long c) const
923         {
924             return this->m(r,c) - s;
925         }
926     };
927 
928     template <
929         typename EXP,
930         typename T
931         >
932     const typename disable_if<is_matrix<T>, matrix_op<op_subr_scalar<EXP> > >::type operator- (
933         const matrix_exp<EXP>& m,
934         const T& val
935     )
936     {
937         typedef typename EXP::type type;
938 
939         typedef op_subr_scalar<EXP> op;
940         return matrix_op<op>(op(m.ref(), static_cast<type>(val)));
941     }
942 
943 // ----------------------------------------------------------------------------------------
944 
945     template <
946         typename EXP1,
947         typename EXP2
948         >
949     bool operator== (
950         const matrix_exp<EXP1>& m1,
951         const matrix_exp<EXP2>& m2
952     )
953     {
954         if (m1.nr() == m2.nr() && m1.nc() == m2.nc())
955         {
956             for (long r = 0; r < m1.nr(); ++r)
957             {
958                 for (long c = 0; c < m1.nc(); ++c)
959                 {
960                     if (m1(r,c) != m2(r,c))
961                         return false;
962                 }
963             }
964             return true;
965         }
966         return false;
967     }
968 
969     template <
970         typename EXP1,
971         typename EXP2
972         >
973     inline bool operator!= (
974         const matrix_exp<EXP1>& m1,
975         const matrix_exp<EXP2>& m2
976     ) { return !(m1 == m2); }
977 
978 // ----------------------------------------------------------------------------------------
979 // ----------------------------------------------------------------------------------------
980 // ----------------------------------------------------------------------------------------
981 
982     template <typename T>
983     struct op_pointer_to_mat;
984     template <typename T>
985     struct op_pointer_to_col_vect;
986 
987     template <
988         typename T,
989         long num_rows,
990         long num_cols,
991         typename mem_manager,
992         typename layout
993         >
994     struct matrix_traits<matrix<T,num_rows, num_cols, mem_manager, layout> >
995     {
996         typedef T type;
997         typedef const T& const_ret_type;
998         typedef mem_manager mem_manager_type;
999         typedef layout layout_type;
1000         const static long NR = num_rows;
1001         const static long NC = num_cols;
1002         const static long cost = 1;
1003 
1004     };
1005 
1006     template <
1007         typename T,
1008         long num_rows,
1009         long num_cols,
1010         typename mem_manager,
1011         typename layout
1012         >
1013     class matrix : public matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >
1014     {
1015 
1016         COMPILE_TIME_ASSERT(num_rows >= 0 && num_cols >= 0);
1017 
1018     public:
1019         typedef typename matrix_traits<matrix>::type type;
1020         typedef typename matrix_traits<matrix>::const_ret_type const_ret_type;
1021         typedef typename matrix_traits<matrix>::mem_manager_type mem_manager_type;
1022         typedef typename matrix_traits<matrix>::layout_type layout_type;
1023         const static long NR = matrix_traits<matrix>::NR;
1024         const static long NC = matrix_traits<matrix>::NC;
1025         const static long cost = matrix_traits<matrix>::cost;
1026         typedef T*          iterator;
1027         typedef const T*    const_iterator;
1028 
1029         matrix ()
1030         {
1031         }
1032 
1033         explicit matrix (
1034             long length
1035         )
1036         {
1037             // This object you are trying to call matrix(length) on is not a column or
1038             // row vector.
1039             COMPILE_TIME_ASSERT(NR == 1 || NC == 1);
1040             DLIB_ASSERT( length >= 0,
1041                 "\tmatrix::matrix(length)"
1042                 << "\n\tlength must be at least 0"
1043                 << "\n\tlength: " << length
1044                 << "\n\tNR:     " << NR
1045                 << "\n\tNC:     " << NC
1046                 << "\n\tthis:   " << this
1047                 );
1048 
1049             if (NR == 1)
1050             {
1051                 DLIB_ASSERT(NC == 0 || NC == length,
1052                     "\tmatrix::matrix(length)"
1053                     << "\n\tSince this is a statically sized matrix length must equal NC"
1054                     << "\n\tlength: " << length
1055                     << "\n\tNR:     " << NR
1056                     << "\n\tNC:     " << NC
1057                     << "\n\tthis:   " << this
1058                     );
1059 
1060                 data.set_size(1,length);
1061             }
1062             else
1063             {
1064                 DLIB_ASSERT(NR == 0 || NR == length,
1065                     "\tvoid matrix::set_size(length)"
1066                     << "\n\tSince this is a statically sized matrix length must equal NR"
1067                     << "\n\tlength: " << length
1068                     << "\n\tNR:     " << NR
1069                     << "\n\tNC:     " << NC
1070                     << "\n\tthis:   " << this
1071                     );
1072 
1073                 data.set_size(length,1);
1074             }
1075         }
1076 
1077         matrix (
1078             long rows,
1079             long cols
1080         )
1081         {
1082             DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) &&
1083                     rows >= 0 && cols >= 0,
1084                 "\tvoid matrix::matrix(rows, cols)"
1085                 << "\n\tYou have supplied conflicting matrix dimensions"
1086                 << "\n\trows: " << rows
1087                 << "\n\tcols: " << cols
1088                 << "\n\tNR:   " << NR
1089                 << "\n\tNC:   " << NC
1090                 );
1091             data.set_size(rows,cols);
1092         }
1093 
1094         template <typename EXP>
1095         matrix (
1096             const matrix_exp<EXP>& m
1097         )
1098         {
1099             // You get an error on this line if the matrix m contains a type that isn't
1100             // the same as the type contained in the target matrix.
1101             COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||
1102                                 (is_matrix<typename EXP::type>::value == true));
1103 
1104             // The matrix you are trying to assign m to is a statically sized matrix and
1105             // m's dimensions don't match that of *this.
1106             COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
1107             COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
1108             DLIB_ASSERT((NR == 0 || NR == m.nr()) && (NC == 0 || NC == m.nc()),
1109                 "\tmatrix& matrix::matrix(const matrix_exp& m)"
1110                 << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size"
1111                 << "\n\tNR:     " << NR
1112                 << "\n\tNC:     " << NC
1113                 << "\n\tm.nr(): " << m.nr()
1114                 << "\n\tm.nc(): " << m.nc()
1115                 << "\n\tthis:   " << this
1116                 );
1117 
1118             data.set_size(m.nr(),m.nc());
1119 
1120             matrix_assign(*this, m);
1121         }
1122 
1123         matrix (
1124             const matrix& m
1125         ) : matrix_exp<matrix>(*this)
1126         {
1127             data.set_size(m.nr(),m.nc());
1128             matrix_assign(*this, m);
1129         }
1130 
1131 #ifdef DLIB_HAS_INITIALIZER_LISTS
1132         matrix(const std::initializer_list<T>& l)
1133         {
1134             if (NR*NC != 0)
1135             {
1136                 DLIB_ASSERT(l.size() == NR*NC,
1137                     "\t matrix::matrix(const std::initializer_list& l)"
1138                     << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a matching size."
1139                     << "\n\t l.size(): "<< l.size()
1140                     << "\n\t NR*NC:    "<< NR*NC);
1141 
1142                 data.set_size(NR, NC);
1143             }
1144             else if (NR!=0)
1145             {
1146                 DLIB_ASSERT(l.size()%NR == 0,
1147                     "\t matrix::matrix(const std::initializer_list& l)"
1148                     << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size."
1149                     << "\n\t l.size(): "<< l.size()
1150                     << "\n\t NR:       "<< NR);
1151 
1152                 if (l.size() != 0)
1153                     data.set_size(NR, l.size()/NR);
1154             }
1155             else if (NC!=0)
1156             {
1157                 DLIB_ASSERT(l.size()%NC == 0,
1158                     "\t matrix::matrix(const std::initializer_list& l)"
1159                     << "\n\t You are trying to initialize a statically sized matrix with a list that doesn't have a compatible size."
1160                     << "\n\t l.size(): "<< l.size()
1161                     << "\n\t NC:       "<< NC);
1162 
1163                 if (l.size() != 0)
1164                     data.set_size(l.size()/NC, NC);
1165             }
1166             else if (l.size() != 0)
1167             {
1168                 data.set_size(l.size(),1);
1169             }
1170 
1171             if (l.size() != 0)
1172             {
1173                 T* d = &data(0,0);
1174                 for (auto&& v : l)
1175                     *d++ = v;
1176             }
1177 
1178         }
1179 
1180         std::unique_ptr<T[]> steal_memory(
1181         )
1182         {
1183             return data.steal_memory();
1184         }
1185 
1186         matrix& operator=(const std::initializer_list<T>& l)
1187         {
1188             matrix temp(l);
1189             temp.swap(*this);
1190             return *this;
1191         }
1192 #endif // DLIB_HAS_INITIALIZER_LISTS
1193 
1194 #ifdef DLIB_HAS_RVALUE_REFERENCES
1195         matrix(matrix&& item)
1196         {
1197         #ifdef MATLAB_MEX_FILE
1198             // You can't move memory around when compiled in a matlab mex file and the
1199             // different locations have different ownership settings.
1200             if (data._private_is_owned_by_matlab() == item.data._private_is_owned_by_matlab())
1201             {
1202                 swap(item);
1203             }
1204             else
1205             {
1206                 data.set_size(item.nr(),item.nc());
1207                 matrix_assign(*this, item);
1208             }
1209         #else
1210             swap(item);
1211         #endif
1212         }
1213 
1214         matrix& operator= (
1215             matrix&& rhs
1216         )
1217         {
1218         #ifdef MATLAB_MEX_FILE
1219             // You can't move memory around when compiled in a matlab mex file and the
1220             // different locations have different ownership settings.
1221             if (data._private_is_owned_by_matlab() == rhs.data._private_is_owned_by_matlab())
1222             {
1223                 swap(rhs);
1224             }
1225             else
1226             {
1227                 data.set_size(rhs.nr(),rhs.nc());
1228                 matrix_assign(*this, rhs);
1229             }
1230         #else
1231             swap(rhs);
1232         #endif
1233             return *this;
1234         }
1235 #endif // DLIB_HAS_RVALUE_REFERENCES
1236 
1237         template <typename U, size_t len>
1238         explicit matrix (
1239             U (&array)[len]
1240         )
1241         {
1242             COMPILE_TIME_ASSERT(NR*NC == len && len > 0);
1243             size_t idx = 0;
1244             for (long r = 0; r < NR; ++r)
1245             {
1246                 for (long c = 0; c < NC; ++c)
1247                 {
1248                     data(r,c) = static_cast<T>(array[idx]);
1249                     ++idx;
1250                 }
1251             }
1252         }
1253 
1254         T& operator() (
1255             long r,
1256             long c
1257         )
1258         {
1259             DLIB_ASSERT(r < nr() && c < nc() &&
1260                    r >= 0 && c >= 0,
1261                 "\tT& matrix::operator(r,c)"
1262                 << "\n\tYou must give a valid row and column"
1263                 << "\n\tr:    " << r
1264                 << "\n\tc:    " << c
1265                 << "\n\tnr(): " << nr()
1266                 << "\n\tnc(): " << nc()
1267                 << "\n\tthis: " << this
1268                 );
1269             return data(r,c);
1270         }
1271 
1272         const T& operator() (
1273             long r,
1274             long c
1275         ) const
1276         {
1277             DLIB_ASSERT(r < nr() && c < nc() &&
1278                    r >= 0 && c >= 0,
1279                 "\tconst T& matrix::operator(r,c)"
1280                 << "\n\tYou must give a valid row and column"
1281                 << "\n\tr:    " << r
1282                 << "\n\tc:    " << c
1283                 << "\n\tnr(): " << nr()
1284                 << "\n\tnc(): " << nc()
1285                 << "\n\tthis: " << this
1286                 );
1287             return data(r,c);
1288         }
1289 
1290         T& operator() (
1291             long i
1292         )
1293         {
1294             // You can only use this operator on column vectors.
1295             COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);
1296             DLIB_ASSERT(nc() == 1 || nr() == 1,
1297                 "\tconst type matrix::operator(i)"
1298                 << "\n\tYou can only use this operator on column or row vectors"
1299                 << "\n\ti:    " << i
1300                 << "\n\tnr(): " << nr()
1301                 << "\n\tnc(): " << nc()
1302                 << "\n\tthis: " << this
1303                 );
1304             DLIB_ASSERT( 0 <= i && i < size(),
1305                 "\tconst type matrix::operator(i)"
1306                 << "\n\tYou must give a valid row/column number"
1307                 << "\n\ti:      " << i
1308                 << "\n\tsize(): " << size()
1309                 << "\n\tthis:   " << this
1310                 );
1311             return data(i);
1312         }
1313 
1314         const T& operator() (
1315             long i
1316         ) const
1317         {
1318             // You can only use this operator on column vectors.
1319             COMPILE_TIME_ASSERT(NC == 1 || NC == 0 || NR == 1 || NR == 0);
1320             DLIB_ASSERT(nc() == 1 || nr() == 1,
1321                 "\tconst type matrix::operator(i)"
1322                 << "\n\tYou can only use this operator on column or row vectors"
1323                 << "\n\ti:    " << i
1324                 << "\n\tnr(): " << nr()
1325                 << "\n\tnc(): " << nc()
1326                 << "\n\tthis: " << this
1327                 );
1328             DLIB_ASSERT( 0 <= i && i < size(),
1329                 "\tconst type matrix::operator(i)"
1330                 << "\n\tYou must give a valid row/column number"
1331                 << "\n\ti:      " << i
1332                 << "\n\tsize(): " << size()
1333                 << "\n\tthis:   " << this
1334                 );
1335             return data(i);
1336         }
1337 
1338         inline operator const type (
1339         ) const
1340         {
1341             COMPILE_TIME_ASSERT(NC == 1 || NC == 0);
1342             COMPILE_TIME_ASSERT(NR == 1 || NR == 0);
1343             DLIB_ASSERT( nr() == 1 && nc() == 1 ,
1344                 "\tmatrix::operator const type"
1345                 << "\n\tYou can only attempt to implicit convert a matrix to a scalar if"
1346                 << "\n\tthe matrix is a 1x1 matrix"
1347                 << "\n\tnr(): " << nr()
1348                 << "\n\tnc(): " << nc()
1349                 << "\n\tthis: " << this
1350                 );
1351             return data(0);
1352         }
1353 
1354 #ifdef MATLAB_MEX_FILE
1355         void _private_set_mxArray(
1356             mxArray* mem
1357         )
1358         {
1359             data._private_set_mxArray(mem);
1360         }
1361 
1362         mxArray* _private_release_mxArray(
1363         )
1364         {
1365             return data._private_release_mxArray();
1366         }
1367 
1368         void _private_mark_owned_by_matlab()
1369         {
1370             data._private_mark_owned_by_matlab();
1371         }
1372 
1373         bool _private_is_owned_by_matlab()
1374         {
1375             return data._private_is_owned_by_matlab();
1376         }
1377 #endif
1378 
1379         void set_size (
1380             long rows,
1381             long cols
1382         )
1383         {
1384             DLIB_ASSERT( (NR == 0 || NR == rows) && ( NC == 0 || NC == cols) &&
1385                     rows >= 0 && cols >= 0,
1386                 "\tvoid matrix::set_size(rows, cols)"
1387                 << "\n\tYou have supplied conflicting matrix dimensions"
1388                 << "\n\trows: " << rows
1389                 << "\n\tcols: " << cols
1390                 << "\n\tNR:   " << NR
1391                 << "\n\tNC:   " << NC
1392                 << "\n\tthis: " << this
1393                 );
1394             if (nr() != rows || nc() != cols)
1395                 data.set_size(rows,cols);
1396         }
1397 
1398         void set_size (
1399             long length
1400         )
1401         {
1402             // This object you are trying to call set_size(length) on is not a column or
1403             // row vector.
1404             COMPILE_TIME_ASSERT(NR == 1 || NC == 1);
1405             DLIB_ASSERT( length >= 0,
1406                 "\tvoid matrix::set_size(length)"
1407                 << "\n\tlength must be at least 0"
1408                 << "\n\tlength: " << length
1409                 << "\n\tNR:     " << NR
1410                 << "\n\tNC:     " << NC
1411                 << "\n\tthis:   " << this
1412                 );
1413 
1414             if (NR == 1)
1415             {
1416                 DLIB_ASSERT(NC == 0 || NC == length,
1417                     "\tvoid matrix::set_size(length)"
1418                     << "\n\tSince this is a statically sized matrix length must equal NC"
1419                     << "\n\tlength: " << length
1420                     << "\n\tNR:     " << NR
1421                     << "\n\tNC:     " << NC
1422                     << "\n\tthis:   " << this
1423                     );
1424 
1425                 if (nc() != length)
1426                     data.set_size(1,length);
1427             }
1428             else
1429             {
1430                 DLIB_ASSERT(NR == 0 || NR == length,
1431                     "\tvoid matrix::set_size(length)"
1432                     << "\n\tSince this is a statically sized matrix length must equal NR"
1433                     << "\n\tlength: " << length
1434                     << "\n\tNR:     " << NR
1435                     << "\n\tNC:     " << NC
1436                     << "\n\tthis:   " << this
1437                     );
1438 
1439                 if (nr() != length)
1440                     data.set_size(length,1);
1441             }
1442         }
1443 
1444         long nr (
1445         ) const { return data.nr(); }
1446 
1447         long nc (
1448         ) const { return data.nc(); }
1449 
1450         long size (
1451         ) const { return data.nr()*data.nc(); }
1452 
1453         template <typename U, size_t len>
1454         matrix& operator= (
1455             U (&array)[len]
1456         )
1457         {
1458             COMPILE_TIME_ASSERT(NR*NC == len && len > 0);
1459             size_t idx = 0;
1460             for (long r = 0; r < NR; ++r)
1461             {
1462                 for (long c = 0; c < NC; ++c)
1463                 {
1464                     data(r,c) = static_cast<T>(array[idx]);
1465                     ++idx;
1466                 }
1467             }
1468             return *this;
1469         }
1470 
1471         template <typename EXP>
1472         matrix& operator= (
1473             const matrix_exp<EXP>& m
1474         )
1475         {
1476             // You get an error on this line if the matrix you are trying to
1477             // assign m to is a statically sized matrix and  m's dimensions don't
1478             // match that of *this.
1479             COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
1480             COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
1481             DLIB_ASSERT((NR == 0 || nr() == m.nr()) &&
1482                    (NC == 0 || nc() == m.nc()),
1483                 "\tmatrix& matrix::operator=(const matrix_exp& m)"
1484                 << "\n\tYou are trying to assign a dynamically sized matrix to a statically sized matrix with the wrong size"
1485                 << "\n\tnr():   " << nr()
1486                 << "\n\tnc():   " << nc()
1487                 << "\n\tm.nr(): " << m.nr()
1488                 << "\n\tm.nc(): " << m.nc()
1489                 << "\n\tthis:   " << this
1490                 );
1491 
1492             // You get an error on this line if the matrix m contains a type that isn't
1493             // the same as the type contained in the target matrix.
1494             COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true) ||
1495                                 (is_matrix<typename EXP::type>::value == true));
1496             if (m.destructively_aliases(*this) == false)
1497             {
1498                 // This if statement is seemingly unnecessary since set_size() contains this
1499                 // exact same if statement.  However, structuring the code this way causes
1500                 // gcc to handle the way it inlines this function in a much more favorable way.
1501                 if (data.nr() == m.nr() && data.nc() == m.nc())
1502                 {
1503                     matrix_assign(*this, m);
1504                 }
1505                 else
1506                 {
1507                     set_size(m.nr(),m.nc());
1508                     matrix_assign(*this, m);
1509                 }
1510             }
1511             else
1512             {
1513                 // we have to use a temporary matrix object here because
1514                 // *this is aliased inside the matrix_exp m somewhere.
1515                 matrix temp;
1516                 temp.set_size(m.nr(),m.nc());
1517                 matrix_assign(temp, m);
1518                 temp.swap(*this);
1519             }
1520             return *this;
1521         }
1522 
1523         template <typename EXP>
1524         matrix& operator += (
1525             const matrix_exp<EXP>& m
1526         )
1527         {
1528             // The matrix you are trying to assign m to is a statically sized matrix and
1529             // m's dimensions don't match that of *this.
1530             COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
1531             COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
1532             COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));
1533             if (nr() == m.nr() && nc() == m.nc())
1534             {
1535                 if (m.destructively_aliases(*this) == false)
1536                 {
1537                     matrix_assign(*this, *this + m);
1538                 }
1539                 else
1540                 {
1541                     // we have to use a temporary matrix object here because
1542                     // this->data is aliased inside the matrix_exp m somewhere.
1543                     matrix temp;
1544                     temp.set_size(m.nr(),m.nc());
1545                     matrix_assign(temp, *this + m);
1546                     temp.swap(*this);
1547                 }
1548             }
1549             else
1550             {
1551                 DLIB_ASSERT(size() == 0,
1552                     "\t const matrix::operator+=(m)"
1553                     << "\n\t You are trying to add two matrices that have incompatible dimensions.");
1554                 *this = m;
1555             }
1556             return *this;
1557         }
1558 
1559 
1560         template <typename EXP>
1561         matrix& operator -= (
1562             const matrix_exp<EXP>& m
1563         )
1564         {
1565             // The matrix you are trying to assign m to is a statically sized matrix and
1566             // m's dimensions don't match that of *this.
1567             COMPILE_TIME_ASSERT(EXP::NR == NR || NR == 0 || EXP::NR == 0);
1568             COMPILE_TIME_ASSERT(EXP::NC == NC || NC == 0 || EXP::NC == 0);
1569             COMPILE_TIME_ASSERT((is_same_type<typename EXP::type,type>::value == true));
1570             if (nr() == m.nr() && nc() == m.nc())
1571             {
1572                 if (m.destructively_aliases(*this) == false)
1573                 {
1574                     matrix_assign(*this, *this - m);
1575                 }
1576                 else
1577                 {
1578                     // we have to use a temporary matrix object here because
1579                     // this->data is aliased inside the matrix_exp m somewhere.
1580                     matrix temp;
1581                     temp.set_size(m.nr(),m.nc());
1582                     matrix_assign(temp, *this - m);
1583                     temp.swap(*this);
1584                 }
1585             }
1586             else
1587             {
1588                 DLIB_ASSERT(size() == 0,
1589                     "\t const matrix::operator-=(m)"
1590                     << "\n\t You are trying to subtract two matrices that have incompatible dimensions.");
1591                 *this = -m;
1592             }
1593             return *this;
1594         }
1595 
1596         template <typename EXP>
1597         matrix& operator *= (
1598             const matrix_exp<EXP>& m
1599         )
1600         {
1601             *this = *this * m;
1602             return *this;
1603         }
1604 
1605         matrix& operator += (
1606             const matrix& m
1607         )
1608         {
1609             const long size = m.nr()*m.nc();
1610             if (nr() == m.nr() && nc() == m.nc())
1611             {
1612                 for (long i = 0; i < size; ++i)
1613                     data(i) += m.data(i);
1614             }
1615             else
1616             {
1617                 DLIB_ASSERT(this->size() == 0,
1618                     "\t const matrix::operator+=(m)"
1619                     << "\n\t You are trying to add two matrices that have incompatible dimensions.");
1620 
1621                 set_size(m.nr(), m.nc());
1622                 for (long i = 0; i < size; ++i)
1623                     data(i) = m.data(i);
1624             }
1625             return *this;
1626         }
1627 
1628         matrix& operator -= (
1629             const matrix& m
1630         )
1631         {
1632             const long size = m.nr()*m.nc();
1633             if (nr() == m.nr() && nc() == m.nc())
1634             {
1635                 for (long i = 0; i < size; ++i)
1636                     data(i) -= m.data(i);
1637             }
1638             else
1639             {
1640                 DLIB_ASSERT(this->size() == 0,
1641                     "\t const matrix::operator-=(m)"
1642                     << "\n\t You are trying to subtract two matrices that have incompatible dimensions.");
1643                 set_size(m.nr(), m.nc());
1644                 for (long i = 0; i < size; ++i)
1645                     data(i) = -m.data(i);
1646             }
1647             return *this;
1648         }
1649 
1650         matrix& operator += (
1651             const T val
1652         )
1653         {
1654             const size_t size = nr()*(size_t)nc();
1655             for (size_t i = 0; i < size; ++i)
1656                 data(i) += val;
1657 
1658             return *this;
1659         }
1660 
1661         matrix& operator -= (
1662             const T val
1663         )
1664         {
1665             const size_t size = nr()*(size_t)nc();
1666             for (size_t i = 0; i < size; ++i)
1667                 data(i) -= val;
1668 
1669             return *this;
1670         }
1671 
1672         matrix& operator *= (
1673             const T a
1674         )
1675         {
1676             *this = *this * a;
1677             return *this;
1678         }
1679 
1680         matrix& operator /= (
1681             const T a
1682         )
1683         {
1684             *this = *this / a;
1685             return *this;
1686         }
1687 
1688         matrix& operator= (
1689             const matrix& m
1690         )
1691         {
1692             if (this != &m)
1693             {
1694                 set_size(m.nr(),m.nc());
1695                 const long size = m.nr()*m.nc();
1696                 for (long i = 0; i < size; ++i)
1697                     data(i) = m.data(i);
1698             }
1699             return *this;
1700         }
1701 
1702         void swap (
1703             matrix& item
1704         )
1705         {
1706             data.swap(item.data);
1707         }
1708 
1709         template <typename U>
1710         bool aliases (
1711             const matrix_exp<U>&
1712         ) const { return false; }
1713 
1714         bool aliases (
1715             const matrix_exp<matrix<T,num_rows,num_cols, mem_manager,layout> >& item
1716         ) const { return (this == &item); }
1717 
1718         template <typename U>
1719         bool destructively_aliases (
1720             const matrix_exp<U>&
1721         ) const { return false; }
1722 
1723         // These two aliases() routines are defined in matrix_mat.h
1724         bool aliases (
1725             const matrix_exp<matrix_op<op_pointer_to_mat<T> > >& item
1726         ) const;
1727         bool aliases (
1728             const matrix_exp<matrix_op<op_pointer_to_col_vect<T> > >& item
1729         ) const;
1730 
1731         iterator begin()
1732         {
1733             if (size() != 0)
1734                 return &data(0,0);
1735             else
1736                 return 0;
1737         }
1738 
1739         iterator end()
1740         {
1741             if (size() != 0)
1742                 return &data(0,0)+size();
1743             else
1744                 return 0;
1745         }
1746 
1747         const_iterator begin()  const
1748         {
1749             if (size() != 0)
1750                 return &data(0,0);
1751             else
1752                 return 0;
1753         }
1754 
1755         const_iterator end() const
1756         {
1757             if (size() != 0)
1758                 return &data(0,0)+size();
1759             else
1760                 return 0;
1761         }
1762 
1763     private:
1764         struct literal_assign_helper
1765         {
1766             /*
1767                 This struct is a helper struct returned by the operator<<() function below.  It is
1768                 used primarily to enable us to put DLIB_CASSERT statements on the usage of the
1769                 operator<< form of matrix assignment.
1770             */
1771 
1772             literal_assign_helper(const literal_assign_helper& item) : m(item.m), r(item.r), c(item.c), has_been_used(false) {}
1773             explicit literal_assign_helper(matrix* m_): m(m_), r(0), c(0),has_been_used(false) {next();}
1774             ~literal_assign_helper() noexcept(false)
1775             {
1776                 DLIB_CASSERT(!has_been_used || r == (*m).nr(),
1777                              "You have used the matrix comma based assignment incorrectly by failing to\n"
1778                              "supply a full set of values for every element of a matrix object.\n");
1779             }
1780 
1781             const literal_assign_helper& operator, (
1782                 const T& val
1783             ) const
1784             {
1785                 DLIB_CASSERT(r < (*m).nr() && c < (*m).nc(),
1786                              "You have used the matrix comma based assignment incorrectly by attempting to\n" <<
1787                              "supply more values than there are elements in the matrix object being assigned to.\n\n" <<
1788                              "Did you forget to call set_size()?"
1789                              << "\n\t r: " << r
1790                              << "\n\t c: " << c
1791                              << "\n\t m->nr(): " << (*m).nr()
1792                              << "\n\t m->nc(): " << (*m).nc());
1793                 (*m)(r,c) = val;
1794                 next();
1795                 has_been_used = true;
1796                 return *this;
1797             }
1798 
1799         private:
1800 
1801             friend class matrix<T,num_rows,num_cols,mem_manager,layout>;
1802 
1803             void next (
1804             ) const
1805             {
1806                 ++c;
1807                 if (c == (*m).nc())
1808                 {
1809                     c = 0;
1810                     ++r;
1811                 }
1812             }
1813 
1814             matrix* m;
1815             mutable long r;
1816             mutable long c;
1817             mutable bool has_been_used;
1818         };
1819 
1820     public:
1821 
1822         matrix& operator = (
1823             const literal_assign_helper& val
1824         )
1825         {
1826             *this = *val.m;
1827             return *this;
1828         }
1829 
1830         const literal_assign_helper operator = (
1831             const T& val
1832         )
1833         {
1834             // assign the given value to every spot in this matrix
1835             const size_t size = nr()*(size_t)nc();
1836             for (size_t i = 0; i < size; ++i)
1837                 data(i) = val;
1838 
1839             // Now return the literal_assign_helper so that the user
1840             // can use the overloaded comma notation to initialize
1841             // the matrix if they want to.
1842             return literal_assign_helper(this);
1843         }
1844 
1845     private:
1846 
1847 
1848         typename layout::template layout<T,NR,NC,mem_manager> data;
1849     };
1850 
1851 // ----------------------------------------------------------------------------------------
1852 // ----------------------------------------------------------------------------------------
1853 // ----------------------------------------------------------------------------------------
1854 
1855     template <
1856         typename T,
1857         long NR,
1858         long NC,
1859         typename mm,
1860         typename l
1861         >
1862     void swap(
1863         matrix<T,NR,NC,mm,l>& a,
1864         matrix<T,NR,NC,mm,l>& b
1865     ) { a.swap(b); }
1866 
1867     template <
1868         typename T,
1869         long NR,
1870         long NC,
1871         typename mm,
1872         typename l
1873         >
1874     void serialize (
1875         const matrix<T,NR,NC,mm,l>& item,
1876         std::ostream& out
1877     )
1878     {
1879         try
1880         {
1881             // The reason the serialization is a little funny is because we are trying to
1882             // maintain backwards compatibility with an older serialization format used by
1883             // dlib while also encoding things in a way that lets the array2d and matrix
1884             // objects have compatible serialization formats.
1885             serialize(-item.nr(),out);
1886             serialize(-item.nc(),out);
1887             for (long r = 0; r < item.nr(); ++r)
1888             {
1889                 for (long c = 0; c < item.nc(); ++c)
1890                 {
1891                     serialize(item(r,c),out);
1892                 }
1893             }
1894         }
1895         catch (serialization_error& e)
1896         {
1897             throw serialization_error(e.info + "\n   while serializing dlib::matrix");
1898         }
1899     }
1900 
1901     template <
1902         typename T,
1903         long NR,
1904         long NC,
1905         typename mm,
1906         typename l
1907         >
1908     void deserialize (
1909         matrix<T,NR,NC,mm,l>& item,
1910         std::istream& in
1911     )
1912     {
1913         try
1914         {
1915             long nr, nc;
1916             deserialize(nr,in);
1917             deserialize(nc,in);
1918 
1919             // this is the newer serialization format
1920             if (nr < 0 || nc < 0)
1921             {
1922                 nr *= -1;
1923                 nc *= -1;
1924             }
1925 
1926             if (NR != 0 && nr != NR)
1927                 throw serialization_error("Error while deserializing a dlib::matrix.  Invalid rows");
1928             if (NC != 0 && nc != NC)
1929                 throw serialization_error("Error while deserializing a dlib::matrix.  Invalid columns");
1930 
1931             item.set_size(nr,nc);
1932             for (long r = 0; r < nr; ++r)
1933             {
1934                 for (long c = 0; c < nc; ++c)
1935                 {
1936                     deserialize(item(r,c),in);
1937                 }
1938             }
1939         }
1940         catch (serialization_error& e)
1941         {
1942             throw serialization_error(e.info + "\n   while deserializing a dlib::matrix");
1943         }
1944     }
1945 
1946 // ----------------------------------------------------------------------------------------
1947 
1948     template <
1949         typename T,
1950         long NR,
1951         long NC,
1952         typename mm,
1953         typename l
1954         >
1955     void serialize (
1956         const ramdump_t<matrix<T,NR,NC,mm,l>>& item_,
1957         std::ostream& out
1958     )
1959     {
1960         auto& item = item_.item;
1961         serialize(item.nr(), out);
1962         serialize(item.nc(), out);
1963         if (item.size() != 0)
1964             out.write((char*)&item(0,0), sizeof(item(0,0))*item.size());
1965     }
1966 
1967     template <
1968         typename T,
1969         long NR,
1970         long NC,
1971         typename mm,
1972         typename l
1973         >
1974     void deserialize (
1975         ramdump_t<matrix<T,NR,NC,mm,l>>&& item_,
1976         std::istream& in
1977     )
1978     {
1979         auto& item = item_.item;
1980         long nr, nc;
1981         deserialize(nr, in);
1982         deserialize(nc, in);
1983         item.set_size(nr,nc);
1984         if (item.size() != 0)
1985             in.read((char*)&item(0,0), sizeof(item(0,0))*item.size());
1986     }
1987 
1988 // ----------------------------------------------------------------------------------------
1989 
1990     template <
1991         typename EXP
1992         >
1993     std::ostream& operator<< (
1994         std::ostream& out,
1995         const matrix_exp<EXP>& m
1996     )
1997     {
1998         using namespace std;
1999         const streamsize old = out.width();
2000 
2001         // first figure out how wide we should make each field
2002         string::size_type w = 0;
2003         ostringstream sout;
2004         for (long r = 0; r < m.nr(); ++r)
2005         {
2006             for (long c = 0; c < m.nc(); ++c)
2007             {
2008                 sout << m(r,c);
2009                 w = std::max(sout.str().size(),w);
2010                 sout.str("");
2011             }
2012         }
2013 
2014         // now actually print it
2015         for (long r = 0; r < m.nr(); ++r)
2016         {
2017             for (long c = 0; c < m.nc(); ++c)
2018             {
2019                 out.width(static_cast<streamsize>(w));
2020                 out << m(r,c) << " ";
2021             }
2022             out << "\n";
2023         }
2024         out.width(old);
2025         return out;
2026     }
2027 
2028     /*
2029     template <
2030         typename T,
2031         long NR,
2032         long NC,
2033         typename MM,
2034         typename L
2035         >
2036     std::istream& operator>> (
2037         std::istream& in,
2038         matrix<T,NR,NC,MM,L>& m
2039     );
2040 
2041     This function is defined inside the matrix_read_from_istream.h file.
2042     */
2043 
2044 // ----------------------------------------------------------------------------------------
2045 
2046     class print_matrix_as_csv_helper
2047     {
2048         /*!
2049             This object is used to define an io manipulator for matrix expressions.
2050             In particular, this code allows you to write statements like:
2051                 cout << csv << yourmatrix;
2052             and have it print the matrix with commas separating each element.
2053         !*/
2054     public:
2055         print_matrix_as_csv_helper (std::ostream& out_) : out(out_) {}
2056 
2057         template <typename EXP>
2058         std::ostream& operator<< (
2059             const matrix_exp<EXP>& m
2060         )
2061         {
2062             for (long r = 0; r < m.nr(); ++r)
2063             {
2064                 for (long c = 0; c < m.nc(); ++c)
2065                 {
2066                     if (c+1 == m.nc())
2067                         out << m(r,c) << "\n";
2068                     else
2069                         out << m(r,c) << ", ";
2070                 }
2071             }
2072             return out;
2073         }
2074 
2075     private:
2076         std::ostream& out;
2077     };
2078 
2079     class print_matrix_as_csv {};
2080     const print_matrix_as_csv csv = print_matrix_as_csv();
2081     inline print_matrix_as_csv_helper operator<< (
2082         std::ostream& out,
2083         const print_matrix_as_csv&
2084     )
2085     {
2086         return print_matrix_as_csv_helper(out);
2087     }
2088 
2089 // ----------------------------------------------------------------------------------------
2090 // ----------------------------------------------------------------------------------------
2091 // ----------------------------------------------------------------------------------------
2092 
2093     template <typename EXP>
2094     class const_temp_matrix;
2095 
2096     template <
2097         typename EXP
2098         >
2099     struct matrix_traits<const_temp_matrix<EXP> >
2100     {
2101         typedef typename EXP::type type;
2102         typedef typename EXP::const_ret_type const_ret_type;
2103         typedef typename EXP::mem_manager_type mem_manager_type;
2104         typedef typename EXP::layout_type layout_type;
2105         const static long NR = EXP::NR;
2106         const static long NC = EXP::NC;
2107         const static long cost = 1;
2108     };
2109 
2110     template <typename EXP>
2111     class const_temp_matrix : public matrix_exp<const_temp_matrix<EXP> >, noncopyable
2112     {
2113     public:
2114         typedef typename matrix_traits<const_temp_matrix>::type type;
2115         typedef typename matrix_traits<const_temp_matrix>::const_ret_type const_ret_type;
2116         typedef typename matrix_traits<const_temp_matrix>::mem_manager_type mem_manager_type;
2117         typedef typename matrix_traits<const_temp_matrix>::layout_type layout_type;
2118         const static long NR = matrix_traits<const_temp_matrix>::NR;
2119         const static long NC = matrix_traits<const_temp_matrix>::NC;
2120         const static long cost = matrix_traits<const_temp_matrix>::cost;
2121 
2122         const_temp_matrix (
2123             const matrix_exp<EXP>& item
2124         ) :
2125             ref_(item.ref())
2126         {}
2127         const_temp_matrix (
2128             const EXP& item
2129         ) :
2130             ref_(item)
2131         {}
2132 
2133         const_ret_type operator() (
2134             long r,
2135             long c
2136         ) const { return ref_(r,c); }
2137 
2138         const_ret_type operator() ( long i ) const
2139         { return ref_(i); }
2140 
2141         template <typename U>
2142         bool aliases (
2143             const matrix_exp<U>& item
2144         ) const { return ref_.aliases(item); }
2145 
2146         template <typename U>
2147         bool destructively_aliases (
2148             const matrix_exp<U>& item
2149         ) const { return ref_.destructively_aliases(item); }
2150 
2151         long nr (
2152         ) const { return ref_.nr(); }
2153 
2154         long nc (
2155         ) const { return ref_.nc(); }
2156 
2157     private:
2158 
2159         typename conditional_matrix_temp<const EXP, (EXP::cost <= 1)>::type ref_;
2160     };
2161 
2162 // ----------------------------------------------------------------------------------------
2163 
2164     typedef matrix<double,0,0,default_memory_manager,column_major_layout> matrix_colmajor;
2165     typedef matrix<float,0,0,default_memory_manager,column_major_layout> fmatrix_colmajor;
2166 
2167 }
2168 
2169 #ifdef _MSC_VER
2170 // restore warnings back to their previous settings
2171 #pragma warning(pop)
2172 #endif
2173 
2174 #endif // DLIB_MATRIx_
2175 
2176