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_SUBEXP_
4 #define DLIB_MATRIx_SUBEXP_
5 
6 #include "matrix_subexp_abstract.h"
7 #include "matrix_op.h"
8 #include "matrix.h"
9 #include "../geometry/rectangle.h"
10 #include "matrix_expressions.h"
11 #include "matrix_mat.h"
12 
13 
14 
15 namespace dlib
16 {
17 
18 // ----------------------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------------------
20 // ----------------------------------------------------------------------------------------
21 
22     template <long start, long inc, long end>
range()23     const matrix_range_static_exp<start,inc,end> range (
24     )
25     {
26         COMPILE_TIME_ASSERT(inc > 0);
27         return matrix_range_static_exp<start,inc,end>();
28     }
29 
30     template <long start, long end>
range()31     const matrix_range_static_exp<start,1,end> range (
32     )
33     {
34         return matrix_range_static_exp<start,1,end>();
35     }
36 
range(long start,long end)37     inline const matrix_range_exp<long> range (
38         long start,
39         long end
40     )
41     {
42         return matrix_range_exp<long>(start,end);
43     }
44 
range(long start,long inc,long end)45     inline const matrix_range_exp<long> range (
46         long start,
47         long inc,
48         long end
49     )
50     {
51         DLIB_ASSERT(inc > 0,
52             "\tconst matrix_exp range(start, inc, end)"
53             << "\n\tInvalid inputs to this function"
54             << "\n\tstart: " << start
55             << "\n\tinc:   " << inc
56             << "\n\tend:   " << end
57             );
58 
59         return matrix_range_exp<long>(start,inc,end);
60     }
61 
62 // ----------------------------------------------------------------------------------------
63 
64     template <typename M>
65     struct op_subm
66     {
op_submop_subm67         op_subm (
68             const M& m_x,
69             const long& r_x,
70             const long& c_x,
71             const long& nr_x,
72             const long& nc_x
73         ) : m(m_x), r_(r_x), c_(c_x), nr_(nr_x), nc_(nc_x) { }
74 
75         const M& m;
76         const long r_;
77         const long c_;
78         const long nr_;
79         const long nc_;
80 
81         const static long cost = M::cost+1;
82         typedef typename M::type type;
83         typedef typename M::const_ret_type const_ret_type;
84         typedef typename M::mem_manager_type mem_manager_type;
85         typedef typename M::layout_type layout_type;
86         const static long NR = 0;
87         const static long NC = 0;
88 
applyop_subm89         const_ret_type apply ( long r, long c) const { return m(r+r_,c+c_); }
90 
nrop_subm91         long nr () const { return nr_; }
ncop_subm92         long nc () const { return nc_; }
93 
aliasesop_subm94         template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
destructively_aliasesop_subm95         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
96     };
97 
98     template <
99         typename EXP
100         >
subm(const matrix_exp<EXP> & m,long r,long c,long nr,long nc)101     const matrix_op<op_subm<EXP> > subm (
102         const matrix_exp<EXP>& m,
103         long r,
104         long c,
105         long nr,
106         long nc
107     )
108     {
109         DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(),
110             "\tconst matrix_exp subm(const matrix_exp& m, r, c, nr, nc)"
111             << "\n\tYou have specified invalid sub matrix dimensions"
112             << "\n\tm.nr(): " << m.nr()
113             << "\n\tm.nc(): " << m.nc()
114             << "\n\tr:      " << r
115             << "\n\tc:      " << c
116             << "\n\tnr:     " << nr
117             << "\n\tnc:     " << nc
118             );
119 
120         typedef op_subm<EXP> op;
121         return matrix_op<op>(op(m.ref(),r,c,nr,nc));
122     }
123 
124 // ----------------------------------------------------------------------------------------
125 
126     template <
127         typename EXP
128         >
subm_clipped(const matrix_exp<EXP> & m,long r,long c,long nr,long nc)129     const matrix_op<op_subm<EXP> > subm_clipped (
130         const matrix_exp<EXP>& m,
131         long r,
132         long c,
133         long nr,
134         long nc
135     )
136     {
137         rectangle box(c,r,c+nc-1,r+nr-1);
138         box = box.intersect(get_rect(m));
139         typedef op_subm<EXP> op;
140         return matrix_op<op>(op(m.ref(),box.top(),box.left(),box.height(),box.width()));
141     }
142 
143 // ----------------------------------------------------------------------------------------
144 
145     template <
146         typename EXP
147         >
subm(const matrix_exp<EXP> & m,const rectangle & rect)148     const matrix_op<op_subm<EXP> > subm (
149         const matrix_exp<EXP>& m,
150         const rectangle& rect
151     )
152     {
153         DLIB_ASSERT(get_rect(m).contains(rect) == true,
154             "\tconst matrix_exp subm(const matrix_exp& m, const rectangle& rect)"
155             << "\n\tYou have specified invalid sub matrix dimensions"
156             << "\n\tm.nr(): " << m.nr()
157             << "\n\tm.nc(): " << m.nc()
158             << "\n\trect.left():   " << rect.left()
159             << "\n\trect.top():    " << rect.top()
160             << "\n\trect.right():  " << rect.right()
161             << "\n\trect.bottom(): " << rect.bottom()
162             );
163 
164         typedef op_subm<EXP> op;
165         return matrix_op<op>(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width()));
166     }
167 
168 // ----------------------------------------------------------------------------------------
169 
170     template <
171         typename EXP
172         >
subm_clipped(const matrix_exp<EXP> & m,rectangle rect)173     const matrix_op<op_subm<EXP> > subm_clipped (
174         const matrix_exp<EXP>& m,
175         rectangle rect
176     )
177     {
178         rect = rect.intersect(get_rect(m));
179 
180         typedef op_subm<EXP> op;
181         return matrix_op<op>(op(m.ref(),rect.top(),rect.left(),rect.height(),rect.width()));
182     }
183 
184 // ----------------------------------------------------------------------------------------
185 
186     template <typename M1, typename M2, typename M3>
187     struct op_subm_range
188     {
op_subm_rangeop_subm_range189         op_subm_range( const M1& m1_, const M2& rows_, const M3& cols_) :
190             m1(m1_), rows(rows_), cols(cols_) {}
191         const M1& m1;
192         const M2& rows;
193         const M3& cols;
194 
195         const static long cost = M1::cost+M2::cost+M3::cost;
196         typedef typename M1::type type;
197         typedef typename M1::const_ret_type const_ret_type;
198         typedef typename M1::mem_manager_type mem_manager_type;
199         typedef typename M1::layout_type layout_type;
200         const static long NR = M2::NC*M2::NR;
201         const static long NC = M3::NC*M3::NR;
202 
applyop_subm_range203         const_ret_type apply ( long r, long c) const { return m1(rows(r),cols(c)); }
204 
nrop_subm_range205         long nr () const { return rows.size(); }
ncop_subm_range206         long nc () const { return cols.size(); }
207 
aliasesop_subm_range208         template <typename U> bool aliases               ( const matrix_exp<U>& item) const
209         { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }
destructively_aliasesop_subm_range210         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
211         { return m1.aliases(item) || rows.aliases(item) || cols.aliases(item); }
212     };
213 
214     template <
215         typename EXP,
216         typename EXPr,
217         typename EXPc
218         >
subm(const matrix_exp<EXP> & m,const matrix_exp<EXPr> & rows,const matrix_exp<EXPc> & cols)219     const matrix_op<op_subm_range<EXP,EXPr,EXPc> > subm (
220         const matrix_exp<EXP>& m,
221         const matrix_exp<EXPr>& rows,
222         const matrix_exp<EXPc>& cols
223     )
224     {
225         // the rows and cols matrices must contain integer elements
226         COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPr::type>::is_integer);
227         COMPILE_TIME_ASSERT(std::numeric_limits<typename EXPc::type>::is_integer);
228 
229         DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&
230                     (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1),
231             "\tconst matrix_exp subm(const matrix_exp& m, const matrix_exp& rows, const matrix_exp& cols)"
232             << "\n\tYou have given invalid arguments to this function"
233             << "\n\tm.nr():     " << m.nr()
234             << "\n\tm.nc():     " << m.nc()
235             << "\n\tmin(rows):  " << min(rows)
236             << "\n\tmax(rows):  " << max(rows)
237             << "\n\tmin(cols):  " << min(cols)
238             << "\n\tmax(cols):  " << max(cols)
239             << "\n\trows.nr():  " << rows.nr()
240             << "\n\trows.nc():  " << rows.nc()
241             << "\n\tcols.nr():  " << cols.nr()
242             << "\n\tcols.nc():  " << cols.nc()
243             );
244 
245         typedef op_subm_range<EXP,EXPr,EXPc> op;
246         return matrix_op<op>(op(m.ref(),rows.ref(),cols.ref()));
247     }
248 
249 // ----------------------------------------------------------------------------------------
250 
251     template <typename M>
252     struct op_rowm
253     {
op_rowmop_rowm254         op_rowm(const M& m_, const long& row_) : m(m_), row(row_) {}
255         const M& m;
256         const long row;
257 
258         const static long cost = M::cost;
259         const static long NR = 1;
260         const static long NC = M::NC;
261         typedef typename M::type type;
262         typedef typename M::const_ret_type const_ret_type;
263         typedef typename M::mem_manager_type mem_manager_type;
264         typedef typename M::layout_type layout_type;
applyop_rowm265         const_ret_type apply ( long, long c) const { return m(row,c); }
266 
nrop_rowm267         long nr () const { return 1; }
ncop_rowm268         long nc () const { return m.nc(); }
269 
aliasesop_rowm270         template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
destructively_aliasesop_rowm271         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
272     };
273 
274     template <
275         typename EXP
276         >
rowm(const matrix_exp<EXP> & m,long row)277     const matrix_op<op_rowm<EXP> > rowm (
278         const matrix_exp<EXP>& m,
279         long row
280     )
281     {
282         DLIB_ASSERT(row >= 0 && row < m.nr(),
283             "\tconst matrix_exp rowm(const matrix_exp& m, row)"
284             << "\n\tYou have specified invalid sub matrix dimensions"
285             << "\n\tm.nr(): " << m.nr()
286             << "\n\tm.nc(): " << m.nc()
287             << "\n\trow:    " << row
288             );
289 
290         typedef op_rowm<EXP> op;
291         return matrix_op<op>(op(m.ref(),row));
292     }
293 
294     template <typename EXP>
295     struct rowm_exp
296     {
297         typedef matrix_op<op_rowm<EXP> > type;
298     };
299 
300 // ----------------------------------------------------------------------------------------
301 
302     template <typename M>
303     struct op_rowm2
304     {
op_rowm2op_rowm2305         op_rowm2(const M& m_, const long& row_, const long& len) : m(m_), row(row_), length(len) {}
306         const M& m;
307         const long row;
308         const long length;
309 
310         const static long cost = M::cost;
311         const static long NR = 1;
312         const static long NC = 0;
313         typedef typename M::type type;
314         typedef typename M::const_ret_type const_ret_type;
315         typedef typename M::mem_manager_type mem_manager_type;
316         typedef typename M::layout_type layout_type;
applyop_rowm2317         const_ret_type apply ( long , long c) const { return m(row,c); }
318 
nrop_rowm2319         long nr () const { return 1; }
ncop_rowm2320         long nc () const { return length; }
321 
aliasesop_rowm2322         template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
destructively_aliasesop_rowm2323         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
324     };
325 
326     template <
327         typename EXP
328         >
rowm(const matrix_exp<EXP> & m,long row,long length)329     const matrix_op<op_rowm2<EXP> > rowm (
330         const matrix_exp<EXP>& m,
331         long row,
332         long length
333     )
334     {
335         DLIB_ASSERT(row >= 0 && row < m.nr() &&
336                     length >= 0 && length <= m.nc(),
337             "\tconst matrix_exp rowm(const matrix_exp& m, row, length)"
338             << "\n\tYou have specified invalid sub matrix dimensions"
339             << "\n\tm.nr(): " << m.nr()
340             << "\n\tm.nc(): " << m.nc()
341             << "\n\trow:    " << row
342             << "\n\tlength: " << length
343             );
344 
345         typedef op_rowm2<EXP> op;
346         return matrix_op<op>(op(m.ref(), row, length));
347     }
348 
349 // ----------------------------------------------------------------------------------------
350 
351     template <typename M1, typename M2>
352     struct op_rowm_range
353     {
op_rowm_rangeop_rowm_range354         op_rowm_range( const M1& m1_, const M2& rows_) : m1(m1_), rows(rows_) {}
355         const M1& m1;
356         const M2& rows;
357 
358         const static long cost = M1::cost+M2::cost;
359         typedef typename M1::type type;
360         typedef typename M1::const_ret_type const_ret_type;
361         typedef typename M1::mem_manager_type mem_manager_type;
362         typedef typename M1::layout_type layout_type;
363         const static long NR = M2::NC*M2::NR;
364         const static long NC = M1::NC;
365 
applyop_rowm_range366         const_ret_type apply ( long r, long c) const { return m1(rows(r),c); }
367 
nrop_rowm_range368         long nr () const { return rows.size(); }
ncop_rowm_range369         long nc () const { return m1.nc(); }
370 
aliasesop_rowm_range371         template <typename U> bool aliases               ( const matrix_exp<U>& item) const
372         { return m1.aliases(item) || rows.aliases(item); }
destructively_aliasesop_rowm_range373         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
374         { return m1.aliases(item) || rows.aliases(item); }
375     };
376 
377     template <
378         typename EXP1,
379         typename EXP2
380         >
rowm(const matrix_exp<EXP1> & m,const matrix_exp<EXP2> & rows)381     const matrix_op<op_rowm_range<EXP1,EXP2> > rowm (
382         const matrix_exp<EXP1>& m,
383         const matrix_exp<EXP2>& rows
384     )
385     {
386         // the rows matrix must contain integer elements
387         COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);
388 
389 #ifdef ENABLE_ASSERTS
390         if (rows.size() != 0) {
391             DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1),
392                 "\tconst matrix_exp rowm(const matrix_exp& m, const matrix_exp& rows)"
393                 << "\n\tYou have given invalid arguments to this function"
394                 << "\n\tm.nr():     " << m.nr()
395                 << "\n\tm.nc():     " << m.nc()
396                 << "\n\tmin(rows):  " << min(rows)
397                 << "\n\tmax(rows):  " << max(rows)
398                 << "\n\trows.nr():  " << rows.nr()
399                 << "\n\trows.nc():  " << rows.nc()
400             );
401         }
402 #endif // ENABLE_ASSERTS
403 
404         typedef op_rowm_range<EXP1,EXP2> op;
405         return matrix_op<op>(op(m.ref(),rows.ref()));
406     }
407 
408 // ----------------------------------------------------------------------------------------
409 
410     template <typename M>
411     struct op_colm
412     {
op_colmop_colm413         op_colm(const M& m_, const long& col_) : m(m_), col(col_) {}
414         const M& m;
415         const long col;
416 
417         const static long cost = M::cost;
418         const static long NR = M::NR;
419         const static long NC = 1;
420         typedef typename M::type type;
421         typedef typename M::const_ret_type const_ret_type;
422         typedef typename M::mem_manager_type mem_manager_type;
423         typedef typename M::layout_type layout_type;
applyop_colm424         const_ret_type apply ( long r, long) const { return m(r,col); }
425 
nrop_colm426         long nr () const { return m.nr(); }
ncop_colm427         long nc () const { return 1; }
428 
aliasesop_colm429         template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
destructively_aliasesop_colm430         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
431     };
432 
433     template <
434         typename EXP
435         >
colm(const matrix_exp<EXP> & m,long col)436     const matrix_op<op_colm<EXP> > colm (
437         const matrix_exp<EXP>& m,
438         long col
439     )
440     {
441         DLIB_ASSERT(col >= 0 && col < m.nc(),
442             "\tconst matrix_exp colm(const matrix_exp& m, row)"
443             << "\n\tYou have specified invalid sub matrix dimensions"
444             << "\n\tm.nr(): " << m.nr()
445             << "\n\tm.nc(): " << m.nc()
446             << "\n\tcol:    " << col
447             );
448 
449         typedef op_colm<EXP> op;
450         return matrix_op<op>(op(m.ref(),col));
451     }
452 
453     template <typename EXP>
454     struct colm_exp
455     {
456         typedef matrix_op<op_colm<EXP> > type;
457     };
458 
459 // ----------------------------------------------------------------------------------------
460 
461     template <typename M>
462     struct op_colm2
463     {
op_colm2op_colm2464         op_colm2(const M& m_, const long& col_, const long& len) : m(m_), col(col_), length(len) {}
465         const M& m;
466         const long col;
467         const long length;
468 
469         const static long cost = M::cost;
470         const static long NR = 0;
471         const static long NC = 1;
472         typedef typename M::type type;
473         typedef typename M::const_ret_type const_ret_type;
474         typedef typename M::mem_manager_type mem_manager_type;
475         typedef typename M::layout_type layout_type;
applyop_colm2476         const_ret_type apply ( long r, long ) const { return m(r,col); }
477 
nrop_colm2478         long nr () const { return length; }
ncop_colm2479         long nc () const { return 1; }
480 
aliasesop_colm2481         template <typename U> bool aliases               ( const matrix_exp<U>& item) const { return m.aliases(item); }
destructively_aliasesop_colm2482         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const { return m.aliases(item); }
483     };
484 
485     template <
486         typename EXP
487         >
colm(const matrix_exp<EXP> & m,long col,long length)488     const matrix_op<op_colm2<EXP> > colm (
489         const matrix_exp<EXP>& m,
490         long col,
491         long length
492     )
493     {
494         DLIB_ASSERT(col >= 0 && col < m.nc() &&
495                     length >= 0 && length <= m.nr(),
496             "\tconst matrix_exp colm(const matrix_exp& m, col, length)"
497             << "\n\tYou have specified invalid sub matrix dimensions"
498             << "\n\tm.nr(): " << m.nr()
499             << "\n\tm.nc(): " << m.nc()
500             << "\n\tcol:    " << col
501             << "\n\tlength: " << length
502             );
503 
504         typedef op_colm2<EXP> op;
505         return matrix_op<op>(op(m.ref(),col, length));
506     }
507 
508 // ----------------------------------------------------------------------------------------
509 
510     template <typename M1, typename M2>
511     struct op_colm_range
512     {
op_colm_rangeop_colm_range513         op_colm_range( const M1& m1_, const M2& cols_) : m1(m1_), cols(cols_) {}
514         const M1& m1;
515         const M2& cols;
516 
517         typedef typename M1::type type;
518         typedef typename M1::const_ret_type const_ret_type;
519         typedef typename M1::mem_manager_type mem_manager_type;
520         typedef typename M1::layout_type layout_type;
521         const static long NR = M1::NR;
522         const static long NC = M2::NC*M2::NR;
523         const static long cost = M1::cost+M2::cost;
524 
applyop_colm_range525         const_ret_type apply (long r, long c) const { return m1(r,cols(c)); }
526 
nrop_colm_range527         long nr () const { return m1.nr(); }
ncop_colm_range528         long nc () const { return cols.size(); }
529 
aliasesop_colm_range530         template <typename U> bool aliases               ( const matrix_exp<U>& item) const
531         { return m1.aliases(item) || cols.aliases(item); }
destructively_aliasesop_colm_range532         template <typename U> bool destructively_aliases ( const matrix_exp<U>& item) const
533         { return m1.aliases(item) || cols.aliases(item); }
534     };
535 
536     template <
537         typename EXP1,
538         typename EXP2
539         >
colm(const matrix_exp<EXP1> & m,const matrix_exp<EXP2> & cols)540     const matrix_op<op_colm_range<EXP1,EXP2> > colm (
541         const matrix_exp<EXP1>& m,
542         const matrix_exp<EXP2>& cols
543     )
544     {
545         // the rows matrix must contain integer elements
546         COMPILE_TIME_ASSERT(std::numeric_limits<typename EXP2::type>::is_integer);
547 
548 #ifdef ENABLE_ASSERTS
549         if (cols.size() != 0) {
550             DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1),
551                 "\tconst matrix_exp colm(const matrix_exp& m, const matrix_exp& cols)"
552                 << "\n\tYou have given invalid arguments to this function"
553                 << "\n\tm.nr():     " << m.nr()
554                 << "\n\tm.nc():     " << m.nc()
555                 << "\n\tmin(cols):  " << min(cols)
556                 << "\n\tmax(cols):  " << max(cols)
557                 << "\n\tcols.nr():  " << cols.nr()
558                 << "\n\tcols.nc():  " << cols.nc()
559             );
560         }
561 #endif // ENABLE_ASSERTS
562 
563         typedef op_colm_range<EXP1,EXP2> op;
564         return matrix_op<op>(op(m.ref(),cols.ref()));
565     }
566 
567 // ----------------------------------------------------------------------------------------
568 
569     template <typename T>
570     class assignable_ptr_matrix
571     {
572     public:
573         typedef T type;
574         typedef row_major_layout layout_type;
575         typedef matrix<T,0,0,default_memory_manager,layout_type> matrix_type;
576 
assignable_ptr_matrix(T * ptr_,long nr_,long nc_)577         assignable_ptr_matrix(
578             T* ptr_,
579             long nr_,
580             long nc_
581         ) : ptr(ptr_), height(nr_), width(nc_){}
582 
operator()583         T& operator() (
584             long r,
585             long c
586         )
587         {
588             return ptr[r*width + c];
589         }
590 
operator()591         const T& operator() (
592             long r,
593             long c
594         ) const
595         {
596             return ptr[r*width + c];
597         }
598 
nr()599         long nr() const { return height; }
nc()600         long nc() const { return width; }
601 
602         template <typename EXP>
603         assignable_ptr_matrix& operator= (
604             const matrix_exp<EXP>& exp
605         )
606         {
607             // You can only assign to a set_ptrm() expression with a source matrix that
608             // contains the same type of elements as the target (i.e. you can't mix double
609             // and float types).
610             COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));
611 
612             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
613                 "\tassignable_matrix_expression set_ptrm()"
614                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
615                 << "\n\texp.nr() (source matrix): " << exp.nr()
616                 << "\n\texp.nc() (source matrix): " << exp.nc()
617                 << "\n\twidth (target matrix):    " << width
618                 << "\n\theight (target matrix):   " << height
619                 );
620 
621             if (exp.destructively_aliases(mat(ptr,height,width)) == false)
622             {
623                 matrix_assign(*this, exp);
624             }
625             else
626             {
627                 // make a temporary copy of the matrix we are going to assign to ptr to
628                 // avoid aliasing issues during the copy
629                 this->operator=(tmp(exp));
630             }
631 
632             return *this;
633         }
634 
635         template <typename EXP>
636         assignable_ptr_matrix& operator+= (
637             const matrix_exp<EXP>& exp
638         )
639         {
640             // You can only assign to a set_ptrm() expression with a source matrix that
641             // contains the same type of elements as the target (i.e. you can't mix double
642             // and float types).
643             COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));
644 
645             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
646                 "\tassignable_matrix_expression set_ptrm()"
647                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
648                 << "\n\texp.nr() (source matrix): " << exp.nr()
649                 << "\n\texp.nc() (source matrix): " << exp.nc()
650                 << "\n\twidth (target matrix):    " << width
651                 << "\n\theight (target matrix):   " << height
652                 );
653 
654             if (exp.destructively_aliases(mat(ptr,height,width)) == false)
655             {
656                 matrix_assign(*this, mat(ptr,height,width)+exp);
657             }
658             else
659             {
660                 // make a temporary copy of the matrix we are going to assign to ptr to
661                 // avoid aliasing issues during the copy
662                 this->operator+=(tmp(exp));
663             }
664 
665             return *this;
666         }
667 
668         template <typename EXP>
669         assignable_ptr_matrix& operator-= (
670             const matrix_exp<EXP>& exp
671         )
672         {
673             // You can only assign to a set_ptrm() expression with a source matrix that
674             // contains the same type of elements as the target (i.e. you can't mix double
675             // and float types).
676             COMPILE_TIME_ASSERT((is_same_type<T, typename EXP::type>::value == true));
677 
678             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
679                 "\tassignable_matrix_expression set_ptrm()"
680                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
681                 << "\n\texp.nr() (source matrix): " << exp.nr()
682                 << "\n\texp.nc() (source matrix): " << exp.nc()
683                 << "\n\twidth (target matrix):    " << width
684                 << "\n\theight (target matrix):   " << height
685                 );
686 
687             if (exp.destructively_aliases(mat(ptr,height,width)) == false)
688             {
689                 matrix_assign(*this, mat(ptr,height,width)-exp);
690             }
691             else
692             {
693                 // make a temporary copy of the matrix we are going to assign to ptr to
694                 // avoid aliasing issues during the copy
695                 this->operator-=(tmp(exp));
696             }
697 
698             return *this;
699         }
700 
701         assignable_ptr_matrix& operator= (
702             const T& value
703         )
704         {
705             const long size = width*height;
706             for (long i = 0; i < size; ++i)
707                 ptr[i] = value;
708 
709             return *this;
710         }
711 
712         assignable_ptr_matrix& operator+= (
713             const T& value
714         )
715         {
716             const long size = width*height;
717             for (long i = 0; i < size; ++i)
718                 ptr[i] += value;
719 
720             return *this;
721         }
722 
723         assignable_ptr_matrix& operator-= (
724             const T& value
725         )
726         {
727             const long size = width*height;
728             for (long i = 0; i < size; ++i)
729                 ptr[i] -= value;
730 
731             return *this;
732         }
733 
734 
735         T* ptr;
736         const long height;
737         const long width;
738     };
739 
740 
741     template <typename T>
742     assignable_ptr_matrix<T> set_ptrm (
743         T* ptr,
744         long nr,
745         long nc = 1
746     )
747     {
748         DLIB_ASSERT(nr >= 0 && nc >= 0,
749             "\t assignable_matrix_expression set_ptrm(T* ptr, long nr, long nc)"
750             << "\n\t The dimensions can't be negative."
751             << "\n\t nr: " << nr
752             << "\n\t nc: " << nc
753             );
754 
755 
756         return assignable_ptr_matrix<T>(ptr,nr,nc);
757     }
758 
759 // ----------------------------------------------------------------------------------------
760 
761     template <typename T, long NR, long NC, typename mm, typename l>
762     class assignable_sub_matrix
763     {
764     public:
765         typedef T type;
766         typedef l layout_type;
767         typedef matrix<T,NR,NC,mm,l> matrix_type;
768 
assignable_sub_matrix(matrix<T,NR,NC,mm,l> & m_,long top_,long left_,long height_,long width_)769         assignable_sub_matrix(
770             matrix<T,NR,NC,mm,l>& m_,
771             long top_,
772             long left_,
773             long height_,
774             long width_
775         ) : m(m_), left(left_), top(top_), width(width_), height(height_) {}
776 
operator()777         T& operator() (
778             long r,
779             long c
780         )
781         {
782             return m(r+top,c+left);
783         }
784 
operator()785         const T& operator() (
786             long r,
787             long c
788         ) const
789         {
790             return m(r+top,c+left);
791         }
792 
nr()793         long nr() const { return height; }
nc()794         long nc() const { return width; }
795 
796         template <typename EXP>
797         assignable_sub_matrix& operator= (
798             const matrix_exp<EXP>& exp
799         )
800         {
801             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
802                 "\tassignable_matrix_expression set_subm()"
803                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
804                 << "\n\texp.nr() (source matrix): " << exp.nr()
805                 << "\n\texp.nc() (source matrix): " << exp.nc()
806                 << "\n\twidth (target matrix):    " << width
807                 << "\n\theight (target matrix):   " << height
808                 );
809 
810             if (exp.destructively_aliases(m) == false)
811             {
812                 matrix_assign(*this, exp);
813             }
814             else
815             {
816                 // make a temporary copy of the matrix we are going to assign to m to
817                 // avoid aliasing issues during the copy
818                 this->operator=(tmp(exp));
819             }
820 
821             return *this;
822         }
823 
824         template <typename EXP>
825         assignable_sub_matrix& operator+= (
826             const matrix_exp<EXP>& exp
827         )
828         {
829             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
830                 "\tassignable_matrix_expression set_subm()"
831                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
832                 << "\n\texp.nr() (source matrix): " << exp.nr()
833                 << "\n\texp.nc() (source matrix): " << exp.nc()
834                 << "\n\twidth (target matrix):    " << width
835                 << "\n\theight (target matrix):   " << height
836                 );
837 
838             if (exp.destructively_aliases(m) == false)
839             {
840                 matrix_assign(*this, subm(m,top,left,height,width)+exp);
841             }
842             else
843             {
844                 // make a temporary copy of the matrix we are going to assign to m to
845                 // avoid aliasing issues during the copy
846                 this->operator+=(tmp(exp));
847             }
848 
849             return *this;
850         }
851 
852         template <typename EXP>
853         assignable_sub_matrix& operator-= (
854             const matrix_exp<EXP>& exp
855         )
856         {
857             DLIB_ASSERT( exp.nr() == height && exp.nc() == width,
858                 "\tassignable_matrix_expression set_subm()"
859                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
860                 << "\n\texp.nr() (source matrix): " << exp.nr()
861                 << "\n\texp.nc() (source matrix): " << exp.nc()
862                 << "\n\twidth (target matrix):    " << width
863                 << "\n\theight (target matrix):   " << height
864                 );
865 
866             if (exp.destructively_aliases(m) == false)
867             {
868                 matrix_assign(*this, subm(m,top,left,height,width)-exp);
869             }
870             else
871             {
872                 // make a temporary copy of the matrix we are going to assign to m to
873                 // avoid aliasing issues during the copy
874                 this->operator-=(tmp(exp));
875             }
876 
877             return *this;
878         }
879 
880         assignable_sub_matrix& operator= (
881             const T& value
882         )
883         {
884             const long bottom = top+height-1;
885             const long right = left+width-1;
886             for (long r = top; r <= bottom; ++r)
887             {
888                 for (long c = left; c <= right; ++c)
889                 {
890                     m(r,c) = value;
891                 }
892             }
893 
894             return *this;
895         }
896 
897         assignable_sub_matrix& operator+= (
898             const T& value
899         )
900         {
901             const long bottom = top+height-1;
902             const long right = left+width-1;
903             for (long r = top; r <= bottom; ++r)
904             {
905                 for (long c = left; c <= right; ++c)
906                 {
907                     m(r,c) += value;
908                 }
909             }
910 
911             return *this;
912         }
913 
914         assignable_sub_matrix& operator-= (
915             const T& value
916         )
917         {
918             const long bottom = top+height-1;
919             const long right = left+width-1;
920             for (long r = top; r <= bottom; ++r)
921             {
922                 for (long c = left; c <= right; ++c)
923                 {
924                     m(r,c) -= value;
925                 }
926             }
927 
928             return *this;
929         }
930 
931 
932         matrix<T,NR,NC,mm,l>& m;
933         const long left, top, width, height;
934     };
935 
936 
937     template <typename T, long NR, long NC, typename mm, typename l>
set_subm(matrix<T,NR,NC,mm,l> & m,const rectangle & rect)938     assignable_sub_matrix<T,NR,NC,mm,l> set_subm (
939         matrix<T,NR,NC,mm,l>& m,
940         const rectangle& rect
941     )
942     {
943         DLIB_ASSERT(get_rect(m).contains(rect) == true,
944             "\tassignable_matrix_expression set_subm(matrix& m, const rectangle& rect)"
945             << "\n\tYou have specified invalid sub matrix dimensions"
946             << "\n\tm.nr(): " << m.nr()
947             << "\n\tm.nc(): " << m.nc()
948             << "\n\trect.left():   " << rect.left()
949             << "\n\trect.top():    " << rect.top()
950             << "\n\trect.right():  " << rect.right()
951             << "\n\trect.bottom(): " << rect.bottom()
952             );
953 
954 
955         return assignable_sub_matrix<T,NR,NC,mm,l>(m,rect.top(), rect.left(), rect.height(), rect.width());
956     }
957 
958 
959     template <typename T, long NR, long NC, typename mm, typename l>
set_subm(matrix<T,NR,NC,mm,l> & m,long r,long c,long nr,long nc)960     assignable_sub_matrix<T,NR,NC,mm,l> set_subm (
961         matrix<T,NR,NC,mm,l>& m,
962         long r,
963         long c,
964         long nr,
965         long nc
966     )
967     {
968         DLIB_ASSERT(r >= 0 && c >= 0 && nr >= 0 && nc >= 0 && r+nr <= m.nr() && c+nc <= m.nc(),
969                     "\tassignable_matrix_expression set_subm(matrix& m, r, c, nr, nc)"
970                     << "\n\tYou have specified invalid sub matrix dimensions"
971                     << "\n\tm.nr(): " << m.nr()
972                     << "\n\tm.nc(): " << m.nc()
973                     << "\n\tr:      " << r
974                     << "\n\tc:      " << c
975                     << "\n\tnr:     " << nr
976                     << "\n\tnc:     " << nc
977         );
978 
979         return assignable_sub_matrix<T,NR,NC,mm,l>(m,r,c, nr, nc);
980     }
981 
982 // ----------------------------------------------------------------------------------------
983 
984     template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>
985     class assignable_sub_range_matrix
986     {
987     public:
988         typedef T type;
989         typedef l layout_type;
990         typedef matrix<T,NR,NC,mm,l> matrix_type;
991 
assignable_sub_range_matrix(matrix<T,NR,NC,mm,l> & m_,const EXPr & rows_,const EXPc & cols_)992         assignable_sub_range_matrix(
993             matrix<T,NR,NC,mm,l>& m_,
994             const EXPr& rows_,
995             const EXPc& cols_
996         ) : m(m_), rows(rows_), cols(cols_) {}
997 
operator()998         T& operator() (
999             long r,
1000             long c
1001         )
1002         {
1003             return m(rows(r),cols(c));
1004         }
1005 
nr()1006         long nr() const { return rows.size(); }
nc()1007         long nc() const { return cols.size(); }
1008 
1009 
1010         template <typename EXP>
1011         assignable_sub_range_matrix& operator= (
1012             const matrix_exp<EXP>& exp
1013         )
1014         {
1015             DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
1016                 "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
1017                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1018                 << "\n\texp.nr() (source matrix): " << exp.nr()
1019                 << "\n\texp.nc() (source matrix): " << exp.nc()
1020                 << "\n\trows.size() (target matrix):  " << rows.size()
1021                 << "\n\tcols.size() (target matrix):  " << cols.size()
1022                 );
1023 
1024             if (exp.destructively_aliases(m) == false)
1025             {
1026                 matrix_assign(*this, exp);
1027             }
1028             else
1029             {
1030                 // make a temporary copy of the matrix we are going to assign to m to
1031                 // avoid aliasing issues during the copy
1032                 this->operator=(tmp(exp));
1033             }
1034 
1035             return *this;
1036         }
1037 
1038         template <typename EXP>
1039         assignable_sub_range_matrix& operator+= (
1040             const matrix_exp<EXP>& exp
1041         )
1042         {
1043             DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
1044                 "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
1045                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1046                 << "\n\texp.nr() (source matrix): " << exp.nr()
1047                 << "\n\texp.nc() (source matrix): " << exp.nc()
1048                 << "\n\trows.size() (target matrix):  " << rows.size()
1049                 << "\n\tcols.size() (target matrix):  " << cols.size()
1050                 );
1051 
1052             if (exp.destructively_aliases(m) == false)
1053             {
1054                 matrix_assign(*this, subm(m,rows,cols)+exp);
1055             }
1056             else
1057             {
1058                 // make a temporary copy of the matrix we are going to assign to m to
1059                 // avoid aliasing issues during the copy
1060                 this->operator+=(tmp(exp));
1061             }
1062 
1063             return *this;
1064         }
1065 
1066         template <typename EXP>
1067         assignable_sub_range_matrix& operator-= (
1068             const matrix_exp<EXP>& exp
1069         )
1070         {
1071             DLIB_ASSERT( exp.nr() == rows.size() && exp.nc() == cols.size(),
1072                 "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp rows, const matrix_exp cols)"
1073                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1074                 << "\n\texp.nr() (source matrix): " << exp.nr()
1075                 << "\n\texp.nc() (source matrix): " << exp.nc()
1076                 << "\n\trows.size() (target matrix):  " << rows.size()
1077                 << "\n\tcols.size() (target matrix):  " << cols.size()
1078                 );
1079 
1080             if (exp.destructively_aliases(m) == false)
1081             {
1082                 matrix_assign(*this, subm(m,rows,cols)-exp);
1083             }
1084             else
1085             {
1086                 // make a temporary copy of the matrix we are going to assign to m to
1087                 // avoid aliasing issues during the copy
1088                 this->operator-=(tmp(exp));
1089             }
1090 
1091             return *this;
1092         }
1093 
1094         assignable_sub_range_matrix& operator= (
1095             const T& value
1096         )
1097         {
1098             for (long r = 0; r < rows.size(); ++r)
1099             {
1100                 for (long c = 0; c < cols.size(); ++c)
1101                 {
1102                     m(rows(r),cols(c)) = value;
1103                 }
1104             }
1105 
1106             return *this;
1107         }
1108 
1109         assignable_sub_range_matrix& operator+= (
1110             const T& value
1111         )
1112         {
1113             for (long r = 0; r < rows.size(); ++r)
1114             {
1115                 for (long c = 0; c < cols.size(); ++c)
1116                 {
1117                     m(rows(r),cols(c)) += value;
1118                 }
1119             }
1120 
1121             return *this;
1122         }
1123 
1124         assignable_sub_range_matrix& operator-= (
1125             const T& value
1126         )
1127         {
1128             for (long r = 0; r < rows.size(); ++r)
1129             {
1130                 for (long c = 0; c < cols.size(); ++c)
1131                 {
1132                     m(rows(r),cols(c)) -= value;
1133                 }
1134             }
1135 
1136             return *this;
1137         }
1138 
1139     private:
1140 
1141         matrix<T,NR,NC,mm,l>& m;
1142         const EXPr rows;
1143         const EXPc cols;
1144     };
1145 
1146     template <typename T, long NR, long NC, typename mm, typename l, typename EXPr, typename EXPc>
set_subm(matrix<T,NR,NC,mm,l> & m,const matrix_exp<EXPr> & rows,const matrix_exp<EXPc> & cols)1147     assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc > set_subm (
1148         matrix<T,NR,NC,mm,l>& m,
1149         const matrix_exp<EXPr>& rows,
1150         const matrix_exp<EXPc>& cols
1151     )
1152     {
1153         DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && 0 <= min(cols) && max(cols) < m.nc() &&
1154                     (rows.nr() == 1 || rows.nc() == 1) && (cols.nr() == 1 || cols.nc() == 1),
1155             "\tassignable_matrix_expression set_subm(matrix& m, const matrix_exp& rows, const matrix_exp& cols)"
1156             << "\n\tYou have specified invalid sub matrix dimensions"
1157             << "\n\tm.nr():     " << m.nr()
1158             << "\n\tm.nc():     " << m.nc()
1159             << "\n\tmin(rows):  " << min(rows)
1160             << "\n\tmax(rows):  " << max(rows)
1161             << "\n\tmin(cols):  " << min(cols)
1162             << "\n\tmax(cols):  " << max(cols)
1163             << "\n\trows.nr():  " << rows.nr()
1164             << "\n\trows.nc():  " << rows.nc()
1165             << "\n\tcols.nr():  " << cols.nr()
1166             << "\n\tcols.nc():  " << cols.nc()
1167             );
1168 
1169         return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,EXPc >(m,rows.ref(),cols.ref());
1170     }
1171 
1172 // ----------------------------------------------------------------------------------------
1173 
1174     template <typename T, long NR, long NC, typename mm, typename l, typename EXPr>
set_rowm(matrix<T,NR,NC,mm,l> & m,const matrix_exp<EXPr> & rows)1175     assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> > set_rowm (
1176         matrix<T,NR,NC,mm,l>& m,
1177         const matrix_exp<EXPr>& rows
1178     )
1179     {
1180         DLIB_ASSERT(0 <= min(rows) && max(rows) < m.nr() && (rows.nr() == 1 || rows.nc() == 1),
1181             "\tassignable_matrix_expression set_rowm(matrix& m, const matrix_exp& rows)"
1182             << "\n\tYou have specified invalid sub matrix dimensions"
1183             << "\n\tm.nr():     " << m.nr()
1184             << "\n\tm.nc():     " << m.nc()
1185             << "\n\tmin(rows):  " << min(rows)
1186             << "\n\tmax(rows):  " << max(rows)
1187             << "\n\trows.nr():  " << rows.nr()
1188             << "\n\trows.nc():  " << rows.nc()
1189             );
1190 
1191         return assignable_sub_range_matrix<T,NR,NC,mm,l,EXPr,matrix_range_exp<long> >(m,rows.ref(),range(0,m.nc()-1));
1192     }
1193 
1194 // ----------------------------------------------------------------------------------------
1195 
1196     template <typename T, long NR, long NC, typename mm, typename l, typename EXPc>
set_colm(matrix<T,NR,NC,mm,l> & m,const matrix_exp<EXPc> & cols)1197     assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc > set_colm (
1198         matrix<T,NR,NC,mm,l>& m,
1199         const matrix_exp<EXPc>& cols
1200     )
1201     {
1202         DLIB_ASSERT(0 <= min(cols) && max(cols) < m.nc() && (cols.nr() == 1 || cols.nc() == 1),
1203             "\tassignable_matrix_expression set_colm(matrix& m, const matrix_exp& cols)"
1204             << "\n\tYou have specified invalid sub matrix dimensions"
1205             << "\n\tm.nr():     " << m.nr()
1206             << "\n\tm.nc():     " << m.nc()
1207             << "\n\tmin(cols):  " << min(cols)
1208             << "\n\tmax(cols):  " << max(cols)
1209             << "\n\tcols.nr():  " << cols.nr()
1210             << "\n\tcols.nc():  " << cols.nc()
1211             );
1212 
1213         return assignable_sub_range_matrix<T,NR,NC,mm,l,matrix_range_exp<long>,EXPc >(m,range(0,m.nr()-1),cols.ref());
1214     }
1215 
1216 // ----------------------------------------------------------------------------------------
1217 
1218     template <typename T, long NR, long NC, typename mm, typename l>
1219     class assignable_col_matrix
1220     {
1221     public:
1222         typedef T type;
1223         typedef l layout_type;
1224         typedef matrix<T,NR,NC,mm,l> matrix_type;
1225 
assignable_col_matrix(matrix<T,NR,NC,mm,l> & m_,const long col_)1226         assignable_col_matrix(
1227             matrix<T,NR,NC,mm,l>& m_,
1228             const long col_
1229         ) : m(m_), col(col_) {}
1230 
operator()1231         T& operator() (
1232             long r,
1233             long
1234         )
1235         {
1236             return m(r,col);
1237         }
1238 
operator()1239         const T& operator() (
1240             long r,
1241             long
1242         ) const
1243         {
1244             return m(r,col);
1245         }
1246 
nr()1247         long nr() const { return m.nr(); }
nc()1248         long nc() const { return 1; }
1249 
1250         template <typename EXP>
1251         assignable_col_matrix& operator= (
1252             const matrix_exp<EXP>& exp
1253         )
1254         {
1255             DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
1256                 "\tassignable_matrix_expression set_colm()"
1257                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1258                 << "\n\texp.nr() (source matrix): " << exp.nr()
1259                 << "\n\texp.nc() (source matrix): " << exp.nc()
1260                 << "\n\tm.nr() (target matrix):   " << m.nr()
1261                 );
1262 
1263             if (exp.destructively_aliases(m) == false)
1264             {
1265                 matrix_assign(*this, exp);
1266             }
1267             else
1268             {
1269                 // make a temporary copy of the matrix we are going to assign to m to
1270                 // avoid aliasing issues during the copy
1271                 this->operator=(tmp(exp));
1272             }
1273 
1274             return *this;
1275         }
1276 
1277         template <typename EXP>
1278         assignable_col_matrix& operator+= (
1279             const matrix_exp<EXP>& exp
1280         )
1281         {
1282             DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
1283                 "\tassignable_matrix_expression set_colm()"
1284                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1285                 << "\n\texp.nr() (source matrix): " << exp.nr()
1286                 << "\n\texp.nc() (source matrix): " << exp.nc()
1287                 << "\n\tm.nr() (target matrix):   " << m.nr()
1288                 );
1289 
1290             if (exp.destructively_aliases(m) == false)
1291             {
1292                 matrix_assign(*this, colm(m,col)+exp);
1293             }
1294             else
1295             {
1296                 // make a temporary copy of the matrix we are going to assign to m to
1297                 // avoid aliasing issues during the copy
1298                 this->operator+=(tmp(exp));
1299             }
1300 
1301             return *this;
1302         }
1303 
1304         template <typename EXP>
1305         assignable_col_matrix& operator-= (
1306             const matrix_exp<EXP>& exp
1307         )
1308         {
1309             DLIB_ASSERT( exp.nc() == 1 && exp.nr() == m.nr(),
1310                 "\tassignable_matrix_expression set_colm()"
1311                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1312                 << "\n\texp.nr() (source matrix): " << exp.nr()
1313                 << "\n\texp.nc() (source matrix): " << exp.nc()
1314                 << "\n\tm.nr() (target matrix):   " << m.nr()
1315                 );
1316 
1317             if (exp.destructively_aliases(m) == false)
1318             {
1319                 matrix_assign(*this, colm(m,col)-exp);
1320             }
1321             else
1322             {
1323                 // make a temporary copy of the matrix we are going to assign to m to
1324                 // avoid aliasing issues during the copy
1325                 this->operator-=(tmp(exp));
1326             }
1327 
1328             return *this;
1329         }
1330 
1331         assignable_col_matrix& operator= (
1332             const T& value
1333         )
1334         {
1335             for (long i = 0; i < m.nr(); ++i)
1336             {
1337                 m(i,col) = value;
1338             }
1339 
1340             return *this;
1341         }
1342 
1343         assignable_col_matrix& operator+= (
1344             const T& value
1345         )
1346         {
1347             for (long i = 0; i < m.nr(); ++i)
1348             {
1349                 m(i,col) += value;
1350             }
1351 
1352             return *this;
1353         }
1354 
1355         assignable_col_matrix& operator-= (
1356             const T& value
1357         )
1358         {
1359             for (long i = 0; i < m.nr(); ++i)
1360             {
1361                 m(i,col) -= value;
1362             }
1363 
1364             return *this;
1365         }
1366 
1367 
1368         matrix<T,NR,NC,mm,l>& m;
1369         const long col;
1370     };
1371 
1372 
1373     template <typename T, long NR, long NC, typename mm, typename l>
set_colm(matrix<T,NR,NC,mm,l> & m,const long col)1374     assignable_col_matrix<T,NR,NC,mm,l> set_colm (
1375         matrix<T,NR,NC,mm,l>& m,
1376         const long col
1377     )
1378     {
1379         DLIB_ASSERT(col >= 0 && col < m.nc(),
1380             "\tassignable_matrix_expression set_colm(matrix& m, col)"
1381             << "\n\tYou have specified invalid sub matrix dimensions"
1382             << "\n\tm.nr(): " << m.nr()
1383             << "\n\tm.nc(): " << m.nc()
1384             << "\n\tcol:    " << col
1385             );
1386 
1387 
1388         return assignable_col_matrix<T,NR,NC,mm,l>(m,col);
1389     }
1390 
1391 // ----------------------------------------------------------------------------------------
1392 
1393 
1394     template <typename T, long NR, long NC, typename mm, typename l>
1395     class assignable_row_matrix
1396     {
1397     public:
1398         typedef T type;
1399         typedef l layout_type;
1400         typedef matrix<T,NR,NC,mm,l> matrix_type;
1401 
assignable_row_matrix(matrix<T,NR,NC,mm,l> & m_,const long row_)1402         assignable_row_matrix(
1403             matrix<T,NR,NC,mm,l>& m_,
1404             const long row_
1405         ) : m(m_), row(row_) {}
1406 
1407 
operator()1408         T& operator() (
1409             long ,
1410             long c
1411         )
1412         {
1413             return m(row,c);
1414         }
1415 
operator()1416         const T& operator() (
1417             long ,
1418             long c
1419         ) const
1420         {
1421             return m(row,c);
1422         }
1423 
nr()1424         long nr() const { return 1; }
nc()1425         long nc() const { return m.nc(); }
1426 
1427 
1428         template <typename EXP>
1429         assignable_row_matrix& operator= (
1430             const matrix_exp<EXP>& exp
1431         )
1432         {
1433             DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
1434                 "\tassignable_matrix_expression set_rowm()"
1435                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1436                 << "\n\texp.nr() (source matrix): " << exp.nr()
1437                 << "\n\texp.nc() (source matrix): " << exp.nc()
1438                 << "\n\tm.nc() (target matrix):   " << m.nc()
1439                 );
1440 
1441             if (exp.destructively_aliases(m) == false)
1442             {
1443                 matrix_assign(*this, exp);
1444             }
1445             else
1446             {
1447                 // make a temporary copy of the matrix we are going to assign to m to
1448                 // avoid aliasing issues during the copy
1449                 this->operator=(tmp(exp));
1450             }
1451 
1452             return *this;
1453         }
1454 
1455         template <typename EXP>
1456         assignable_row_matrix& operator+= (
1457             const matrix_exp<EXP>& exp
1458         )
1459         {
1460             DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
1461                 "\tassignable_matrix_expression set_rowm()"
1462                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1463                 << "\n\texp.nr() (source matrix): " << exp.nr()
1464                 << "\n\texp.nc() (source matrix): " << exp.nc()
1465                 << "\n\tm.nc() (target matrix):   " << m.nc()
1466                 );
1467 
1468             if (exp.destructively_aliases(m) == false)
1469             {
1470                 matrix_assign(*this, rowm(m,row)+exp);
1471             }
1472             else
1473             {
1474                 // make a temporary copy of the matrix we are going to assign to m to
1475                 // avoid aliasing issues during the copy
1476                 this->operator+=(tmp(exp));
1477             }
1478 
1479             return *this;
1480         }
1481 
1482         template <typename EXP>
1483         assignable_row_matrix& operator-= (
1484             const matrix_exp<EXP>& exp
1485         )
1486         {
1487             DLIB_ASSERT( exp.nr() == 1 && exp.nc() == m.nc(),
1488                 "\tassignable_matrix_expression set_rowm()"
1489                 << "\n\tYou have tried to assign to this object using a matrix that isn't the right size"
1490                 << "\n\texp.nr() (source matrix): " << exp.nr()
1491                 << "\n\texp.nc() (source matrix): " << exp.nc()
1492                 << "\n\tm.nc() (target matrix):   " << m.nc()
1493                 );
1494 
1495             if (exp.destructively_aliases(m) == false)
1496             {
1497                 matrix_assign(*this, rowm(m,row)-exp);
1498             }
1499             else
1500             {
1501                 // make a temporary copy of the matrix we are going to assign to m to
1502                 // avoid aliasing issues during the copy
1503                 this->operator-=(tmp(exp));
1504             }
1505 
1506             return *this;
1507         }
1508 
1509         assignable_row_matrix& operator= (
1510             const T& value
1511         )
1512         {
1513             for (long i = 0; i < m.nc(); ++i)
1514             {
1515                 m(row,i) = value;
1516             }
1517 
1518             return *this;
1519         }
1520 
1521         assignable_row_matrix& operator+= (
1522             const T& value
1523         )
1524         {
1525             for (long i = 0; i < m.nc(); ++i)
1526             {
1527                 m(row,i) += value;
1528             }
1529 
1530             return *this;
1531         }
1532 
1533         assignable_row_matrix& operator-= (
1534             const T& value
1535         )
1536         {
1537             for (long i = 0; i < m.nc(); ++i)
1538             {
1539                 m(row,i) -= value;
1540             }
1541 
1542             return *this;
1543         }
1544 
1545 
1546         matrix<T,NR,NC,mm,l>& m;
1547         const long row;
1548     };
1549 
1550 
1551     template <typename T, long NR, long NC, typename mm, typename l>
set_rowm(matrix<T,NR,NC,mm,l> & m,const long row)1552     assignable_row_matrix<T,NR,NC,mm,l> set_rowm (
1553         matrix<T,NR,NC,mm,l>& m,
1554         const long row
1555     )
1556     {
1557         DLIB_ASSERT(row >= 0 && row < m.nr(),
1558             "\tassignable_matrix_expression set_rowm(matrix& m, row)"
1559             << "\n\tYou have specified invalid sub matrix dimensions"
1560             << "\n\tm.nr(): " << m.nr()
1561             << "\n\tm.nc(): " << m.nc()
1562             << "\n\trow:    " << row
1563             );
1564 
1565 
1566         return assignable_row_matrix<T,NR,NC,mm,l>(m,row);
1567     }
1568 
1569 // ----------------------------------------------------------------------------------------
1570 
1571 }
1572 
1573 #endif // DLIB_MATRIx_SUBEXP_
1574 
1575