Beispiel #1
0
        /// <summary>
        /// Returns a deep-copy clone of the vector.
        /// </summary>
        /// <returns>A deep-copy clone of the vector.</returns>
        public Vector <T> Clone()
        {
            var result = Build.SameAs(this);

            Storage.CopyToUnchecked(result.Storage, ExistingData.AssumeZeros);
            return(result);
        }
Beispiel #2
0
        /// <summary>
        /// Solves a system of linear equations, <b>Ax = b</b>, with A LU factorized.
        /// </summary>
        /// <param name="input">The right hand side vector, <b>b</b>.</param>
        /// <returns>The left hand side <see cref="Vector{T}"/>, <b>x</b>.</returns>
        public virtual Vector <T> Solve(Vector <T> input)
        {
            var x = v_builder.SameAs(input, input.Count);

            Solve(input, x);
            return(x);
        }
Beispiel #3
0
        /// <summary>
        /// Solves a system of linear equations, <b>Ax = b</b>, with A EVD factorized.
        /// </summary>
        /// <param name="input">The right hand side vector, <b>b</b>.</param>
        /// <returns>The left hand side <see cref="Vector{T}"/>, <b>x</b>.</returns>
        public virtual Vector <T> Solve(Vector <T> input)
        {
            var x = v_builder.SameAs(EigenVectors, EigenVectors.ColumnCount);

            Solve(input, x);
            return(x);
        }
Beispiel #4
0
        /// <summary>
        /// Solves a system of linear equations, <b>Ax = b</b>, with A SVD factorized.
        /// </summary>
        /// <param name="input">The right hand side vector, <b>b</b>.</param>
        /// <returns>The left hand side <see cref="Vector{T}"/>, <b>x</b>.</returns>
        public virtual Vector <T> Solve(Vector <T> input)
        {
            if (!VectorsComputed)
            {
                throw new InvalidOperationException("Resources.SingularVectorsNotComputed");
            }

            var x = v_builder.SameAs(U, VT.ColumnCount);

            Solve(input, x);
            return(x);
        }
        public static Vector <T> SameAs <T>(this VectorBuilder <T> builder, Vector <T> example, Func <T> f) where T : struct, global::System.IEquatable <T>, global::System.IFormattable
        {
            Contract.Requires(builder != null);
            Contract.Requires(example != null);
            Contract.Requires(f != null);

            var result = builder.SameAs(example);

            Contract.Assume(result != null);

            result.MapInplace(x => f());
            return(result);
        }
