예제 #1
0
        /// <summary>Creates a 'n x r' matrix B such that B * B' is a correlation matrix and 'near' to the specified symmetric, normalized matrix of dimension n. A rank reduction will apply if r is strict less than n.
        /// </summary>
        /// <param name="rawCorrelationMatrix">The symmetric, normalized matrix where to find the 'nearest' correlation matrix.</param>
        /// <param name="state">The state of the operation in its <see cref="PseudoSqrtMatrixDecomposer.State"/> representation (output).</param>
        /// <param name="triangularMatrixType">A value indicating which part of <paramref name="rawCorrelationMatrix"/> to take into account.</param>
        /// <param name="outputEntries">This argument will be used to store the matrix entries of the resulting matrix B, i.e. the return value array points to this array if != <c>null</c>; otherwise a memory allocation will be done.</param>
        /// <param name="worksspaceContainer">A specific <see cref="PseudoSqrtMatrixDecomposer.WorkspaceContainer"/> object to reduce memory allocation; ignored if <c>null</c>.</param>
        /// <returns>A <see cref="DenseMatrix"/> object that represents a matrix B such that B * B' is the 'nearest' correlation matrix with respect to <paramref name="rawCorrelationMatrix"/>.</returns>
        /// <remarks>In general the return object does <b>not</b> represents the pseudo-root of <paramref name="rawCorrelationMatrix"/>, i.e. output of the Cholesky decomposition.
        /// <para>The parameters <paramref name="outputEntries"/>, <paramref name="worksspaceContainer"/> allows to avoid memory allocation and to re-use arrays if the calculation of correlation matrices will be done often.</para></remarks>
        public override DenseMatrix Create(DenseMatrix rawCorrelationMatrix, out State state, double[] outputEntries = null, PseudoSqrtMatrixDecomposer.WorkspaceContainer worksspaceContainer = null, BLAS.TriangularMatrixType triangularMatrixType = BLAS.TriangularMatrixType.LowerTriangularMatrix)
        {
            if (rawCorrelationMatrix.IsQuadratic == false)
            {
                throw new ArgumentException("rawCorrelationMatrix");
            }
            int n = rawCorrelationMatrix.RowCount;

            var ws = worksspaceContainer as Workspace;

            if ((ws == null) || (ws.Dimension < n))
            {
                ws = new Workspace(n, this);
            }

            /* calculate an initial value for the optimizer:
             *   (i) Apply the EZN algorithm for the calculation of a matrix B_0 such that B_0 * B_0^t is near to the (raw) correlation matrix
             *   (ii) calculate angle parameters \theta such that B_0 = B(\theta).
             *  */
            State initState;
            var   initialAngleParameterMatrix = GetAngleParameter(m_InitialDecomposer.Create(rawCorrelationMatrix, out initState, outputEntries, ws.InitalDecomposerWorkspace, triangularMatrixType), ws.ArgMinData);

            /* prepare and apply optimization algorithm: */
            int rank = initState.Rank;

            if ((outputEntries == null) || (outputEntries.Length < n * n))
            {
                outputEntries = new double[n * rank];
            }

            var B            = new DenseMatrix(n, rank, outputEntries, createDeepCopyOfArgument: false);
            var C            = new DenseMatrix(n, n, ws.CorrelationMatrixData, createDeepCopyOfArgument: false);
            var optAlgorithm = m_MultiDimOptimizer.Create(n * (rank - 1));

            optAlgorithm.SetFunction(theta =>
            {
                GetParametricMatrix(theta, B);
                C.AddAssignment(B, B.T, beta: 0.0); // C = B * B^t

                VectorUnit.Basics.Sub(n * n, C.Data, rawCorrelationMatrix.Data, ws.TempDifferences);
                return(BLAS.Level1.dnrm2sq(n * n, ws.TempDifferences));
            });
            double minimum;
            var    optState = optAlgorithm.FindMinimum(ws.ArgMinData, out minimum);

            state = State.Create(rank, optState.IterationsNeeded, InfoOutputDetailLevel,
                                 Tuple.Create <string, IInfoOutputQueriable>("Initial.State", initState),
                                 Tuple.Create <string, IInfoOutputQueriable>("Final.Optimizer", optState),
                                 Tuple.Create <string, IInfoOutputQueriable>("Initial.Parameters", initialAngleParameterMatrix),
                                 InfoOutputDetailLevel.IsAtLeastAsComprehensiveAs(InfoOutputDetailLevel.High) ? Tuple.Create <string, IInfoOutputQueriable>("Final.Parameters", new DenseMatrix(n, rank, ws.ArgMinData, createDeepCopyOfArgument: false)) : null
                                 );

            GetParametricMatrix(ws.ArgMinData, B); // B should be already set to B(\theta^*), we just want to be sure that B is correct on exit
            return(B);
        }
        public void Create_RebonatoJaeckelExample2_BenchmarkResult()
        {
            int n = 3;
            var rawCorrelationMatrix = new DenseMatrix(n, n, new[] { 1.0, 0.9, 0.7, 0.9, 1.0, 0.3, 0.7, 0.3, 1.0 });

            var matrixDecomposer = new EznMatrixDecomposer(BasicComponents.Containers.InfoOutputDetailLevel.Full);

            PseudoSqrtMatrixDecomposer.State state;
            var actual = matrixDecomposer.Create(rawCorrelationMatrix, out state);

            int expectedRank = 2;

            Assert.That(state.Rank, Is.EqualTo(expectedRank), String.Format("Rank should be {0}, but was {1}.", expectedRank, state.Rank));

            var expected = new DenseMatrix(n, state.Rank, new[] { // the values taken from the reference are re-ordered and with a negative sign
                -0.06238, -0.50292, 0.67290,
                -0.99805, -0.86434, -0.73974
            });

            Assert.That(actual.Data.Take(actual.RowCount * actual.ColumnCount).ToArray(), Is.EqualTo(expected.Data).AsCollection.Within(1E-4));
        }
        public void CreateSymmetric_RebonatoJaeckelExample2_BenchmarkResult()
        {
            int n = 3;
            var rawCorrelationMatrix = new SymmetricMatrix(n, new[] { 1.0, 0.9, 0.7, 1.0, 0.3, 1.0 });

            var matrixDecomposer = new EznMatrixDecomposer();
            int rank;

            var actual = matrixDecomposer.Create(rawCorrelationMatrix, out rank);

            int expectedRank = 2;

            Assert.That(rank, Is.EqualTo(expectedRank), String.Format("Rank should be {0}, but was {1}.", expectedRank, rank));

            var expected = new DenseMatrix(n, rank, new[] { // the values taken from the reference are re-ordered and same(!) columns are with a negative sign
                -0.06238, -0.50292, 0.67290,
                0.99805, 0.86434, 0.73974
            });

            Assert.That(actual.Data.Take(actual.RowCount * actual.ColumnCount).ToArray(), Is.EqualTo(expected.Data).AsCollection.Within(1E-4));
        }
        public void Create_RebonatoJaeckelExample1_BenchmarkResult()
        {
            int n = 3;
            var rawCorrelationMatrix = new DenseMatrix(n, n, new[] {
                1.0, 0.9, 0.7,
                0.9, 1.0, 0.4,
                0.7, 0.4, 1.0
            });

            var matrixDecomposer = new EznMatrixDecomposer();

            PseudoSqrtMatrixDecomposer.State state;
            var actual = matrixDecomposer.Create(rawCorrelationMatrix, out state);

            Assert.That(state.Rank, Is.EqualTo(n), String.Format("Rank should be {0}, but was {1}.", n, state.Rank));

            var expected = new DenseMatrix(n, n, new[] {  // the values taken from the reference are re-ordered with a negative sign
                0.13192, -0.10021, -0.05389,
                -0.08718, -0.45536, 0.63329,
                -0.98742, -0.88465, -0.77203
            });

            Assert.That(actual.Data, Is.EqualTo(expected.Data).AsCollection.Within(1E-4));
        }