コード例 #1
0
        /// <summary>
        /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
        /// </summary>
        /// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</b>.</param>
        /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
        public override void Solve(Matrix <Numerics.Complex32> input, Matrix <Numerics.Complex32> result)
        {
            // The solution X should have the same number of columns as B
            if (input.ColumnCount != result.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension);
            }

            // The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
            if (EigenValues.Count != input.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension);
            }

            // The solution X row dimension is equal to the column dimension of A
            if (EigenValues.Count != result.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension);
            }

            if (IsSymmetric)
            {
                var order = EigenValues.Count;
                var tmp   = new Numerics.Complex32[order];

                for (var k = 0; k < order; k++)
                {
                    for (var j = 0; j < order; j++)
                    {
                        Numerics.Complex32 value = 0.0f;
                        if (j < order)
                        {
                            for (var i = 0; i < order; i++)
                            {
                                value += ((DenseMatrix)EigenVectors).Values[(j * order) + i].Conjugate() * input.At(i, k);
                            }

                            value /= (float)EigenValues[j].Real;
                        }

                        tmp[j] = value;
                    }

                    for (var j = 0; j < order; j++)
                    {
                        Numerics.Complex32 value = 0.0f;
                        for (var i = 0; i < order; i++)
                        {
                            value += ((DenseMatrix)EigenVectors).Values[(i * order) + j] * tmp[i];
                        }

                        result.At(j, k, value);
                    }
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
            }
        }
コード例 #2
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>
        /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
        public override void Solve(Vector <Numerics.Complex32> input, Vector <Numerics.Complex32> result)
        {
            // Ax=b where A is an m x m matrix
            // Check that b is a column vector with m entries
            if (EigenValues.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            // Check that x is a column vector with n entries
            if (EigenValues.Count != result.Count)
            {
                throw new ArgumentException(Resources.ArgumentMatrixDimensions);
            }

            if (IsSymmetric)
            {
                // Symmetric case -> x = V * inv(λ) * VH * b;
                var order = EigenValues.Count;
                var tmp   = new Numerics.Complex32[order];
                Numerics.Complex32 value;

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    if (j < order)
                    {
                        for (var i = 0; i < order; i++)
                        {
                            value += ((DenseMatrix)EigenVectors).Values[(j * order) + i].Conjugate() * input[i];
                        }

                        value /= (float)EigenValues[j].Real;
                    }

                    tmp[j] = value;
                }

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    for (var i = 0; i < order; i++)
                    {
                        value += ((DenseMatrix)EigenVectors).Values[(i * order) + j] * tmp[i];
                    }

                    result[j] = value;
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
            }
        }
コード例 #3
0
        /// <summary>
        /// Reduces a complex hermitian matrix to a real symmetric tridiagonal matrix using unitary similarity transformations.
        /// </summary>
        /// <param name="matrixA">Source matrix to reduce</param>
        /// <param name="d">Output: Arrays for internal storage of real parts of eigenvalues</param>
        /// <param name="e">Output: Arrays for internal storage of imaginary parts of eigenvalues</param>
        /// <param name="tau">Output: Arrays that contains further information about the transformations.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>This is derived from the Algol procedures HTRIDI by 
        /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for 
        /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding 
        /// Fortran subroutine in EISPACK.</remarks>
        internal static void SymmetricTridiagonalize(Numerics.Complex32[] matrixA, float[] d, float[] e, Numerics.Complex32[] tau, int order)
        {
            float hh;
            tau[order - 1] = Numerics.Complex32.One;

            for (var i = 0; i < order; i++)
            {
                d[i] = matrixA[i*order + i].Real;
            }

            // Householder reduction to tridiagonal form.
            for (var i = order - 1; i > 0; i--)
            {
                // Scale to avoid under/overflow.
                var scale = 0.0f;
                var h = 0.0f;

                for (var k = 0; k < i; k++)
                {
                    scale = scale + Math.Abs(matrixA[k*order + i].Real) + Math.Abs(matrixA[k*order + i].Imaginary);
                }

                if (scale == 0.0f)
                {
                    tau[i - 1] = Numerics.Complex32.One;
                    e[i] = 0.0f;
                }
                else
                {
                    for (var k = 0; k < i; k++)
                    {
                        matrixA[k*order + i] /= scale;
                        h += matrixA[k*order + i].MagnitudeSquared;
                    }

                    Numerics.Complex32 g = (float) Math.Sqrt(h);
                    e[i] = scale*g.Real;

                    Numerics.Complex32 temp;
                    var im1Oi = (i - 1)*order + i;
                    var f = matrixA[im1Oi];
                    if (f.Magnitude != 0.0f)
                    {
                        temp = -(matrixA[im1Oi].Conjugate()*tau[i].Conjugate())/f.Magnitude;
                        h += f.Magnitude*g.Real;
                        g = 1.0f + (g/f.Magnitude);
                        matrixA[im1Oi] *= g;
                    }
                    else
                    {
                        temp = -tau[i].Conjugate();
                        matrixA[im1Oi] = g;
                    }

                    if ((f.Magnitude == 0.0f) || (i != 1))
                    {
                        f = Numerics.Complex32.Zero;
                        for (var j = 0; j < i; j++)
                        {
                            var tmp = Numerics.Complex32.Zero;
                            var jO = j*order;
                            // Form element of A*U.
                            for (var k = 0; k <= j; k++)
                            {
                                tmp += matrixA[k*order + j]*matrixA[k*order + i].Conjugate();
                            }

                            for (var k = j + 1; k <= i - 1; k++)
                            {
                                tmp += matrixA[jO + k].Conjugate()*matrixA[k*order + i].Conjugate();
                            }

                            // Form element of P
                            tau[j] = tmp/h;
                            f += (tmp/h)*matrixA[jO + i];
                        }

                        hh = f.Real/(h + h);

                        // Form the reduced A.
                        for (var j = 0; j < i; j++)
                        {
                            f = matrixA[j*order + i].Conjugate();
                            g = tau[j] - (hh*f);
                            tau[j] = g.Conjugate();

                            for (var k = 0; k <= j; k++)
                            {
                                matrixA[k*order + j] -= (f*tau[k]) + (g*matrixA[k*order + i]);
                            }
                        }
                    }

                    for (var k = 0; k < i; k++)
                    {
                        matrixA[k*order + i] *= scale;
                    }

                    tau[i - 1] = temp.Conjugate();
                }

                hh = d[i];
                d[i] = matrixA[i*order + i].Real;
                matrixA[i*order + i] = new Numerics.Complex32(hh, scale*(float) Math.Sqrt(h));
            }

            hh = d[0];
            d[0] = matrixA[0].Real;
            matrixA[0] = hh;
            e[0] = 0.0f;
        }
