Beispiel #1
0
        /// <summary>
        /// Initializes eigenvalue decomposition.
        /// </summary>
        /// <param name="A">Square matrix</param>
        /// <param name="eps">Epsilon [0, 1]</param>
        public EVD(float[,] A, float eps = 1e-16f)
        {
            if (!Matrice.IsSquare(A))
            {
                throw new Exception("The matrix must be square");
            }

            this.n   = A.GetLength(0);
            this.Re  = new float[n];
            this.Im  = new float[n];
            this.eps = Maths.Float(eps);

            // for symmetric matrices eigen-value decomposition
            // without Hessenberg form.
            if (Matrice.IsSymmetric(A))
            {
                hessenberg = Jagged.Zero(n, n);
                matrices   = Jagged.ToJagged(A);

                tred2(); // Tridiagonalize.
                tql2();  // Diagonalize.
            }
            // with Hessenberg form.
            else
            {
                matrices   = Jagged.Zero(n, n);
                hessenberg = Jagged.ToJagged(A);
                orthogonal = new float[n];

                orthes(); // Reduce to Hessenberg form.
                hqr2();   // Reduce Hessenberg to real Schur form.
            }
        }
Beispiel #2
0
        /// <summary>
        /// Initializes generalized eigenvalue decomposition.
        /// </summary>
        /// <param name="a">Matrix A</param>
        /// <param name="b">Matrix B</param>
        /// <param name="eps">Epsilon [0, 1]</param>
        public GEVD(float[,] a, float[,] b, float eps = 1e-16f)
        {
            if (a.GetLength(0) != a.GetLength(1))
            {
                throw new ArgumentException("The matrix must be square");
            }

            if (b.GetLength(0) != b.GetLength(1))
            {
                throw new ArgumentException("The matrix must be square");
            }

            if (a.GetLength(0) != b.GetLength(0) || a.GetLength(1) != b.GetLength(1))
            {
                throw new ArgumentException("Matrices should be the same size");
            }

            // params
            this.n    = a.GetLength(0);
            this.ar   = new float[n];
            this.ai   = new float[n];
            this.beta = new float[n];
            this.Z    = Jagged.Zero(n, n);
            var  A    = Jagged.ToJagged(a);
            var  B    = Jagged.ToJagged(b);
            bool matz = true;
            int  ierr = 0;


            // reduces A to upper Hessenberg form and B to upper
            // triangular form using orthogonal transformations
            qzhes(n, A, B, matz, Z);

            // reduces the Hessenberg matrix A to quasi-triangular form
            // using orthogonal transformations while maintaining the
            // triangular form of the B matrix.
            qzit(n, A, B, Maths.Float(eps), matz, Z, ref ierr);

            // reduces the quasi-triangular matrix further, so that any
            // remaining 2-by-2 blocks correspond to pairs of complex
            // eigenvalues, and returns quantities whose ratios give the
            // generalized eigenvalues.
            qzval(n, A, B, ar, ai, beta, matz, Z);

            // computes the eigenvectors of the triangular problem and
            // transforms the results back to the original coordinate system.
            qzvec(n, A, B, ar, ai, beta, Z);
        }
