コード例 #1
0
        public static void Test02()
        {
            int NR = 100;
            int NC = 5;

            // erzeuge Basisfunktionen
            var X = new DoubleMatrix(NR, NC);

            for (int c = 0; c < 5; ++c)
            {
                double rt = (c + 1) * 4;
                for (int r = 0; r < NR; ++r)
                {
                    X[r, c] = Math.Exp(-r / rt);
                }
            }

            var y = new DoubleMatrix(NR, 1);

            for (int r = 0; r < NR; ++r)
            {
                double sum = 0;
                for (int c = 0; c < 5; ++c)
                {
                    double amp = 1 - 0.4 * Math.Abs(c - 2);
                    sum += amp * X[r, c];
                }
                y[r, 0] = sum;
            }

            var XtX = new DoubleMatrix(5, 5);

            MatrixMath.MultiplyFirstTransposed(X, X, XtX);

            var Xty = new DoubleMatrix(5, 1);

            MatrixMath.MultiplyFirstTransposed(X, y, Xty);
            FastNonnegativeLeastSquares.Execution(XtX, Xty, null, out var x, out var w);

            Assert.AreEqual(0.2, x[0, 0], 1e-6);
            Assert.AreEqual(0.6, x[1, 0], 1e-6);
            Assert.AreEqual(1.0, x[2, 0], 1e-6);
            Assert.AreEqual(0.6, x[3, 0], 1e-6);
            Assert.AreEqual(0.2, x[4, 0], 1e-6);
        }
コード例 #2
0
        /// <summary>Solves system of linear equations Ax = b using Gaussian elimination with partial pivoting.</summary>
        /// <param name="A">Elements of matrix 'A'. This array is modified during solution!</param>
        /// <param name="b">Right part 'b'. This array is also modified during solution!</param>
        /// <param name="x">Vector to store the result, i.e. the solution to the problem a x = b.</param>
        public void Solve(IROMatrix <double> A, IReadOnlyList <double> b, IVector <double> x)
        {
            if (_temp_A.RowCount != A.RowCount || _temp_A.ColumnCount != A.ColumnCount)
            {
                _temp_A = new MatrixWrapperStructForLeftSpineJaggedArray <double>(A.RowCount, A.ColumnCount);
            }
            if (b.Count != _temp_b?.Length)
            {
                _temp_b = new double[b.Count];
            }
            if (b.Count != _temp_x?.Length)
            {
                _temp_x = new double[b.Count];
            }

            MatrixMath.Copy(A, _temp_A);
            VectorMath.Copy(b, _temp_b);
            SolveDestructive(_temp_A, _temp_b, _temp_x);
            VectorMath.Copy(_temp_x, x);
        }
コード例 #3
0
ファイル: WorksheetAnalysis.cs プロジェクト: Altaxo/Altaxo
		/// <summary>
		/// For a given set of spectra, predicts the y-values and stores them in the matrix <c>predictedY</c>
		/// </summary>
		/// <param name="mcalib">The calibration model of the analysis.</param>
		/// <param name="preprocessOptions">The information how to preprocess the spectra.</param>
		/// <param name="matrixX">The matrix of spectra to predict. Each spectrum is a row in the matrix.</param>
		/// <param name="numberOfFactors">The number of factors used for prediction.</param>
		/// <param name="predictedY">On return, this matrix holds the predicted y-values. Each row in this matrix corresponds to the same row (spectrum) in matrixX.</param>
		/// <param name="spectralResiduals">If you set this parameter to a appropriate matrix, the spectral residuals will be stored in this matrix. Set this parameter to null if you don't need the residuals.</param>
		public virtual void CalculatePredictedY(
			IMultivariateCalibrationModel mcalib,
			SpectralPreprocessingOptions preprocessOptions,
			IMatrix matrixX,
			int numberOfFactors,
			MatrixMath.BEMatrix predictedY,
			IMatrix spectralResiduals)
		{
			MultivariateRegression.PreprocessSpectraForPrediction(mcalib, preprocessOptions, matrixX);

			MultivariateRegression regress = this.CreateNewRegressionObject();
			regress.SetCalibrationModel(mcalib);

			regress.PredictedYAndSpectralResidualsFromPreprocessed(matrixX, numberOfFactors, predictedY, spectralResiduals);

			MultivariateRegression.PostprocessY(mcalib.PreprocessingModel, predictedY);
		}
