Пример #1
0
        /// <summary>
        /// Multiplies a scalar to each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">
        /// The scalar to multiply.
        /// </param>
        /// <param name="result">
        /// The vector to store the result of the multiplication.
        /// </param>
        protected override void DoMultiply(Complex scalar, Vector <Complex> result)
        {
            var sparseResult = result as SparseVector;

            if (sparseResult == null)
            {
                result.Clear();
                for (var index = 0; index < _storage.ValueCount; index++)
                {
                    result.At(_storage.Indices[index], scalar * _storage.Values[index]);
                }
            }
            else
            {
                if (!ReferenceEquals(this, result))
                {
                    sparseResult._storage.ValueCount = _storage.ValueCount;
                    sparseResult._storage.Indices    = new int[_storage.ValueCount];
                    Buffer.BlockCopy(_storage.Indices, 0, sparseResult._storage.Indices, 0, _storage.ValueCount * Constants.SizeOfInt);
                    sparseResult._storage.Values = new Complex[_storage.ValueCount];
                    Array.Copy(_storage.Values, sparseResult._storage.Values, _storage.ValueCount);
                }

                Control.LinearAlgebraProvider.ScaleArray(scalar, sparseResult._storage.Values, sparseResult._storage.Values);
            }
        }
Пример #2
0
        /// <summary>
        /// Returns the largest absolute value from the unsorted data array.
        /// Returns NaN if data is empty or any entry is NaN.
        /// </summary>
        /// <param name="data">Sample array, no sorting is assumed.</param>
        public static Complex64 MaximumMagnitudePhase(Complex64[] data)
        {
            if (data.Length == 0)
            {
                return(new Complex64(double.NaN, double.NaN));
            }

            double    maxMagnitude = 0.0d;
            Complex64 max          = Complex64.Zero;

            for (int i = 0; i < data.Length; i++)
            {
                double magnitude = data[i].Magnitude;
                if (double.IsNaN(magnitude))
                {
                    return(new Complex64(double.NaN, double.NaN));
                }
                if (magnitude > maxMagnitude || magnitude == maxMagnitude && data[i].Phase > max.Phase)
                {
                    maxMagnitude = magnitude;
                    max          = data[i];
                }
            }

            return(max);
        }
Пример #3
0
 /// <summary>
 /// Scale vector <paramref name="a"/> by <paramref name="z"/> starting from index <paramref name="start"/>
 /// </summary>
 /// <param name="a">Source vector</param>
 /// <param name="start">Row to scale from</param>
 /// <param name="z">Scale value</param>
 private static void CscalVector(Complex[] a, int start, Complex z)
 {
     for (var i = start; i < a.Length; i++)
     {
         a[i] = a[i] * z;
     }
 }
Пример #4
0
        /// <summary>
        /// Multiplies each element of the matrix by a scalar and places results into the result matrix.
        /// </summary>
        /// <param name="scalar">The scalar to multiply the matrix with.</param>
        /// <param name="result">The matrix to store the result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
        /// <exception cref="ArgumentException">If the result matrix's dimensions are not the same as this matrix.</exception>
        protected override void DoMultiply(Complex scalar, Matrix <Complex> result)
        {
            if (scalar == 0.0)
            {
                result.Clear();
                return;
            }

            if (scalar == 1.0)
            {
                CopyTo(result);
                return;
            }

            var diagResult = result as DiagonalMatrix;

            if (diagResult == null)
            {
                base.Multiply(scalar, result);
            }
            else
            {
                if (!ReferenceEquals(this, result))
                {
                    CopyTo(diagResult);
                }

                Control.LinearAlgebraProvider.ScaleArray(scalar, _data, diagResult._data);
            }
        }
Пример #5
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>
        /// <param name="result">The left hand side <see cref="Matrix{T}"/>, <b>x</b>.</param>
        public override void Solve(Vector <Complex> input, Vector <Complex> result)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (!ComputeVectors)
            {
                throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
            }

            // Ax=b where A is an m x n matrix
            // Check that b is a column vector with m entries
            if (MatrixU.RowCount != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            // Check that x is a column vector with n entries
            if (MatrixVT.ColumnCount != result.Count)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(MatrixVT, result);
            }

            var mn  = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount);
            var tmp = new Complex[MatrixVT.ColumnCount];

            for (var j = 0; j < MatrixVT.ColumnCount; j++)
            {
                var value = Complex.Zero;
                if (j < mn)
                {
                    for (var i = 0; i < MatrixU.RowCount; i++)
                    {
                        value += MatrixU.At(i, j).Conjugate() * input[i];
                    }

                    value /= VectorS[j];
                }

                tmp[j] = value;
            }

            for (var j = 0; j < MatrixVT.ColumnCount; j++)
            {
                var value = Complex.Zero;
                for (var i = 0; i < MatrixVT.ColumnCount; i++)
                {
                    value += MatrixVT.At(i, j).Conjugate() * tmp[i];
                }

                result[j] = value;
            }
        }
Пример #6
0
        /// <summary>
        /// Returns the smallest absolute value from the unsorted data array.
        /// Returns NaN if data is empty or any entry is NaN.
        /// </summary>
        /// <param name="data">Sample array, no sorting is assumed.</param>
        public static Complex64 MinimumMagnitudePhase(Complex64[] data)
        {
            if (data.Length == 0)
            {
                return(new Complex64(double.NaN, double.NaN));
            }

            double    minMagnitude = double.PositiveInfinity;
            Complex64 min          = new Complex64(double.PositiveInfinity, double.PositiveInfinity);

            for (int i = 0; i < data.Length; i++)
            {
                double magnitude = data[i].Magnitude;
                if (double.IsNaN(magnitude))
                {
                    return(new Complex64(double.NaN, double.NaN));
                }
                if (magnitude < minMagnitude || magnitude == minMagnitude && data[i].Phase < min.Phase)
                {
                    minMagnitude = magnitude;
                    min          = data[i];
                }
            }

            return(min);
        }
Пример #7
0
 /// <summary>
 /// Create a new diagonal matrix with the given number of rows and columns.
 /// All diagonal cells of the matrix will be initialized to the provided value, all non-diagonal ones to zero.
 /// Zero-length matrices are not supported.
 /// </summary>
 /// <exception cref="ArgumentException">If the row or column count is less than one.</exception>
 public DiagonalMatrix(int rows, int columns, Complex diagonalValue)
     : this(rows, columns)
 {
     for (var i = 0; i < _data.Length; i++)
     {
         _data[i] = diagonalValue;
     }
 }
Пример #8
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UserEvd"/> class. This object will compute the
        /// the eigenvalue decomposition when the constructor is called and cache it's decomposition.
        /// </summary>
        /// <param name="matrix">The matrix to factor.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If EVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
        public UserEvd(Matrix<Complex> matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare);
            }

            var order = matrix.RowCount;

            // Initialize matricies for eigenvalues and eigenvectors
            MatrixEv = DenseMatrix.Identity(order);
            MatrixD = matrix.CreateMatrix(order, order);
            VectorEv = new DenseVector(order);
           
            IsSymmetric = true;

            for (var i = 0; IsSymmetric && i < order; i++)
            {
                for (var j = 0; IsSymmetric && j < order; j++)
                {
                    IsSymmetric &= matrix.At(i, j) == matrix.At(j, i).Conjugate();
                }
            }

            if (IsSymmetric)
            {
                var matrixCopy = matrix.ToArray();
                var tau = new Complex[order];
                var d = new double[order];
                var e = new double[order];

                SymmetricTridiagonalize(matrixCopy, d, e, tau, order);
                SymmetricDiagonalize(d, e, order);
                SymmetricUntridiagonalize(matrixCopy, tau, order);

                for (var i = 0; i < order; i++)
                {
                    VectorEv[i] = new Complex(d[i], e[i]);
                }
            }
            else
            {
                var matrixH = matrix.ToArray();
                NonsymmetricReduceToHessenberg(matrixH, order);
                NonsymmetricReduceHessenberToRealSchur(matrixH, order);
            }

            MatrixD.SetDiagonal(VectorEv);
        }
Пример #9
0
        /// <summary>
        /// Multiplies a scalar to each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to multiply.</param>
        /// <param name="result">The vector to store the result of the multiplication.</param>
        /// <remarks></remarks>
        protected override void DoMultiply(Complex scalar, Vector <Complex> result)
        {
            var denseResult = result as DenseVector;

            if (denseResult == null)
            {
                base.DoMultiply(scalar, result);
            }
            else
            {
                Control.LinearAlgebraProvider.ScaleArray(scalar, _values, denseResult.Values);
            }
        }
        public void FourierBluesteinIsReversible(FourierOptions options)
        {
            var dft = new DiscreteFourierTransform();

            var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), 0x7FFF);
            var work = new Complex[samples.Length];
            samples.CopyTo(work, 0);

            dft.BluesteinForward(work, options);
            Assert.IsFalse(work.ListAlmostEqual(samples, 6));

            dft.BluesteinInverse(work, options);
            AssertHelpers.ListAlmostEqual(samples, work, 10);
        }
Пример #11
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UserCholesky"/> class. This object will compute the
        /// Cholesky factorization when the constructor is called and cache it's factorization.
        /// </summary>
        /// <param name="matrix">The matrix to factor.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
        /// <exception cref="ArgumentException">If <paramref name="matrix"/> is not positive definite.</exception>
        public UserCholesky(Matrix <Complex> matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare);
            }

            // Create a new matrix for the Cholesky factor, then perform factorization (while overwriting).
            CholeskyFactor = matrix.Clone();
            var tmpColumn = new Complex[CholeskyFactor.RowCount];

            // Main loop - along the diagonal
            for (var ij = 0; ij < CholeskyFactor.RowCount; ij++)
            {
                // "Pivot" element
                var tmpVal = CholeskyFactor.At(ij, ij);

                if (tmpVal.Real > 0.0)
                {
                    tmpVal = tmpVal.SquareRoot();
                    CholeskyFactor.At(ij, ij, tmpVal);
                    tmpColumn[ij] = tmpVal;

                    // Calculate multipliers and copy to local column
                    // Current column, below the diagonal
                    for (var i = ij + 1; i < CholeskyFactor.RowCount; i++)
                    {
                        CholeskyFactor.At(i, ij, CholeskyFactor.At(i, ij) / tmpVal);
                        tmpColumn[i] = CholeskyFactor.At(i, ij);
                    }

                    // Remaining columns, below the diagonal
                    DoCholeskyStep(CholeskyFactor, CholeskyFactor.RowCount, ij + 1, CholeskyFactor.RowCount, tmpColumn, Control.NumberOfParallelWorkerThreads);
                }
                else
                {
                    throw new ArgumentException(Resources.ArgumentMatrixPositiveDefinite);
                }

                for (var i = ij + 1; i < CholeskyFactor.RowCount; i++)
                {
                    CholeskyFactor.At(ij, i, Complex.Zero);
                }
            }
        }
