Exemplo n.º 1
0
        public void MatrixInverseTest(int rounds, int count,
                                      bool doLuM = true, bool doLuV = true, bool doLu2 = true,
                                      bool doGj2 = false,
                                      bool doQrI = true, bool doQr2 = true)
        {
            bool   doMul     = true;
            double luEpsilon = 1e-5;
            double qrEpsilon = 4e-5;

            Test.Begin("matrix inverse tests");
            Report.Line("epsilon for lu tests: {0:e0}", luEpsilon);
            Report.Line("epsilon for qr tests: {0:e0}", qrEpsilon);
            bool showWorst = true;
            bool showTypes = true;
            var  rnd       = new RandomSystem(19680713);

            var tc           = 4;
            var typeStatsOpt = Stats <M44d> .ComputeCountMaxMean;

            Stats <M44d>[] luiTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] lumTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] luvTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] lu2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] gj2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] qriTypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            Stats <M44d>[] qr2TypeStats = new Stats <M44d> [tc].Set(typeStatsOpt);
            string[]       typenames    = new string[] { "Rotation", "Scale", "Translation", "Mixed" };

            var histoStatsOpt = StatsOptions.MaxMean;
            var luiHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var lumHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var luvHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var lu2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var gj2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var qriHistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);
            var qr2HistoStats = new HistogramAndStats <M44d>(-16, 0, 16, histoStatsOpt);

            M44d[] mats  = new M44d[count];
            M44d[] luis  = new M44d[count];
            M44d[] lums  = new M44d[count];
            M44d[] luvs  = new M44d[count];
            M44d[] lu2s  = new M44d[count];
            M44d[] gj2s  = new M44d[count];
            M44d[] qris  = new M44d[count];
            M44d[] qr2s  = new M44d[count];
            int[]  types = new int[count].SetByIndex(i => - 1);

            bool failedLuM = false, failedLuV = false, failedLu2 = false;
            bool failedQr2  = false;
            var  chainStats = new Stats <bool>(StatsOptions.MaxMean);

            for (int j = 0; j < rounds; j++)
            {
                using (Report.JobTimed("creating {0} matrices round {1} of {2}", count, j + 1, rounds))
                    for (int i = 0; i < count; i++)
                    {
                        M44d mat         = M44d.Identity;
                        var  chainLength = 0;
                        do
                        {
                            int type = rnd.UniformInt(3);
                            if (types[i] == -1)
                            {
                                types[i] = type;
                            }
                            else if (types[i] != type)
                            {
                                types[i] = 3; //mixed type
                            }
                            switch (type)
                            {
                            case 0:
                                V3d    axis          = V3d.Zero;
                                double squaredLength = 0.0;
                                do
                                {
                                    axis = new V3d(2 * rnd.UniformDoubleFullClosed() - 1,
                                                   2 * rnd.UniformDoubleFullClosed() - 1,
                                                   2 * rnd.UniformDoubleFullClosed() - 1);
                                    squaredLength = axis.LengthSquared;
                                }while (squaredLength == 0);
                                axis *= 1.0 / Fun.Sqrt(squaredLength);
                                double alpha = 2 * Constant.Pi * rnd.UniformDoubleFull()
                                               - Constant.Pi;
                                M44d rot = M44d.Rotation(axis, alpha);
                                mat = rot * mat;
                                chainLength++;
                                break;

                            case 1:
                                var  s0    = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0;
                                var  s1    = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0;
                                var  s2    = rnd.UniformDouble() < 0.5 ? -4.0 : 4.0;
                                M44d scale = M44d.Scale(
                                    s0 * (1.0 - rnd.UniformDoubleFull()),
                                    s1 * (1.0 - rnd.UniformDoubleFull()),
                                    s2 * (1.0 - rnd.UniformDoubleFull()));
                                mat = scale * mat;
                                chainLength++;
                                break;

                            case 2:
                                M44d shift = M44d.Translation(
                                    32 * rnd.UniformDoubleFullClosed() - 16,
                                    32 * rnd.UniformDoubleFullClosed() - 16,
                                    32 * rnd.UniformDoubleFullClosed() - 16);
                                mat = shift * mat;
                                chainLength++;
                                break;

                            default:
                                break;
                            }
                        }while (rnd.UniformDouble() > 0.25);
                        mats[i] = mat;
                        chainStats.Add(chainLength);
                    }

                if (doQr2)
                {
                    using (Report.JobTimed("qr [,] factorization"))
                        for (int i = 0; i < count; i++)
                        {
                            qr2s[i] = mats[i].QrInverse2();
                        }
                }

                if (doQrI)
                {
                    using (Report.JobTimed("qr factorization"))
                        for (int i = 0; i < count; i++)
                        {
                            qris[i] = mats[i].QrInverse();
                        }
                }

                if (doGj2)
                {
                    using (Report.JobTimed("gauss jordan"))
                        for (int i = 0; i < count; i++)
                        {
                            gj2s[i] = mats[i].NumericallyInstableGjInverse2();
                        }
                }

                if (doLu2)
                {
                    using (Report.JobTimed("lu [,] factorization"))
                        for (int i = 0; i < count; i++)
                        {
                            lu2s[i] = mats[i].LuInverse2();
                        }
                }

                if (doLuV)
                {
                    using (Report.JobTimed("lu vector solve factorization"))
                        for (int i = 0; i < count; i++)
                        {
                            luvs[i] = mats[i].LuInverseV();
                        }
                }

                if (doLuM)
                {
                    using (Report.JobTimed("lu matrix solve factorization"))
                        for (int i = 0; i < count; i++)
                        {
                            lums[i] = mats[i].LuInverseM();
                        }
                }

                using (Report.JobTimed("lu factorization"))
                    for (int i = 0; i < count; i++)
                    {
                        luis[i] = mats[i].LuInverse();
                    }

                Test.Begin("analysis");
                for (int i = 0; i < count; i++)
                {
                    M44d   luid  = mats[i] * luis[i];
                    double plErr = M44d.DistanceMax(luid, M44d.Identity);
                    Test.IsTrue(plErr < luEpsilon);
                    luiHistoStats.AddLog10Hist(plErr, mats[i]);
                    luiTypeStats[types[i]].Add(plErr);
                    if (doMul)
                    {
                        var    m0       = new Matrix <double>((double[])mats[i], 4, 4);
                        var    m1       = new Matrix <double>((double[])luis[i], 4, 4);
                        var    id       = m0.Multiply(m1);
                        double deltaErr = M44d.Distance1(luid, new M44d(id.Data));
                        Test.IsTrue(deltaErr == 0.0);
                    }


                    if (doLuM)
                    {
                        M44d   msid  = mats[i] * lums[i];
                        double error = M44d.DistanceMax(msid, M44d.Identity);
                        lumHistoStats.AddLog10Hist(error, mats[i]);
                        lumTypeStats[types[i]].Add(error);
                        double deltaErr = M44d.Distance1(luis[i], lums[i]);
                        if (!Test.IsTrue(deltaErr == 0.0))
                        {
                            failedLuM = true;
                        }
                    }
                    if (doLuV)
                    {
                        M44d   vsid  = mats[i] * luvs[i];
                        double error = M44d.DistanceMax(vsid, M44d.Identity);
                        luvHistoStats.AddLog10Hist(error, mats[i]);
                        luvTypeStats[types[i]].Add(error);
                        double deltaErr = M44d.Distance1(luis[i], luvs[i]);
                        if (!Test.IsTrue(deltaErr == 0.0))
                        {
                            failedLuV = true;
                        }
                    }
                    if (doLu2)
                    {
                        M44d   a2id  = mats[i] * lu2s[i];
                        double error = M44d.DistanceMax(a2id, M44d.Identity);
                        lu2HistoStats.AddLog10Hist(error, mats[i]);
                        lu2TypeStats[types[i]].Add(error);
                        double deltaErr = M44d.Distance1(luis[i], lu2s[i]);
                        if (!Test.IsTrue(deltaErr == 0.0))
                        {
                            failedLu2 = true;
                        }
                    }
                    if (doGj2)
                    {
                        M44d   gjid  = mats[i] * gj2s[i];
                        double error = M44d.DistanceMax(gjid, M44d.Identity);
                        gj2HistoStats.AddLog10Hist(error, mats[i]);
                        gj2TypeStats[types[i]].Add(error);
                    }
                    if (doQrI)
                    {
                        M44d   qrid  = mats[i] * qris[i];
                        double error = M44d.DistanceMax(qrid, M44d.Identity);
                        qriHistoStats.AddLog10Hist(error, mats[i]);
                        qriTypeStats[types[i]].Add(error);
                        Test.IsTrue(error < qrEpsilon);
                    }
                    if (doQr2)
                    {
                        M44d   qrid  = mats[i] * qr2s[i];
                        double error = M44d.DistanceMax(qrid, M44d.Identity);
                        qr2HistoStats.AddLog10Hist(error, mats[i]);
                        qr2TypeStats[types[i]].Add(error);
                        double deltaErr = M44d.Distance1(qris[i], qr2s[i]);
                        if (!Test.IsTrue(deltaErr == 0.0))
                        {
                            failedQr2 = true;
                        }
                    }
                }
                Test.End();
            }

            Report.Value("matrix chain lengths", chainStats);
            Report.Value("lu factorization error", luiHistoStats.Stats);
            if (showTypes)
            {
                for (int ti = 0; ti < tc; ti++)
                {
                    Report.Value("lu " + typenames[ti] + " matrix factorization error",
                                 luiTypeStats[ti]);
                }
            }
            Report.Value("lu factorization log error histogram", luiHistoStats.Histogram);

            if (showWorst)
            {
                using (Report.Job("worst matrix")) WriteMat(luiHistoStats.Stats.MaxData);
                using (Report.Job("worst inverse")) WriteMat(luiHistoStats.Stats.MaxData.LuInverse());
                using (Report.Job("worst result")) WriteMat(luiHistoStats.Stats.MaxData
                                                            * luiHistoStats.Stats.MaxData.LuInverse());
            }

            if (failedLuM)
            {
                Report.Value("lu matrix solve factorization error", lumHistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("lu matrix solve " + typenames[ti] + " matrix factorization error",
                                     lumTypeStats[ti]);
                    }
                }
                Report.Value("lu matrix solve factorization log error histogram", lumHistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(lumHistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(lumHistoStats.Stats.MaxData.LuInverseM());
                    using (Report.Job("worst result")) WriteMat(lumHistoStats.Stats.MaxData
                                                                * lumHistoStats.Stats.MaxData.LuInverseM());
                }
            }

            if (failedLuV)
            {
                Report.Value("lu vector solve factorization error", luvHistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("lu vector solve " + typenames[ti] + " matrix factorization error",
                                     luvTypeStats[ti]);
                    }
                }
                Report.Value("lu vector solve factorization log error histogram", luvHistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(luvHistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(luvHistoStats.Stats.MaxData.LuInverseV());
                    using (Report.Job("worst result")) WriteMat(luvHistoStats.Stats.MaxData
                                                                * luvHistoStats.Stats.MaxData.LuInverseV());
                }
            }

            if (failedLu2)
            {
                Report.Value("lu [,] factorization error", lu2HistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("lu [,] " + typenames[ti] + " matrix factorization error",
                                     lu2TypeStats[ti]);
                    }
                }
                Report.Value("lu [,] factorization log error histogram", lu2HistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(lu2HistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(lu2HistoStats.Stats.MaxData.LuInverse2());
                    using (Report.Job("worst result")) WriteMat(lu2HistoStats.Stats.MaxData
                                                                * lu2HistoStats.Stats.MaxData.LuInverse2());
                }
            }

            if (doGj2)
            {
                Report.Value("gauss jordan error", gj2HistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("gj " + typenames[ti] + " matrix factorization error",
                                     gj2TypeStats[ti]);
                    }
                }
                Report.Value("gauss jordan log error histogram", gj2HistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(gj2HistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(gj2HistoStats.Stats.MaxData.NumericallyInstableGjInverse2());
                    using (Report.Job("worst result")) WriteMat(gj2HistoStats.Stats.MaxData
                                                                * gj2HistoStats.Stats.MaxData.NumericallyInstableGjInverse2());
                }
            }

            if (doQrI)
            {
                Report.Value("qr factorization error", qr2HistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("qr " + typenames[ti] + " matrix factorization error",
                                     qriTypeStats[ti]);
                    }
                }
                Report.Value("qr factorization log error histogram", qriHistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(qriHistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(qriHistoStats.Stats.MaxData.QrInverse());
                    using (Report.Job("worst result")) WriteMat(qriHistoStats.Stats.MaxData
                                                                * qriHistoStats.Stats.MaxData.QrInverse());
                }
            }
            if (failedQr2)
            {
                Report.Value("qr [,] factorization error", qr2HistoStats.Stats);
                if (showTypes)
                {
                    for (int ti = 0; ti < tc; ti++)
                    {
                        Report.Value("qr [,] " + typenames[ti] + " matrix factorization error",
                                     qr2TypeStats[ti]);
                    }
                }
                Report.Value("qr [,] factorization log error histogram", qr2HistoStats.Histogram);
                if (showWorst)
                {
                    using (Report.Job("worst matrix")) WriteMat(qr2HistoStats.Stats.MaxData);
                    using (Report.Job("worst inverse")) WriteMat(qr2HistoStats.Stats.MaxData.QrInverse2());
                    using (Report.Job("worst result")) WriteMat(qr2HistoStats.Stats.MaxData
                                                                * qr2HistoStats.Stats.MaxData.QrInverse2());
                }
            }
            Test.End();
        }