コード例 #4
0
        /// <summary>
        /// Nonsymmetric reduction to Hessenberg form.
        /// </summary>
        /// <param name="dataEv">Data array of matrix V (eigenvectors)</param>
        /// <param name="matrixH">Array for internal storage of nonsymmetric Hessenberg form.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>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.</remarks>
        internal static void NonsymmetricReduceToHessenberg(Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order)
        {
            var ort = new Numerics.Complex32[order];

            for (var m = 1; m < order - 1; m++)
            {
                // Scale column.
                var scale = 0.0f;
                var mm1O = (m - 1)*order;
                for (var i = m; i < order; i++)
                {
                    scale += Math.Abs(matrixH[mm1O + i].Real) + Math.Abs(matrixH[mm1O + i].Imaginary);
                }

                if (scale != 0.0f)
                {
                    // Compute Householder transformation.
                    var h = 0.0f;
                    for (var i = order - 1; i >= m; i--)
                    {
                        ort[i] = matrixH[mm1O + i]/scale;
                        h += ort[i].MagnitudeSquared;
                    }

                    var g = (float) Math.Sqrt(h);
                    if (ort[m].Magnitude != 0)
                    {
                        h = h + (ort[m].Magnitude*g);
                        g /= ort[m].Magnitude;
                        ort[m] = (1.0f + g)*ort[m];
                    }
                    else
                    {
                        ort[m] = g;
                        matrixH[mm1O + m] = scale;
                    }

                    // Apply Householder similarity transformation
                    // H = (I-u*u'/h)*H*(I-u*u')/h)
                    for (var j = m; j < order; j++)
                    {
                        var f = Numerics.Complex32.Zero;
                        var jO = j*order;
                        for (var i = order - 1; i >= m; i--)
                        {
                            f += ort[i].Conjugate()*matrixH[jO + i];
                        }

                        f = f/h;
                        for (var i = m; i < order; i++)
                        {
                            matrixH[jO + i] -= f*ort[i];
                        }
                    }

                    for (var i = 0; i < order; i++)
                    {
                        var f = Numerics.Complex32.Zero;
                        for (var j = order - 1; j >= m; j--)
                        {
                            f += ort[j]*matrixH[j*order + i];
                        }

                        f = f/h;
                        for (var j = m; j < order; j++)
                        {
                            matrixH[j*order + i] -= f*ort[j].Conjugate();
                        }
                    }

                    ort[m] = scale*ort[m];
                    matrixH[mm1O + m] *= -g;
                }
            }

            // Accumulate transformations (Algol's ortran).
            for (var i = 0; i < order; i++)
            {
                for (var j = 0; j < order; j++)
                {
                    dataEv[(j*order) + i] = i == j ? Numerics.Complex32.One : Numerics.Complex32.Zero;
                }
            }

            for (var m = order - 2; m >= 1; m--)
            {
                var mm1O = (m - 1)*order;
                var mm1Om = mm1O + m;
                if (matrixH[mm1Om] != Numerics.Complex32.Zero && ort[m] != Numerics.Complex32.Zero)
                {
                    var norm = (matrixH[mm1Om].Real*ort[m].Real) + (matrixH[mm1Om].Imaginary*ort[m].Imaginary);

                    for (var i = m + 1; i < order; i++)
                    {
                        ort[i] = matrixH[mm1O + i];
                    }

                    for (var j = m; j < order; j++)
                    {
                        var g = Numerics.Complex32.Zero;
                        for (var i = m; i < order; i++)
                        {
                            g += ort[i].Conjugate()*dataEv[(j*order) + i];
                        }

                        // Double division avoids possible underflow
                        g /= norm;
                        for (var i = m; i < order; i++)
                        {
                            dataEv[(j*order) + i] += g*ort[i];
                        }
                    }
                }
            }

            // Create real subdiagonal elements.
            for (var i = 1; i < order; i++)
            {
                var im1 = i - 1;
                var im1O = im1*order;
                var im1Oi = im1O + i;
                var iO = i*order;
                if (matrixH[im1Oi].Imaginary != 0.0f)
                {
                    var y = matrixH[im1Oi]/matrixH[im1Oi].Magnitude;
                    matrixH[im1Oi] = matrixH[im1Oi].Magnitude;
                    for (var j = i; j < order; j++)
                    {
                        matrixH[j*order + i] *= y.Conjugate();
                    }

                    for (var j = 0; j <= Math.Min(i + 1, order - 1); j++)
                    {
                        matrixH[iO + j] *= y;
                    }

                    for (var j = 0; j < order; j++)
                    {
                        dataEv[(i*order) + j] *= y;
                    }
                }
            }
        }