Пример #12
0
        public void FourierDefaultTransformSatisfiesParsevalsTheorem(int count)
        {
            var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), count);

            var timeSpaceEnergy = (from s in samples select s.MagnitudeSquared()).Mean();

            var work = new Complex[samples.Length];
            samples.CopyTo(work, 0);

            // Default -> Symmetric Scaling
            Transform.FourierForward(work);

            var frequencySpaceEnergy = (from s in work select s.MagnitudeSquared()).Mean();

            Assert.AreEqual(timeSpaceEnergy, frequencySpaceEnergy, 1e-12);
        }
Пример #13
0
        public static void AlmostEqual(Complex expected, Complex actual)
        {
            if (expected.IsNaN() && actual.IsNaN() || expected.IsInfinity() && expected.IsInfinity())
            {
                return;
            }

            if (!expected.Real.AlmostEqual(actual.Real))
            {
                Assert.Fail("Real components are not equal. Expected:{0}; Actual:{1}", expected.Real, actual.Real);
            }

            if (!expected.Imaginary.AlmostEqual(actual.Imaginary))
            {
                Assert.Fail("Imaginary components are not equal. Expected:{0}; Actual:{1}", expected.Imaginary, actual.Imaginary);
            }
        }
Пример #14
0
        /// <summary>
        /// Adds a scalar to each element of the vector and stores the result in the result vector.
        /// Warning, the new 'sparse vector' with a non-zero scalar added to it will be a 100% filled
        /// sparse vector and very inefficient. Would be better to work with a dense vector instead.
        /// </summary>
        /// <param name="scalar">
        /// The scalar to add.
        /// </param>
        /// <param name="result">
        /// The vector to store the result of the addition.
        /// </param>
        protected override void DoAdd(Complex scalar, Vector <Complex> result)
        {
            if (scalar == Complex.Zero)
            {
                if (!ReferenceEquals(this, result))
                {
                    CopyTo(result);
                }

                return;
            }

            if (ReferenceEquals(this, result))
            {
                //populate a new vector with the scalar
                var vnonZeroValues  = new Complex[Count];
                var vnonZeroIndices = new int[Count];
                for (int index = 0; index < Count; index++)
                {
                    vnonZeroIndices[index] = index;
                    vnonZeroValues[index]  = scalar;
                }

                //populate the non zero values from this
                var indices = _storage.Indices;
                var values  = _storage.Values;
                for (int j = 0; j < _storage.ValueCount; j++)
                {
                    vnonZeroValues[indices[j]] = values[j] + scalar;
                }

                //assign this vectors arrary to the new arrays.
                _storage.Values     = vnonZeroValues;
                _storage.Indices    = vnonZeroIndices;
                _storage.ValueCount = Count;
            }
            else
            {
                for (var index = 0; index < Count; index++)
                {
                    result.At(index, At(index) + scalar);
                }
            }
        }
Пример #15
0
        /// <summary>
        /// Returns an array of starting vectors.
        /// </summary>
        /// <param name="maximumNumberOfStartingVectors">The maximum number of starting vectors that should be created.</param>
        /// <param name="numberOfVariables">The number of variables.</param>
        /// <returns>
        ///  An array with starting vectors. The array will never be larger than the
        ///  <paramref name="maximumNumberOfStartingVectors"/> but it may be smaller if
        ///  the <paramref name="numberOfVariables"/> is smaller than
        ///  the <paramref name="maximumNumberOfStartingVectors"/>.
        /// </returns>
        static IList <Vector> CreateStartingVectors(int maximumNumberOfStartingVectors, int numberOfVariables)
        {
            // Create no more starting vectors than the size of the problem - 1
            // Get random values and then orthogonalize them with
            // modified Gramm - Schmidt
            var count = NumberOfStartingVectorsToCreate(maximumNumberOfStartingVectors, numberOfVariables);

            // Get a random set of samples based on the standard normal distribution with
            // mean = 0 and sd = 1
            var distribution = new Normal();

            Matrix matrix = new DenseMatrix(numberOfVariables, count);

            for (var i = 0; i < matrix.ColumnCount; i++)
            {
                var samples   = new Complex[matrix.RowCount];
                var samplesRe = distribution.Samples().Take(matrix.RowCount).ToArray();
                var samplesIm = distribution.Samples().Take(matrix.RowCount).ToArray();
                for (int j = 0; j < matrix.RowCount; j++)
                {
                    samples[j] = new Complex(samplesRe[j], samplesIm[j]);
                }

                // Set the column
                matrix.SetColumn(i, samples);
            }

            // Compute the orthogonalization.
            var gs = matrix.GramSchmidt();
            var orthogonalMatrix = gs.Q;

            // Now transfer this to vectors
            var result = new List <Vector>();

            for (var i = 0; i < orthogonalMatrix.ColumnCount; i++)
            {
                result.Add((Vector)orthogonalMatrix.Column(i));

                // Normalize the result vector
                result[i].Multiply(1 / result[i].L2Norm(), result[i]);
            }

            return(result);
        }
Пример #16
0
        /// <summary>
        /// Subtracts a scalar from each element of the vector and stores the result in the result vector.
        /// </summary>
        /// <param name="scalar">The scalar to subtract.</param>
        /// <param name="result">The vector to store the result of the subtraction.</param>
        protected override void DoSubtract(Complex scalar, Vector <Complex> result)
        {
            var dense = result as DenseVector;

            if (dense == null)
            {
                base.DoSubtract(scalar, result);
            }
            else
            {
                CommonParallel.For(0, _values.Length, 4096, (a, b) =>
                {
                    for (int i = a; i < b; i++)
                    {
                        dense._values[i] = _values[i] - scalar;
                    }
                });
            }
        }
Пример #17
0
        /// <summary>
        /// Multiplies this matrix with another matrix and places the results into the result matrix.
        /// </summary>
        /// <param name="other">The matrix to multiply with.</param>
        /// <param name="result">The result of the multiplication.</param>
        /// <exception cref="ArgumentNullException">If the other matrix is <see langword="null" />.</exception>
        /// <exception cref="ArgumentNullException">If the result matrix is <see langword="null" />.</exception>
        /// <exception cref="ArgumentException">If <strong>this.Columns != other.Rows</strong>.</exception>
        /// <exception cref="ArgumentException">If the result matrix's dimensions are not the this.Rows x other.Columns.</exception>
        public override void Multiply(Matrix <Complex> other, Matrix <Complex> result)
        {
            if (other == null)
            {
                throw new ArgumentNullException("other");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (ColumnCount != other.RowCount)
            {
                throw DimensionsDontMatch <ArgumentException>(this, other);
            }

            if (result.RowCount != RowCount || result.ColumnCount != other.ColumnCount)
            {
                throw DimensionsDontMatch <ArgumentException>(this, result);
            }

            var m = other as DiagonalMatrix;
            var r = result as DiagonalMatrix;

            if (m == null || r == null)
            {
                base.Multiply(other, result);
            }
            else
            {
                var thisDataCopy  = new Complex[r._data.Length];
                var otherDataCopy = new Complex[r._data.Length];
                Array.Copy(_data, thisDataCopy, (r._data.Length > _data.Length) ? _data.Length : r._data.Length);
                Array.Copy(m._data, otherDataCopy, (r._data.Length > m._data.Length) ? m._data.Length : r._data.Length);

                Control.LinearAlgebraProvider.PointWiseMultiplyArrays(thisDataCopy, otherDataCopy, r._data);
            }
        }
Пример #18
0
 /// <summary>
 /// Subtracts a scalar from each element of the vector and stores the result in the result vector.
 /// </summary>
 /// <param name="scalar">
 /// The scalar to subtract.
 /// </param>
 /// <param name="result">
 /// The vector to store the result of the subtraction.
 /// </param>
 protected override void DoSubtract(Complex scalar, Vector <Complex> result)
 {
     DoAdd(-scalar, result);
 }
Пример #19
0
 public SparseVector(int length, Complex value)
     : this(SparseVectorStorage <Complex> .OfInit(length, i => value))
 {
 }
Пример #20
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<Complex> input, Matrix<Complex> result)
        {
            // Check for proper arguments.
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("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 (VectorEv.Count != input.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension);
            }

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

            if (IsSymmetric)
            {
                var order = VectorEv.Count;
                var tmp = new Complex[order];

                for (var k = 0; k < order; k++)
                {
                    for (var j = 0; j < order; j++)
                    {
                        Complex value = 0.0;
                        if (j < order)
                        {
                            for (var i = 0; i < order; i++)
                            {
                                value += MatrixEv.At(i, j).Conjugate() * input.At(i, k);
                            }

                            value /= VectorEv[j].Real;
                        }

                        tmp[j] = value;
                    }

                    for (var j = 0; j < order; j++)
                    {
                        Complex value = 0.0;
                        for (var i = 0; i < order; i++)
                        {
                            value += MatrixEv.At(j, i) * tmp[i];
                        }

                        result.At(j, k, value);
                    }
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric); 
            }
        }