コード例 #4
0
ファイル: QRDecomposition.cs プロジェクト: olesar/Altaxo
        /** Least squares solution of A*X = B
         *          @param B    A Matrix with as many rows as A and any number of columns.
         *          @return     X that minimizes the two norm of Q*R*X-B.
         *          @exception  IllegalArgumentException  Matrix row dimensions must agree.
         *          @exception  RuntimeException  Matrix is rank deficient.
         */

        public void Solve(IROMatrix <double> B, IMatrix <double> result)
        {
            if (B.RowCount != m)
            {
                throw new ArgumentException("Matrix row dimensions must agree.");
            }
            if (!IsFullRank())
            {
                throw new Exception("Matrix is rank deficient.");
            }

            // Copy right hand side
            int nx = B.ColumnCount;

            double[][] X;
            if (_solveMatrixWorkspace != null && _solveMatrixWorkspace.RowCount == B.RowCount && _solveMatrixWorkspace.ColumnCount == B.ColumnCount)
            {
                X = _solveMatrixWorkspace.Array;
                MatrixMath.Copy(B, _solveMatrixWorkspace);
            }
            else
            {
                X = JaggedArrayMath.GetMatrixCopy(B);
                _solveMatrixWorkspace = new JaggedArrayMatrix(X, B.RowCount, B.ColumnCount);
            }

            // Compute Y = transpose(Q)*B
            for (int k = 0; k < n; k++)
            {
                for (int j = 0; j < nx; j++)
                {
                    double s = 0.0;
                    for (int i = k; i < m; i++)
                    {
                        s += QR[i][k] * X[i][j];
                    }
                    s = -s / QR[k][k];
                    for (int i = k; i < m; i++)
                    {
                        X[i][j] += s * QR[i][k];
                    }
                }
            }
            // Solve R*X = Y;
            for (int k = n - 1; k >= 0; k--)
            {
                for (int j = 0; j < nx; j++)
                {
                    X[k][j] /= Rdiag[k];
                }
                for (int i = 0; i < k; i++)
                {
                    for (int j = 0; j < nx; j++)
                    {
                        X[i][j] -= X[k][j] * QR[i][k];
                    }
                }
            }

            MatrixMath.Submatrix(_solveMatrixWorkspace, result, 0, 0);
        }
        /// <summary>
        /// Factorize a nonnegative matrix A into two nonnegative matrices B and C so that A is nearly equal to B*C.
        /// Tikhonovs the nm f3.
        /// </summary>
        /// <param name="A">Matrix to factorize.</param>
        /// <param name="r">The number of factors.</param>
        /// <param name="B0">Original B matrix. Can be null.</param>
        /// <param name="C0">Original C matrix. Can be null.</param>
        /// <param name="oldalpha">The oldalpha.</param>
        /// <param name="oldbeta">The oldbeta.</param>
        /// <param name="gammaB">The gamma b.</param>
        /// <param name="gammaC">The gamma c.</param>
        /// <param name="maxiter">The maxiter.</param>
        /// <param name="tol">The tol.</param>
        public static void TikhonovNMF3(
            IMatrix <double> A,
            int r,
            IMatrix <double> B0,
            IMatrix <double> C0,
            IVector <double> oldalpha,
            IVector <double> oldbeta,
            IMatrix <double> gammaB,
            IMatrix <double> gammaC,
            int maxiter,
            double tol)
        {
            // The converged version of the algorithm
            // Use complementary slackness as stopping criterion
            // format long;
            // Check the input matrix

            if (null == A)
            {
                throw new ArgumentNullException(nameof(A));
            }

            if (MatrixMath.Min(A) < 0)
            {
                throw new ArgumentException("Input matrix must not contain negative elements", nameof(A));
            }

            int m = A.RowCount;
            int n = A.ColumnCount;

            // Check input arguments

            //if ˜exist(’r’)

            if (null == B0)
            {
                B0 = DoubleMatrix.Random(m, r);
            }

            if (null == C0)
            {
                C0 = DoubleMatrix.Random(r, n);
            }

            if (null == oldalpha)
            {
                oldalpha = new DoubleVector(n);
            }

            if (null == oldbeta)
            {
                oldbeta = new DoubleVector(m);
            }

            if (null == gammaB)
            {
                gammaB = new DoubleMatrix(m, 1);
                gammaB.SetMatrixElements(0.1); // small values lead to better convergence property
            }

            if (null == gammaC)
            {
                gammaC = new DoubleMatrix(n, 1);
                gammaC.SetMatrixElements(0.1); // small values lead	to better convergence property
            }

            if (0 == maxiter)
            {
                maxiter = 1000;
            }

            if (double.IsNaN(tol) || tol <= 0)
            {
                tol = 1.0e-9;
            }

            var B = B0;

            B0 = null;
            var C = C0;

            C0 = null;
            var newalpha = oldalpha;
            var newbeta  = oldbeta;

            var AtA = new DoubleMatrix(n, n);

            MatrixMath.MultiplyFirstTransposed(A, A, AtA);
            double trAtA = MatrixMath.Trace(AtA);

            var olderror = new DoubleVector(maxiter + 1);

            var BtA = new DoubleMatrix(r, n);

            MatrixMath.MultiplyFirstTransposed(B, A, BtA);

            var CtBtA = new DoubleMatrix(n, n);

            MatrixMath.MultiplyFirstTransposed(C, BtA, CtBtA);

            var BtB = new DoubleMatrix(r, r);

            MatrixMath.MultiplyFirstTransposed(B, B, BtB);

            var BtBC = new DoubleMatrix(r, n);

            MatrixMath.Multiply(BtB, C, BtBC);
            var CtBtBC = new DoubleMatrix(n, n);

            MatrixMath.MultiplyFirstTransposed(C, BtBC, CtBtBC);

            var BtDgNewbeta = new DoubleMatrix(r, m);

            MatrixMath.MultiplyFirstTransposed(B, DoubleMatrix.Diag(newbeta), BtDgNewbeta);
            var BtDgNewbetaB = new DoubleMatrix(r, r); // really rxr ?

            MatrixMath.Multiply(BtDgNewbeta, B, BtDgNewbetaB);

            var CDgNewalpha = new DoubleMatrix(r, n);

            MatrixMath.Multiply(C, DoubleMatrix.Diag(newalpha), CDgNewalpha);
            var CtCDgNewalpha = new DoubleMatrix(n, n);

            MatrixMath.MultiplyFirstTransposed(C, CDgNewalpha, CtCDgNewalpha);

            olderror[0] =
                0.5 * trAtA -
                MatrixMath.Trace(CtBtA) +
                0.5 * MatrixMath.Trace(CtBtBC) +
                0.5 * MatrixMath.Trace(BtDgNewbetaB) +
                0.5 * MatrixMath.Trace(CtCDgNewalpha);

            double sigma = 1.0e-9;
            double delta = sigma;

            for (int iteration = 1; iteration <= maxiter; ++iteration)
            {
                var CCt = new DoubleMatrix(r, r);
                MatrixMath.MultiplySecondTransposed(C, C, CCt);

                var gradB  = new DoubleMatrix(m, r);
                var tempMR = new DoubleMatrix(m, r);
                //gradB = B*CCt - A*C’ +diag(newbeta)*B;
                MatrixMath.Multiply(B, CCt, gradB);
                MatrixMath.MultiplySecondTransposed(A, C, tempMR);
                MatrixMath.Add(gradB, tempMR, gradB);
                MatrixMath.Multiply(DoubleMatrix.Diag(newbeta), B, tempMR);
                MatrixMath.Add(gradB, tempMR, gradB);

                // Bm = max(B, (gradB < 0)	*	sigma);
                var sigMR = new DoubleMatrix(m, r);
                sigMR.SetMatrixElements((i, j) => gradB[i, j] < 0 ? sigma : 0);
                var Bm = new DoubleMatrix(m, r);
                Bm.SetMatrixElements((i, j) => Math.Max(B[i, j], sigMR[i, j]));
            }
        }