コード例 #5
0
        /// <summary>
        /// Nonsymmetric reduction from Hessenberg to real Schur form.
        /// </summary>
        /// <param name="vectorV">Data array of the eigenvectors</param>
        /// <param name="dataEv">Data array of matrix V (eigenvectors)</param>
        /// <param name="matrixH">Array for internal storage of nonsymmetric Hessenberg form.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>This is derived from the Algol procedure hqr2,
        /// by Martin and Wilkinson, Handbook for Auto. Comp.,
        /// Vol.ii-Linear Algebra, and the corresponding
        /// Fortran subroutine in EISPACK.</remarks>
        internal static void NonsymmetricReduceHessenberToRealSchur(Numerics.Complex32[] vectorV, Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order)
        {
            // Initialize
            var n = order - 1;
            var eps = (float) Precision.SingleMachinePrecision;

            float norm;
            Numerics.Complex32 x, y, z, exshift = Numerics.Complex32.Zero;

            // Outer loop over eigenvalue index
            var iter = 0;
            while (n >= 0)
            {
                // Look for single small sub-diagonal element
                var l = n;
                while (l > 0)
                {
                    var lm1 = l - 1;
                    var lm1O = lm1*order;
                    var lO = l*order;
                    var tst1 = Math.Abs(matrixH[lm1O + lm1].Real) + Math.Abs(matrixH[lm1O + lm1].Imaginary) + Math.Abs(matrixH[lO + l].Real) + Math.Abs(matrixH[lO + l].Imaginary);
                    if (Math.Abs(matrixH[lm1O + l].Real) < eps*tst1)
                    {
                        break;
                    }

                    l--;
                }

                var nm1 = n - 1;
                var nm1O = nm1*order;
                var nO = n*order;
                var nOn = nO + n;
                // Check for convergence
                // One root found
                if (l == n)
                {
                    matrixH[nOn] += exshift;
                    vectorV[n] = matrixH[nOn];
                    n--;
                    iter = 0;
                }
                else
                {
                    // Form shift
                    Numerics.Complex32 s;
                    if (iter != 10 && iter != 20)
                    {
                        s = matrixH[nOn];
                        x = matrixH[nO + nm1]*matrixH[nm1O + n].Real;

                        if (x.Real != 0.0f || x.Imaginary != 0.0f)
                        {
                            y = (matrixH[nm1O + nm1] - s)/2.0f;
                            z = ((y*y) + x).SquareRoot();
                            if ((y.Real*z.Real) + (y.Imaginary*z.Imaginary) < 0.0)
                            {
                                z *= -1.0f;
                            }

                            x /= y + z;
                            s = s - x;
                        }
                    }
                    else
                    {
                        // Form exceptional shift
                        s = Math.Abs(matrixH[nm1O + n].Real) + Math.Abs(matrixH[(n - 2)*order + nm1].Real);
                    }

                    for (var i = 0; i <= n; i++)
                    {
                        matrixH[i*order + i] -= s;
                    }

                    exshift += s;
                    iter++;

                    // Reduce to triangle (rows)
                    for (var i = l + 1; i <= n; i++)
                    {
                        var im1 = i - 1;
                        var im1O = im1*order;
                        var im1Oim1 = im1O + im1;
                        s = matrixH[im1O + i].Real;
                        norm = SpecialFunctions.Hypotenuse(matrixH[im1Oim1].Magnitude, s.Real);
                        x = matrixH[im1Oim1]/norm;
                        vectorV[i - 1] = x;
                        matrixH[im1Oim1] = norm;
                        matrixH[im1O + i] = new Numerics.Complex32(0.0f, s.Real/norm);

                        for (var j = i; j < order; j++)
                        {
                            var jO = j*order;
                            y = matrixH[jO + im1];
                            z = matrixH[jO + i];
                            matrixH[jO + im1] = (x.Conjugate()*y) + (matrixH[im1O + i].Imaginary*z);
                            matrixH[jO + i] = (x*z) - (matrixH[im1O + i].Imaginary*y);
                        }
                    }

                    s = matrixH[nOn];
                    if (s.Imaginary != 0.0f)
                    {
                        s /= matrixH[nOn].Magnitude;
                        matrixH[nOn] = matrixH[nOn].Magnitude;

                        for (var j = n + 1; j < order; j++)
                        {
                            matrixH[j*order + n] *= s.Conjugate();
                        }
                    }

                    // Inverse operation (columns).
                    for (var j = l + 1; j <= n; j++)
                    {
                        x = vectorV[j - 1];
                        var jO = j*order;
                        var jm1 = j - 1;
                        var jm1O = jm1*order;
                        var jm1Oj = jm1O + j;
                        for (var i = 0; i <= j; i++)
                        {
                            var jm1Oi = jm1O + i;
                            z = matrixH[jO + i];
                            if (i != j)
                            {
                                y = matrixH[jm1Oi];
                                matrixH[jm1Oi] = (x*y) + (matrixH[jm1O + j].Imaginary*z);
                            }
                            else
                            {
                                y = matrixH[jm1Oi].Real;
                                matrixH[jm1Oi] = new Numerics.Complex32((x.Real*y.Real) - (x.Imaginary*y.Imaginary) + (matrixH[jm1O + j].Imaginary*z.Real), matrixH[jm1Oi].Imaginary);
                            }

                            matrixH[jO + i] = (x.Conjugate()*z) - (matrixH[jm1O + j].Imaginary*y);
                        }

                        for (var i = 0; i < order; i++)
                        {
                            y = dataEv[((j - 1)*order) + i];
                            z = dataEv[(j*order) + i];
                            dataEv[jm1O + i] = (x*y) + (matrixH[jm1Oj].Imaginary*z);
                            dataEv[jO + i] = (x.Conjugate()*z) - (matrixH[jm1Oj].Imaginary*y);
                        }
                    }

                    if (s.Imaginary != 0.0f)
                    {
                        for (var i = 0; i <= n; i++)
                        {
                            matrixH[nO + i] *= s;
                        }

                        for (var i = 0; i < order; i++)
                        {
                            dataEv[nO + i] *= s;
                        }
                    }
                }
            }

            // All roots found.
            // Backsubstitute to find vectors of upper triangular form
            norm = 0.0f;
            for (var i = 0; i < order; i++)
            {
                for (var j = i; j < order; j++)
                {
                    norm = Math.Max(norm, Math.Abs(matrixH[j*order + i].Real) + Math.Abs(matrixH[j*order + i].Imaginary));
                }
            }

            if (order == 1)
            {
                return;
            }

            if (norm == 0.0)
            {
                return;
            }

            for (n = order - 1; n > 0; n--)
            {
                var nO = n*order;
                var nOn = nO + n;
                x = vectorV[n];
                matrixH[nOn] = 1.0f;

                for (var i = n - 1; i >= 0; i--)
                {
                    z = 0.0f;
                    for (var j = i + 1; j <= n; j++)
                    {
                        z += matrixH[j*order + i]*matrixH[nO + j];
                    }

                    y = x - vectorV[i];
                    if (y.Real == 0.0f && y.Imaginary == 0.0f)
                    {
                        y = eps*norm;
                    }

                    matrixH[nO + i] = z/y;

                    // Overflow control
                    var tr = Math.Abs(matrixH[nO + i].Real) + Math.Abs(matrixH[nO + i].Imaginary);
                    if ((eps*tr)*tr > 1)
                    {
                        for (var j = i; j <= n; j++)
                        {
                            matrixH[nO + j] = matrixH[nO + j]/tr;
                        }
                    }
                }
            }

            // Back transformation to get eigenvectors of original matrix
            for (var j = order - 1; j > 0; j--)
            {
                var jO = j*order;
                for (var i = 0; i < order; i++)
                {
                    z = Numerics.Complex32.Zero;
                    for (var k = 0; k <= j; k++)
                    {
                        z += dataEv[(k*order) + i]*matrixH[jO + k];
                    }

                    dataEv[jO + i] = z;
                }
            }
        }