Пример #21
0
        /// <summary>
        /// Nonsymmetric reduction from Hessenberg to real Schur form.
        /// </summary>
        /// <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>
        private void NonsymmetricReduceHessenberToRealSchur(Complex[,] matrixH, int order)
        {
            // Initialize
            var n = order - 1;
            var eps = Precision.DoubleMachinePrecision;

            double norm;
            Complex x, y, z, exshift = Complex.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 tst1 = Math.Abs(matrixH[l - 1, l - 1].Real) + Math.Abs(matrixH[l - 1, l - 1].Imaginary) + Math.Abs(matrixH[l, l].Real) + Math.Abs(matrixH[l, l].Imaginary);
                    if (Math.Abs(matrixH[l, l - 1].Real) < eps * tst1)
                    {
                        break;
                    }

                    l--;
                }

                // Check for convergence
                // One root found
                if (l == n)
                {
                    matrixH[n, n] += exshift;
                    VectorEv[n] = matrixH[n, n];
                    n--;
                    iter = 0;
                }
                else
                {
                    // Form shift
                    Complex s;
                    if (iter != 10 && iter != 20)
                    {
                        s = matrixH[n, n];
                        x = matrixH[n - 1, n] * matrixH[n, n - 1].Real;

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

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

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

                    exshift += s;
                    iter++;

                    // Reduce to triangle (rows)
                    for (var i = l + 1; i <= n; i++)
                    {
                        s = matrixH[i, i - 1].Real;
                        norm = SpecialFunctions.Hypotenuse(matrixH[i - 1, i - 1].Magnitude, s.Real);
                        x = matrixH[i - 1, i - 1] / norm;
                        VectorEv[i - 1] = x;
                        matrixH[i - 1, i - 1] = norm;
                        matrixH[i, i - 1] = new Complex(0.0, s.Real / norm);

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

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

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

                    // Inverse operation (columns).
                    for (var j = l + 1; j <= n; j++)
                    {
                        x = VectorEv[j - 1];
                        for (var i = 0; i <= j; i++)
                        {
                            z = matrixH[i, j];
                            if (i != j)
                            {
                                y = matrixH[i, j - 1];
                                matrixH[i, j - 1] = (x * y) + (matrixH[j, j - 1].Imaginary * z);
                            }
                            else
                            {
                                y = matrixH[i, j - 1].Real;
                                matrixH[i, j - 1] = new Complex((x.Real * y.Real) - (x.Imaginary * y.Imaginary) + (matrixH[j, j - 1].Imaginary * z.Real), matrixH[i, j - 1].Imaginary);
                            }

                            matrixH[i, j] = (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y);
                        }

                        for (var i = 0; i < order; i++)
                        {
                            y = MatrixEv.At(i, j - 1);
                            z = MatrixEv.At(i, j);
                            MatrixEv.At(i, j - 1, (x * y) + (matrixH[j, j - 1].Imaginary * z));
                            MatrixEv.At(i, j, (x.Conjugate() * z) - (matrixH[j, j - 1].Imaginary * y));
                        }
                    }

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

                        for (var i = 0; i < order; i++)
                        {
                            MatrixEv.At(i, n, MatrixEv.At(i, n) * s);
                        }
                    }
                }
            }

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

            if (order == 1)
            {
                return;
            }

            if (norm == 0.0)
            {
                return;
            }

            for (n = order - 1; n > 0; n--)
            {
                x = VectorEv[n];
                matrixH[n, n] = 1.0;

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

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

                    matrixH[i, n] = z / y;

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

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

                    MatrixEv.At(i, j, z);
                }
            }
        }
Пример #22
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>
        private static void SymmetricTridiagonalize(Complex[,] matrixA, double[] d, double[] e, Complex[] tau, int order)
        {
            double hh;
            tau[order - 1] = Complex.One;

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

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

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

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

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

                    Complex temp;
                    var f = matrixA[i, i - 1];
                    if (f.Magnitude != 0)
                    {
                        temp = -(matrixA[i, i - 1].Conjugate() * tau[i].Conjugate()) / f.Magnitude;
                        h += f.Magnitude * g.Real;
                        g = 1.0 + (g / f.Magnitude);
                        matrixA[i, i - 1] *= g;
                    }
                    else
                    {
                        temp = -tau[i].Conjugate();
                        matrixA[i, i - 1] = g;
                    }

                    if ((f.Magnitude == 0) || (i != 1))
                    {
                        f = Complex.Zero;
                        for (var j = 0; j < i; j++)
                        {
                            var tmp = Complex.Zero;

                            // Form element of A*U.
                            for (var k = 0; k <= j; k++)
                            {
                                tmp += matrixA[j, k] * matrixA[i, k].Conjugate();
                            }

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

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

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

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

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

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

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

                hh = d[i];
                d[i] = matrixA[i, i].Real;
                matrixA[i, i] = new Complex(hh, scale * Math.Sqrt(h));
            }

            hh = d[0];
            d[0] = matrixA[0, 0].Real;
            matrixA[0, 0] = hh;
            e[0] = 0.0;
        }
Пример #23
0
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient <see cref="Matrix"/>, <c>A</c>.</param>
        /// <param name="input">The solution <see cref="Vector"/>, <c>b</c>.</param>
        /// <param name="result">The result <see cref="Vector"/>, <c>x</c>.</param>
        public void Solve(Matrix matrix, Vector input, Vector result)
        {
            // If we were stopped before, we are no longer
            // We're doing this at the start of the method to ensure
            // that we can use these fields immediately.
            _hasBeenStopped = false;

            // Parameters checks
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
            }

            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (result.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            if (input.Count != matrix.RowCount)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(input, result);
            }

            // Initialize the solver fields
            // Set the convergence monitor
            if (_iterator == null)
            {
                _iterator = Iterator.CreateDefault();
            }

            if (_preconditioner == null)
            {
                _preconditioner = new UnitPreconditioner();
            }

            _preconditioner.Initialize(matrix);

            // Compute r_0 = b - Ax_0 for some initial guess x_0
            // In this case we take x_0 = vector
            // This is basically a SAXPY so it could be made a lot faster
            Vector residuals = new DenseVector(matrix.RowCount);

            CalculateTrueResidual(matrix, residuals, result, input);

            // Choose r~ (for example, r~ = r_0)
            var tempResiduals = residuals.Clone();

            // create seven temporary vectors needed to hold temporary
            // coefficients. All vectors are mangled in each iteration.
            // These are defined here to prevent stressing the garbage collector
            Vector vecP     = new DenseVector(residuals.Count);
            Vector vecPdash = new DenseVector(residuals.Count);
            Vector nu       = new DenseVector(residuals.Count);
            Vector vecS     = new DenseVector(residuals.Count);
            Vector vecSdash = new DenseVector(residuals.Count);
            Vector temp     = new DenseVector(residuals.Count);
            Vector temp2    = new DenseVector(residuals.Count);

            // create some temporary double variables that are needed
            // to hold values in between iterations
            Complex currentRho = 0;
            Complex alpha      = 0;
            Complex omega      = 0;

            var iterationNumber = 0;

            while (ShouldContinue(iterationNumber, result, input, residuals))
            {
                // rho_(i-1) = r~^T r_(i-1) // dotproduct r~ and r_(i-1)
                var oldRho = currentRho;
                currentRho = tempResiduals.ConjugateDotProduct(residuals);

                // if (rho_(i-1) == 0) // METHOD FAILS
                // If rho is only 1 ULP from zero then we fail.
                if (currentRho.Real.AlmostEqual(0, 1) && currentRho.Imaginary.AlmostEqual(0, 1))
                {
                    // Rho-type breakdown
                    throw new Exception("Iterative solver experience a numerical break down");
                }

                if (iterationNumber != 0)
                {
                    // beta_(i-1) = (rho_(i-1)/rho_(i-2))(alpha_(i-1)/omega(i-1))
                    var beta = (currentRho / oldRho) * (alpha / omega);

                    // p_i = r_(i-1) + beta_(i-1)(p_(i-1) - omega_(i-1) * nu_(i-1))
                    nu.Multiply(-omega, temp);
                    vecP.Add(temp, temp2);
                    temp2.CopyTo(vecP);

                    vecP.Multiply(beta, vecP);
                    vecP.Add(residuals, temp2);
                    temp2.CopyTo(vecP);
                }
                else
                {
                    // p_i = r_(i-1)
                    residuals.CopyTo(vecP);
                }

                // SOLVE Mp~ = p_i // M = preconditioner
                _preconditioner.Approximate(vecP, vecPdash);

                // nu_i = Ap~
                matrix.Multiply(vecPdash, nu);

                // alpha_i = rho_(i-1)/ (r~^T nu_i) = rho / dotproduct(r~ and nu_i)
                alpha = currentRho * 1 / tempResiduals.ConjugateDotProduct(nu);

                // s = r_(i-1) - alpha_i nu_i
                nu.Multiply(-alpha, temp);
                residuals.Add(temp, vecS);

                // Check if we're converged. If so then stop. Otherwise continue;
                // Calculate the temporary result.
                // Be careful not to change any of the temp vectors, except for
                // temp. Others will be used in the calculation later on.
                // x_i = x_(i-1) + alpha_i * p^_i + s^_i
                vecPdash.Multiply(alpha, temp);
                temp.Add(vecSdash, temp2);
                temp2.CopyTo(temp);
                temp.Add(result, temp2);
                temp2.CopyTo(temp);

                // Check convergence and stop if we are converged.
                if (!ShouldContinue(iterationNumber, temp, input, vecS))
                {
                    temp.CopyTo(result);

                    // Calculate the true residual
                    CalculateTrueResidual(matrix, residuals, result, input);

                    // Now recheck the convergence
                    if (!ShouldContinue(iterationNumber, result, input, residuals))
                    {
                        // We're all good now.
                        return;
                    }

                    // Continue the calculation
                    iterationNumber++;
                    continue;
                }

                // SOLVE Ms~ = s
                _preconditioner.Approximate(vecS, vecSdash);

                // temp = As~
                matrix.Multiply(vecSdash, temp);

                // omega_i = temp^T s / temp^T temp
                omega = temp.ConjugateDotProduct(vecS) / temp.ConjugateDotProduct(temp);

                // x_i = x_(i-1) + alpha_i p^ + omega_i s^
                temp.Multiply(-omega, residuals);
                residuals.Add(vecS, temp2);
                temp2.CopyTo(residuals);

                vecSdash.Multiply(omega, temp);
                result.Add(temp, temp2);
                temp2.CopyTo(result);

                vecPdash.Multiply(alpha, temp);
                result.Add(temp, temp2);
                temp2.CopyTo(result);

                // for continuation it is necessary that omega_i != 0.0
                // If omega is only 1 ULP from zero then we fail.
                if (omega.Real.AlmostEqual(0, 1) && omega.Imaginary.AlmostEqual(0, 1))
                {
                    // Omega-type breakdown
                    throw new Exception("Iterative solver experience a numerical break down");
                }

                if (!ShouldContinue(iterationNumber, result, input, residuals))
                {
                    // Recalculate the residuals and go round again. This is done to ensure that
                    // we have the proper residuals.
                    // The residual calculation based on omega_i * s can be off by a factor 10. So here
                    // we calculate the real residual (which can be expensive) but we only do it if we're
                    // sufficiently close to the finish.
                    CalculateTrueResidual(matrix, residuals, result, input);
                }

                iterationNumber++;
            }
        }