コード例 #6
0
        /// <summary>
        /// Execution of the fast nonnegative least squares algorithm. The algorithm finds a vector x with all elements xi&gt;=0 which minimizes |X*x-y|.
        /// </summary>
        /// <param name="XtX">X transposed multiplied by X, thus a square matrix.</param>
        /// <param name="Xty">X transposed multiplied by Y, thus a matrix with one column and same number of rows as X.</param>
        /// <param name="isRestrictedToPositiveValues">Function that takes the parameter index as argument and returns true if the parameter at this index is restricted to positive values; otherwise the return value must be false.</param>
        /// <param name="tolerance">Used to decide if a solution element is less than or equal to zero. If this is null, a default tolerance of tolerance = MAX(SIZE(XtX)) * NORM(XtX,1) * EPS is used.</param>
        /// <param name="x">Output: solution vector (matrix with one column and number of rows according to dimension of X.</param>
        /// <param name="w">Output: Lagrange vector. Elements which take place in the fit are set to 0. Elements fixed to zero contain a negative number.</param>
        /// <remarks>
        /// <para>
        /// Literature: Rasmus Bro and Sijmen De Jong, 'A fast non-negativity-constrained least squares algorithm', Journal of Chemometrics, Vol. 11, 393-401 (1997)
        /// </para>
        /// <para>
        /// Algorithm modified by Dirk Lellinger 2015 to allow a mixture of restricted and unrestricted parameters.
        /// </para>
        /// </remarks>
        public static void Execution(IROMatrix <double> XtX, IROMatrix <double> Xty, Func <int, bool> isRestrictedToPositiveValues, double?tolerance, out IMatrix <double> x, out IMatrix <double> w)
        {
            if (null == XtX)
            {
                throw new ArgumentNullException(nameof(XtX));
            }
            if (null == Xty)
            {
                throw new ArgumentNullException(nameof(Xty));
            }
            if (null == isRestrictedToPositiveValues)
            {
                throw new ArgumentNullException(nameof(isRestrictedToPositiveValues));
            }

            if (XtX.RowCount != XtX.ColumnCount)
            {
                throw new ArgumentException("Matrix should be a square matrix", nameof(XtX));
            }
            if (Xty.ColumnCount != 1)
            {
                throw new ArgumentException(nameof(Xty) + " should be a column vector (number of columns should be equal to 1)", nameof(Xty));
            }
            if (Xty.RowCount != XtX.ColumnCount)
            {
                throw new ArgumentException("Number of rows in " + nameof(Xty) + " should match number of columns in " + nameof(XtX), nameof(Xty));
            }

            var matrixGenerator = new Func <int, int, DoubleMatrix>((rows, cols) => new DoubleMatrix(rows, cols));

            // if nargin < 3
            //   tol = 10 * eps * norm(XtX, 1) * length(XtX);
            // end
            double tol = tolerance.HasValue ? tolerance.Value : 10 * DoubleConstants.DBL_EPSILON * MatrixMath.Norm(XtX, MatrixNorm.M1Norm) * Math.Max(XtX.RowCount, XtX.ColumnCount);

            //	[m, n] = size(XtX);
            int n = XtX.ColumnCount;

            // P = zeros(1, n);
            // Z = 1:n;
            var  P = new bool[n]; // POSITIVE SET: all indices which are currently not fixed are marked with TRUE (Negative set is simply this, but inverted)
            bool initializationOfSolutionRequired = false;

            for (int i = 0; i < n; ++i)
            {
                bool isNotRestricted = !isRestrictedToPositiveValues(i);
                P[i] = isNotRestricted;
                initializationOfSolutionRequired |= isNotRestricted;
            }

            // x = P';
            x = matrixGenerator(n, 1);

            // w = Xty-XtX*x;
            w = matrixGenerator(n, 1);
            MatrixMath.Copy(Xty, w);
            var helper_n_1 = matrixGenerator(n, 1);

            MatrixMath.Multiply(XtX, x, helper_n_1);
            MatrixMath.Subtract(w, helper_n_1, w);

            // set up iteration criterion
            int iter  = 0;
            int itmax = 30 * n;

            // outer loop to put variables into set to hold positive coefficients
            // while any(Z) & any(w(ZZ) > tol)
            while (initializationOfSolutionRequired || (P.Any(ele => false == ele) && w.Any((r, c, ele) => false == P[r] && ele > tol)))
            {
                if (initializationOfSolutionRequired)
                {
                    initializationOfSolutionRequired = false;
                }
                else
                {
                    // [wt, t] = max(w(ZZ));
                    // t = ZZ(t);
                    int    t  = -1; // INDEX
                    double wt = double.NegativeInfinity;
                    for (int i = 0; i < n; ++i)
                    {
                        if (!P[i])
                        {
                            if (w[i, 0] > wt)
                            {
                                wt = w[i, 0];
                                t  = i;
                            }
                        }
                    }

                    // P(1, t) = t;
                    // Z(t) = 0;
                    P[t] = true;
                }

                // z(PP')=(Xty(PP)'/XtX(PP,PP)');
                var subXty      = Xty.SubMatrix(P, 0, matrixGenerator); // Xty(PP)'
                var subXtX      = XtX.SubMatrix(P, P, matrixGenerator);
                var solver      = new DoubleLUDecomp(subXtX);
                var subSolution = solver.Solve(subXty);
                var z           = matrixGenerator(n, 1);
                for (int i = 0, ii = 0; i < n; ++i)
                {
                    z[i, 0] = P[i] ? subSolution[ii++, 0] : 0;
                }

                // C. Inner loop (to remove elements from the positive set which no longer belong to)
                while (z.Any((r, c, ele) => true == P[r] && ele <= tol && isRestrictedToPositiveValues(r)) && iter < itmax)
                {
                    ++iter;
                    // QQ = find((z <= tol) & P');
                    //alpha = min(x(QQ)./ (x(QQ) - z(QQ)));
                    double alpha = double.PositiveInfinity;
                    for (int i = 0; i < n; ++i)
                    {
                        if ((z[i, 0] <= tol && true == P[i] && isRestrictedToPositiveValues(i)))
                        {
                            alpha = Math.Min(alpha, x[i, 0] / (x[i, 0] - z[i, 0]));
                        }
                    }
                    // x = x + alpha * (z - x);
                    for (int i = 0; i < n; ++i)
                    {
                        x[i, 0] += alpha * (z[i, 0] - x[i, 0]);
                    }

                    // ij = find(abs(x) < tol & P' ~= 0);
                    // Z(ij) = ij';
                    // P(ij) = zeros(1, length(ij));

                    for (int i = 0; i < n; ++i)
                    {
                        if (Math.Abs(x[i, 0]) < tol && P[i] == true && isRestrictedToPositiveValues(i))
                        {
                            P[i] = false;
                        }
                    }

                    //PP = find(P);
                    //ZZ = find(Z);
                    //nzz = size(ZZ);
                    //z(PP) = (Xty(PP)'/XtX(PP,PP)');

                    subXty      = Xty.SubMatrix(P, 0, matrixGenerator);
                    subXtX      = XtX.SubMatrix(P, P, matrixGenerator);
                    solver      = new DoubleLUDecomp(subXtX);
                    subSolution = solver.Solve(subXty);

                    for (int i = 0, ii = 0; i < n; ++i)
                    {
                        z[i, 0] = P[i] ? subSolution[ii++, 0] : 0;
                    }
                } // end inner loop

                MatrixMath.Copy(z, x);
                MatrixMath.Copy(Xty, w);
                MatrixMath.Multiply(XtX, x, helper_n_1);
                MatrixMath.Subtract(w, helper_n_1, w);
            }
        }