コード例 #6
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>
        /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
        public override void Solve(Vector<Numerics.Complex32> input, Vector<Numerics.Complex32> result)
        {
            // Ax=b where A is an m x m matrix
            // Check that b is a column vector with m entries
            if (EigenValues.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            // Check that x is a column vector with n entries
            if (EigenValues.Count != result.Count)
            {
                throw new ArgumentException(Resources.ArgumentMatrixDimensions);
            }

            if (IsSymmetric)
            {
                // Symmetric case -> x = V * inv(λ) * VH * b;
                var order = EigenValues.Count;
                var tmp = new Numerics.Complex32[order];
                Numerics.Complex32 value;

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    if (j < order)
                    {
                        for (var i = 0; i < order; i++)
                        {
                            value += ((DenseMatrix) EigenVectors).Values[(j*order) + i].Conjugate()*input[i];
                        }

                        value /= (float) EigenValues[j].Real;
                    }

                    tmp[j] = value;
                }

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    for (var i = 0; i < order; i++)
                    {
                        value += ((DenseMatrix) EigenVectors).Values[(i*order) + j]*tmp[i];
                    }

                    result[j] = value;
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
            }
        }
コード例 #7
0
        /// <summary>
        /// Solves a system of linear equations, <b>AX = B</b>, with A SVD factorized.
        /// </summary>
        /// <param name="input">The right hand side <see cref="Matrix{T}"/>, <b>B</b>.</param>
        /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>X</b>.</param>
        public override void Solve(Matrix<Numerics.Complex32> input, Matrix<Numerics.Complex32> result)
        {
            // The solution X should have the same number of columns as B
            if (input.ColumnCount != result.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension);
            }

            // The dimension compatibility conditions for X = A\B require the two matrices A and B to have the same number of rows
            if (EigenValues.Count != input.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension);
            }

            // The solution X row dimension is equal to the column dimension of A
            if (EigenValues.Count != result.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameColumnDimension);
            }

            if (IsSymmetric)
            {
                var order = EigenValues.Count;
                var tmp = new Numerics.Complex32[order];

                for (var k = 0; k < order; k++)
                {
                    for (var j = 0; j < order; j++)
                    {
                        Numerics.Complex32 value = 0.0f;
                        if (j < order)
                        {
                            for (var i = 0; i < order; i++)
                            {
                                value += ((DenseMatrix) EigenVectors).Values[(j*order) + i].Conjugate()*input.At(i, k);
                            }

                            value /= (float) EigenValues[j].Real;
                        }

                        tmp[j] = value;
                    }

                    for (var j = 0; j < order; j++)
                    {
                        Numerics.Complex32 value = 0.0f;
                        for (var i = 0; i < order; i++)
                        {
                            value += ((DenseMatrix) EigenVectors).Values[(i*order) + j]*tmp[i];
                        }

                        result.At(j, k, value);
                    }
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
            }
        }
