File indexing completed on 2025-01-19 03:55:05

0001 /*****************************************************************************/
0002 // Copyright 2006-2019 Adobe Systems Incorporated
0003 // All Rights Reserved.
0004 //
0005 // NOTICE:  Adobe permits you to use, modify, and distribute this file in
0006 // accordance with the terms of the Adobe license agreement accompanying it.
0007 /*****************************************************************************/
0008 
0009 #include "dng_matrix.h"
0010 
0011 #include "dng_assertions.h"
0012 #include "dng_exceptions.h"
0013 #include "dng_utils.h"
0014 
0015 /*****************************************************************************/
0016 
0017 dng_matrix::dng_matrix ()
0018 
0019     :   fRows (0)
0020     ,   fCols (0)
0021 
0022     {
0023 
0024     }
0025 
0026 /*****************************************************************************/
0027 
0028 dng_matrix::dng_matrix (uint32 rows,
0029                         uint32 cols)
0030 
0031     :   fRows (0)
0032     ,   fCols (0)
0033 
0034     {
0035 
0036     if (rows < 1 || rows > kMaxColorPlanes ||
0037         cols < 1 || cols > kMaxColorPlanes)
0038         {
0039 
0040         ThrowProgramError ();
0041 
0042         }
0043 
0044     fRows = rows;
0045     fCols = cols;
0046 
0047     for (uint32 row = 0; row < fRows; row++)
0048         for (uint32 col = 0; col < fCols; col++)
0049             {
0050 
0051             fData [row] [col] = 0.0;
0052 
0053             }
0054 
0055     }
0056 
0057 /*****************************************************************************/
0058 
0059 dng_matrix::dng_matrix (const dng_matrix &m)
0060 
0061     :   fRows (m.fRows)
0062     ,   fCols (m.fCols)
0063 
0064     {
0065 
0066     for (uint32 row = 0; row < fRows; row++)
0067         for (uint32 col = 0; col < fCols; col++)
0068             {
0069 
0070             fData [row] [col] = m.fData [row] [col];
0071 
0072             }
0073 
0074     }
0075 
0076 /*****************************************************************************/
0077 
0078 void dng_matrix::Clear ()
0079     {
0080 
0081     fRows = 0;
0082     fCols = 0;
0083 
0084     }
0085 
0086 /*****************************************************************************/
0087 
0088 void dng_matrix::SetIdentity (uint32 count)
0089     {
0090 
0091     *this = dng_matrix (count, count);
0092 
0093     for (uint32 j = 0; j < count; j++)
0094         {
0095 
0096         fData [j] [j] = 1.0;
0097 
0098         }
0099 
0100     }
0101 
0102 /******************************************************************************/
0103 
0104 bool dng_matrix::operator== (const dng_matrix &m) const
0105     {
0106 
0107     if (Rows () != m.Rows () ||
0108         Cols () != m.Cols ())
0109         {
0110 
0111         return false;
0112 
0113         }
0114 
0115     for (uint32 j = 0; j < Rows (); j++)
0116         for (uint32 k = 0; k < Cols (); k++)
0117             {
0118 
0119             if (fData [j] [k] != m.fData [j] [k])
0120                 {
0121 
0122                 return false;
0123 
0124                 }
0125 
0126             }
0127 
0128     return true;
0129 
0130     }
0131 
0132 /******************************************************************************/
0133 
0134 bool dng_matrix::IsDiagonal () const
0135     {
0136 
0137     if (IsEmpty ())
0138         {
0139         return false;
0140         }
0141 
0142     if (Rows () != Cols ())
0143         {
0144         return false;
0145         }
0146 
0147     for (uint32 j = 0; j < Rows (); j++)
0148         for (uint32 k = 0; k < Cols (); k++)
0149             {
0150 
0151             if (j != k)
0152                 {
0153 
0154                 if (fData [j] [k] != 0.0)
0155                     {
0156                     return false;
0157                     }
0158 
0159                 }
0160 
0161             }
0162 
0163     return true;
0164 
0165     }
0166 
0167 /******************************************************************************/
0168 
0169 bool dng_matrix::IsIdentity () const
0170     {
0171 
0172     if (IsDiagonal ())
0173         {
0174 
0175         for (uint32 j = 0; j < Rows (); j++)
0176             {
0177 
0178             if (fData [j] [j] != 1.0)
0179                 {
0180                 return false;
0181                 }
0182 
0183             }
0184 
0185         return true;
0186 
0187         }
0188 
0189     return false;
0190 
0191     }
0192 
0193 /******************************************************************************/
0194 
0195 real64 dng_matrix::MaxEntry () const
0196     {
0197 
0198     if (IsEmpty ())
0199         {
0200 
0201         return 0.0;
0202 
0203         }
0204 
0205     real64 m = fData [0] [0];
0206 
0207     for (uint32 j = 0; j < Rows (); j++)
0208         for (uint32 k = 0; k < Cols (); k++)
0209             {
0210 
0211             m = Max_real64 (m, fData [j] [k]);
0212 
0213             }
0214 
0215     return m;
0216 
0217     }
0218 
0219 /******************************************************************************/
0220 
0221 real64 dng_matrix::MinEntry () const
0222     {
0223 
0224     if (IsEmpty ())
0225         {
0226 
0227         return 0.0;
0228 
0229         }
0230 
0231     real64 m = fData [0] [0];
0232 
0233     for (uint32 j = 0; j < Rows (); j++)
0234         for (uint32 k = 0; k < Cols (); k++)
0235             {
0236 
0237             m = Min_real64 (m, fData [j] [k]);
0238 
0239             }
0240 
0241     return m;
0242 
0243     }
0244 
0245 /*****************************************************************************/
0246 
0247 void dng_matrix::Scale (real64 factor)
0248     {
0249 
0250     for (uint32 j = 0; j < Rows (); j++)
0251         for (uint32 k = 0; k < Cols (); k++)
0252             {
0253 
0254             fData [j] [k] *= factor;
0255 
0256             }
0257 
0258     }
0259 
0260 /*****************************************************************************/
0261 
0262 void dng_matrix::Round (real64 factor)
0263     {
0264 
0265     real64 invFactor = 1.0 / factor;
0266 
0267     for (uint32 j = 0; j < Rows (); j++)
0268         for (uint32 k = 0; k < Cols (); k++)
0269             {
0270 
0271             fData [j] [k] = Round_int32 (fData [j] [k] * factor) * invFactor;
0272 
0273             }
0274 
0275     }
0276 
0277 /*****************************************************************************/
0278 
0279 void dng_matrix::SafeRound (real64 factor)
0280     {
0281 
0282     real64 invFactor = 1.0 / factor;
0283 
0284     for (uint32 j = 0; j < Rows (); j++)
0285         {
0286 
0287         // Round each row to the specified accuracy, but make sure the
0288         // a rounding does not affect the total of the elements in a row
0289         // more than necessary.
0290 
0291         real64 error = 0.0;
0292 
0293         for (uint32 k = 0; k < Cols (); k++)
0294             {
0295 
0296             fData [j] [k] += error;
0297 
0298             real64 rounded = Round_int32 (fData [j] [k] * factor) * invFactor;
0299 
0300             error = fData [j] [k] - rounded;
0301 
0302             fData [j] [k] = rounded;
0303 
0304             }
0305 
0306         }
0307 
0308     }
0309 
0310 /*****************************************************************************/
0311 
0312 bool dng_matrix::AlmostEqual (const dng_matrix &m,
0313                               real64 slop) const
0314     {
0315 
0316     if (Rows () != m.Rows () ||
0317         Cols () != m.Cols ())
0318         {
0319         return false;
0320         }
0321 
0322     for (uint32 j = 0; j < Rows (); j++)
0323         {
0324 
0325         for (uint32 k = 0; k < Cols (); k++)
0326             {
0327 
0328             if (Abs_real64 (fData [j] [k] - m [j] [k]) > slop)
0329                 {
0330                 return false;
0331                 }
0332 
0333             }
0334 
0335         }
0336 
0337     return true;
0338 
0339     }
0340 
0341 /*****************************************************************************/
0342 
0343 bool dng_matrix::AlmostIdentity (real64 slop) const
0344     {
0345 
0346     dng_matrix m;
0347 
0348     m.SetIdentity (Rows ());
0349 
0350     return AlmostEqual (m, slop);
0351 
0352     }
0353 
0354 /*****************************************************************************/
0355 
0356 dng_matrix_3by3::dng_matrix_3by3 ()
0357 
0358     :   dng_matrix (3, 3)
0359 
0360     {
0361     }
0362 
0363 /*****************************************************************************/
0364 
0365 dng_matrix_3by3::dng_matrix_3by3 (const dng_matrix &m)
0366 
0367     :   dng_matrix (m)
0368 
0369     {
0370 
0371     if (Rows () != 3 ||
0372         Cols () != 3)
0373         {
0374 
0375         ThrowMatrixMath ();
0376 
0377         }
0378 
0379     }
0380 
0381 /*****************************************************************************/
0382 
0383 dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a01, real64 a02,
0384                                   real64 a10, real64 a11, real64 a12,
0385                                   real64 a20, real64 a21, real64 a22)
0386 
0387 
0388     :   dng_matrix (3, 3)
0389 
0390     {
0391 
0392     fData [0] [0] = a00;
0393     fData [0] [1] = a01;
0394     fData [0] [2] = a02;
0395 
0396     fData [1] [0] = a10;
0397     fData [1] [1] = a11;
0398     fData [1] [2] = a12;
0399 
0400     fData [2] [0] = a20;
0401     fData [2] [1] = a21;
0402     fData [2] [2] = a22;
0403 
0404     }
0405 
0406 /*****************************************************************************/
0407 
0408 dng_matrix_3by3::dng_matrix_3by3 (real64 a00, real64 a11, real64 a22)
0409 
0410     :   dng_matrix (3, 3)
0411 
0412     {
0413 
0414     fData [0] [0] = a00;
0415     fData [1] [1] = a11;
0416     fData [2] [2] = a22;
0417 
0418     }
0419 
0420 /*****************************************************************************/
0421 
0422 dng_matrix_4by3::dng_matrix_4by3 ()
0423 
0424     :   dng_matrix (4, 3)
0425 
0426     {
0427     }
0428 
0429 /*****************************************************************************/
0430 
0431 dng_matrix_4by3::dng_matrix_4by3 (const dng_matrix &m)
0432 
0433     :   dng_matrix (m)
0434 
0435     {
0436 
0437     if (Rows () != 4 ||
0438         Cols () != 3)
0439         {
0440 
0441         ThrowMatrixMath ();
0442 
0443         }
0444 
0445     }
0446 
0447 /*****************************************************************************/
0448 
0449 dng_matrix_4by3::dng_matrix_4by3 (real64 a00, real64 a01, real64 a02,
0450                                   real64 a10, real64 a11, real64 a12,
0451                                   real64 a20, real64 a21, real64 a22,
0452                                   real64 a30, real64 a31, real64 a32)
0453 
0454 
0455     :   dng_matrix (4, 3)
0456 
0457     {
0458 
0459     fData [0] [0] = a00;
0460     fData [0] [1] = a01;
0461     fData [0] [2] = a02;
0462 
0463     fData [1] [0] = a10;
0464     fData [1] [1] = a11;
0465     fData [1] [2] = a12;
0466 
0467     fData [2] [0] = a20;
0468     fData [2] [1] = a21;
0469     fData [2] [2] = a22;
0470 
0471     fData [3] [0] = a30;
0472     fData [3] [1] = a31;
0473     fData [3] [2] = a32;
0474 
0475     }
0476 
0477 /*****************************************************************************/
0478 
0479 dng_matrix_4by4::dng_matrix_4by4 ()
0480 
0481     :   dng_matrix (4, 4)
0482 
0483     {
0484 
0485     }
0486 
0487 /*****************************************************************************/
0488 
0489 dng_matrix_4by4::dng_matrix_4by4 (const dng_matrix &m)
0490 
0491     :   dng_matrix (m)
0492 
0493     {
0494 
0495     // Input must be either 3x3 or 4x4.
0496 
0497     const bool is3by3 = (m.Rows () == 3 &&
0498                          m.Cols () == 3);
0499 
0500     const bool is4by4 = (m.Rows () == 4 &&
0501                          m.Cols () == 4);
0502 
0503     if (!is3by3 && !is4by4)
0504         {
0505 
0506         ThrowMatrixMath ();
0507 
0508         }
0509 
0510     // For 3x3 case, pad to 4x4 (equivalent 4x4 matrix).
0511 
0512     if (is3by3)
0513         {
0514 
0515         fRows = 4;
0516         fCols = 4;
0517 
0518         fData [0] [3] = 0.0;
0519         fData [1] [3] = 0.0;
0520         fData [2] [3] = 0.0;
0521 
0522         fData [3] [0] = 0.0;
0523         fData [3] [1] = 0.0;
0524         fData [3] [2] = 0.0;
0525 
0526         fData [3] [3] = 1.0;
0527 
0528         }
0529 
0530     }
0531 
0532 /*****************************************************************************/
0533 
0534 dng_matrix_4by4::dng_matrix_4by4 (real64 a00, real64 a01, real64 a02, real64 a03,
0535                                   real64 a10, real64 a11, real64 a12, real64 a13,
0536                                   real64 a20, real64 a21, real64 a22, real64 a23,
0537                                   real64 a30, real64 a31, real64 a32, real64 a33)
0538 
0539     :   dng_matrix (4, 4)
0540 
0541     {
0542 
0543     fData [0] [0] = a00;
0544     fData [0] [1] = a01;
0545     fData [0] [2] = a02;
0546     fData [0] [3] = a03;
0547 
0548     fData [1] [0] = a10;
0549     fData [1] [1] = a11;
0550     fData [1] [2] = a12;
0551     fData [1] [3] = a13;
0552 
0553     fData [2] [0] = a20;
0554     fData [2] [1] = a21;
0555     fData [2] [2] = a22;
0556     fData [2] [3] = a23;
0557 
0558     fData [3] [0] = a30;
0559     fData [3] [1] = a31;
0560     fData [3] [2] = a32;
0561     fData [3] [3] = a33;
0562 
0563     }
0564 
0565 /*****************************************************************************/
0566 
0567 dng_matrix_4by4::dng_matrix_4by4 (real64 a00,
0568                                   real64 a11,
0569                                   real64 a22,
0570                                   real64 a33)
0571 
0572     :   dng_matrix (4, 4)
0573 
0574     {
0575 
0576     fData [0] [0] = a00;
0577     fData [1] [1] = a11;
0578     fData [2] [2] = a22;
0579     fData [3] [3] = a33;
0580 
0581     }
0582 
0583 /*****************************************************************************/
0584 
0585 dng_vector::dng_vector ()
0586 
0587     :   fCount (0)
0588 
0589     {
0590 
0591     }
0592 
0593 /*****************************************************************************/
0594 
0595 dng_vector::dng_vector (uint32 count)
0596 
0597     :   fCount (0)
0598 
0599     {
0600 
0601     if (count < 1 || count > kMaxColorPlanes)
0602         {
0603 
0604         ThrowProgramError ();
0605 
0606         }
0607 
0608     fCount = count;
0609 
0610     for (uint32 index = 0; index < fCount; index++)
0611         {
0612 
0613         fData [index] = 0.0;
0614 
0615         }
0616 
0617     }
0618 
0619 /*****************************************************************************/
0620 
0621 dng_vector::dng_vector (const dng_vector &v)
0622 
0623     :   fCount (v.fCount)
0624 
0625     {
0626 
0627     for (uint32 index = 0; index < fCount; index++)
0628         {
0629 
0630         fData [index] = v.fData [index];
0631 
0632         }
0633 
0634     }
0635 
0636 /*****************************************************************************/
0637 
0638 void dng_vector::Clear ()
0639     {
0640 
0641     fCount = 0;
0642 
0643     }
0644 
0645 /*****************************************************************************/
0646 
0647 void dng_vector::SetIdentity (uint32 count)
0648     {
0649 
0650     *this = dng_vector (count);
0651 
0652     for (uint32 j = 0; j < count; j++)
0653         {
0654 
0655         fData [j] = 1.0;
0656 
0657         }
0658 
0659     }
0660 
0661 /******************************************************************************/
0662 
0663 bool dng_vector::operator== (const dng_vector &v) const
0664     {
0665 
0666     if (Count () != v.Count ())
0667         {
0668 
0669         return false;
0670 
0671         }
0672 
0673     for (uint32 j = 0; j < Count (); j++)
0674         {
0675 
0676         if (fData [j] != v.fData [j])
0677             {
0678 
0679             return false;
0680 
0681             }
0682 
0683         }
0684 
0685     return true;
0686 
0687     }
0688 
0689 /******************************************************************************/
0690 
0691 real64 dng_vector::MaxEntry () const
0692     {
0693 
0694     if (IsEmpty ())
0695         {
0696 
0697         return 0.0;
0698 
0699         }
0700 
0701     real64 m = fData [0];
0702 
0703     for (uint32 j = 0; j < Count (); j++)
0704         {
0705 
0706         m = Max_real64 (m, fData [j]);
0707 
0708         }
0709 
0710     return m;
0711 
0712     }
0713 
0714 /******************************************************************************/
0715 
0716 real64 dng_vector::MinEntry () const
0717     {
0718 
0719     if (IsEmpty ())
0720         {
0721 
0722         return 0.0;
0723 
0724         }
0725 
0726     real64 m = fData [0];
0727 
0728     for (uint32 j = 0; j < Count (); j++)
0729         {
0730 
0731         m = Min_real64 (m, fData [j]);
0732 
0733         }
0734 
0735     return m;
0736 
0737     }
0738 
0739 /*****************************************************************************/
0740 
0741 void dng_vector::Scale (real64 factor)
0742     {
0743 
0744     for (uint32 j = 0; j < Count (); j++)
0745         {
0746 
0747         fData [j] *= factor;
0748 
0749         }
0750 
0751     }
0752 
0753 /*****************************************************************************/
0754 
0755 void dng_vector::Round (real64 factor)
0756     {
0757 
0758     real64 invFactor = 1.0 / factor;
0759 
0760     for (uint32 j = 0; j < Count (); j++)
0761         {
0762 
0763         fData [j] = Round_int32 (fData [j] * factor) * invFactor;
0764 
0765         }
0766 
0767     }
0768 
0769 /*****************************************************************************/
0770 
0771 dng_matrix dng_vector::AsDiagonal () const
0772     {
0773 
0774     dng_matrix M (Count (), Count ());
0775 
0776     for (uint32 j = 0; j < Count (); j++)
0777         {
0778 
0779         M [j] [j] = fData [j];
0780 
0781         }
0782 
0783     return M;
0784 
0785     }
0786 
0787 /*****************************************************************************/
0788 
0789 dng_matrix dng_vector::AsColumn () const
0790     {
0791 
0792     dng_matrix M (Count (), 1);
0793 
0794     for (uint32 j = 0; j < Count (); j++)
0795         {
0796 
0797         M [j] [0] = fData [j];
0798 
0799         }
0800 
0801     return M;
0802 
0803     }
0804 
0805 /******************************************************************************/
0806 
0807 dng_vector_3::dng_vector_3 ()
0808 
0809     :   dng_vector (3)
0810 
0811     {
0812     }
0813 
0814 /******************************************************************************/
0815 
0816 dng_vector_3::dng_vector_3 (const dng_vector &v)
0817 
0818     :   dng_vector (v)
0819 
0820     {
0821 
0822     if (Count () != 3)
0823         {
0824 
0825         ThrowMatrixMath ();
0826 
0827         }
0828 
0829     }
0830 
0831 /******************************************************************************/
0832 
0833 dng_vector_3::dng_vector_3 (real64 a0,
0834                             real64 a1,
0835                             real64 a2)
0836 
0837     :   dng_vector (3)
0838 
0839     {
0840 
0841     fData [0] = a0;
0842     fData [1] = a1;
0843     fData [2] = a2;
0844 
0845     }
0846 
0847 /******************************************************************************/
0848 
0849 dng_vector_4::dng_vector_4 ()
0850 
0851     :   dng_vector (4)
0852 
0853     {
0854     }
0855 
0856 /******************************************************************************/
0857 
0858 dng_vector_4::dng_vector_4 (const dng_vector &v)
0859 
0860     :   dng_vector (v)
0861 
0862     {
0863 
0864     if (Count () != 4)
0865         {
0866 
0867         ThrowMatrixMath ();
0868 
0869         }
0870 
0871     }
0872 
0873 /******************************************************************************/
0874 
0875 dng_vector_4::dng_vector_4 (real64 a0,
0876                             real64 a1,
0877                             real64 a2,
0878                             real64 a3)
0879 
0880     :   dng_vector (4)
0881 
0882     {
0883 
0884     fData [0] = a0;
0885     fData [1] = a1;
0886     fData [2] = a2;
0887     fData [3] = a3;
0888 
0889     }
0890 
0891 /******************************************************************************/
0892 
0893 dng_matrix operator* (const dng_matrix &A,
0894                       const dng_matrix &B)
0895     {
0896 
0897     if (A.Cols () != B.Rows ())
0898         {
0899 
0900         ThrowMatrixMath ();
0901 
0902         }
0903 
0904     dng_matrix C (A.Rows (), B.Cols ());
0905 
0906     for (uint32 j = 0; j < C.Rows (); j++)
0907         for (uint32 k = 0; k < C.Cols (); k++)
0908             {
0909 
0910             C [j] [k] = 0.0;
0911 
0912             for (uint32 m = 0; m < A.Cols (); m++)
0913                 {
0914 
0915                 real64 aa = A [j] [m];
0916 
0917                 real64 bb = B [m] [k];
0918 
0919                 C [j] [k] += aa * bb;
0920 
0921                 }
0922 
0923             }
0924 
0925     return C;
0926 
0927     }
0928 
0929 /******************************************************************************/
0930 
0931 dng_vector operator* (const dng_matrix &A,
0932                       const dng_vector &B)
0933     {
0934 
0935     if (A.Cols () != B.Count ())
0936         {
0937 
0938         ThrowMatrixMath ();
0939 
0940         }
0941 
0942     dng_vector C (A.Rows ());
0943 
0944     for (uint32 j = 0; j < C.Count (); j++)
0945         {
0946 
0947         C [j] = 0.0;
0948 
0949         for (uint32 m = 0; m < A.Cols (); m++)
0950             {
0951 
0952             real64 aa = A [j] [m];
0953 
0954             real64 bb = B [m];
0955 
0956             C [j] += aa * bb;
0957 
0958             }
0959 
0960         }
0961 
0962     return C;
0963 
0964     }
0965 
0966 /******************************************************************************/
0967 
0968 dng_matrix operator* (real64 scale,
0969                       const dng_matrix &A)
0970     {
0971 
0972     dng_matrix B (A);
0973 
0974     B.Scale (scale);
0975 
0976     return B;
0977 
0978     }
0979 
0980 /******************************************************************************/
0981 
0982 dng_vector operator* (real64 scale,
0983                       const dng_vector &A)
0984     {
0985 
0986     dng_vector B (A);
0987 
0988     B.Scale (scale);
0989 
0990     return B;
0991 
0992     }
0993 
0994 /******************************************************************************/
0995 
0996 dng_matrix operator+ (const dng_matrix &A,
0997                       const dng_matrix &B)
0998     {
0999 
1000     if (A.Cols () != B.Cols () ||
1001         A.Rows () != B.Rows ())
1002         {
1003 
1004         ThrowMatrixMath ();
1005 
1006         }
1007 
1008     dng_matrix C (A);
1009 
1010     for (uint32 j = 0; j < C.Rows (); j++)
1011         for (uint32 k = 0; k < C.Cols (); k++)
1012             {
1013 
1014             C [j] [k] += B [j] [k];
1015 
1016             }
1017 
1018     return C;
1019 
1020     }
1021 
1022 /******************************************************************************/
1023 
1024 dng_vector operator- (const dng_vector &a,
1025                       const dng_vector &b)
1026     {
1027 
1028     uint32 count = a.Count ();
1029 
1030     DNG_REQUIRE (count == b.Count (),
1031                  "Mismatch count in Dot");
1032 
1033     if (!count)
1034         {
1035         return dng_vector ();
1036         }
1037 
1038     dng_vector result (count);
1039 
1040     for (uint32 i = 0; i < count; i++)
1041         {
1042 
1043         result [i] = a [i] - b [i];
1044 
1045         }
1046 
1047     return result;
1048 
1049     }
1050 
1051 /******************************************************************************/
1052 
1053 const real64 kNearZero = 1.0E-10;
1054 
1055 /******************************************************************************/
1056 
1057 // Work around bug #1294195, which may be a hardware problem on a specific machine.
1058 // This pragma turns on "improved" floating-point consistency.
1059 #ifdef _MSC_VER
1060 #pragma optimize ("p", on)
1061 #endif
1062 
1063 static dng_matrix Invert3by3 (const dng_matrix &A)
1064     {
1065 
1066     real64 a00 = A [0] [0];
1067     real64 a01 = A [0] [1];
1068     real64 a02 = A [0] [2];
1069     real64 a10 = A [1] [0];
1070     real64 a11 = A [1] [1];
1071     real64 a12 = A [1] [2];
1072     real64 a20 = A [2] [0];
1073     real64 a21 = A [2] [1];
1074     real64 a22 = A [2] [2];
1075 
1076     real64 temp [3] [3];
1077 
1078     temp [0] [0] = a11 * a22 - a21 * a12;
1079     temp [0] [1] = a21 * a02 - a01 * a22;
1080     temp [0] [2] = a01 * a12 - a11 * a02;
1081     temp [1] [0] = a20 * a12 - a10 * a22;
1082     temp [1] [1] = a00 * a22 - a20 * a02;
1083     temp [1] [2] = a10 * a02 - a00 * a12;
1084     temp [2] [0] = a10 * a21 - a20 * a11;
1085     temp [2] [1] = a20 * a01 - a00 * a21;
1086     temp [2] [2] = a00 * a11 - a10 * a01;
1087 
1088     real64 det = (a00 * temp [0] [0] +
1089                   a01 * temp [1] [0] +
1090                   a02 * temp [2] [0]);
1091 
1092     if (Abs_real64 (det) < kNearZero)
1093         {
1094 
1095         ThrowMatrixMath ();
1096 
1097         }
1098 
1099     dng_matrix B (3, 3);
1100 
1101     for (uint32 j = 0; j < 3; j++)
1102         for (uint32 k = 0; k < 3; k++)
1103             {
1104 
1105             B [j] [k] = temp [j] [k] / det;
1106 
1107             }
1108 
1109     return B;
1110 
1111     }
1112 
1113 // Reset floating-point optimization. See comment above.
1114 #ifdef _MSC_VER
1115 #pragma optimize ("p", off)
1116 #endif
1117 
1118 /******************************************************************************/
1119 
1120 static dng_matrix InvertNbyN (const dng_matrix &A)
1121     {
1122 
1123     uint32 i;
1124     uint32 j;
1125     uint32 k;
1126 
1127     const uint32 n = A.Rows ();
1128 
1129     const uint32 augmented_cols = 2 * n;
1130 
1131     real64 temp [kMaxColorPlanes] [kMaxColorPlanes * 2];
1132 
1133     memset (temp, 0, sizeof (temp));
1134 
1135     for (i = 0; i < n; i++)
1136         for (j = 0; j < n; j++)
1137             {
1138 
1139             temp [i] [j    ] = A [i] [j];
1140 
1141             temp [i] [j + n] = (i == j ? 1.0 : 0.0);
1142 
1143             }
1144 
1145     for (i = 0; i < n; i++)
1146         {
1147 
1148         // Find row iMax with largest absolute entry in column i.
1149 
1150         uint32 iMax =  i;
1151         real64 vMax = -1.0;
1152 
1153         for (k = i; k < n; k++)
1154             {
1155 
1156             real64 v = Abs_real64 (A [k] [i]);
1157 
1158             if (v > vMax)
1159                 {
1160                 vMax = v;
1161                 iMax = k;
1162                 }
1163 
1164             }
1165 
1166         real64 alpha = temp [iMax] [i];
1167 
1168         if (Abs_real64 (alpha) < kNearZero)
1169             {
1170 
1171             ThrowMatrixMath ();
1172 
1173             }
1174 
1175         // Swap rows i and iMax, column by column.
1176 
1177         if (i != iMax)
1178             {
1179 
1180             for (j = 0; j < augmented_cols; j++)
1181                 {
1182 
1183                 std::swap (temp [i   ] [j],
1184                            temp [iMax] [j]);
1185 
1186                 }
1187 
1188             }
1189 
1190         for (j = 0; j < augmented_cols; j++)
1191             {
1192 
1193             temp [i] [j] /= alpha;
1194 
1195             }
1196 
1197         for (k = 0; k < n; k++)
1198             {
1199 
1200             if (i != k)
1201                 {
1202 
1203                 real64 beta = temp [k] [i];
1204 
1205                 for (j = 0; j < augmented_cols; j++)
1206                     {
1207 
1208                     temp [k] [j] -= beta * temp [i] [j];
1209 
1210                     }
1211 
1212                 }
1213 
1214             }
1215 
1216         }
1217 
1218     dng_matrix B (n, n);
1219 
1220     for (i = 0; i < n; i++)
1221         for (j = 0; j < n; j++)
1222             {
1223 
1224             B [i] [j] = temp [i] [j + n];
1225 
1226             }
1227 
1228     return B;
1229 
1230     }
1231 
1232 /******************************************************************************/
1233 
1234 dng_matrix Transpose (const dng_matrix &A)
1235     {
1236 
1237     dng_matrix B (A.Cols (), A.Rows ());
1238 
1239     for (uint32 j = 0; j < B.Rows (); j++)
1240         for (uint32 k = 0; k < B.Cols (); k++)
1241             {
1242 
1243             B [j] [k] = A [k] [j];
1244 
1245             }
1246 
1247     return B;
1248 
1249     }
1250 
1251 /******************************************************************************/
1252 
1253 dng_matrix Invert (const dng_matrix &A)
1254     {
1255 
1256     if (A.Rows () < 2 || A.Cols () < 2)
1257         {
1258 
1259         ThrowMatrixMath ();
1260 
1261         }
1262 
1263     if (A.Rows () == A.Cols ())
1264         {
1265 
1266         if (A.Rows () == 3)
1267             {
1268 
1269             return Invert3by3 (A);
1270 
1271             }
1272 
1273         return InvertNbyN (A);
1274 
1275         }
1276 
1277     else
1278         {
1279 
1280         // Compute the pseudo inverse.
1281 
1282         dng_matrix B = Transpose (A);
1283 
1284         return Invert (B * A) * B;
1285 
1286         }
1287 
1288     }
1289 
1290 /******************************************************************************/
1291 
1292 dng_matrix Invert (const dng_matrix &A,
1293                    const dng_matrix &hint)
1294     {
1295 
1296     if (A.Rows () == A   .Cols () ||
1297         A.Rows () != hint.Cols () ||
1298         A.Cols () != hint.Rows ())
1299         {
1300 
1301         return Invert (A);
1302 
1303         }
1304 
1305     else
1306         {
1307 
1308         // Use the specified hint matrix.
1309 
1310         return Invert (hint * A) * hint;
1311 
1312         }
1313 
1314     }
1315 
1316 /*****************************************************************************/
1317 
1318 real64 Dot (const dng_vector &a,
1319             const dng_vector &b)
1320     {
1321 
1322     DNG_REQUIRE (a.Count () == b.Count (),
1323                  "Cannot take dot product between vectors of different size.");
1324 
1325     // DNG_REQUIRE (a.Count () > 0,
1326     //           "Cannot take dot product with an empty vector.");
1327 
1328     real64 sum = 0.0;
1329 
1330     for (uint32 j = 0; j < a.Count (); j++)
1331         {
1332 
1333         sum += (a [j] * b [j]);
1334 
1335         }
1336 
1337     return sum;
1338 
1339     }
1340 
1341 /*****************************************************************************/
1342 
1343 real64 Distance (const dng_vector &a,
1344                  const dng_vector &b)
1345     {
1346 
1347     dng_vector c = a - b;
1348 
1349     return sqrt (Dot (c, c));
1350 
1351     }
1352 
1353 /*****************************************************************************/