Пример #24
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 <Complex> input, Matrix <Complex> result)
        {
            // Check for proper arguments.
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (!ComputeVectors)
            {
                throw new InvalidOperationException(Resources.SingularVectorsNotComputed);
            }

            // 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 (MatrixU.RowCount != input.RowCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSameRowDimension);
            }

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

            var mn = Math.Min(MatrixU.RowCount, MatrixVT.ColumnCount);
            var bn = input.ColumnCount;

            var tmp = new Complex[MatrixVT.ColumnCount];

            for (var k = 0; k < bn; k++)
            {
                for (var j = 0; j < MatrixVT.ColumnCount; j++)
                {
                    var value = Complex.Zero;
                    if (j < mn)
                    {
                        for (var i = 0; i < MatrixU.RowCount; i++)
                        {
                            value += MatrixU.At(i, j).Conjugate() * input.At(i, k);
                        }

                        value /= VectorS[j];
                    }

                    tmp[j] = value;
                }

                for (var j = 0; j < MatrixVT.ColumnCount; j++)
                {
                    var value = Complex.Zero;
                    for (var i = 0; i < MatrixVT.ColumnCount; i++)
                    {
                        value += MatrixVT.At(i, j).Conjugate() * tmp[i];
                    }

                    result.At(j, k, value);
                }
            }
        }
Пример #25
0
 public void CanDetermineIfZeroValueComplexNumber()
 {
     var complex = new Complex(0, 0);
     Assert.IsTrue(complex.IsZero(), "Zero complex number.");
 }
Пример #26
0
        public static void AlmostEqualRelative(Complex expected, Complex actual, int decimalPlaces)
        {
            if (!expected.Real.AlmostEqualRelative(actual.Real, decimalPlaces))
            {
                Assert.Fail("Real components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Real, actual.Real);
            }

            if (!expected.Imaginary.AlmostEqualRelative(actual.Imaginary, decimalPlaces))
            {
                Assert.Fail("Imaginary components are not equal within {0} places. Expected:{1}; Actual:{2}", decimalPlaces, expected.Imaginary, actual.Imaginary);
            }
        }
Пример #27
0
 /// <summary>
 /// Scale column <paramref name="column"/> by <paramref name="z"/> starting from row <paramref name="rowStart"/>
 /// </summary>
 /// <param name="a">Source matrix</param>
 /// <param name="rowCount">The number of rows in <paramref name="a"/> </param>
 /// <param name="column">Column to scale</param>
 /// <param name="rowStart">Row to scale from</param>
 /// <param name="z">Scale value</param>
 private static void CscalColumn(Matrix <Complex> a, int rowCount, int column, int rowStart, Complex z)
 {
     for (var i = rowStart; i < rowCount; i++)
     {
         a.At(i, column, a.At(i, column) * z);
     }
 }
Пример #28
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UserSvd"/> class. This object will compute the
        /// the singular value decomposition when the constructor is called and cache it's decomposition.
        /// </summary>
        /// <param name="matrix">The matrix to factor.</param>
        /// <param name="computeVectors">Compute the singular U and VT vectors or not.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="NonConvergenceException"></exception>
        public UserSvd(Matrix <Complex> matrix, bool computeVectors)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            ComputeVectors = computeVectors;
            var nm         = Math.Min(matrix.RowCount + 1, matrix.ColumnCount);
            var matrixCopy = matrix.Clone();

            VectorS  = matrixCopy.CreateVector(nm);
            MatrixU  = matrixCopy.CreateMatrix(matrixCopy.RowCount, matrixCopy.RowCount);
            MatrixVT = matrixCopy.CreateMatrix(matrixCopy.ColumnCount, matrixCopy.ColumnCount);

            const int Maxiter = 1000;
            var       e       = new Complex[matrixCopy.ColumnCount];
            var       work    = new Complex[matrixCopy.RowCount];

            int     i, j;
            int     l, lp1;
            var     cs = 0.0;
            var     sn = 0.0;
            Complex 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].
                    VectorS[l] = Cnrm2Column(matrixCopy, matrixCopy.RowCount, l, l);
                    if (VectorS[l].Magnitude != 0.0)
                    {
                        if (matrixCopy.At(l, l).Magnitude != 0.0)
                        {
                            VectorS[l] = Csign(VectorS[l], matrixCopy.At(l, l));
                        }

                        CscalColumn(matrixCopy, matrixCopy.RowCount, l, l, 1.0 / VectorS[l]);
                        matrixCopy.At(l, l, (Complex.One + matrixCopy.At(l, l)));
                    }

                    VectorS[l] = -VectorS[l];
                }

                for (j = lp1; j < matrixCopy.ColumnCount; j++)
                {
                    if (l < nct)
                    {
                        if (VectorS[l].Magnitude != 0.0)
                        {
                            // Apply the transformation.
                            t = -Cdotc(matrixCopy, matrixCopy.RowCount, l, j, l) / matrixCopy.At(l, l);
                            if (t != Complex.Zero)
                            {
                                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).Conjugate();
                }

                if (ComputeVectors && l < nct)
                {
                    // Place the transformation in u for subsequent back multiplication.
                    for (i = l; i < matrixCopy.RowCount; i++)
                    {
                        MatrixU.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 = Cnrm2Vector(e, lp1);
                e[l] = enorm;
                if (e[l].Magnitude != 0.0)
                {
                    if (e[lp1].Magnitude != 0.0)
                    {
                        e[l] = Csign(e[l], e[lp1]);
                    }

                    CscalVector(e, lp1, 1.0 / e[l]);
                    e[lp1] = Complex.One + e[lp1];
                }

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

                    for (j = lp1; j < matrixCopy.ColumnCount; j++)
                    {
                        if (e[j] != Complex.Zero)
                        {
                            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]).Conjugate();
                        if (ww != Complex.Zero)
                        {
                            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++)
                    {
                        MatrixVT.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)
            {
                VectorS[nctp1 - 1] = matrixCopy.At((nctp1 - 1), (nctp1 - 1));
            }

            if (matrixCopy.RowCount < m)
            {
                VectorS[m - 1] = Complex.Zero;
            }

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

            e[m - 1] = Complex.Zero;

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

                    MatrixU.At(j, j, Complex.One);
                }

                for (l = nct - 1; l >= 0; l--)
                {
                    if (VectorS[l].Magnitude != 0.0)
                    {
                        for (j = l + 1; j < ncu; j++)
                        {
                            t = -Cdotc(MatrixU, matrixCopy.RowCount, l, j, l) / MatrixU.At(l, l);
                            if (t != Complex.Zero)
                            {
                                for (var ii = l; ii < matrixCopy.RowCount; ii++)
                                {
                                    MatrixU.At(ii, j, MatrixU.At(ii, j) + (t * MatrixU.At(ii, l)));
                                }
                            }
                        }

                        CscalColumn(MatrixU, matrixCopy.RowCount, l, l, -1.0);
                        MatrixU.At(l, l, Complex.One + MatrixU.At(l, l));
                        for (i = 0; i < l; i++)
                        {
                            MatrixU.At(i, l, Complex.Zero);
                        }
                    }
                    else
                    {
                        for (i = 0; i < matrixCopy.RowCount; i++)
                        {
                            MatrixU.At(i, l, Complex.Zero);
                        }

                        MatrixU.At(l, l, Complex.One);
                    }
                }
            }

            // 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].Magnitude != 0.0)
                        {
                            for (j = lp1; j < matrixCopy.ColumnCount; j++)
                            {
                                t = -Cdotc(MatrixVT, matrixCopy.ColumnCount, l, j, lp1) / MatrixVT.At(lp1, l);
                                if (t != Complex.Zero)
                                {
                                    for (var ii = l; ii < matrixCopy.ColumnCount; ii++)
                                    {
                                        MatrixVT.At(ii, j, MatrixVT.At(ii, j) + (t * MatrixVT.At(ii, l)));
                                    }
                                }
                            }
                        }
                    }

                    for (i = 0; i < matrixCopy.ColumnCount; i++)
                    {
                        MatrixVT.At(i, l, Complex.Zero);
                    }

                    MatrixVT.At(l, l, Complex.One);
                }
            }

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

                    if (ComputeVectors)
                    {
                        CscalColumn(MatrixU, matrixCopy.RowCount, i, 0, r);
                    }
                }

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

                if (e[i].Magnitude != 0.0)
                {
                    t              = e[i].Magnitude;
                    r              = t / e[i];
                    e[i]           = t;
                    VectorS[i + 1] = VectorS[i + 1] * r;
                    if (ComputeVectors)
                    {
                        CscalColumn(MatrixVT, matrixCopy.ColumnCount, i + 1, 0, r);
                    }
                }
            }

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

            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 NonConvergenceException();
                }

                // This section of the program inspects for negligible elements in the s and e arrays. On
                // completion the variables kase and l are set as follows.
                // Kase = 1     if VectorS[m] and e[l-1] are negligible and l < m
                // Kase = 2     if VectorS[l] is negligible and l < m
                // Kase = 3     if e[l-1] is negligible, l < m, and VectorS[l, ..., VectorS[m] are not negligible (qr step).
                // Лase = 4     if e[m-1] is negligible (convergence).
                double ztest;
                double test;
                for (l = m - 2; l >= 0; l--)
                {
                    test  = VectorS[l].Magnitude + VectorS[l + 1].Magnitude;
                    ztest = test + e[l].Magnitude;
                    if (ztest.AlmostEqualInDecimalPlaces(test, 15))
                    {
                        e[l] = Complex.Zero;
                        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 + e[ls].Magnitude;
                        }

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

                        ztest = test + VectorS[ls].Magnitude;
                        if (ztest.AlmostEqualInDecimalPlaces(test, 15))
                        {
                            VectorS[ls] = Complex.Zero;
                            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 kase.
                int    k;
                double f;
                switch (kase)
                {
                // Deflate negligible VectorS[m].
                case 1:
                    f        = e[m - 2].Real;
                    e[m - 2] = Complex.Zero;
                    double t1;
                    for (var kk = l; kk < m - 1; kk++)
                    {
                        k  = m - 2 - kk + l;
                        t1 = VectorS[k].Real;
                        Srotg(ref t1, ref f, ref cs, ref sn);
                        VectorS[k] = t1;
                        if (k != l)
                        {
                            f        = -sn * e[k - 1].Real;
                            e[k - 1] = cs * e[k - 1];
                        }

                        if (ComputeVectors)
                        {
                            Csrot(MatrixVT, matrixCopy.ColumnCount, k, m - 1, cs, sn);
                        }
                    }

                    break;

                // Split at negligible VectorS[l].
                case 2:
                    f        = e[l - 1].Real;
                    e[l - 1] = Complex.Zero;
                    for (k = l; k < m; k++)
                    {
                        t1 = VectorS[k].Real;
                        Srotg(ref t1, ref f, ref cs, ref sn);
                        VectorS[k] = t1;
                        f          = -sn * e[k].Real;
                        e[k]       = cs * e[k];
                        if (ComputeVectors)
                        {
                            Csrot(MatrixU, 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, VectorS[m - 1].Magnitude);
                    scale = Math.Max(scale, VectorS[m - 2].Magnitude);
                    scale = Math.Max(scale, e[m - 2].Magnitude);
                    scale = Math.Max(scale, VectorS[l].Magnitude);
                    scale = Math.Max(scale, e[l].Magnitude);
                    var sm    = VectorS[m - 1].Real / scale;
                    var smm1  = VectorS[m - 2].Real / scale;
                    var emm1  = e[m - 2].Real / scale;
                    var sl    = VectorS[l].Real / scale;
                    var el    = e[l].Real / 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++)
                    {
                        Srotg(ref f, ref g, ref cs, ref sn);
                        if (k != l)
                        {
                            e[k - 1] = f;
                        }

                        f              = (cs * VectorS[k].Real) + (sn * e[k].Real);
                        e[k]           = (cs * e[k]) - (sn * VectorS[k]);
                        g              = sn * VectorS[k + 1].Real;
                        VectorS[k + 1] = cs * VectorS[k + 1];
                        if (ComputeVectors)
                        {
                            Csrot(MatrixVT, matrixCopy.ColumnCount, k, k + 1, cs, sn);
                        }

                        Srotg(ref f, ref g, ref cs, ref sn);
                        VectorS[k]     = f;
                        f              = (cs * e[k].Real) + (sn * VectorS[k + 1].Real);
                        VectorS[k + 1] = (-sn * e[k]) + (cs * VectorS[k + 1]);
                        g              = sn * e[k + 1].Real;
                        e[k + 1]       = cs * e[k + 1];
                        if (ComputeVectors && k < matrixCopy.RowCount)
                        {
                            Csrot(MatrixU, matrixCopy.RowCount, k, k + 1, cs, sn);
                        }
                    }

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

                // Convergence.
                case 4:
                    // Make the singular value  positive
                    if (VectorS[l].Real < 0.0)
                    {
                        VectorS[l] = -VectorS[l];
                        if (ComputeVectors)
                        {
                            CscalColumn(MatrixVT, matrixCopy.ColumnCount, l, 0, -1.0);
                        }
                    }

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

                        t              = VectorS[l];
                        VectorS[l]     = VectorS[l + 1];
                        VectorS[l + 1] = t;
                        if (ComputeVectors && l < matrixCopy.ColumnCount)
                        {
                            Swap(MatrixVT, matrixCopy.ColumnCount, l, l + 1);
                        }

                        if (ComputeVectors && l < matrixCopy.RowCount)
                        {
                            Swap(MatrixU, matrixCopy.RowCount, l, l + 1);
                        }

                        l = l + 1;
                    }

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

            if (ComputeVectors)
            {
                MatrixVT = MatrixVT.ConjugateTranspose();
            }

            // 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 = matrixCopy.CreateVector(nm);
                for (i = 0; i < nm; i++)
                {
                    tmp[i] = VectorS[i];
                }

                VectorS = tmp;
            }
        }
Пример #29
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UserLU"/> class. This object will compute the
        /// LU factorization when the constructor is called and cache it's factorization.
        /// </summary>
        /// <param name="matrix">The matrix to factor.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If <paramref name="matrix"/> is not a square matrix.</exception>
        public UserLU(Matrix <Complex> matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare);
            }

            // Create an array for the pivot indices.
            var order = matrix.RowCount;

            Factors = matrix.Clone();
            Pivots  = new int[order];

            // Initialize the pivot matrix to the identity permutation.
            for (var i = 0; i < order; i++)
            {
                Pivots[i] = i;
            }

            var vectorLUcolj = new Complex[order];

            for (var j = 0; j < order; j++)
            {
                // Make a copy of the j-th column to localize references.
                for (var i = 0; i < order; i++)
                {
                    vectorLUcolj[i] = Factors.At(i, j);
                }

                // Apply previous transformations.
                for (var i = 0; i < order; i++)
                {
                    var kmax = Math.Min(i, j);
                    var s    = Complex.Zero;
                    for (var k = 0; k < kmax; k++)
                    {
                        s += Factors.At(i, k) * vectorLUcolj[k];
                    }

                    vectorLUcolj[i] -= s;
                    Factors.At(i, j, vectorLUcolj[i]);
                }

                // Find pivot and exchange if necessary.
                var p = j;
                for (var i = j + 1; i < order; i++)
                {
                    if (vectorLUcolj[i].Magnitude > vectorLUcolj[p].Magnitude)
                    {
                        p = i;
                    }
                }

                if (p != j)
                {
                    for (var k = 0; k < order; k++)
                    {
                        var temp = Factors.At(p, k);
                        Factors.At(p, k, Factors.At(j, k));
                        Factors.At(j, k, temp);
                    }

                    Pivots[j] = p;
                }

                // Compute multipliers.
                if (j < order & Factors.At(j, j) != 0.0)
                {
                    for (var i = j + 1; i < order; i++)
                    {
                        Factors.At(i, j, (Factors.At(i, j) / Factors.At(j, j)));
                    }
                }
            }
        }