コード例 #8
0
        /// <summary>
        /// Nonsymmetric reduction from Hessenberg to real Schur form.
        /// </summary>
        /// <param name="vectorV">Data array of the eigenvectors</param>
        /// <param name="dataEv">Data array of matrix V (eigenvectors)</param>
        /// <param name="matrixH">Array for internal storage of nonsymmetric Hessenberg form.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>This is derived from the Algol procedure hqr2,
        /// by Martin and Wilkinson, Handbook for Auto. Comp.,
        /// Vol.ii-Linear Algebra, and the corresponding
        /// Fortran subroutine in EISPACK.</remarks>
        internal static void NonsymmetricReduceHessenberToRealSchur(Numerics.Complex32[] vectorV, Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order)
        {
            // Initialize
            var n   = order - 1;
            var eps = (float)Precision.SingleMachinePrecision;

            float norm;

            Numerics.Complex32 x, y, z, exshift = Numerics.Complex32.Zero;

            // Outer loop over eigenvalue index
            var iter = 0;

            while (n >= 0)
            {
                // Look for single small sub-diagonal element
                var l = n;
                while (l > 0)
                {
                    var lm1  = l - 1;
                    var lm1O = lm1 * order;
                    var lO   = l * order;
                    var tst1 = Math.Abs(matrixH[lm1O + lm1].Real) + Math.Abs(matrixH[lm1O + lm1].Imaginary) + Math.Abs(matrixH[lO + l].Real) + Math.Abs(matrixH[lO + l].Imaginary);
                    if (Math.Abs(matrixH[lm1O + l].Real) < eps * tst1)
                    {
                        break;
                    }

                    l--;
                }

                var nm1  = n - 1;
                var nm1O = nm1 * order;
                var nO   = n * order;
                var nOn  = nO + n;
                // Check for convergence
                // One root found
                if (l == n)
                {
                    matrixH[nOn] += exshift;
                    vectorV[n]    = matrixH[nOn];
                    n--;
                    iter = 0;
                }
                else
                {
                    // Form shift
                    Numerics.Complex32 s;
                    if (iter != 10 && iter != 20)
                    {
                        s = matrixH[nOn];
                        x = matrixH[nO + nm1] * matrixH[nm1O + n].Real;

                        if (x.Real != 0.0f || x.Imaginary != 0.0f)
                        {
                            y = (matrixH[nm1O + nm1] - s) / 2.0f;
                            z = ((y * y) + x).SquareRoot();
                            if ((y.Real * z.Real) + (y.Imaginary * z.Imaginary) < 0.0)
                            {
                                z *= -1.0f;
                            }

                            x /= y + z;
                            s  = s - x;
                        }
                    }
                    else
                    {
                        // Form exceptional shift
                        s = Math.Abs(matrixH[nm1O + n].Real) + Math.Abs(matrixH[(n - 2) * order + nm1].Real);
                    }

                    for (var i = 0; i <= n; i++)
                    {
                        matrixH[i * order + i] -= s;
                    }

                    exshift += s;
                    iter++;

                    // Reduce to triangle (rows)
                    for (var i = l + 1; i <= n; i++)
                    {
                        var im1     = i - 1;
                        var im1O    = im1 * order;
                        var im1Oim1 = im1O + im1;
                        s                 = matrixH[im1O + i].Real;
                        norm              = SpecialFunctions.Hypotenuse(matrixH[im1Oim1].Magnitude, s.Real);
                        x                 = matrixH[im1Oim1] / norm;
                        vectorV[i - 1]    = x;
                        matrixH[im1Oim1]  = norm;
                        matrixH[im1O + i] = new Numerics.Complex32(0.0f, s.Real / norm);

                        for (var j = i; j < order; j++)
                        {
                            var jO = j * order;
                            y = matrixH[jO + im1];
                            z = matrixH[jO + i];
                            matrixH[jO + im1] = (x.Conjugate() * y) + (matrixH[im1O + i].Imaginary * z);
                            matrixH[jO + i]   = (x * z) - (matrixH[im1O + i].Imaginary * y);
                        }
                    }

                    s = matrixH[nOn];
                    if (s.Imaginary != 0.0f)
                    {
                        s           /= matrixH[nOn].Magnitude;
                        matrixH[nOn] = matrixH[nOn].Magnitude;

                        for (var j = n + 1; j < order; j++)
                        {
                            matrixH[j * order + n] *= s.Conjugate();
                        }
                    }

                    // Inverse operation (columns).
                    for (var j = l + 1; j <= n; j++)
                    {
                        x = vectorV[j - 1];
                        var jO    = j * order;
                        var jm1   = j - 1;
                        var jm1O  = jm1 * order;
                        var jm1Oj = jm1O + j;
                        for (var i = 0; i <= j; i++)
                        {
                            var jm1Oi = jm1O + i;
                            z = matrixH[jO + i];
                            if (i != j)
                            {
                                y = matrixH[jm1Oi];
                                matrixH[jm1Oi] = (x * y) + (matrixH[jm1O + j].Imaginary * z);
                            }
                            else
                            {
                                y = matrixH[jm1Oi].Real;
                                matrixH[jm1Oi] = new Numerics.Complex32((x.Real * y.Real) - (x.Imaginary * y.Imaginary) + (matrixH[jm1O + j].Imaginary * z.Real), matrixH[jm1Oi].Imaginary);
                            }

                            matrixH[jO + i] = (x.Conjugate() * z) - (matrixH[jm1O + j].Imaginary * y);
                        }

                        for (var i = 0; i < order; i++)
                        {
                            y = dataEv[((j - 1) * order) + i];
                            z = dataEv[(j * order) + i];
                            dataEv[jm1O + i] = (x * y) + (matrixH[jm1Oj].Imaginary * z);
                            dataEv[jO + i]   = (x.Conjugate() * z) - (matrixH[jm1Oj].Imaginary * y);
                        }
                    }

                    if (s.Imaginary != 0.0f)
                    {
                        for (var i = 0; i <= n; i++)
                        {
                            matrixH[nO + i] *= s;
                        }

                        for (var i = 0; i < order; i++)
                        {
                            dataEv[nO + i] *= s;
                        }
                    }
                }
            }

            // All roots found.
            // Backsubstitute to find vectors of upper triangular form
            norm = 0.0f;
            for (var i = 0; i < order; i++)
            {
                for (var j = i; j < order; j++)
                {
                    norm = Math.Max(norm, Math.Abs(matrixH[j * order + i].Real) + Math.Abs(matrixH[j * order + i].Imaginary));
                }
            }

            if (order == 1)
            {
                return;
            }

            if (norm == 0.0)
            {
                return;
            }

            for (n = order - 1; n > 0; n--)
            {
                var nO  = n * order;
                var nOn = nO + n;
                x            = vectorV[n];
                matrixH[nOn] = 1.0f;

                for (var i = n - 1; i >= 0; i--)
                {
                    z = 0.0f;
                    for (var j = i + 1; j <= n; j++)
                    {
                        z += matrixH[j * order + i] * matrixH[nO + j];
                    }

                    y = x - vectorV[i];
                    if (y.Real == 0.0f && y.Imaginary == 0.0f)
                    {
                        y = eps * norm;
                    }

                    matrixH[nO + i] = z / y;

                    // Overflow control
                    var tr = Math.Abs(matrixH[nO + i].Real) + Math.Abs(matrixH[nO + i].Imaginary);
                    if ((eps * tr) * tr > 1)
                    {
                        for (var j = i; j <= n; j++)
                        {
                            matrixH[nO + j] = matrixH[nO + j] / tr;
                        }
                    }
                }
            }

            // Back transformation to get eigenvectors of original matrix
            for (var j = order - 1; j > 0; j--)
            {
                var jO = j * order;
                for (var i = 0; i < order; i++)
                {
                    z = Numerics.Complex32.Zero;
                    for (var k = 0; k <= j; k++)
                    {
                        z += dataEv[(k * order) + i] * matrixH[jO + k];
                    }

                    dataEv[jO + i] = z;
                }
            }
        }
