dlib C++ Library - matrix.cpp

    // Copyright (C) 2006  Davis E. King (davisking@users.sourceforge.net)
    // License: Boost Software License   See LICENSE.txt for the full license.

    #include <dlib/matrix.h>
    #include <sstream>
    #include <string>
    #include <cstdlib>
    #include <ctime>
    #include <vector>
    #include "../stl_checked.h"
    #include "../array.h"
    #include "../rand.h"

    #include "tester.h"
    #include <dlib/memory_manager_stateless.h>
    #include <dlib/array2d.h>

    namespace
    {

        using namespace test;
        using namespace dlib;
        using namespace std;

        logger dlog("test.matrix");

        void matrix_test (
        )
        /*!
            ensures
                - runs tests on the matrix stuff compliance with the specs
        !*/
        {
            typedef memory_manager_stateless<char>::kernel_2_2a MM;
            print_spinner();

            const double ident[] = {
                1, 0, 0, 0,
                0, 1, 0, 0,
                0, 0, 1, 0,
                0, 0, 0, 1 };

            const double uniform3[] = {
                3, 3, 3, 3,
                3, 3, 3, 3,
                3, 3, 3, 3,
                3, 3, 3, 3
            };

            const double uniform1[] = {
                1, 1, 1, 1,
                1, 1, 1, 1,
                1, 1, 1, 1,
                1, 1, 1, 1
            };

            const double uniform0[] = {
                0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0,
                0, 0, 0, 0
            };

            const int array[] = {
                42, 58, 9, 1,
                9, 5, 8, 2,
                98, 28, 4, 77,
                9, 2, 44, 88 };

            const int array2[] = {
                1, 22, 3,
                4, 52, 6,
                7, 8, 9 };

            const int array2_r[] = {
                52, 6, 4,
                8, 9, 7,
                22, 3, 1
            };

            const double array_f[] = {
                -0.99,
                0.99};

            matrix<double,2,1,MM> fm(array_f);

            DLIB_CASSERT(fm.size() == 2,"");
            matrix<double> dfm(fm);
            DLIB_CASSERT(round(fm)(0) == -1,"");
            DLIB_CASSERT(round(fm)(1) == 1,"");
            DLIB_CASSERT(round(dfm)(0) == -1,"");
            DLIB_CASSERT(round(dfm)(1) == 1,"");
            DLIB_CASSERT(round(dfm).size() == dfm.size(),"");

            const int array3[] = { 1, 2, 3, 4 };

            matrix<double,3,3,MM> m3(array2);
            matrix<double> dm3;
            DLIB_CASSERT(dm3.size() == 0,"");
            DLIB_CASSERT(dm3.nr() == 0,"");
            DLIB_CASSERT(dm3.nc() == 0,"");
            dm3.set_size(3,4);
            DLIB_CASSERT(dm3.nr() == 3,"");
            DLIB_CASSERT(dm3.nc() == 4,"");
            DLIB_CASSERT(dm3.size() == 3*4,"");
            dm3.set_size(3,3);
            DLIB_CASSERT(dm3.nr() == 3,"");
            DLIB_CASSERT(dm3.nc() == 3,"");
            dm3 = m3;
            dm3(0,0)++;
            DLIB_CASSERT( dm3 != m3,"");
            dm3 = m3;
            DLIB_CASSERT( dm3 == m3,"");
            DLIB_CASSERT( abs(sum(squared(normalize(dm3))) - 1.0) < 1e-10,"");

            matrix<double,3,4> mrc;
            mrc.set_size(3,4);

            set_all_elements(mrc,1);
            matrix<double,2,3> mrc2;
            set_all_elements(mrc2,1);
            DLIB_CASSERT((removerc<1,1>(mrc) == mrc2),"");
            DLIB_CASSERT((removerc(mrc,1,1) == mrc2),"");

            matrix<int,3,3> m4, m5, m6;
            set_all_elements(m4, 4);
            set_all_elements(m5, 4);
            set_all_elements(m6, 1);

            DLIB_CASSERT(squared(m4) == pointwise_multiply(m4,m4),"");
            DLIB_CASSERT(cubed(m4) == pointwise_multiply(m4,m4,m4),"");
            DLIB_CASSERT(pow(matrix_cast<double>(m4),2) == squared(matrix_cast<double>(m4)),"");
            DLIB_CASSERT(pow(matrix_cast<double>(m4),3) == cubed(matrix_cast<double>(m4)),"");

            matrix<int> dm4;
            matrix<int,0,0,memory_manager_stateless<char>::kernel_2_2a> dm5;
            dm4 = dm4;
            dm4 = dm5;
            DLIB_CASSERT(dm4.nr() == 0,"");
            dm4 = m4;
            dm5 = m5;
            DLIB_CASSERT(dm4 == dm5,"");

            DLIB_CASSERT(m4 == m5,"");
            DLIB_CASSERT(m6 != m5,"");
            m4.swap(m6);
            DLIB_CASSERT(m6 == m5,"");
            DLIB_CASSERT(m4 != m5,"");

            DLIB_CASSERT(m3.nr() == 3,"");
            DLIB_CASSERT(m3.nc() == 3,"");

            matrix<double,4,1> v(array3), v2;
            DLIB_CASSERT(v.nr() == 4,"");
            DLIB_CASSERT(v.nc() == 1,"");

            std::vector<double> stdv(4);
            std_vector_c<double> stdv_c(4);
            dlib::array<double>::expand_1a_c arr;
            arr.expand(4);
            for (long i = 0; i < 4; ++i)
                stdv[i] = stdv_c[i] = arr[i] = i+1;

            DLIB_CASSERT(vector_to_matrix(stdv)(0) == 1,"");
            DLIB_CASSERT(vector_to_matrix(stdv)(1) == 2,"");
            DLIB_CASSERT(vector_to_matrix(stdv)(2) == 3,"");
            DLIB_CASSERT(vector_to_matrix(stdv)(3) == 4,"");
            DLIB_CASSERT(vector_to_matrix(stdv).nr() == 4,"");
            DLIB_CASSERT(vector_to_matrix(stdv).nc() == 1,"");
            DLIB_CASSERT(vector_to_matrix(stdv).size() == 4,"");
            DLIB_CASSERT(equal(trans(vector_to_matrix(stdv))*vector_to_matrix(stdv), trans(v)*v), "");
            DLIB_CASSERT(equal(trans(vector_to_matrix(stdv))*vector_to_matrix(stdv), tmp(trans(v)*v)), "");

            DLIB_CASSERT(vector_to_matrix(stdv_c)(0) == 1,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c)(1) == 2,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c)(2) == 3,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c)(3) == 4,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c).nr() == 4,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c).nc() == 1,"");
            DLIB_CASSERT(vector_to_matrix(stdv_c).size() == 4,"");
            DLIB_CASSERT(equal(trans(vector_to_matrix(stdv_c))*vector_to_matrix(stdv_c), trans(v)*v), "");

            DLIB_CASSERT(vector_to_matrix(arr)(0) == 1,"");
            DLIB_CASSERT(vector_to_matrix(arr)(1) == 2,"");
            DLIB_CASSERT(vector_to_matrix(arr)(2) == 3,"");
            DLIB_CASSERT(vector_to_matrix(arr)(3) == 4,"");
            DLIB_CASSERT(vector_to_matrix(arr).nr() == 4,"");
            DLIB_CASSERT(vector_to_matrix(arr).nc() == 1,"");
            DLIB_CASSERT(vector_to_matrix(arr).size() == 4,"");
            DLIB_CASSERT(equal(trans(vector_to_matrix(arr))*vector_to_matrix(arr), trans(v)*v), "");

            DLIB_CASSERT(v(0) == 1,"");
            DLIB_CASSERT(v(1) == 2,"");
            DLIB_CASSERT(v(2) == 3,"");
            DLIB_CASSERT(v(3) == 4,"");
            matrix<double> dv = v;
            DLIB_CASSERT((trans(v)*v).size() == 1,"");
            DLIB_CASSERT((trans(v)*v).nr() == 1,"");
            DLIB_CASSERT((trans(v)*dv).nr() == 1,"");
            DLIB_CASSERT((trans(dv)*dv).nr() == 1,"");
            DLIB_CASSERT((trans(dv)*v).nr() == 1,"");
            DLIB_CASSERT((trans(v)*v).nc() == 1,"");
            DLIB_CASSERT((trans(v)*dv).nc() == 1,"");
            DLIB_CASSERT((trans(dv)*dv).nc() == 1,"");
            DLIB_CASSERT((trans(dv)*v).nc() == 1,"");
            DLIB_CASSERT((trans(v)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4,"");
            DLIB_CASSERT((trans(dv)*v)(0) == 1*1 + 2*2 + 3*3 + 4*4,"");
            DLIB_CASSERT((trans(dv)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4,"");
            DLIB_CASSERT((trans(v)*dv)(0) == 1*1 + 2*2 + 3*3 + 4*4,"");

            dv = trans(dv)*v;
            DLIB_CASSERT(dv.nr() == 1,"");
            DLIB_CASSERT(dv.nc() == 1,"");

            dm3 = m3;
            DLIB_CASSERT(floor(det(m3)+0.01) == -444,"");
            DLIB_CASSERT(floor(det(dm3)+0.01) == -444,"");
            DLIB_CASSERT(min(m3) == 1,"");
            DLIB_CASSERT(min(dm3) == 1,"");
            DLIB_CASSERT(max(m3) == 52,"");
            DLIB_CASSERT(max(dm3) == 52,"");
            DLIB_CASSERT(sum(m3) == 112,"");
            DLIB_CASSERT(sum(dm3) == 112,"");
            DLIB_CASSERT(prod(m3) == 41513472,"");
            DLIB_CASSERT(prod(dm3) == 41513472,"");
            DLIB_CASSERT(prod(diag(m3)) == 1*52*9,"");
            DLIB_CASSERT(prod(diag(dm3)) == 1*52*9,"");
            DLIB_CASSERT(sum(diag(m3)) == 1+52+9,"");
            DLIB_CASSERT(sum(diag(dm3)) == 1+52+9,"");
            DLIB_CASSERT((round(10000*m3*inv(m3))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*dm3*inv(m3))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*dm3*inv(dm3))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*m3*inv(dm3))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*tmp(m3*inv(m3)))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*tmp(dm3*inv(m3)))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*tmp(dm3*inv(dm3)))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT((round(10000*tmp(m3*inv(dm3)))/10000 == identity_matrix<double,3>()),"");
            DLIB_CASSERT(-1*m3 == -m3,"");
            DLIB_CASSERT(-1*dm3 == -m3,"");
            DLIB_CASSERT(-1*m3 == -dm3,"");
            DLIB_CASSERT(-1*dm3 == -dm3,"");

            DLIB_CASSERT(m3 == dm3,"");
            m3(1,1) = 99;
            DLIB_CASSERT(m3 != dm3,"");
            m3 = dm3;
            DLIB_CASSERT(m3 == dm3,"");

            matrix<double,4,4,MM> mident(ident);
            matrix<double,4,4> muniform0(uniform0);
            matrix<double,4,4> muniform1(uniform1);
            matrix<double,4,4> muniform3(uniform3);
            matrix<double,4,4> m1(array), m2;
            DLIB_CASSERT(m1.nr() == 4,"");
            DLIB_CASSERT(m1.nc() == 4,"");

            DLIB_CASSERT(muniform1 + muniform1 + muniform1 == muniform3,"");
            DLIB_CASSERT(muniform1*2 + muniform1 + muniform1 - muniform1 == muniform3,"");
            DLIB_CASSERT(2*muniform1 + muniform1 + muniform1 - muniform1 == muniform3,"");
            DLIB_CASSERT(muniform1 + muniform1 + muniform1 - muniform3 == muniform0,"");
            DLIB_CASSERT(muniform3/3 == muniform1,"");
            DLIB_CASSERT(v != m1,"");
            DLIB_CASSERT(v == v,"");
            DLIB_CASSERT(m1 == m1,"");

            muniform0.swap(muniform1);
            DLIB_CASSERT((muniform1 == matrix_cast<double>(uniform_matrix<long,4,4,0>())),"");
            DLIB_CASSERT((muniform0 == matrix_cast<double>(uniform_matrix<long,4,4,1>())),"");
            DLIB_CASSERT((muniform1 == matrix_cast<double>(uniform_matrix<long>(4,4,0))),"");
            DLIB_CASSERT((muniform0 == matrix_cast<double>(uniform_matrix<long>(4,4,1))),"");
            swap(muniform0,muniform1);

            DLIB_CASSERT((mident == identity_matrix<double,4>()),"");
            DLIB_CASSERT((muniform0 == matrix_cast<double>(uniform_matrix<long,4,4,0>())),"");
            DLIB_CASSERT((muniform1 == matrix_cast<double>(uniform_matrix<long,4,4,1>())),"");
            DLIB_CASSERT((muniform3 == matrix_cast<double>(uniform_matrix<long,4,4,3>())),"");
            DLIB_CASSERT((muniform1*8 == matrix_cast<double>(uniform_matrix<long,4,4,8>())),"");

            set_all_elements(m2,7);
            DLIB_CASSERT(m2 == muniform1*7,"");
            m2 = array;
            DLIB_CASSERT(m2 == m1,"");

            const double m1inv[] = {
                -0.00946427624, 0.0593272941,  0.00970564379,  -0.00973323731,
                0.0249312057,   -0.0590122427, -0.00583102756, 0.00616002729,
                -0.00575431149, 0.110081189,   -0.00806792253, 0.00462297692,
                0.00327847478,  -0.0597669712, 0.00317386196,  0.00990759201
            };

            m2 = m1inv;
            DLIB_CASSERT((round(m2*m1) == identity_matrix<double,4>()),"");
            DLIB_CASSERT((round(tmp(m2*m1)) == identity_matrix<double,4>()),"");

            DLIB_CASSERT(round(m2*10000) == round(inv(m1)*10000),"");
            DLIB_CASSERT(m1 == abs(-1*m1),"");
            DLIB_CASSERT(abs(m2) == abs(-1*m2),"");

            DLIB_CASSERT(floor(det(m1)+0.01) == 3297875,"\nm1: \n" << m1 << "\ndet(m1): " << det(m1));

            ostringstream sout;
            m1 = m2;
            serialize(m1,sout);
            set_all_elements(m1,0);
            istringstream sin(sout.str());
            deserialize(m1,sin);
            DLIB_CASSERT(round(100000*m1) == round(100000*m2),"m1: \n" << m1 << endl << "m2: \n" << m2);

            set_all_elements(v,2);
            v2 =  pointwise_multiply(v, v*2);
            set_all_elements(v,8);
            DLIB_CASSERT(v == v2,"");
            DLIB_CASSERT(v == tmp(v2),"");
            DLIB_CASSERT((v == rotate<2,0>(v)),"");

            m4 = array2;
            m5 = array2_r;
            DLIB_CASSERT((m5 == rotate<1,1>(m4)),"");

            m5 = array2;
            DLIB_CASSERT((m5*2 == pointwise_multiply(m5,uniform_matrix<int,3,3,2>())),"");
            DLIB_CASSERT((tmp(m5*2) == tmp(pointwise_multiply(m5,uniform_matrix<int,3,3,2>()))),"");

            v = tmp(v);

            matrix<double> dm10(10,5);
            DLIB_CASSERT(dm10.nr() == 10,"");
            DLIB_CASSERT(dm10.nc() == 5,"");
            set_all_elements(dm10,4);
            DLIB_CASSERT(dm10.nr() == 10,"");
            DLIB_CASSERT(dm10.nc() == 5,"");
            matrix<double,10,5> m10;
            DLIB_CASSERT(m10.nr() == 10,"");
            DLIB_CASSERT(m10.nc() == 5,"");
            set_all_elements(m10,4);
            DLIB_CASSERT(dm10 == m10,"");
            DLIB_CASSERT((clamp<0,3>(dm10) == clamp<0,3>(m10)),"");
            DLIB_CASSERT((clamp<0,3>(dm10)(0,2) == 3),"");

            set_all_elements(dm10,1);
            set_all_elements(m10,4);
            DLIB_CASSERT(4*dm10 == m10,"");
            DLIB_CASSERT(5*dm10 - dm10 == m10,"");
            DLIB_CASSERT((16*dm10)/4 == m10,"");
            DLIB_CASSERT(dm10+dm10+2*dm10 == m10,"");
            DLIB_CASSERT(dm10+tmp(dm10+2*dm10) == m10,"");
            set_all_elements(dm10,4);
            DLIB_CASSERT(dm10 == m10,"");
            DLIB_CASSERT(sum(abs(sigmoid(dm10) -sigmoid(m10))) < 1e-10,sum(abs(sigmoid(dm10) -sigmoid(m10))) );

            matrix<double, 7, 7,MM> m7;
            matrix<double> dm7(7,7);
            for (long r= 0; r< dm7.nr(); ++r)
            {
                for (long c = 0; c < dm7.nc(); ++c)
                {
                    dm7(r,c) = r*c/3.3;
                }
            }
            m7 = dm7;

            DLIB_CASSERT(inv(dm7) == inv(m7),"");
            DLIB_CASSERT(det(dm7) == det(m7),"");
            DLIB_CASSERT(min(dm7) == min(m7),"");
            DLIB_CASSERT(max(dm7) == max(m7),"");
            DLIB_CASSERT(abs(sum(dm7) - sum(m7)) < 1e-14,sum(dm7) - sum(m7));
            DLIB_CASSERT(prod(dm7) == prod(m7),"");
            DLIB_CASSERT(diag(dm7) == diag(m7),"");
            DLIB_CASSERT(trans(dm7) == trans(m7),"");
            DLIB_CASSERT(abs(dm7) == abs(m7),"");
            DLIB_CASSERT(round(dm7) == round(m7),"");
            DLIB_CASSERT(matrix_cast<int>(dm7) == matrix_cast<int>(m7),"");
            DLIB_CASSERT((rotate<2,3>(dm7) == rotate<2,3>(m7)),"");
            DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7) - pointwise_multiply(m7,m7))) < 1e-10,"");
            DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7))) < 1e-10,"");
            DLIB_CASSERT((sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7))) < 1e-10,
                         (sum(pointwise_multiply(dm7,dm7,dm7,dm7) - pointwise_multiply(m7,m7,m7,m7)))
            );

            matrix<double> temp(5,5);
            matrix<double> dsm(5,5);
            matrix<double,5,5,MM> sm;

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,1);

            dsm += dsm;
            sm += sm;
            DLIB_CASSERT(dsm == 2*temp,"");
            DLIB_CASSERT(sm == 2*temp,"");
            temp = dsm*sm + dsm;
            dsm += dsm*sm;
            DLIB_CASSERT(temp == dsm,temp - dsm);

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,1);

            dsm += dsm;
            sm += sm;
            DLIB_CASSERT(dsm == 2*temp,"");
            DLIB_CASSERT(sm == 2*temp,"");
            temp = dsm*sm + dsm;
            sm += dsm*sm;
            DLIB_CASSERT(temp == sm,temp - sm);

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,1);

            dsm += dsm;
            sm += sm;
            DLIB_CASSERT(dsm == 2*temp,"");
            DLIB_CASSERT(sm == 2*temp,"");
            temp = sm - dsm*sm ;
            sm -= dsm*sm;
            DLIB_CASSERT(temp == sm,temp - sm);

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,1);

            dsm += dsm;
            sm += sm;
            DLIB_CASSERT(dsm == 2*temp,"");
            DLIB_CASSERT(sm == 2*temp,"");
            temp = dsm - dsm*sm ;
            dsm -= dsm*sm;
            DLIB_CASSERT(temp == dsm,temp - dsm);

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,2);

            dsm *= 2;
            sm *= 2;
            DLIB_CASSERT(dsm == temp,"");
            DLIB_CASSERT(sm == temp,"");
            dsm /= 2;
            sm /= 2;
            DLIB_CASSERT(dsm == temp/2,"");
            DLIB_CASSERT(sm == temp/2,"");

            dsm += dsm;
            sm += sm;
            DLIB_CASSERT(dsm == temp,"");
            DLIB_CASSERT(sm == temp,"");
            dsm += sm;
            sm += dsm;
            DLIB_CASSERT(dsm == 2*temp,"");
            DLIB_CASSERT(sm == temp*3,"");
            dsm -= sm;
            sm -= dsm;
            DLIB_CASSERT(dsm == -temp,"");
            DLIB_CASSERT(sm == 4*temp,"");
            sm -= sm;
            dsm -= dsm;
            DLIB_CASSERT(dsm == 0*temp,"");
            DLIB_CASSERT(sm == 0*temp,"");

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,3);
            dsm += sm+sm;
            DLIB_CASSERT(dsm == temp,"");

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,-1);
            dsm -= sm+sm;
            DLIB_CASSERT(dsm == temp,"");

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,-1);
            sm -= dsm+dsm;
            DLIB_CASSERT(sm == temp,"");

            set_all_elements(dsm,1);
            set_all_elements(sm,1);
            set_all_elements(temp,3);
            sm += dsm+dsm;
            DLIB_CASSERT(sm == temp,"");

            // test the implicit conversion to bool stuff
            {
                matrix<float> bt1(3,1);
                matrix<float,3,1> bt2;
                set_all_elements(bt1,2);
                set_all_elements(bt2,3);

                DLIB_CASSERT(trans(bt1)*bt2 == 18,"");
            }
            {
                matrix<float,3,1> bt1;
                matrix<float> bt2(3,1);
                set_all_elements(bt1,2);
                set_all_elements(bt2,3);

                DLIB_CASSERT(trans(bt1)*bt2 == 18,"");
            }
            {
                matrix<float> bt1(3,1);
                matrix<float> bt2(3,1);
                set_all_elements(bt1,2);
                set_all_elements(bt2,3);

                DLIB_CASSERT(trans(bt1)*bt2 == 18,"");
            }
            {
                matrix<float,3,1> bt1;
                matrix<float,3,1> bt2;
                set_all_elements(bt1,2);
                set_all_elements(bt2,3);

                DLIB_CASSERT(trans(bt1)*bt2 == 18,"");
            }

            {
                srand(423452);
                const long M = 50;
                const long N = 40;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double> u, u2;
                matrix<double> q, q2;
                matrix<double> v, v2;

                matrix<double> a2;
                a2 = tmp(a/2);

                svd2(true,true,a2+a2,u,q,v);

                double err = sum(round(1e10*(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))));
                DLIB_CASSERT(  err == 0,"err: " << err);
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,M>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");

                svd2(false,true,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");
                DLIB_CASSERT(equal(v2,v),"");
                svd2(true,false,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");
                DLIB_CASSERT(equal(u2,u),"");
                svd2(false,false,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");

            }

            {
                srand(423452);
                const long M = 3;
                const long N = 3;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double,M,M> u, u2;
                matrix<double> q, q2;
                matrix<double,N,N> v, v2;

                matrix<double,M,N,MM> a2;
                a2 = tmp(a/2);

                svd2(true,true,a2+a2,u,q,v);

                double err = sum(round(1e10*(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))));
                DLIB_CASSERT(  err == 0,"err: " << err);
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,M>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");

                svd2(false,true,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");
                DLIB_CASSERT(equal(v2,v),"");
                svd2(true,false,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");
                DLIB_CASSERT(equal(u2,u),"");
                svd2(false,false,a2+a2,u2,q2,v2);
                DLIB_CASSERT(equal(q2,q),"");

            }

            {
                srand(423452);
                const long M = 10;
                const long N = 7;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double,M,M> u;
                matrix<double> q;
                matrix<double,N,N> v;

                matrix<double,M,N,MM> a2;
                a2 = tmp(a/2);

                svd2(true,true,a2+a2,u,q,v);

                double err = sum(round(1e10*(a - subm(u,get_rect(a2+a2))*diagm(q)*trans(v))));
                DLIB_CASSERT(  err == 0,"err: " << err);
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,M>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");
            }

            {
                srand(423452);
                const long M = 10;
                const long N = 7;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double,M> u(M,N);
                matrix<double> w;
                matrix<double,N,N> v(N,N);

                matrix<double,M,N,MM> a2;
                a2 = tmp(a/2);

                svd(a2+a2,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,N>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");
            }

            {
                srand(423452);
                const long M = 1;
                const long N = 1;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double,M,N> u;
                matrix<double> w;
                matrix<double,N,N> v;

                matrix<double,M,N> a2;
                a2 = tmp(a/2);

                svd(a2+a2,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,N>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");
            }

            {
                srand(53434);
                const long M = 5;
                const long N = 5;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double,0,N> u(M,N);
                matrix<double,N,N> w;
                matrix<double> v;

                svd(a,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,N>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");
            }

            {
                srand(11234);
                const long M = 9;
                const long N = 4;

                matrix<double,0,0,MM> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double> u;
                matrix<double,0,0,MM> w;
                matrix<double> v;

                svd(a,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
                DLIB_CASSERT((round(1e10*trans(u)*u)  == 1e10*identity_matrix<double,N>()),"");
                DLIB_CASSERT((round(1e10*trans(v)*v)  == 1e10*identity_matrix<double,N>()),"");
            }

            {
                srand(53934);
                const long M = 2;
                const long N = 4;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double> u;
                matrix<double> w;
                matrix<double> v;

                svd(a,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
            }

            {
                srand(53234);
                const long M = 9;
                const long N = 40;

                matrix<double> a(M,N);
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = 10*((double)::rand())/RAND_MAX;
                    }
                }

                matrix<double> u;
                matrix<double> w;
                matrix<double> v;

                svd(a,u,w,v);

                DLIB_CASSERT(  sum(round(1e10*(a - u*w*trans(v)))) == 0,"");
            }

            {
                matrix<double> a(3,3);
                matrix<double,3,3> b;
                set_all_elements(a,0);

                a(0,0) = 1;
                a(1,1) = 2;
                a(2,2) = 3;
                b = a;

                DLIB_CASSERT(diag(a)(0) == 1,"");
                DLIB_CASSERT(diag(a)(1) == 2,"");
                DLIB_CASSERT(diag(a)(2) == 3,"");
                DLIB_CASSERT(diag(a).nr() == 3,"");
                DLIB_CASSERT(diag(a).nc() == 1,"");

                DLIB_CASSERT(diag(b)(0) == 1,"");
                DLIB_CASSERT(diag(b)(1) == 2,"");
                DLIB_CASSERT(diag(b)(2) == 3,"");
                DLIB_CASSERT(diag(b).nr() == 3,"");
                DLIB_CASSERT(diag(b).nc() == 1,"");

                DLIB_CASSERT(pointwise_multiply(a,b)(0,0) == 1,"");
                DLIB_CASSERT(pointwise_multiply(a,b)(1,1) == 4,"");
                DLIB_CASSERT(pointwise_multiply(a,b)(2,2) == 9,"");
                DLIB_CASSERT(pointwise_multiply(a,b)(1,0) == 0,"");
                DLIB_CASSERT(pointwise_multiply(a,b,a)(1,0) == 0,"");
                DLIB_CASSERT(pointwise_multiply(a,b,a,b)(1,0) == 0,"");

                DLIB_CASSERT(complex_matrix(a,b)(0,0) == std::complex<double>(1,1),"");
                DLIB_CASSERT(complex_matrix(a,b)(2,2) == std::complex<double>(3,3),"");
                DLIB_CASSERT(complex_matrix(a,b)(2,1) == std::complex<double>(0,0),"");
            }

            {
                matrix<float,3,1> m1, m2;
                set_all_elements(m1,2.0);
                set_all_elements(m2,1.0/2.0);
                DLIB_CASSERT(reciprocal(m1) == m2,"");
                DLIB_CASSERT((reciprocal(uniform_matrix<float,3,1>(2.0)) == m2),"");
                DLIB_CASSERT((round_zeros(uniform_matrix<float,3,1>(1e-8f)) == uniform_matrix<float,3,1>(0)) ,"");
                set_all_elements(m1,2.0);
                m2 = m1;
                m1(1,0) = static_cast<float>(1e-8);
                m2(1,0) = 0;
                DLIB_CASSERT(round_zeros(m1) == m2,"");
                m1 = round_zeros(m1);
                DLIB_CASSERT(m1 == m2,"");
            }

            {
                matrix<matrix<double,2,2> > m;
                m.set_size(3,3);
                set_all_elements(m,uniform_matrix<double,2,2>(1));
                DLIB_CASSERT((sum(m) == uniform_matrix<double,2,2>(9)),"");
                DLIB_CASSERT((round_zeros(sqrt(sum(m)) - uniform_matrix<double,2,2>(3)) == uniform_matrix<double,2,2>(0)),"");
            }

            {
                matrix<int,2,2> m1;
                matrix<int> m2;
                m2.set_size(2,2);

                set_all_elements(m1,2);
                m2 = uniform_matrix<int,2,2>(2);

                m1 = m1 + m2;
                DLIB_CASSERT((m1 == uniform_matrix<int,2,2>(4)),"");

                set_all_elements(m1,2);
                set_all_elements(m2,2);
                m1 = m1*m1;
                DLIB_CASSERT((m1 == uniform_matrix<int,2,2>(8)),"");

                m1(1,0) = 1;
                set_all_elements(m2,8);
                m2(0,1) = 1;
                m1 = trans(m1);
                DLIB_CASSERT(m1 == m2,"");
            }

            {
                matrix<double,2,3> m;
                matrix<double> m2(2,3);

                set_all_elements(m,1);
                DLIB_CASSERT(mean(m) == 1,"");
                set_all_elements(m,2);
                DLIB_CASSERT(mean(m) == 2,"");
                m(0,0) = 1;
                m(0,1) = 1;
                m(0,2) = 1;
                DLIB_CASSERT(abs(mean(m) - 1.5) < 1e-10,"");
                DLIB_CASSERT(abs(variance(m) - 0.3) < 1e-10,"");

                set_all_elements(m2,1);
                DLIB_CASSERT(mean(m2) == 1,"");
                set_all_elements(m2,2);
                DLIB_CASSERT(mean(m2) == 2,"");
                m2(0,0) = 1;
                m2(0,1) = 1;
                m2(0,2) = 1;
                DLIB_CASSERT(abs(mean(m2) - 1.5) < 1e-10,"");
                DLIB_CASSERT(abs(variance(m2) - 0.3) < 1e-10,"");

                set_all_elements(m,0);
                DLIB_CASSERT(abs(variance(m)) < 1e-10,"");
                set_all_elements(m,1);
                DLIB_CASSERT(abs(variance(m)) < 1e-10,"");
                set_all_elements(m,23.4);
                DLIB_CASSERT(abs(variance(m)) < 1e-10,"");
            }

            {
                matrix<matrix<double,3,1,MM>,2,2,MM> m;
                set_all_elements(m,uniform_matrix<double,3,1>(1));
                DLIB_CASSERT((round_zeros(variance(m)) == uniform_matrix<double,3,1>(0)),"");
                DLIB_CASSERT((round_zeros(mean(m)) == uniform_matrix<double,3,1>(1)),"");
                m(0,0) = uniform_matrix<double,3,1>(9);
                DLIB_CASSERT((round_zeros(variance(m)) == uniform_matrix<double,3,1>(16)),"");
                DLIB_CASSERT((round_zeros(mean(m)) == uniform_matrix<double,3,1>(3)),"");

                matrix<matrix<double> > m2(2,2);
                set_all_elements(m2,uniform_matrix<double,3,1>(1));
                DLIB_CASSERT((round_zeros(variance(m2)) == uniform_matrix<double,3,1>(0)),"");
                DLIB_CASSERT((round_zeros(mean(m2)) == uniform_matrix<double,3,1>(1)),"");
                m2(0,0) = uniform_matrix<double,3,1>(9);
                DLIB_CASSERT((round_zeros(variance(m2)) == uniform_matrix<double,3,1>(16)),"");
                DLIB_CASSERT((round_zeros(mean(m2)) == uniform_matrix<double,3,1>(3)),"");
            }

            {
                matrix<complex<double>,2,2,MM> m;
                set_all_elements(m,complex<double>(1,2));
                DLIB_CASSERT((conj(m) == uniform_matrix<complex<double>,2,2>(conj(m(0,0)))),"");
                DLIB_CASSERT((real(m) == uniform_matrix<double,2,2>(1)),"");
                DLIB_CASSERT((imag(m) == uniform_matrix<double,2,2>(2)),"");
                DLIB_CASSERT((sum(abs(norm(m) - uniform_matrix<double,2,2>(5))) < 1e-10 ),norm(m));

            }

            {
                matrix<double,5,5> m(5,5);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT(mi.nr() == m.nc(),"");
                DLIB_CASSERT(mi.nc() == m.nr(),"");
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())),"");
                DLIB_CASSERT((equal(round_zeros(m*mi,0.000001) , identity_matrix<double,5>())),"");
            }
            {
                matrix<double,5,0,MM> m(5,5);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())),"");
            }

            {
                matrix<double,0,5,MM> m(5,5);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())),"");
            }

            {
                matrix<double> m(5,5);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,5>())),"");
            }

            {
                matrix<double,5,2> m;

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT(mi.nr() == m.nc(),"");
                DLIB_CASSERT(mi.nc() == m.nr(),"");
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())),"");
            }

            {
                matrix<double> m(5,2);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m(r,c) = r*c;
                    }
                }

                m = cos(exp(m));

                matrix<double> mi = pinv(m );
                DLIB_CASSERT(mi.nr() == m.nc(),"");
                DLIB_CASSERT(mi.nc() == m.nr(),"");
                DLIB_CASSERT((equal(round_zeros(mi*m,0.000001) , identity_matrix<double,2>())),"");
            }

            {
                matrix<long> a1(5,1);
                matrix<long,0,0,MM> a2(1,5);
                matrix<long,5,1> b1(5,1);
                matrix<long,1,5> b2(1,5);
                matrix<long,0,1> c1(5,1);
                matrix<long,1,0> c2(1,5);
                matrix<long,0,1,MM> d1(5,1);
                matrix<long,1,0,MM> d2(1,5);

                for (long i = 0; i < 5; ++i)
                {
                    a1(i) = i;
                    a2(i) = i;
                    b1(i) = i;
                    b2(i) = i;
                    c1(i) = i;
                    c2(i) = i;
                    d1(i) = i;
                    d2(i) = i;
                }

                DLIB_CASSERT(a1 == trans(a2),"");
                DLIB_CASSERT(a1 == trans(b2),"");
                DLIB_CASSERT(a1 == trans(c2),"");
                DLIB_CASSERT(a1 == trans(d2),"");

                DLIB_CASSERT(a1 == b1,"");
                DLIB_CASSERT(a1 == c1,"");
                DLIB_CASSERT(a1 == d1,"");

                DLIB_CASSERT(trans(a1) == c2,"");
                DLIB_CASSERT(trans(b1) == c2,"");
                DLIB_CASSERT(trans(c1) == c2,"");
                DLIB_CASSERT(trans(d1) == c2,"");

                DLIB_CASSERT(sum(a1) == 10,"");
                DLIB_CASSERT(sum(a2) == 10,"");
                DLIB_CASSERT(sum(b1) == 10,"");
                DLIB_CASSERT(sum(b2) == 10,"");
                DLIB_CASSERT(sum(c1) == 10,"");
                DLIB_CASSERT(sum(c2) == 10,"");
                DLIB_CASSERT(sum(d1) == 10,"");
                DLIB_CASSERT(sum(d2) == 10,"");

                const matrix<long> orig1 = a1;
                const matrix<long> orig2 = a2;

                ostringstream sout;
                serialize(a1,sout);
                serialize(a2,sout);
                serialize(b1,sout);
                serialize(b2,sout);
                serialize(c1,sout);
                serialize(c2,sout);
                serialize(d1,sout);
                serialize(d2,sout);

                DLIB_CASSERT(a1 == orig1,"");
                DLIB_CASSERT(a2 == orig2,"");
                DLIB_CASSERT(b1 == orig1,"");
                DLIB_CASSERT(b2 == orig2,"");
                DLIB_CASSERT(c1 == orig1,"");
                DLIB_CASSERT(c2 == orig2,"");
                DLIB_CASSERT(d1 == orig1,"");
                DLIB_CASSERT(d2 == orig2,"");

                set_all_elements(a1,99);
                set_all_elements(a2,99);
                set_all_elements(b1,99);
                set_all_elements(b2,99);
                set_all_elements(c1,99);
                set_all_elements(c2,99);
                set_all_elements(d1,99);
                set_all_elements(d2,99);

                DLIB_CASSERT(a1 != orig1,"");
                DLIB_CASSERT(a2 != orig2,"");
                DLIB_CASSERT(b1 != orig1,"");
                DLIB_CASSERT(b2 != orig2,"");
                DLIB_CASSERT(c1 != orig1,"");
                DLIB_CASSERT(c2 != orig2,"");
                DLIB_CASSERT(d1 != orig1,"");
                DLIB_CASSERT(d2 != orig2,"");

                istringstream sin(sout.str());

                deserialize(a1,sin);
                deserialize(a2,sin);
                deserialize(b1,sin);
                deserialize(b2,sin);
                deserialize(c1,sin);
                deserialize(c2,sin);
                deserialize(d1,sin);
                deserialize(d2,sin);

                DLIB_CASSERT(a1 == orig1,"");
                DLIB_CASSERT(a2 == orig2,"");
                DLIB_CASSERT(b1 == orig1,"");
                DLIB_CASSERT(b2 == orig2,"");
                DLIB_CASSERT(c1 == orig1,"");
                DLIB_CASSERT(c2 == orig2,"");
                DLIB_CASSERT(d1 == orig1,"");
                DLIB_CASSERT(d2 == orig2,"");

            }

            {
                matrix<double,1,0> a(5);
                matrix<double,0,1> b(5);
                matrix<double,1,5> c(5);
                matrix<double,5,1> d(5);
                DLIB_CASSERT(a.nr() == 1,"");
                DLIB_CASSERT(a.nc() == 5,"");
                DLIB_CASSERT(c.nr() == 1,"");
                DLIB_CASSERT(c.nc() == 5,"");

                DLIB_CASSERT(b.nc() == 1,"");
                DLIB_CASSERT(b.nr() == 5,"");
                DLIB_CASSERT(d.nc() == 1,"");
                DLIB_CASSERT(d.nr() == 5,"");
            }

            {
                matrix<double,1,0> a;
                matrix<double,0,1> b;
                matrix<double,1,5> c;
                matrix<double,5,1> d;

                a.set_size(5);
                b.set_size(5);
                c.set_size(5);
                d.set_size(5);

                DLIB_CASSERT(a.nr() == 1,"");
                DLIB_CASSERT(a.nc() == 5,"");
                DLIB_CASSERT(c.nr() == 1,"");
                DLIB_CASSERT(c.nc() == 5,"");

                DLIB_CASSERT(b.nc() == 1,"");
                DLIB_CASSERT(b.nr() == 5,"");
                DLIB_CASSERT(d.nc() == 1,"");
                DLIB_CASSERT(d.nr() == 5,"");
            }

            {
                matrix<double> a(1,5);
                matrix<double> b(5,1);

                set_all_elements(a,1);
                set_all_elements(b,1);

                a = a*b;

                DLIB_CASSERT(a(0) == 5,"");
            }

            {
                matrix<double> a(6,7);

                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = r*a.nc() + c;
                    }
                }

                DLIB_CASSERT(rowm(a,1).nr() == 1,"");
                DLIB_CASSERT(rowm(a,1).nc() == a.nc(),"");
                DLIB_CASSERT(colm(a,1).nr() == a.nr(),"");
                DLIB_CASSERT(colm(a,1).nc() == 1,"");

                for (long c = 0; c < a.nc(); ++c)
                {
                    DLIB_CASSERT( rowm(a,1)(c) == 1*a.nc() + c,"");
                }

                for (long r = 0; r < a.nr(); ++r)
                {
                    DLIB_CASSERT( colm(a,1)(r) == r*a.nc() + 1,"");
                }

                rectangle rect(2, 1, 3+2-1, 2+1-1);
                DLIB_CASSERT(get_rect(a).contains(get_rect(a)), "");
                DLIB_CASSERT(get_rect(a).contains(rect), "");
                for (long r = 0; r < 2; ++r)
                {
                    for (long c = 0; c < 3; ++c)
                    {
                        DLIB_CASSERT(subm(a,1,2,2,3)(r,c) == (r+1)*a.nc() + c+2,"");
                        DLIB_CASSERT(subm(a,1,2,2,3) == subm(a,rect),"");
                    }
                }

                DLIB_CASSERT(subm(a,rectangle()).nr() == 0,"");
                DLIB_CASSERT(subm(a,rectangle()).nc() == 0,"");

            }

            {
                array2d<double>::kernel_1a_c a;
                a.set_size(6,7);

                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a[r][c] = r*a.nc() + c;
                    }
                }

                DLIB_CASSERT(rowm(array_to_matrix(a),1).nr() == 1,"");
                DLIB_CASSERT(rowm(array_to_matrix(a),1).nc() == a.nc(),"");
                DLIB_CASSERT(colm(array_to_matrix(a),1).nr() == a.nr(),"");
                DLIB_CASSERT(colm(array_to_matrix(a),1).nc() == 1,"");

                for (long c = 0; c < a.nc(); ++c)
                {
                    DLIB_CASSERT( rowm(array_to_matrix(a),1)(c) == 1*a.nc() + c,"");
                }

                for (long r = 0; r < a.nr(); ++r)
                {
                    DLIB_CASSERT( colm(array_to_matrix(a),1)(r) == r*a.nc() + 1,"");
                }

                for (long r = 0; r < 2; ++r)
                {
                    for (long c = 0; c < 3; ++c)
                    {
                        DLIB_CASSERT(subm(array_to_matrix(a),1,2,2,3)(r,c) == (r+1)*a.nc() + c+2,"");
                    }
                }

            }

            {
                array2d<double>::kernel_1a_c m;
                m.set_size(5,5);

                for (long r = 0; r < m.nr(); ++r)
                {
                    for (long c = 0; c < m.nc(); ++c)
                    {
                        m[r][c] = r*c;
                    }
                }

                matrix<double> mi = pinv(cos(exp(array_to_matrix(m))) );
                DLIB_CASSERT(mi.nr() == m.nc(),"");
                DLIB_CASSERT(mi.nc() == m.nr(),"");
                DLIB_CASSERT((equal(round_zeros(mi*cos(exp(array_to_matrix(m))),0.000001) , identity_matrix<double,5>())),"");
                DLIB_CASSERT((equal(round_zeros(cos(exp(array_to_matrix(m)))*mi,0.000001) , identity_matrix<double,5>())),"");
            }

            {
                matrix<long,5,5> m1, res;
                matrix<long,2,2> m2;

                set_all_elements(m1,0);

                long res_vals[] = {
                    9, 9, 9, 9, 9,
                    0, 1, 1, 0, 0,
                    0, 1, 1, 0, 2,
                    0, 0, 2, 2, 2,
                    0, 0, 2, 2, 0
                };

                res = res_vals;

                set_all_elements(m2, 1);
                set_subm(m1, rectangle(1,1,2,2)) = subm(m2,0,0,2,2);
                set_all_elements(m2, 2);
                set_subm(m1, 3,2,2,2) = m2;

                set_colm(m1,4) = trans(rowm(m1,4));
                set_rowm(m1,0) = 9;

                DLIB_CASSERT(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);

                set_subm(m1,0,0,5,5) = m1*m1;
                DLIB_CASSERT(m1 == res*res, "m1: \n" << m1 << "\nres*res: \n" << res*res);

                m1 = res;
                set_subm(m1,1,1,2,2) = subm(m1,0,0,2,2);

                long res_vals2[] = {
                    9, 9, 9, 9, 9,
                    0, 9, 9, 0, 0,
                    0, 0, 1, 0, 2,
                    0, 0, 2, 2, 2,
                    0, 0, 2, 2, 0
                };

                res = res_vals2;
                DLIB_CASSERT(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);

            }

            {
                matrix<long,5,5> m1, res;
                matrix<long,2,2> m2;

                set_all_elements(m1,0);

                long res_vals[] = {
                    9, 0, 3, 3, 0,
                    9, 2, 2, 2, 0,
                    9, 2, 2, 2, 0,
                    4, 4, 4, 4, 4,
                    9, 0, 3, 3, 0
                };
                long res_vals_c3[] = {
                    9, 0, 3, 0,
                    9, 2, 2, 0,
                    9, 2, 2, 0,
                    4, 4, 4, 4,
                    9, 0, 3, 0
                };
                long res_vals_r2[] = {
                    9, 0, 3, 3, 0,
                    9, 2, 2, 2, 0,
                    4, 4, 4, 4, 4,
                    9, 0, 3, 3, 0
                };

                matrix<long> temp;

                res = res_vals;

                temp = matrix<long,4,5>(res_vals_r2);
                DLIB_CASSERT(remove_row<2>(res) == temp,"");
                DLIB_CASSERT(remove_row<2>(res)(3,3) == 3,"");
                DLIB_CASSERT(remove_row<2>(res).nr() == 4,"");
                DLIB_CASSERT(remove_row<2>(res).nc() == 5,"");
                DLIB_CASSERT(remove_row(res,2) == temp,"");
                DLIB_CASSERT(remove_row(res,2)(3,3) == 3,"");
                DLIB_CASSERT(remove_row(res,2).nr() == 4,"");
                DLIB_CASSERT(remove_row(res,2).nc() == 5,"");

                temp = matrix<long,5,5>(res_vals);
                temp = remove_row(res,2);
                DLIB_CASSERT((temp == matrix<long,4,5>(res_vals_r2)),"");
                temp = matrix<long,5,5>(res_vals);
                temp = remove_col(res,3);
                DLIB_CASSERT((temp == matrix<long,5,4>(res_vals_c3)),"");

                matrix<long,3,1> vect;
                set_all_elements(vect,1);
                temp = identity_matrix<long>(3);
                temp = temp*vect;
                DLIB_CASSERT(temp == vect,"");

                temp = matrix<long,5,4>(res_vals_c3);
                DLIB_CASSERT(remove_col(res,3) == temp,"");
                DLIB_CASSERT(remove_col(res,3)(2,3) == 0,"");
                DLIB_CASSERT(remove_col(res,3).nr() == 5,"");
                DLIB_CASSERT(remove_col(res,3).nc() == 4,"");

                set_all_elements(m2, 1);
                set_subm(m1, rectangle(1,1,3,2)) = 2;
                set_all_elements(m2, 2);
                set_subm(m1, 3,2,2,2) = 3;

                set_colm(m1,0) = 9;
                set_rowm(m1,0) = rowm(m1,4);
                set_rowm(m1,3) = 4;

                DLIB_CASSERT(m1 == res, "m1: \n" << m1 << "\nres: \n" << res);

            }

            {

                const double stuff[] = {
                    1, 2, 3,
                    6, 3, 3,
                    7, 3, 9};

                matrix<double,3,3> m(stuff);

                // make m be symmetric
                m = m*trans(m);

                matrix<double> L = cholesky_decomposition(m);
                DLIB_CASSERT(equal(L*trans(L), m), "");

                DLIB_CASSERT(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "")
                DLIB_CASSERT(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10), identity_matrix<double>(3), 1e-10),"");
                DLIB_CASSERT(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(3),1e-10),"");

            }

            {

                const double stuff[] = {
                    1, 2, 3, 6, 3, 4,
                    6, 3, 3, 1, 2, 3,
                    7, 3, 9, 54.3, 5, 3,
                    -6, 3, -3, 1, 2, 3,
                    1, 2, 3, 5, -3, 3,
                    7, 3, -9, 54.3, 5, 3
                    };

                matrix<double,6,6> m(stuff);

                // make m be symmetric
                m = m*trans(m);

                matrix<double> L = cholesky_decomposition(m);
                DLIB_CASSERT(equal(L*trans(L), m, 1e-10), L*trans(L)-m);

                DLIB_CASSERT(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "")
                DLIB_CASSERT(equal(inv(m), trans(inv_lower_triangular(L))*inv_lower_triangular((L))), "")
                DLIB_CASSERT(equal(inv(m), trans(inv_lower_triangular(L))*trans(inv_upper_triangular(trans(L)))), "")
                DLIB_CASSERT(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix<double>(6), 1e-10),
                             round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10));
                DLIB_CASSERT(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(6), 1e-10),
                             round_zeros(inv_lower_triangular((L))*(L),1e-10));

            }

            {

                matrix<double,6,6> m(identity_matrix<double>(6)*4.5);

                matrix<double> L = cholesky_decomposition(m);
                DLIB_CASSERT(equal(L*trans(L), m, 1e-10), L*trans(L)-m);

                DLIB_CASSERT(equal(inv(m), inv_upper_triangular(trans(L))*inv_lower_triangular((L))), "")
                DLIB_CASSERT(equal(round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10) , identity_matrix<double>(6), 1e-10),
                             round_zeros(inv_upper_triangular(trans(L))*trans(L),1e-10));
                DLIB_CASSERT(equal(round_zeros(inv_lower_triangular((L))*(L),1e-10) ,identity_matrix<double>(6), 1e-10),
                             round_zeros(inv_lower_triangular((L))*(L),1e-10));

            }

            {

                matrix<double,6,6> m(identity_matrix<double>(6)*4.5);
                m(1,4) = 2;

                DLIB_CASSERT(dlib::equal(inv_upper_triangular(m), inv(m),1e-10), inv_upper_triangular(m)-inv(m));
                DLIB_CASSERT(dlib::equal(inv_lower_triangular(trans(m)), inv(trans(m)),1e-10), inv_lower_triangular(trans(m))-inv(trans(m)));

            }

            {
                matrix<double> a;
                matrix<float> b;
                matrix<int> i;
                a.set_size(1000,10);
                b.set_size(1000,10);
                i.set_size(1000,10);
                dlib::rand::float_1a rnd;
                for (long r = 0; r < a.nr(); ++r)
                {
                    for (long c = 0; c < a.nc(); ++c)
                    {
                        a(r,c) = rnd.get_random_double();
                        b(r,c) = rnd.get_random_float();
                        i(r,c) = r+c*r;
                    }
                }

                // make sure the multiply optimizations aren't messing things up
                DLIB_CASSERT(trans(i)*i == tmp(trans(i)*i),"");
                DLIB_CASSERT(equal(trans(a)*a , tmp(trans(a)*a), 1e-11),max(abs(trans(a)*a - tmp(trans(a)*a))));
                DLIB_CASSERT(equal(trans(b)*b , tmp(trans(b)*b), 1e-3f),max(abs(trans(b)*b - tmp(trans(b)*b))));
            }

            {
                matrix<int,4> i(4,1);
                i(0) = 1;
                i(1) = 2;
                i(2) = 3;
                i(3) = 4;
                matrix<int,4,4> m;
                set_all_elements(m,0);
                m(0,0) = 1;
                m(1,1) = 2;
                m(2,2) = 3;
                m(3,3) = 4;

                DLIB_CASSERT(diagm(i) == m,"");
            }

            {
                matrix<int,1,4> i;
                i(0) = 1;
                i(1) = 2;
                i(2) = 3;
                i(3) = 4;
                matrix<int,4,4> m;
                set_all_elements(m,0);
                m(0,0) = 1;
                m(1,1) = 2;
                m(2,2) = 3;
                m(3,3) = 4;

                DLIB_CASSERT(diagm(i) == m,"");
            }

            {
                matrix<int> i(4,1);
                i(0) = 1;
                i(1) = 2;
                i(2) = 3;
                i(3) = 4;
                matrix<int> m(4,4);
                set_all_elements(m,0);
                m(0,0) = 1;
                m(1,1) = 2;
                m(2,2) = 3;
                m(3,3) = 4;

                DLIB_CASSERT(diagm(i) == m,"");
            }

            {
                matrix<int> i(1,4);
                i(0) = 1;
                i(1) = 2;
                i(2) = 3;
                i(3) = 4;
                matrix<int> m(4,4);
                set_all_elements(m,0);
                m(0,0) = 1;
                m(1,1) = 2;
                m(2,2) = 3;
                m(3,3) = 4;

                DLIB_CASSERT(diagm(i) == m,"");
            }

        }

        class matrix_tester : public tester
        {
        public:
            matrix_tester (
            ) :
                tester ("test_matrix",
                        "Runs tests on the matrix component.")
            {}

            void perform_test (
            )
            {
                matrix_test();
            }
        } a;

    }