Пример #30
0
 public void CanDetermineIfRealNumber()
 {
     var complex = new Complex(-1, 0);
     Assert.IsTrue(complex.IsReal(), "Is a real number.");
 }
Пример #31
0
 public void CanComputeNaturalLogarithm(double real, double imag, double expectedReal, double expectedImag)
 {
     var value = new Complex(real, imag);
     var expected = new Complex(expectedReal, expectedImag);
     AssertHelpers.AlmostEqualRelative(expected, value.Ln(), 14);
 }
Пример #32
0
 public void CanComputeExponential(double real, double imag, double expectedReal, double expectedImag)
 {
     var value = new Complex(real, imag);
     var expected = new Complex(expectedReal, expectedImag);
     AssertHelpers.AlmostEqualRelative(expected, value.Exp(), 15);
 }
Пример #33
0
        public void CanComputeRoot()
        {
            var a = new Complex(0.0, -1.19209289550780998537e-7);
            var b = new Complex(0.0, 0.5);
            AssertHelpers.AlmostEqualRelative(new Complex(0.038550761943650161, 0.019526430428319544), a.Root(b), 13);
            a = new Complex(0.0, 0.5);
            b = new Complex(0.0, -0.5);
            AssertHelpers.AlmostEqualRelative(new Complex(0.007927894711475968, -0.042480480425152213), a.Root(b), 13);
            a = new Complex(0.0, -0.5);
            b = new Complex(0.0, 1.0);
            AssertHelpers.AlmostEqualRelative(new Complex(0.15990905692806806, 0.13282699942462053), a.Root(b), 13);
            a = new Complex(0.0, 2.0);
            b = new Complex(0.0, -2.0);
            AssertHelpers.AlmostEqualRelative(new Complex(0.42882900629436788, 0.15487175246424678), a.Root(b), 13);

            //a = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
            //b = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
            //AssertHelpers.AlmostEqual(new Complex(0.0, 0.0), a.Root(b), 15);
            a = new Complex(0.0, -8.388608e6);
            b = new Complex(1.19209289550780998537e-7, 0.0);
            AssertHelpers.AlmostEqualRelative(new Complex(double.PositiveInfinity, double.NegativeInfinity), a.Root(b), 14);
        }
Пример #34
0
        public void CanComputePower()
        {
            var a = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
            var b = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
            AssertHelpers.AlmostEqualRelative(
                new Complex(9.99998047207974718744e-1, -1.76553541154378695012e-6), a.Power(b), 14);
            a = new Complex(0.0, 1.19209289550780998537e-7);
            b = new Complex(0.0, -1.19209289550780998537e-7);
            AssertHelpers.AlmostEqualRelative(new Complex(1.00000018725172576491, 1.90048076369011843105e-6), a.Power(b), 14);
            a = new Complex(0.0, -1.19209289550780998537e-7);
            b = new Complex(0.0, 0.5);
            AssertHelpers.AlmostEqualRelative(new Complex(-2.56488189382693049636e-1, -2.17823120666116144959), a.Power(b), 14);
            a = new Complex(0.0, 0.5);
            b = new Complex(0.0, -0.5);
            AssertHelpers.AlmostEqualRelative(new Complex(2.06287223508090495171, 7.45007062179724087859e-1), a.Power(b), 14);
            a = new Complex(0.0, -0.5);
            b = new Complex(0.0, 1.0);
            AssertHelpers.AlmostEqualRelative(new Complex(3.70040633557002510874, -3.07370876701949232239), a.Power(b), 14);
            a = new Complex(0.0, 2.0);
            b = new Complex(0.0, -2.0);
            AssertHelpers.AlmostEqualRelative(new Complex(4.24532146387429353891, -2.27479427903521192648e1), a.Power(b), 14);
            a = new Complex(0.0, -8.388608e6);
            b = new Complex(1.19209289550780998537e-7, 0.0);
            AssertHelpers.AlmostEqualRelative(new Complex(1.00000190048219620166, -1.87253870018168043834e-7), a.Power(b), 14);
            a = new Complex(0.0, 0.0);
            b = new Complex(0.0, 0.0);
            AssertHelpers.AlmostEqualRelative(new Complex(1.0, 0.0), a.Power(b), 14);
            a = new Complex(0.0, 0.0);
            b = new Complex(1.0, 0.0);
            AssertHelpers.AlmostEqualRelative(new Complex(0.0, 0.0), a.Power(b), 14);

            a = new Complex(0.0, 0.0);
            b = new Complex(-1.0, 0.0);
            AssertHelpers.AlmostEqualRelative(new Complex(double.PositiveInfinity, 0.0), a.Power(b), 14);
            a = new Complex(0.0, 0.0);
            b = new Complex(-1.0, 1.0);
            AssertHelpers.AlmostEqualRelative(new Complex(double.PositiveInfinity, double.PositiveInfinity), a.Power(b), 14);
            a = new Complex(0.0, 0.0);
            b = new Complex(0.0, 1.0);
            Assert.That(a.Power(b).IsNaN());
        }
