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