Beispiel #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="a"></param>
        private void ludecomp(float[][] a)
        {
            int   i, j, k;
            int   n = a.GetLength(0);
            float alpha, beta;

            this.upper = Jagged.Zero(n, n);
            this.lower = Jagged.Zero(n, n);

            for (i = 0; i < n; i++)
            {
                this.upper[i][i] = 1;
            }

            for (j = 0; j < n; j++)
            {
                for (i = j; i < n; i++)
                {
                    alpha = 0;
                    for (k = 0; k < j; k++)
                    {
                        alpha = alpha + this.lower[i][k] * this.upper[k][j];
                    }
                    this.lower[i][j] = a[i][j] - alpha;
                }

                beta = lower[j][j];

                for (i = j; i < n; i++)
                {
                    alpha = 0;
                    for (k = 0; k < j; k++)
                    {
                        alpha = alpha + this.lower[j][k] * this.upper[k][i];
                    }

                    if (beta != 0)
                    {
                        this.upper[j][i] = (a[j][i] - alpha) / beta;
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="A"></param>
        private void svdcmp(float[,] A)
        {
            this.Ur = Jagged.ToJagged(A);
            this.Sr = new float[m];
            this.Vr = Jagged.Zero(m, m);
            float[] rv1 = new float[m];

            int   flag, i, its, j, jj, k, l = 0, nm = 0;
            float anorm, c, f, g, h, e, scale, x, y, z;


            // householder reduction to bidiagonal form
            g = scale = anorm = 0.0f;

            for (i = 0; i < m; i++)
            {
                l      = i + 1;
                rv1[i] = scale * g;
                g      = e = scale = 0;

                if (i < n)
                {
                    for (k = i; k < n; k++)
                    {
                        scale += Math.Abs(Ur[k][i]);
                    }

                    if (scale != 0.0)
                    {
                        for (k = i; k < n; k++)
                        {
                            Ur[k][i] /= scale;
                            e        += Ur[k][i] * Ur[k][i];
                        }

                        f        = Ur[i][i];
                        g        = -Sign((float)Math.Sqrt(e), f);
                        h        = f * g - e;
                        Ur[i][i] = f - g;

                        if (i != m - 1)
                        {
                            for (j = l; j < m; j++)
                            {
                                for (e = 0.0f, k = i; k < n; k++)
                                {
                                    e += Ur[k][i] * Ur[k][j];
                                }

                                f = e / h;

                                for (k = i; k < n; k++)
                                {
                                    Ur[k][j] += f * Ur[k][i];
                                }
                            }
                        }

                        for (k = i; k < n; k++)
                        {
                            Ur[k][i] *= scale;
                        }
                    }
                }

                Sr[i] = scale * g;
                g     = e = scale = 0.0f;

                if ((i < n) && (i != m - 1))
                {
                    for (k = l; k < m; k++)
                    {
                        scale += Math.Abs(Ur[i][k]);
                    }

                    if (scale != 0.0)
                    {
                        for (k = l; k < m; k++)
                        {
                            Ur[i][k] /= scale;
                            e        += Ur[i][k] * Ur[i][k];
                        }

                        f        = Ur[i][l];
                        g        = -Sign((float)Math.Sqrt(e), f);
                        h        = f * g - e;
                        Ur[i][l] = f - g;

                        for (k = l; k < m; k++)
                        {
                            rv1[k] = Ur[i][k] / h;
                        }

                        if (i != n - 1)
                        {
                            for (j = l; j < n; j++)
                            {
                                for (e = 0.0f, k = l; k < m; k++)
                                {
                                    e += Ur[j][k] * Ur[i][k];
                                }
                                for (k = l; k < m; k++)
                                {
                                    Ur[j][k] += e * rv1[k];
                                }
                            }
                        }

                        for (k = l; k < m; k++)
                        {
                            Ur[i][k] *= scale;
                        }
                    }
                }
                anorm = Math.Max(anorm, (Math.Abs(Sr[i]) + Math.Abs(rv1[i])));
            }

            // accumulation of right-hand transformations
            for (i = m - 1; i >= 0; i--)
            {
                if (i < m - 1)
                {
                    if (g != 0.0)
                    {
                        for (j = l; j < m; j++)
                        {
                            Vr[j][i] = (Ur[i][j] / Ur[i][l]) / g;
                        }

                        for (j = l; j < m; j++)
                        {
                            for (e = 0, k = l; k < m; k++)
                            {
                                e += Ur[i][k] * Vr[k][j];
                            }
                            for (k = l; k < m; k++)
                            {
                                Vr[k][j] += e * Vr[k][i];
                            }
                        }
                    }
                    for (j = l; j < m; j++)
                    {
                        Vr[i][j] = Vr[j][i] = 0;
                    }
                }
                Vr[i][i] = 1;
                g        = rv1[i];
                l        = i;
            }

            // accumulation of left-hand transformations
            for (i = m - 1; i >= 0; i--)
            {
                l = i + 1;
                g = Sr[i];

                if (i < m - 1)
                {
                    for (j = l; j < m; j++)
                    {
                        Ur[i][j] = 0.0f;
                    }
                }

                if (g != 0)
                {
                    g = 1.0f / g;

                    if (i != m - 1)
                    {
                        for (j = l; j < m; j++)
                        {
                            for (e = 0, k = l; k < n; k++)
                            {
                                e += Ur[k][i] * Ur[k][j];
                            }

                            f = (e / Ur[i][i]) * g;

                            for (k = i; k < n; k++)
                            {
                                Ur[k][j] += f * Ur[k][i];
                            }
                        }
                    }

                    for (j = i; j < n; j++)
                    {
                        Ur[j][i] *= g;
                    }
                }
                else
                {
                    for (j = i; j < n; j++)
                    {
                        Ur[j][i] = 0;
                    }
                }
                ++Ur[i][i];
            }

            // diagonalization of the bidiagonal form: Loop over singular values
            // and over allowed iterations
            for (k = m - 1; k >= 0; k--)
            {
                for (its = 1; its <= iterations; its++)
                {
                    flag = 1;

                    for (l = k; l >= 0; l--)
                    {
                        // test for splitting
                        nm = l - 1;

                        if (Math.Abs(rv1[l]) + anorm == anorm)
                        {
                            flag = 0;
                            break;
                        }

                        if (Math.Abs(Sr[nm]) + anorm == anorm)
                        {
                            break;
                        }
                    }

                    if (flag != 0)
                    {
                        c = 0.0f;
                        e = 1.0f;
                        for (i = l; i <= k; i++)
                        {
                            f = e * rv1[i];

                            if (Math.Abs(f) + anorm != anorm)
                            {
                                g     = Sr[i];
                                h     = Maths.Hypotenuse(f, g);
                                Sr[i] = h;
                                h     = 1.0f / h;
                                c     = g * h;
                                e     = -f * h;

                                //for (j = 1; j <= m; j++)
                                for (j = 1; j < n; j++)
                                {
                                    y         = Ur[j][nm];
                                    z         = Ur[j][i];
                                    Ur[j][nm] = y * c + z * e;
                                    Ur[j][i]  = z * c - y * e;
                                }
                            }
                        }
                    }

                    z = Sr[k];

                    if (l == k)
                    {
                        // convergence
                        if (z < 0.0)
                        {
                            // singular value is made nonnegative
                            Sr[k] = -z;

                            for (j = 0; j < m; j++)
                            {
                                Vr[j][k] = -Vr[j][k];
                            }
                        }
                        break;
                    }

                    if (its == iterations)
                    {
                        throw new ApplicationException("No convergence in " + iterations.ToString() + " iterations of singular decomposition");
                    }

                    // shift from bottom 2-by-2 minor
                    x  = Sr[l];
                    nm = k - 1;
                    y  = Sr[nm];
                    g  = rv1[nm];
                    h  = rv1[k];
                    f  = ((y - z) * (y + z) + (g - h) * (g + h)) / (2.0f * h * y);
                    g  = Maths.Hypotenuse(f, 1.0f);
                    f  = ((x - z) * (x + z) + h * ((y / (f + Sign(g, f))) - h)) / x;

                    // next QR transformation
                    c = e = 1.0f;

                    for (j = l; j <= nm; j++)
                    {
                        i      = j + 1;
                        g      = rv1[i];
                        y      = Sr[i];
                        h      = e * g;
                        g      = c * g;
                        z      = Maths.Hypotenuse(f, h);
                        rv1[j] = z;
                        c      = f / z;
                        e      = h / z;
                        f      = x * c + g * e;
                        g      = g * c - x * e;
                        h      = y * e;
                        y     *= c;

                        for (jj = 0; jj < m; jj++)
                        {
                            x         = Vr[jj][j];
                            z         = Vr[jj][i];
                            Vr[jj][j] = x * c + z * e;
                            Vr[jj][i] = z * c - x * e;
                        }

                        z     = Maths.Hypotenuse(f, h);
                        Sr[j] = z;

                        if (z != 0)
                        {
                            z = 1.0f / z;
                            c = f * z;
                            e = h * z;
                        }

                        f = c * g + e * y;
                        x = c * y - e * g;

                        for (jj = 0; jj < n; jj++)
                        {
                            y         = Ur[jj][j];
                            z         = Ur[jj][i];
                            Ur[jj][j] = y * c + z * e;
                            Ur[jj][i] = z * c - y * e;
                        }
                    }

                    rv1[l] = 0.0f;
                    rv1[k] = f;
                    Sr[k]  = x;
                }
            }
        }
Beispiel #5
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="A"></param>
        private void orthes(float[,] A)
        {
            // Properties
            int n = A.GetLength(0);

            this.matrices   = Jagged.Zero(n, n);
            this.hessenberg = Jagged.ToJagged(A);
            float[] orthogonal = new float[n];

            // Nonsymmetric reduction to Hessenberg form.
            // This is derived from the Algol procedures orthes and ortran, by Martin and Wilkinson,
            // Handbook for Auto. Comp., Vol.ii-Linear Algebra, and the corresponding Fortran subroutines in EISPACK.
            int   low = 0;
            int   high = n - 1;
            int   m, i, j;
            float scale, h, g, f;

            for (m = low + 1; m <= high - 1; m++)
            {
                // Scale column.

                scale = 0;
                for (i = m; i <= high; i++)
                {
                    scale = scale + System.Math.Abs(hessenberg[i][m - 1]);
                }

                if (scale != 0)
                {
                    // Compute Householder transformation.
                    h = 0;
                    for (i = high; i >= m; i--)
                    {
                        orthogonal[i] = hessenberg[i][m - 1] / scale;
                        h            += orthogonal[i] * orthogonal[i];
                    }

                    g = (float)System.Math.Sqrt(h);
                    if (orthogonal[m] > 0)
                    {
                        g = -g;
                    }

                    h             = h - orthogonal[m] * g;
                    orthogonal[m] = orthogonal[m] - g;

                    // Apply Householder similarity transformation
                    // H = (I - u * u' / h) * H * (I - u * u') / h)
                    for (j = m; j < n; j++)
                    {
                        f = 0;
                        for (i = high; i >= m; i--)
                        {
                            f += orthogonal[i] * hessenberg[i][j];
                        }

                        f = f / h;
                        for (i = m; i <= high; i++)
                        {
                            hessenberg[i][j] -= f * orthogonal[i];
                        }
                    }

                    for (i = 0; i <= high; i++)
                    {
                        f = 0;
                        for (j = high; j >= m; j--)
                        {
                            f += orthogonal[j] * hessenberg[i][j];
                        }

                        f = f / h;
                        for (j = m; j <= high; j++)
                        {
                            hessenberg[i][j] -= f * orthogonal[j];
                        }
                    }

                    orthogonal[m]        = scale * orthogonal[m];
                    hessenberg[m][m - 1] = scale * g;
                }
            }

            // Accumulate transformations (Algol's ortran).
            for (i = 0; i < n; i++)
            {
                for (j = 0; j < n; j++)
                {
                    matrices[i][j] = (i == j ? 1 : 0);
                }
            }

            for (m = high - 1; m >= low + 1; m--)
            {
                if (hessenberg[m][m - 1] != 0)
                {
                    for (i = m + 1; i <= high; i++)
                    {
                        orthogonal[i] = hessenberg[i][m - 1];
                    }

                    for (j = m; j <= high; j++)
                    {
                        g = 0;
                        for (i = m; i <= high; i++)
                        {
                            g += orthogonal[i] * matrices[i][j];
                        }

                        // float division avoids possible underflow.
                        g = (g / orthogonal[m]) / hessenberg[m][m - 1];
                        for (i = m; i <= high; i++)
                        {
                            matrices[i][j] += g * orthogonal[i];
                        }
                    }
                }
            }

            // final reduction:
            if (n > 2)
            {
                for (i = 0; i < n - 2; i++)
                {
                    for (j = i + 2; j < n; j++)
                    {
                        hessenberg[j][i] = 0;
                    }
                }
            }
        }