Пример #35
0
        /// <summary>
        /// Initializes a new instance of the <see cref="UserEvd"/> class. This object will compute the
        /// the eigenvalue decomposition when the constructor is called and cache it's decomposition.
        /// </summary>
        /// <param name="matrix">The matrix to factor.</param>
        /// <exception cref="ArgumentNullException">If <paramref name="matrix"/> is <c>null</c>.</exception>
        /// <exception cref="ArgumentException">If EVD algorithm failed to converge with matrix <paramref name="matrix"/>.</exception>
        public UserEvd(Matrix <double> matrix)
        {
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare);
            }

            var order = matrix.RowCount;

            // Initialize matricies for eigenvalues and eigenvectors
            MatrixEv = matrix.CreateMatrix(order, order);
            MatrixD  = matrix.CreateMatrix(order, order);
            VectorEv = new LinearAlgebra.Complex.DenseVector(order);

            IsSymmetric = true;

            for (var i = 0; IsSymmetric && i < order; i++)
            {
                for (var j = 0; IsSymmetric && j < order; j++)
                {
                    IsSymmetric &= matrix.At(i, j) == matrix.At(j, i);
                }
            }

            var d = new double[order];
            var e = new double[order];

            if (IsSymmetric)
            {
                matrix.CopyTo(MatrixEv);
                d = MatrixEv.Row(order - 1).ToArray();

                SymmetricTridiagonalize(d, e, order);
                SymmetricDiagonalize(d, e, order);
            }
            else
            {
                var matrixH = matrix.ToArray();

                NonsymmetricReduceToHessenberg(matrixH, order);
                NonsymmetricReduceHessenberToRealSchur(matrixH, d, e, order);
            }

            for (var i = 0; i < order; i++)
            {
                MatrixD.At(i, i, d[i]);

                if (e[i] > 0)
                {
                    MatrixD.At(i, i + 1, e[i]);
                }
                else if (e[i] < 0)
                {
                    MatrixD.At(i, i - 1, e[i]);
                }
            }

            for (var i = 0; i < order; i++)
            {
                VectorEv[i] = new Complex(d[i], e[i]);
            }
        }
Пример #36
0
 /// <summary>
 /// Creates a matrix from a 2D array.
 /// </summary>
 /// <param name="data">The 2D array to create this matrix from.</param>
 /// <returns>A matrix with the given values.</returns>
 protected abstract Matrix<Complex> CreateMatrix(Complex[,] data);
Пример #37
0
 /// <summary>
 /// Calculates absolute value of <paramref name="z1"/> multiplied on signum function of <paramref name="z2"/>
 /// </summary>
 /// <param name="z1">Complex value z1</param>
 /// <param name="z2">Complex value z2</param>
 /// <returns>Result multiplication of signum function and absolute value</returns>
 private static Complex Csign(Complex z1, Complex z2)
 {
     return(z1.Magnitude * (z2 / z2.Magnitude));
 }
Пример #38
0
        /// <summary>
        /// Nonsymmetric reduction to Hessenberg form.
        /// </summary>
        /// <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>
        private void NonsymmetricReduceToHessenberg(Complex[,] matrixH, int order)
        {
            var ort = new Complex[order];

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

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

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

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

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

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

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

                    ort[m] = scale * ort[m];
                    matrixH[m, m - 1] *= -g;
                }
            }

            // Accumulate transformations (Algol's ortran).
            for (var i = 0; i < order; i++)
            {
                for (var j = 0; j < order; j++)
                {
                    MatrixEv.At(i, j, i == j ? Complex.One : Complex.Zero);
                }
            }

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

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

                    for (var j = m; j < order; j++)
                    {
                        var g = Complex.Zero;
                        for (var i = m; i < order; i++)
                        {
                            g += ort[i].Conjugate() * MatrixEv.At(i, j);
                        }

                        // Double division avoids possible underflow
                        g /= norm;
                        for (var i = m; i < order; i++)
                        {
                            MatrixEv.At(i, j, MatrixEv.At(i, j) + g * ort[i]);
                        }
                    }
                }
            }
            
            // Create real subdiagonal elements.
            for (var i = 1; i < order; i++)
            {
                if (matrixH[i, i - 1].Imaginary != 0.0)
                {
                    var y = matrixH[i, i - 1] / matrixH[i, i - 1].Magnitude;
                    matrixH[i, i - 1] = matrixH[i, i - 1].Magnitude;
                    for (var j = i; j < order; j++)
                    {
                        matrixH[i, j] *= y.Conjugate();
                    }

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

                    for (var j = 0; j < order; j++)
                    {
                        MatrixEv.At(j, i, MatrixEv.At(j, i) * y);
                    }
                }
            }
        }
Пример #39
0
 public void CanDetermineIfImaginaryUnit()
 {
     var complex = new Complex(0, 1);
     Assert.IsTrue(complex.IsImaginaryOne(), "Imaginary unit");
 }
        public void FourierDefaultTransformIsReversible()
        {
            var samples = SignalGenerator.Random((u, v) => new Complex(u, v), GetUniform(1), 0x7FFF);
            var work = new Complex[samples.Length];
            samples.CopyTo(work, 0);

            Transform.FourierForward(work);
            Assert.IsFalse(work.ListAlmostEqual(samples, 6));

            Transform.FourierInverse(work);
            AssertHelpers.ListAlmostEqual(samples, work, 10);

            Transform.FourierInverse(work, FourierOptions.Default);
            Assert.IsFalse(work.ListAlmostEqual(samples, 6));

            Transform.FourierForward(work, FourierOptions.Default);
            AssertHelpers.ListAlmostEqual(samples, work, 10);
        }
Пример #41
0
 public void CanDetermineIfInfinity()
 {
     var complex = new Complex(double.PositiveInfinity, 1);
     Assert.IsTrue(complex.IsInfinity(), "Real part is infinity.");
     complex = new Complex(1, double.NegativeInfinity);
     Assert.IsTrue(complex.IsInfinity(), "Imaginary part is infinity.");
     complex = new Complex(double.NegativeInfinity, double.PositiveInfinity);
     Assert.IsTrue(complex.IsInfinity(), "Both parts are infinity.");
 }
Пример #42
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<Complex> input, Vector<Complex> result)
        {
            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            // Ax=b where A is an m x m matrix
            // Check that b is a column vector with m entries
            if (VectorEv.Count != input.Count)
            {
                throw new ArgumentException(Resources.ArgumentVectorsSameLength);
            }

            // Check that x is a column vector with n entries
            if (VectorEv.Count != result.Count)
            {
                throw Matrix.DimensionsDontMatch<ArgumentException>(VectorEv, result);
            }

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

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    if (j < order)
                    {
                        for (var i = 0; i < order; i++)
                        {
                            value += MatrixEv.At(i, j).Conjugate() * input[i];
                        }

                        value /= VectorEv[j].Real;
                    }

                    tmp[j] = value;
                }

                for (var j = 0; j < order; j++)
                {
                    value = 0;
                    for (int i = 0; i < order; i++)
                    {
                        value += MatrixEv.At(j, i) * tmp[i];
                    }

                    result[j] = value;
                }
            }
            else
            {
                throw new ArgumentException(Resources.ArgumentMatrixSymmetric);
            }
        }
Пример #43
0
 public void CanDetermineIfNaN()
 {
     var complex = new Complex(double.NaN, 1);
     Assert.IsTrue(complex.IsNaN(), "Real part is NaN.");
     complex = new Complex(1, double.NaN);
     Assert.IsTrue(complex.IsNaN(), "Imaginary part is NaN.");
     complex = new Complex(double.NaN, double.NaN);
     Assert.IsTrue(complex.IsNaN(), "Both parts are NaN.");
 }
Пример #44
0
 public void CanDetermineIfOneValueComplexNumber()
 {
     var complex = new Complex(1, 0);
     Assert.IsTrue(complex.IsOne(), "Complex number with a value of one.");
 }
Пример #45
0
 public void CanDetermineIfRealNonNegativeNumber()
 {
     var complex = new Complex(1, 0);
     Assert.IsTrue(complex.IsReal(), "Is a real non-negative number.");
 }