Beispiel #6
0
        public static UserSvd Create(Matrix <double> matrix, bool computeVectors)
        {
            var nm         = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
            var matrixCopy = matrix.Clone();

            var s  = v_builder.SameAs(matrixCopy, nm);
            var u  = m_builder.SameAs(matrixCopy, matrixCopy.RowCount, matrixCopy.RowCount, fullyMutable: true);
            var vt = m_builder.SameAs(matrixCopy, matrixCopy.ColumnCount, matrixCopy.ColumnCount, fullyMutable: true);

            const int maxiter = 1000;
            var       e = new double[matrixCopy.ColumnCount];
            var       work = new double[matrixCopy.RowCount];
            int       i, j;
            int       l, lp1;
            double    t;

            var ncu = matrixCopy.RowCount;

            // Reduce matrixCopy to bidiagonal form, storing the diagonal elements
            // In s and the super-diagonal elements in e.
            var nct = Math.Min(matrixCopy.RowCount - 1, matrixCopy.ColumnCount);
            var nrt = Math.Max(0, Math.Min(matrixCopy.ColumnCount - 2, matrixCopy.RowCount));
            var lu  = Math.Max(nct, nrt);

            for (l = 0; l < lu; l++)
            {
                lp1 = l + 1;
                if (l < nct)
                {
                    // Compute the transformation for the l-th column and place the l-th diagonal in VectorS[l].
                    var xnorm = Dnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
                    s[l] = xnorm;
                    if (s[l] != 0.0)
                    {
                        if (matrixCopy.At(l, l) != 0.0)
                        {
                            s[l] = Dsign(s[l], matrixCopy.At(l, l));
                        }

                        DscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0 / s[l]);
                        matrixCopy.At(l, l, (1.0 + matrixCopy.At(l, l)));
                    }

                    s[l] = -s[l];
                }

                for (j = lp1; j < matrixCopy.ColumnCount; j++)
                {
                    if (l < nct)
                    {
                        if (s[l] != 0.0)
                        {
                            // Apply the transformation.
                            t = -Ddot(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l);
                            for (var ii = l; ii < matrixCopy.RowCount; ii++)
                            {
                                matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (t * matrixCopy.At(ii, l)));
                            }
                        }
                    }

                    // Place the l-th row of matrixCopy into  e for the
                    // Subsequent calculation of the row transformation.
                    e[j] = matrixCopy.At(l, j);
                }

                if (computeVectors && l < nct)
                {
                    // Place the transformation in u for subsequent back multiplication.
                    for (i = l; i < matrixCopy.RowCount; i++)
                    {
                        u.At(i, l, matrixCopy.At(i, l));
                    }
                }

                if (l >= nrt)
                {
                    continue;
                }

                // Compute the l-th row transformation and place the l-th super-diagonal in e(l).
                var enorm = Dnrm2Vector(e, lp1);
                e[l] = enorm;
                if (e[l] != 0.0)
                {
                    if (e[lp1] != 0.0)
                    {
                        e[l] = Dsign(e[l], e[lp1]);
                    }

                    DscalVector(e, lp1, 1.0 / e[l]);
                    e[lp1] = 1.0 + e[lp1];
                }

                e[l] = -e[l];
                if (lp1 < matrixCopy.RowCount && e[l] != 0.0)
                {
                    // Apply the transformation.
                    for (i = lp1; i < matrixCopy.RowCount; i++)
                    {
                        work[i] = 0.0;
                    }

                    for (j = lp1; j < matrixCopy.ColumnCount; j++)
                    {
                        for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
                        {
                            work[ii] += e[j] * matrixCopy.At(ii, j);
                        }
                    }

                    for (j = lp1; j < matrixCopy.ColumnCount; j++)
                    {
                        var ww = -e[j] / e[lp1];
                        for (var ii = lp1; ii < matrixCopy.RowCount; ii++)
                        {
                            matrixCopy.At(ii, j, matrixCopy.At(ii, j) + (ww * work[ii]));
                        }
                    }
                }

                if (computeVectors)
                {
                    // Place the transformation in v for subsequent back multiplication.
                    for (i = lp1; i < matrixCopy.ColumnCount; i++)
                    {
                        vt.At(i, l, e[i]);
                    }
                }
            }
            // Set up the final bidiagonal matrixCopy or order m.
            var m     = Math.Min(matrixCopy.ColumnCount, matrixCopy.RowCount + 1);
            var nctp1 = nct + 1;
            var nrtp1 = nrt + 1;

            if (nct < matrixCopy.ColumnCount)
            {
                s[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
            }

            if (matrixCopy.RowCount < m)
            {
                s[m - 1] = 0.0;
            }

            if (nrtp1 < m)
            {
                e[nrtp1 - 1] = matrixCopy.At((nrtp1 - 1), (m - 1));
            }

            e[m - 1] = 0.0;

            // If required, generate u.
            if (computeVectors)
            {
                for (j = nctp1 - 1; j < ncu; j++)
                {
                    for (i = 0; i < matrixCopy.RowCount; i++)
                    {
                        u.At(i, j, 0.0);
                    }

                    u.At(j, j, 1.0);
                }

                for (l = nct - 1; l >= 0; l--)
                {
                    if (s[l] != 0.0)
                    {
                        for (j = l + 1; j < ncu; j++)
                        {
                            t = -Ddot(u, matrixCopy.RowCount, l, j, l) / u.At(l, l);
                            for (var ii = l; ii < matrixCopy.RowCount; ii++)
                            {
                                u.At(ii, j, u.At(ii, j) + (t * u.At(ii, l)));
                            }
                        }

                        DscalColumn(u, matrixCopy.RowCount, l, l, -1.0);
                        u.At(l, l, 1.0 + u.At(l, l));
                        for (i = 0; i < l; i++)
                        {
                            u.At(i, l, 0.0);
                        }
                    }
                    else
                    {
                        for (i = 0; i < matrixCopy.RowCount; i++)
                        {
                            u.At(i, l, 0.0);
                        }

                        u.At(l, l, 1.0);
                    }
                }
            }

            // If it is required, generate v.
            if (computeVectors)
            {
                for (l = matrixCopy.ColumnCount - 1; l >= 0; l--)
                {
                    lp1 = l + 1;
                    if (l < nrt)
                    {
                        if (e[l] != 0.0)
                        {
                            for (j = lp1; j < matrixCopy.ColumnCount; j++)
                            {
                                t = -Ddot(vt, matrixCopy.ColumnCount, l, j, lp1) / vt.At(lp1, l);
                                for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
                                {
                                    vt.At(ii, j, vt.At(ii, j) + (t * vt.At(ii, l)));
                                }
                            }
                        }
                    }

                    for (i = 0; i < matrixCopy.ColumnCount; i++)
                    {
                        vt.At(i, l, 0.0);
                    }

                    vt.At(l, l, 1.0);
                }
            }

            // Transform s and e so that they are  double .
            for (i = 0; i < m; i++)
            {
                double r;
                if (s[i] != 0.0)
                {
                    t    = s[i];
                    r    = s[i] / t;
                    s[i] = t;
                    if (i < m - 1)
                    {
                        e[i] = e[i] / r;
                    }

                    if (computeVectors)
                    {
                        DscalColumn(u, matrixCopy.RowCount, i, 0, r);
                    }
                }

                // Exit
                if (i == m - 1)
                {
                    break;
                }

                if (e[i] != 0.0)
                {
                    t        = e[i];
                    r        = t / e[i];
                    e[i]     = t;
                    s[i + 1] = s[i + 1] * r;
                    if (computeVectors)
                    {
                        DscalColumn(vt, matrixCopy.ColumnCount, i + 1, 0, r);
                    }
                }
            }

            // Main iteration loop for the singular values.
            var mn   = m;
            var iter = 0;

            bool AlmostEquals(double val1, double val2)
            {
                if (Math.Abs(val1 - val2) < 1e-8)
                {
                    return(true);
                }
                return(false);
            }

            while (m > 0)
            {
                // Quit if all the singular values have been found. If too many iterations have been performed,
                // throw exception that Convergence Failed
                if (iter >= maxiter)
                {
                    throw new ArgumentException("NonConvergenceException()");;
                }

                // This section of the program inspects for negligible elements in the s and e arrays. On
                // completion the variables case and l are set as follows.
                // Case = 1     if VectorS[m] and e[l-1] are negligible and l < m
                // Case = 2     if VectorS[l] is negligible and l < m
                // Case = 3     if e[l-1] is negligible, l < m, and VectorS[l, ..., VectorS[m] are not negligible (qr step).
                // Case = 4     if e[m-1] is negligible (convergence).
                double ztest;
                double test;
                for (l = m - 2; l >= 0; l--)
                {
                    test  = Math.Abs(s[l]) + Math.Abs(s[l + 1]);
                    ztest = test + Math.Abs(e[l]);
                    if (AlmostEquals(test, ztest))
                    {
                        e[l] = 0.0;
                        break;
                    }
                }

                int kase;
                if (l == m - 2)
                {
                    kase = 4;
                }
                else
                {
                    int ls;
                    for (ls = m - 1; ls > l; ls--)
                    {
                        test = 0.0;
                        if (ls != m - 1)
                        {
                            test = test + Math.Abs(e[ls]);
                        }

                        if (ls != l + 1)
                        {
                            test = test + Math.Abs(e[ls - 1]);
                        }

                        ztest = test + Math.Abs(s[ls]);
                        if (AlmostEquals(test, ztest))
                        {
                            s[ls] = 0.0;
                            break;
                        }
                    }

                    if (ls == l)
                    {
                        kase = 3;
                    }
                    else if (ls == m - 1)
                    {
                        kase = 1;
                    }
                    else
                    {
                        kase = 2;
                        l    = ls;
                    }
                }

                l = l + 1;

                // Perform the task indicated by case.
                int    k;
                double f;
                double sn;
                double cs;
                double t1;
                switch (kase)
                {
                // Deflate negligible VectorS[m].
                case 1:
                    f        = e[m - 2];
                    e[m - 2] = 0.0;
                    for (var kk = l; kk < m - 1; kk++)
                    {
                        k  = m - 2 - kk + l;
                        t1 = s[k];
                        Drotg(ref t1, ref f, out cs, out sn);
                        s[k] = t1;
                        if (k != l)
                        {
                            f        = -sn * e[k - 1];
                            e[k - 1] = cs * e[k - 1];
                        }

                        if (computeVectors)
                        {
                            Drot(vt, matrixCopy.ColumnCount, k, m - 1, cs, sn);
                        }
                    }

                    break;

                // Split at negligible VectorS[l].
                case 2:
                    f        = e[l - 1];
                    e[l - 1] = 0.0;
                    for (k = l; k < m; k++)
                    {
                        t1 = s[k];
                        Drotg(ref t1, ref f, out cs, out sn);
                        s[k] = t1;
                        f    = -sn * e[k];
                        e[k] = cs * e[k];
                        if (computeVectors)
                        {
                            Drot(u, matrixCopy.RowCount, k, l - 1, cs, sn);
                        }
                    }
                    break;

                // Perform one qr step.
                case 3:
                    // Calculate the shift.
                    var scale = 0.0;
                    scale = Math.Max(scale, Math.Abs(s[m - 1]));
                    scale = Math.Max(scale, Math.Abs(s[m - 2]));
                    scale = Math.Max(scale, Math.Abs(e[m - 2]));
                    scale = Math.Max(scale, Math.Abs(s[l]));
                    scale = Math.Max(scale, Math.Abs(e[l]));
                    var sm    = s[m - 1] / scale;
                    var smm1  = s[m - 2] / scale;
                    var emm1  = e[m - 2] / scale;
                    var sl    = s[l] / scale;
                    var el    = e[l] / scale;
                    var b     = (((smm1 + sm) * (smm1 - sm)) + (emm1 * emm1)) / 2.0;
                    var c     = (sm * emm1) * (sm * emm1);
                    var shift = 0.0;
                    if (b != 0.0 || c != 0.0)
                    {
                        shift = Math.Sqrt((b * b) + c);
                        if (b < 0.0)
                        {
                            shift = -shift;
                        }

                        shift = c / (b + shift);
                    }

                    f = ((sl + sm) * (sl - sm)) + shift;
                    var g = sl * el;

                    // Chase zeros.
                    for (k = l; k < m - 1; k++)
                    {
                        Drotg(ref f, ref g, out cs, out sn);
                        if (k != l)
                        {
                            e[k - 1] = f;
                        }

                        f        = (cs * s[k]) + (sn * e[k]);
                        e[k]     = (cs * e[k]) - (sn * s[k]);
                        g        = sn * s[k + 1];
                        s[k + 1] = cs * s[k + 1];
                        if (computeVectors)
                        {
                            Drot(vt, matrixCopy.ColumnCount, k, k + 1, cs, sn);
                        }

                        Drotg(ref f, ref g, out cs, out sn);
                        s[k]     = f;
                        f        = (cs * e[k]) + (sn * s[k + 1]);
                        s[k + 1] = (-sn * e[k]) + (cs * s[k + 1]);
                        g        = sn * e[k + 1];
                        e[k + 1] = cs * e[k + 1];
                        if (computeVectors && k < matrixCopy.RowCount)
                        {
                            Drot(u, matrixCopy.RowCount, k, k + 1, cs, sn);
                        }
                    }

                    e[m - 2] = f;
                    iter     = iter + 1;
                    break;

                // Convergence.
                case 4:
                    // Make the singular value  positive
                    if (s[l] < 0.0)
                    {
                        s[l] = -s[l];
                        if (computeVectors)
                        {
                            DscalColumn(vt, matrixCopy.ColumnCount, l, 0, -1.0);
                        }
                    }

                    // Order the singular value.
                    while (l != mn - 1)
                    {
                        if (s[l] >= s[l + 1])
                        {
                            break;
                        }

                        t        = s[l];
                        s[l]     = s[l + 1];
                        s[l + 1] = t;
                        if (computeVectors && l < matrixCopy.ColumnCount)
                        {
                            Dswap(vt, matrixCopy.ColumnCount, l, l + 1);
                        }

                        if (computeVectors && l < matrixCopy.RowCount)
                        {
                            Dswap(u, matrixCopy.RowCount, l, l + 1);
                        }

                        l = l + 1;
                    }

                    iter = 0;
                    m    = m - 1;
                    break;
                }
            }


            if (computeVectors)
            {
                vt = vt.Transpose();
            }

            // Adjust the size of s if rows < columns. We are using ported copy of linpack's svd code and it uses
            // a singular vector of length mRows+1 when mRows < mColumns. The last element is not used and needs to be removed.
            // we should port lapack's svd routine to remove this problem.
            if (matrixCopy.RowCount < matrixCopy.ColumnCount)
            {
                nm--;
                var tmp = v_builder.SameAs(matrixCopy, nm);
                for (i = 0; i < nm; i++)
                {
                    tmp[i] = s[i];
                }

                s = tmp;
            }

            return(new UserSvd(s, u, vt, computeVectors));
        }