コード例 #7
0
ファイル: JaggedArrayMatrix.cs プロジェクト: olesar/Altaxo
 /// <summary>
 /// Represents the content of the matrix as a string.
 /// </summary>
 /// <returns></returns>
 public override string ToString()
 {
     return(MatrixMath.MatrixToString(null, this));
 }
コード例 #8
0
ファイル: SVDDecomposition.cs プロジェクト: olesar/Altaxo
        /* Modified algorithm which is better for M>>N */

        int gsl_linalg_SV_decomp_mod(IROMatrix A,
                                     IROMatrix X,
                                     IMatrix V, IVector S, IVector work)
        {
            int i, j;

            int M = A.Rows;
            int N = A.Columns;

            if (M < N)
            {
                throw new ArgumentException("svd of MxN matrix, M<N, is not implemented");
            }
            else if (V.Rows != N)
            {
                throw new ArgumentException("square matrix V must match second dimension of matrix A");
            }
            else if (V.Rows != V.Columns)
            {
                throw new ArgumentException("matrix V must be square");
            }
            else if (X.Rows != N)
            {
                throw new ArgumentException("square matrix X must match second dimension of matrix A");
            }
            else if (X.Rows != X.Columns)
            {
                throw new ArgumentException("matrix X must be square");
            }
            else if (S.Length != N)
            {
                throw new ArgumentException("length of vector S must match second dimension of matrix A");
            }
            else if (work.Length != N)
            {
                throw new ArgumentException("length of workspace must match second dimension of matrix A");
            }

            if (N == 1)
            {
                IROVector column = MatrixMath.ColumnToROVector(A, 0); // gsl_vector_view  = gsl_matrix_column(A, 0);
                double    norm   = VectorMath.GetNorm(column);        //gsl_blas_dnrm2(&column.vector);

                S[0]    = norm;                                       // gsl_vector_set(S, 0, norm);
                V[0, 0] = 1;                                          //gsl_matrix_set(V, 0, 0, 1.0);

                if (norm != 0.0)
                {
                    gsl_blas_dscal(1.0 / norm, &column.vector);
                }

                return(GSL_SUCCESS);
            }

            /* Convert A into an upper triangular matrix R */

            for (i = 0; i < N; i++)
            {
                IVector         c     = MatrixMath.ColumnToVector(A, i); // gsl_vector_view c = gsl_matrix_column(A, i);
                gsl_vector_view v     = gsl_vector_subvector(&c.vector, i, M - i);
                double          tau_i = gsl_linalg_householder_transform(&v.vector);

                /* Apply the transformation to the remaining columns */

                if (i + 1 < N)
                {
                    gsl_matrix_view m =
                        gsl_matrix_submatrix(A, i, i + 1, M - i, N - (i + 1));
                    gsl_linalg_householder_hm(tau_i, &v.vector, &m.matrix);
                }

                gsl_vector_set(S, i, tau_i);
            }

            /* Copy the upper triangular part of A into X */

            for (i = 0; i < N; i++)
            {
                for (j = 0; j < i; j++)
                {
                    gsl_matrix_set(X, i, j, 0.0);
                }

                {
                    double Aii = gsl_matrix_get(A, i, i);
                    gsl_matrix_set(X, i, i, Aii);
                }

                for (j = i + 1; j < N; j++)
                {
                    double Aij = gsl_matrix_get(A, i, j);
                    gsl_matrix_set(X, i, j, Aij);
                }
            }

            /* Convert A into an orthogonal matrix L */

            for (j = N; j > 0 && j--;)
            {
                /* Householder column transformation to accumulate L */
                double          tj = gsl_vector_get(S, j);
                gsl_matrix_view m  = gsl_matrix_submatrix(A, j, j, M - j, N - j);
                gsl_linalg_householder_hm1(tj, &m.matrix);
            }

            /* unpack R into X V S */

            gsl_linalg_SV_decomp(X, V, S, work);

            /* Multiply L by X, to obtain U = L X, stored in U */

            {
                gsl_vector_view sum = gsl_vector_subvector(work, 0, N);

                for (i = 0; i < M; i++)
                {
                    gsl_vector_view L_i = gsl_matrix_row(A, i);
                    gsl_vector_set_zero(&sum.vector);

                    for (j = 0; j < N; j++)
                    {
                        double          Lij = gsl_vector_get(&L_i.vector, j);
                        gsl_vector_view X_j = gsl_matrix_row(X, j);
                        gsl_blas_daxpy(Lij, &X_j.vector, &sum.vector);
                    }

                    gsl_vector_memcpy(&L_i.vector, &sum.vector);
                }
            }

            return(GSL_SUCCESS);
        }