Пример #46
0
 public void CanComputeSquare()
 {
     var complex = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(new Complex(0, 2.8421709430403888e-14), complex.Square(), 15);
     complex = new Complex(0.0, 1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(new Complex(-1.4210854715201944e-14, 0.0), complex.Square(), 15);
     complex = new Complex(0.0, -1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(new Complex(-1.4210854715201944e-14, 0.0), complex.Square(), 15);
     complex = new Complex(0.0, 0.5);
     AssertHelpers.AlmostEqualRelative(new Complex(-0.25, 0.0), complex.Square(), 15);
     complex = new Complex(0.0, -0.5);
     AssertHelpers.AlmostEqualRelative(new Complex(-0.25, 0.0), complex.Square(), 15);
     complex = new Complex(0.0, -8.388608e6);
     AssertHelpers.AlmostEqualRelative(new Complex(-70368744177664.0, 0.0), complex.Square(), 15);
 }
Пример #47
0
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
        /// <param name="input">The solution vector, <c>b</c></param>
        /// <param name="result">The result vector, <c>x</c></param>
        public void Solve(Matrix matrix, Vector input, Vector result)
        {
            // If we were stopped before, we are no longer
            // We're doing this at the start of the method to ensure
            // that we can use these fields immediately.
            _hasBeenStopped = false;

            // Error checks
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
            }

            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (input.Count != matrix.RowCount || result.Count != input.Count)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(matrix, input, result);
            }

            // Initialize the solver fields
            // Set the convergence monitor
            if (_iterator == null)
            {
                _iterator = Iterator.CreateDefault();
            }

            if (_preconditioner == null)
            {
                _preconditioner = new UnitPreconditioner();
            }

            _preconditioner.Initialize(matrix);

            // Choose an initial guess x_0
            // Take x_0 = 0
            Vector xtemp = new DenseVector(input.Count);

            // Choose k vectors q_1, q_2, ..., q_k
            // Build a new set if:
            // a) the stored set doesn't exist (i.e. == null)
            // b) Is of an incorrect length (i.e. too long)
            // c) The vectors are of an incorrect length (i.e. too long or too short)
            var useOld = false;

            if (_startingVectors != null)
            {
                // We don't accept collections with zero starting vectors so ...
                if (_startingVectors.Count <= NumberOfStartingVectorsToCreate(_numberOfStartingVectors, input.Count))
                {
                    // Only check the first vector for sizing. If that matches we assume the
                    // other vectors match too. If they don't the process will crash
                    if (_startingVectors[0].Count == input.Count)
                    {
                        useOld = true;
                    }
                }
            }

            _startingVectors = useOld ? _startingVectors : CreateStartingVectors(_numberOfStartingVectors, input.Count);

            // Store the number of starting vectors. Not really necessary but easier to type :)
            var k = _startingVectors.Count;

            // r_0 = b - Ax_0
            // This is basically a SAXPY so it could be made a lot faster
            Vector residuals = new DenseVector(matrix.RowCount);

            CalculateTrueResidual(matrix, residuals, xtemp, input);

            // Define the temporary values
            var c = new Complex[k];

            // Define the temporary vectors
            Vector gtemp = new DenseVector(residuals.Count);

            Vector u     = new DenseVector(residuals.Count);
            Vector utemp = new DenseVector(residuals.Count);
            Vector temp  = new DenseVector(residuals.Count);
            Vector temp1 = new DenseVector(residuals.Count);
            Vector temp2 = new DenseVector(residuals.Count);

            Vector zd = new DenseVector(residuals.Count);
            Vector zg = new DenseVector(residuals.Count);
            Vector zw = new DenseVector(residuals.Count);

            var d = CreateVectorArray(_startingVectors.Count, residuals.Count);

            // g_0 = r_0
            var g = CreateVectorArray(_startingVectors.Count, residuals.Count);

            residuals.CopyTo(g[k - 1]);

            var w = CreateVectorArray(_startingVectors.Count, residuals.Count);

            // FOR (j = 0, 1, 2 ....)
            var iterationNumber = 0;

            while (ShouldContinue(iterationNumber, xtemp, input, residuals))
            {
                // SOLVE M g~_((j-1)k+k) = g_((j-1)k+k)
                _preconditioner.Approximate(g[k - 1], gtemp);

                // w_((j-1)k+k) = A g~_((j-1)k+k)
                matrix.Multiply(gtemp, w[k - 1]);

                // c_((j-1)k+k) = q^T_1 w_((j-1)k+k)
                c[k - 1] = _startingVectors[0].ConjugateDotProduct(w[k - 1]);
                if (c[k - 1].Real.AlmostEqual(0, 1) && c[k - 1].Imaginary.AlmostEqual(0, 1))
                {
                    throw new Exception("Iterative solver experience a numerical break down");
                }

                // alpha_(jk+1) = q^T_1 r_((j-1)k+k) / c_((j-1)k+k)
                var alpha = _startingVectors[0].ConjugateDotProduct(residuals) / c[k - 1];

                // u_(jk+1) = r_((j-1)k+k) - alpha_(jk+1) w_((j-1)k+k)
                w[k - 1].Multiply(-alpha, temp);
                residuals.Add(temp, u);

                // SOLVE M u~_(jk+1) = u_(jk+1)
                _preconditioner.Approximate(u, temp1);
                temp1.CopyTo(utemp);

                // rho_(j+1) = -u^t_(jk+1) A u~_(jk+1) / ||A u~_(jk+1)||^2
                matrix.Multiply(temp1, temp);
                var rho = temp.ConjugateDotProduct(temp);

                // If rho is zero then temp is a zero vector and we're probably
                // about to have zero residuals (i.e. an exact solution).
                // So set rho to 1.0 because in the next step it will turn to zero.
                if (rho.Real.AlmostEqual(0, 1) && rho.Imaginary.AlmostEqual(0, 1))
                {
                    rho = 1.0;
                }

                rho = -u.ConjugateDotProduct(temp) / rho;

                // r_(jk+1) = rho_(j+1) A u~_(jk+1) + u_(jk+1)
                u.CopyTo(residuals);

                // Reuse temp
                temp.Multiply(rho, temp);
                residuals.Add(temp, temp2);
                temp2.CopyTo(residuals);

                // x_(jk+1) = x_((j-1)k_k) - rho_(j+1) u~_(jk+1) + alpha_(jk+1) g~_((j-1)k+k)
                utemp.Multiply(-rho, temp);
                xtemp.Add(temp, temp2);
                temp2.CopyTo(xtemp);

                gtemp.Multiply(alpha, gtemp);
                xtemp.Add(gtemp, temp2);
                temp2.CopyTo(xtemp);

                // Check convergence and stop if we are converged.
                if (!ShouldContinue(iterationNumber, xtemp, input, residuals))
                {
                    // Calculate the true residual
                    CalculateTrueResidual(matrix, residuals, xtemp, input);

                    // Now recheck the convergence
                    if (!ShouldContinue(iterationNumber, xtemp, input, residuals))
                    {
                        // We're all good now.
                        // Exit from the while loop.
                        break;
                    }
                }

                // FOR (i = 1,2, ...., k)
                for (var i = 0; i < k; i++)
                {
                    // z_d = u_(jk+1)
                    u.CopyTo(zd);

                    // z_g = r_(jk+i)
                    residuals.CopyTo(zg);

                    // z_w = 0
                    zw.Clear();

                    // FOR (s = i, ...., k-1) AND j >= 1
                    Complex beta;
                    if (iterationNumber >= 1)
                    {
                        for (var s = i; s < k - 1; s++)
                        {
                            // beta^(jk+i)_((j-1)k+s) = -q^t_(s+1) z_d / c_((j-1)k+s)
                            beta = -_startingVectors[s + 1].ConjugateDotProduct(zd) / c[s];

                            // z_d = z_d + beta^(jk+i)_((j-1)k+s) d_((j-1)k+s)
                            d[s].Multiply(beta, temp);
                            zd.Add(temp, temp2);
                            temp2.CopyTo(zd);

                            // z_g = z_g + beta^(jk+i)_((j-1)k+s) g_((j-1)k+s)
                            g[s].Multiply(beta, temp);
                            zg.Add(temp, temp2);
                            temp2.CopyTo(zg);

                            // z_w = z_w + beta^(jk+i)_((j-1)k+s) w_((j-1)k+s)
                            w[s].Multiply(beta, temp);
                            zw.Add(temp, temp2);
                            temp2.CopyTo(zw);
                        }
                    }

                    beta = rho * c[k - 1];
                    if (beta.Real.AlmostEqual(0, 1) && beta.Imaginary.AlmostEqual(0, 1))
                    {
                        throw new Exception("Iterative solver experience a numerical break down");
                    }

                    // beta^(jk+i)_((j-1)k+k) = -(q^T_1 (r_(jk+1) + rho_(j+1) z_w)) / (rho_(j+1) c_((j-1)k+k))
                    zw.Multiply(rho, temp2);
                    residuals.Add(temp2, temp);
                    beta = -_startingVectors[0].ConjugateDotProduct(temp) / beta;

                    // z_g = z_g + beta^(jk+i)_((j-1)k+k) g_((j-1)k+k)
                    g[k - 1].Multiply(beta, temp);
                    zg.Add(temp, temp2);
                    temp2.CopyTo(zg);

                    // z_w = rho_(j+1) (z_w + beta^(jk+i)_((j-1)k+k) w_((j-1)k+k))
                    w[k - 1].Multiply(beta, temp);
                    zw.Add(temp, temp2);
                    temp2.CopyTo(zw);
                    zw.Multiply(rho, zw);

                    // z_d = r_(jk+i) + z_w
                    residuals.Add(zw, zd);

                    // FOR (s = 1, ... i - 1)
                    for (var s = 0; s < i - 1; s++)
                    {
                        // beta^(jk+i)_(jk+s) = -q^T_s+1 z_d / c_(jk+s)
                        beta = -_startingVectors[s + 1].ConjugateDotProduct(zd) / c[s];

                        // z_d = z_d + beta^(jk+i)_(jk+s) * d_(jk+s)
                        d[s].Multiply(beta, temp);
                        zd.Add(temp, temp2);
                        temp2.CopyTo(zd);

                        // z_g = z_g + beta^(jk+i)_(jk+s) * g_(jk+s)
                        g[s].Multiply(beta, temp);
                        zg.Add(temp, temp2);
                        temp2.CopyTo(zg);
                    }

                    // d_(jk+i) = z_d - u_(jk+i)
                    zd.Subtract(u, d[i]);

                    // g_(jk+i) = z_g + z_w
                    zg.Add(zw, g[i]);

                    // IF (i < k - 1)
                    if (i < k - 1)
                    {
                        // c_(jk+1) = q^T_i+1 d_(jk+i)
                        c[i] = _startingVectors[i + 1].ConjugateDotProduct(d[i]);
                        if (c[i].Real.AlmostEqual(0, 1) && c[i].Imaginary.AlmostEqual(0, 1))
                        {
                            throw new Exception("Iterative solver experience a numerical break down");
                        }

                        // alpha_(jk+i+1) = q^T_(i+1) u_(jk+i) / c_(jk+i)
                        alpha = _startingVectors[i + 1].ConjugateDotProduct(u) / c[i];

                        // u_(jk+i+1) = u_(jk+i) - alpha_(jk+i+1) d_(jk+i)
                        d[i].Multiply(-alpha, temp);
                        u.Add(temp, temp2);
                        temp2.CopyTo(u);

                        // SOLVE M g~_(jk+i) = g_(jk+i)
                        _preconditioner.Approximate(g[i], gtemp);

                        // x_(jk+i+1) = x_(jk+i) + rho_(j+1) alpha_(jk+i+1) g~_(jk+i)
                        gtemp.Multiply(rho * alpha, temp);
                        xtemp.Add(temp, temp2);
                        temp2.CopyTo(xtemp);

                        // w_(jk+i) = A g~_(jk+i)
                        matrix.Multiply(gtemp, w[i]);

                        // r_(jk+i+1) = r_(jk+i) - rho_(j+1) alpha_(jk+i+1) w_(jk+i)
                        w[i].Multiply(-rho * alpha, temp);
                        residuals.Add(temp, temp2);
                        temp2.CopyTo(residuals);

                        // We can check the residuals here if they're close
                        if (!ShouldContinue(iterationNumber, xtemp, input, residuals))
                        {
                            // Recalculate the residuals and go round again. This is done to ensure that
                            // we have the proper residuals.
                            CalculateTrueResidual(matrix, residuals, xtemp, input);
                        }
                    }
                } // END ITERATION OVER i

                iterationNumber++;
            }

            // copy the temporary result to the real result vector
            xtemp.CopyTo(result);
        }