コード例 #9
0
        /// <summary>
        /// Nonsymmetric reduction to Hessenberg form.
        /// </summary>
        /// <param name="dataEv">Data array of matrix V (eigenvectors)</param>
        /// <param name="matrixH">Array for internal storage of nonsymmetric Hessenberg form.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>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.</remarks>
        internal static void NonsymmetricReduceToHessenberg(Numerics.Complex32[] dataEv, Numerics.Complex32[] matrixH, int order)
        {
            var ort = new Numerics.Complex32[order];

            for (var m = 1; m < order - 1; m++)
            {
                // Scale column.
                var scale = 0.0f;
                var mm1O  = (m - 1) * order;
                for (var i = m; i < order; i++)
                {
                    scale += Math.Abs(matrixH[mm1O + i].Real) + Math.Abs(matrixH[mm1O + i].Imaginary);
                }

                if (scale != 0.0f)
                {
                    // Compute Householder transformation.
                    var h = 0.0f;
                    for (var i = order - 1; i >= m; i--)
                    {
                        ort[i] = matrixH[mm1O + i] / scale;
                        h     += ort[i].MagnitudeSquared;
                    }

                    var g = (float)Math.Sqrt(h);
                    if (ort[m].Magnitude != 0)
                    {
                        h      = h + (ort[m].Magnitude * g);
                        g     /= ort[m].Magnitude;
                        ort[m] = (1.0f + g) * ort[m];
                    }
                    else
                    {
                        ort[m]            = g;
                        matrixH[mm1O + m] = scale;
                    }

                    // Apply Householder similarity transformation
                    // H = (I-u*u'/h)*H*(I-u*u')/h)
                    for (var j = m; j < order; j++)
                    {
                        var f  = Numerics.Complex32.Zero;
                        var jO = j * order;
                        for (var i = order - 1; i >= m; i--)
                        {
                            f += ort[i].Conjugate() * matrixH[jO + i];
                        }

                        f = f / h;
                        for (var i = m; i < order; i++)
                        {
                            matrixH[jO + i] -= f * ort[i];
                        }
                    }

                    for (var i = 0; i < order; i++)
                    {
                        var f = Numerics.Complex32.Zero;
                        for (var j = order - 1; j >= m; j--)
                        {
                            f += ort[j] * matrixH[j * order + i];
                        }

                        f = f / h;
                        for (var j = m; j < order; j++)
                        {
                            matrixH[j * order + i] -= f * ort[j].Conjugate();
                        }
                    }

                    ort[m]             = scale * ort[m];
                    matrixH[mm1O + m] *= -g;
                }
            }

            // Accumulate transformations (Algol's ortran).
            for (var i = 0; i < order; i++)
            {
                for (var j = 0; j < order; j++)
                {
                    dataEv[(j * order) + i] = i == j ? Numerics.Complex32.One : Numerics.Complex32.Zero;
                }
            }

            for (var m = order - 2; m >= 1; m--)
            {
                var mm1O  = (m - 1) * order;
                var mm1Om = mm1O + m;
                if (matrixH[mm1Om] != Numerics.Complex32.Zero && ort[m] != Numerics.Complex32.Zero)
                {
                    var norm = (matrixH[mm1Om].Real * ort[m].Real) + (matrixH[mm1Om].Imaginary * ort[m].Imaginary);

                    for (var i = m + 1; i < order; i++)
                    {
                        ort[i] = matrixH[mm1O + i];
                    }

                    for (var j = m; j < order; j++)
                    {
                        var g = Numerics.Complex32.Zero;
                        for (var i = m; i < order; i++)
                        {
                            g += ort[i].Conjugate() * dataEv[(j * order) + i];
                        }

                        // Double division avoids possible underflow
                        g /= norm;
                        for (var i = m; i < order; i++)
                        {
                            dataEv[(j * order) + i] += g * ort[i];
                        }
                    }
                }
            }

            // Create real subdiagonal elements.
            for (var i = 1; i < order; i++)
            {
                var im1   = i - 1;
                var im1O  = im1 * order;
                var im1Oi = im1O + i;
                var iO    = i * order;
                if (matrixH[im1Oi].Imaginary != 0.0f)
                {
                    var y = matrixH[im1Oi] / matrixH[im1Oi].Magnitude;
                    matrixH[im1Oi] = matrixH[im1Oi].Magnitude;
                    for (var j = i; j < order; j++)
                    {
                        matrixH[j * order + i] *= y.Conjugate();
                    }

                    for (var j = 0; j <= Math.Min(i + 1, order - 1); j++)
                    {
                        matrixH[iO + j] *= y;
                    }

                    for (var j = 0; j < order; j++)
                    {
                        dataEv[(i * order) + j] *= y;
                    }
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Reduces a complex hermitian matrix to a real symmetric tridiagonal matrix using unitary similarity transformations.
        /// </summary>
        /// <param name="matrixA">Source matrix to reduce</param>
        /// <param name="d">Output: Arrays for internal storage of real parts of eigenvalues</param>
        /// <param name="e">Output: Arrays for internal storage of imaginary parts of eigenvalues</param>
        /// <param name="tau">Output: Arrays that contains further information about the transformations.</param>
        /// <param name="order">Order of initial matrix</param>
        /// <remarks>This is derived from the Algol procedures HTRIDI by
        /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for
        /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding
        /// Fortran subroutine in EISPACK.</remarks>
        internal static void SymmetricTridiagonalize(Numerics.Complex32[] matrixA, float[] d, float[] e, Numerics.Complex32[] tau, int order)
        {
            float hh;

            tau[order - 1] = Numerics.Complex32.One;

            for (var i = 0; i < order; i++)
            {
                d[i] = matrixA[i * order + i].Real;
            }

            // Householder reduction to tridiagonal form.
            for (var i = order - 1; i > 0; i--)
            {
                // Scale to avoid under/overflow.
                var scale = 0.0f;
                var h     = 0.0f;

                for (var k = 0; k < i; k++)
                {
                    scale = scale + Math.Abs(matrixA[k * order + i].Real) + Math.Abs(matrixA[k * order + i].Imaginary);
                }

                if (scale == 0.0f)
                {
                    tau[i - 1] = Numerics.Complex32.One;
                    e[i]       = 0.0f;
                }
                else
                {
                    for (var k = 0; k < i; k++)
                    {
                        matrixA[k * order + i] /= scale;
                        h += matrixA[k * order + i].MagnitudeSquared;
                    }

                    Numerics.Complex32 g = (float)Math.Sqrt(h);
                    e[i] = scale * g.Real;

                    Numerics.Complex32 temp;
                    var im1Oi = (i - 1) * order + i;
                    var f     = matrixA[im1Oi];
                    if (f.Magnitude != 0.0f)
                    {
                        temp            = -(matrixA[im1Oi].Conjugate() * tau[i].Conjugate()) / f.Magnitude;
                        h              += f.Magnitude * g.Real;
                        g               = 1.0f + (g / f.Magnitude);
                        matrixA[im1Oi] *= g;
                    }
                    else
                    {
                        temp           = -tau[i].Conjugate();
                        matrixA[im1Oi] = g;
                    }

                    if ((f.Magnitude == 0.0f) || (i != 1))
                    {
                        f = Numerics.Complex32.Zero;
                        for (var j = 0; j < i; j++)
                        {
                            var tmp = Numerics.Complex32.Zero;
                            var jO  = j * order;
                            // Form element of A*U.
                            for (var k = 0; k <= j; k++)
                            {
                                tmp += matrixA[k * order + j] * matrixA[k * order + i].Conjugate();
                            }

                            for (var k = j + 1; k <= i - 1; k++)
                            {
                                tmp += matrixA[jO + k].Conjugate() * matrixA[k * order + i].Conjugate();
                            }

                            // Form element of P
                            tau[j] = tmp / h;
                            f     += (tmp / h) * matrixA[jO + i];
                        }

                        hh = f.Real / (h + h);

                        // Form the reduced A.
                        for (var j = 0; j < i; j++)
                        {
                            f      = matrixA[j * order + i].Conjugate();
                            g      = tau[j] - (hh * f);
                            tau[j] = g.Conjugate();

                            for (var k = 0; k <= j; k++)
                            {
                                matrixA[k * order + j] -= (f * tau[k]) + (g * matrixA[k * order + i]);
                            }
                        }
                    }

                    for (var k = 0; k < i; k++)
                    {
                        matrixA[k * order + i] *= scale;
                    }

                    tau[i - 1] = temp.Conjugate();
                }

                hh   = d[i];
                d[i] = matrixA[i * order + i].Real;
                matrixA[i * order + i] = new Numerics.Complex32(hh, scale * (float)Math.Sqrt(h));
            }

            hh         = d[0];
            d[0]       = matrixA[0].Real;
            matrixA[0] = hh;
            e[0]       = 0.0f;
        }