Пример #48
0
        /// <summary>
        /// Solves the matrix equation Ax = b, where A is the coefficient matrix, b is the
        /// solution vector and x is the unknown vector.
        /// </summary>
        /// <param name="matrix">The coefficient matrix, <c>A</c>.</param>
        /// <param name="input">The solution vector, <c>b</c></param>
        /// <param name="result">The result vector, <c>x</c></param>
        public void Solve(Matrix matrix, Vector input, Vector result)
        {
            // If we were stopped before, we are no longer
            // We're doing this at the start of the method to ensure
            // that we can use these fields immediately.
            _hasBeenStopped = false;

            // Error checks
            if (matrix == null)
            {
                throw new ArgumentNullException("matrix");
            }

            if (matrix.RowCount != matrix.ColumnCount)
            {
                throw new ArgumentException(Resources.ArgumentMatrixSquare, "matrix");
            }

            if (input == null)
            {
                throw new ArgumentNullException("input");
            }

            if (result == null)
            {
                throw new ArgumentNullException("result");
            }

            if (input.Count != matrix.RowCount || result.Count != input.Count)
            {
                throw Matrix.DimensionsDontMatch <ArgumentException>(matrix, input, result);
            }

            // Initialize the solver fields
            // Set the convergence monitor
            if (_iterator == null)
            {
                _iterator = Iterator.CreateDefault();
            }

            if (_preconditioner == null)
            {
                _preconditioner = new UnitPreconditioner();
            }

            _preconditioner.Initialize(matrix);

            // x_0 is initial guess
            // Take x_0 = 0
            Vector xtemp = new DenseVector(input.Count);

            // r_0 = b - Ax_0
            // This is basically a SAXPY so it could be made a lot faster
            Vector residuals = new DenseVector(matrix.RowCount);

            CalculateTrueResidual(matrix, residuals, xtemp, input);

            // Define the temporary scalars
            Complex beta = 0;

            // Define the temporary vectors
            // rDash_0 = r_0
            Vector rdash = DenseVector.OfVector(residuals);

            // t_-1 = 0
            Vector t  = new DenseVector(residuals.Count);
            Vector t0 = new DenseVector(residuals.Count);

            // w_-1 = 0
            Vector w = new DenseVector(residuals.Count);

            // Define the remaining temporary vectors
            Vector c = new DenseVector(residuals.Count);
            Vector p = new DenseVector(residuals.Count);
            Vector s = new DenseVector(residuals.Count);
            Vector u = new DenseVector(residuals.Count);
            Vector y = new DenseVector(residuals.Count);
            Vector z = new DenseVector(residuals.Count);

            Vector temp  = new DenseVector(residuals.Count);
            Vector temp2 = new DenseVector(residuals.Count);
            Vector temp3 = new DenseVector(residuals.Count);

            // for (k = 0, 1, .... )
            var iterationNumber = 0;

            while (ShouldContinue(iterationNumber, xtemp, input, residuals))
            {
                // p_k = r_k + beta_(k-1) * (p_(k-1) - u_(k-1))
                p.Subtract(u, temp);

                temp.Multiply(beta, temp2);
                residuals.Add(temp2, p);

                // Solve M b_k = p_k
                _preconditioner.Approximate(p, temp);

                // s_k = A b_k
                matrix.Multiply(temp, s);

                // alpha_k = (r*_0 * r_k) / (r*_0 * s_k)
                var alpha = rdash.ConjugateDotProduct(residuals) / rdash.ConjugateDotProduct(s);

                // y_k = t_(k-1) - r_k - alpha_k * w_(k-1) + alpha_k s_k
                s.Subtract(w, temp);
                t.Subtract(residuals, y);

                temp.Multiply(alpha, temp2);
                y.Add(temp2, temp3);
                temp3.CopyTo(y);

                // Store the old value of t in t0
                t.CopyTo(t0);

                // t_k = r_k - alpha_k s_k
                s.Multiply(-alpha, temp2);
                residuals.Add(temp2, t);

                // Solve M d_k = t_k
                _preconditioner.Approximate(t, temp);

                // c_k = A d_k
                matrix.Multiply(temp, c);
                var cdot = c.ConjugateDotProduct(c);

                // cDot can only be zero if c is a zero vector
                // We'll set cDot to 1 if it is zero to prevent NaN's
                // Note that the calculation should continue fine because
                // c.DotProduct(t) will be zero and so will c.DotProduct(y)
                if (cdot.Real.AlmostEqual(0, 1) && cdot.Imaginary.AlmostEqual(0, 1))
                {
                    cdot = 1.0;
                }

                // Even if we don't want to do any BiCGStab steps we'll still have
                // to do at least one at the start to initialize the
                // system, but we'll only have to take special measures
                // if we don't do any so ...
                var     ctdot = c.ConjugateDotProduct(t);
                Complex eta;
                Complex sigma;
                if (((_numberOfBiCgStabSteps == 0) && (iterationNumber == 0)) || ShouldRunBiCgStabSteps(iterationNumber))
                {
                    // sigma_k = (c_k * t_k) / (c_k * c_k)
                    sigma = ctdot / cdot;

                    // eta_k = 0
                    eta = 0;
                }
                else
                {
                    var ydot = y.ConjugateDotProduct(y);

                    // yDot can only be zero if y is a zero vector
                    // We'll set yDot to 1 if it is zero to prevent NaN's
                    // Note that the calculation should continue fine because
                    // y.DotProduct(t) will be zero and so will c.DotProduct(y)
                    if (ydot.Real.AlmostEqual(0, 1) && ydot.Imaginary.AlmostEqual(0, 1))
                    {
                        ydot = 1.0;
                    }

                    var ytdot = y.ConjugateDotProduct(t);
                    var cydot = c.ConjugateDotProduct(y);

                    var denom = (cdot * ydot) - (cydot * cydot);

                    // sigma_k = ((y_k * y_k)(c_k * t_k) - (y_k * t_k)(c_k * y_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k))
                    sigma = ((ydot * ctdot) - (ytdot * cydot)) / denom;

                    // eta_k = ((c_k * c_k)(y_k * t_k) - (y_k * c_k)(c_k * t_k)) / ((c_k * c_k)(y_k * y_k) - (y_k * c_k)(c_k * y_k))
                    eta = ((cdot * ytdot) - (cydot * ctdot)) / denom;
                }

                // u_k = sigma_k s_k + eta_k (t_(k-1) - r_k + beta_(k-1) u_(k-1))
                u.Multiply(beta, temp2);
                t0.Add(temp2, temp);

                temp.Subtract(residuals, temp3);
                temp3.CopyTo(temp);
                temp.Multiply(eta, temp);

                s.Multiply(sigma, temp2);
                temp.Add(temp2, u);

                // z_k = sigma_k r_k +_ eta_k z_(k-1) - alpha_k u_k
                z.Multiply(eta, z);
                u.Multiply(-alpha, temp2);
                z.Add(temp2, temp3);
                temp3.CopyTo(z);

                residuals.Multiply(sigma, temp2);
                z.Add(temp2, temp3);
                temp3.CopyTo(z);

                // x_(k+1) = x_k + alpha_k p_k + z_k
                p.Multiply(alpha, temp2);
                xtemp.Add(temp2, temp3);
                temp3.CopyTo(xtemp);

                xtemp.Add(z, temp3);
                temp3.CopyTo(xtemp);

                // r_(k+1) = t_k - eta_k y_k - sigma_k c_k
                // Copy the old residuals to a temp vector because we'll
                // need those in the next step
                residuals.CopyTo(t0);

                y.Multiply(-eta, temp2);
                t.Add(temp2, residuals);

                c.Multiply(-sigma, temp2);
                residuals.Add(temp2, temp3);
                temp3.CopyTo(residuals);

                // beta_k = alpha_k / sigma_k * (r*_0 * r_(k+1)) / (r*_0 * r_k)
                // But first we check if there is a possible NaN. If so just reset beta to zero.
                beta = (!sigma.Real.AlmostEqual(0, 1) || !sigma.Imaginary.AlmostEqual(0, 1)) ? alpha / sigma * rdash.ConjugateDotProduct(residuals) / rdash.ConjugateDotProduct(t0) : 0;

                // w_k = c_k + beta_k s_k
                s.Multiply(beta, temp2);
                c.Add(temp2, w);

                // Get the real value
                _preconditioner.Approximate(xtemp, result);

                // Now check for convergence
                if (!ShouldContinue(iterationNumber, result, input, residuals))
                {
                    // Recalculate the residuals and go round again. This is done to ensure that
                    // we have the proper residuals.
                    CalculateTrueResidual(matrix, residuals, result, input);
                }

                // Next iteration.
                iterationNumber++;
            }
        }
Пример #49
0
 public void CanComputeSquareRoot()
 {
     var complex = new Complex(1.19209289550780998537e-7, 1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(
         new Complex(0.00037933934912842666, 0.00015712750315077684), complex.SquareRoot(), 14);
     complex = new Complex(0.0, 1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(
         new Complex(0.00024414062499999973, 0.00024414062499999976), complex.SquareRoot(), 14);
     complex = new Complex(0.0, -1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(
         new Complex(0.00024414062499999973, -0.00024414062499999976), complex.SquareRoot(), 14);
     complex = new Complex(0.0, 0.5);
     AssertHelpers.AlmostEqualRelative(new Complex(0.5, 0.5), complex.SquareRoot(), 14);
     complex = new Complex(0.0, -0.5);
     AssertHelpers.AlmostEqualRelative(new Complex(0.5, -0.5), complex.SquareRoot(), 14);
     complex = new Complex(0.0, -8.388608e6);
     AssertHelpers.AlmostEqualRelative(new Complex(2048.0, -2048.0), complex.SquareRoot(), 14);
     complex = new Complex(8.388608e6, 1.19209289550780998537e-7);
     AssertHelpers.AlmostEqualRelative(new Complex(2896.3093757400989, 2.0579515874459933e-11), complex.SquareRoot(), 14);
     complex = new Complex(0.0, 0.0);
     AssertHelpers.AlmostEqualRelative(Complex.Zero, complex.SquareRoot(), 14);
 }