/// <overloads> /// There are two permuations of the constructor, both require a parameter corresponding /// to the left-most column of a Toeplitz matrix. /// </overloads> /// <summary> /// Constructor with <c>ComplexDoubleVector</c> parameter. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <exception cref="ArgumentNullException"> /// <B>T</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> is zero. /// </exception> public ComplexDoubleSymmetricLevinson(IROComplexDoubleVector T) { // check parameter if (T == null) { throw new System.ArgumentNullException("T"); } else if (T.Length == 0) { throw new RankException("The length of T is zero."); } // save the vector m_LeftColumn = new ComplexDoubleVector(T); m_Order = m_LeftColumn.Length; // allocate memory for lower triangular matrix m_LowerTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_LowerTriangle[i] = new Complex[i + 1]; } // allocate memory for diagonal m_Diagonal = new Complex[m_Order]; }
public static IComplexDoubleMatrix AU(IComplexDoubleMatrix A, IROComplexDoubleVector u, int r1, int r2, int c1, int c2) { if (r2 < r1) { return(A); } return(AU(A, u, r1, r2, c1, c2, new ComplexDoubleVector(r2 - r1 + 1))); }
public static IComplexDoubleMatrix UA(IROComplexDoubleVector u, IComplexDoubleMatrix A, int r1, int r2, int c1, int c2) { if (c1 > c2) { return(A); } return(UA(u, A, r1, r2, c1, c2, new ComplexDoubleVector(c2 - c1 + 1))); }
/// <overloads> /// Solve a symmetric square Toeplitz system. /// </overloads> /// <summary> /// Solve a symmetric square Toeplitz system with a right-side vector. /// </summary> /// <param name="Y">The right-hand side of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// Parameter <B>Y</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>Y</B> is not equal to the number of rows in the Toeplitz matrix. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member solves the linear system <B>TX</B> = <B>Y</B>, where <B>T</B> is /// the symmetric square Toeplitz matrix, <B>X</B> is the unknown solution vector /// and <B>Y</B> is a known vector. /// <para> /// The class implicitly decomposes the inverse Toeplitz matrix into a <b>UDL</b> factorisation /// using the Levinson algorithm, and then calculates the solution vector. /// </para> /// </remarks> public ComplexDoubleVector Solve(IROComplexDoubleVector Y) { ComplexDoubleVector X; // check parameters if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (m_Order != Y.Length) { throw new RankException("The length of Y is not equal to the number of rows in the Toeplitz matrix."); } Compute(); if (m_IsSingular == true) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } int i, j, l; // index/loop variables Complex Inner; // inner product Complex G; // scaling constant Complex[] A; // reference to current order coefficients // allocate memory for solution X = new ComplexDoubleVector(m_Order) { // setup zero order solution [0] = Y[0] / m_LeftColumn[0] }; // solve systems of increasing order for (i = 1; i < m_Order; i++) { // calculate inner product Inner = Y[i]; for (j = 0, l = i; j < i; j++, l--) { Inner -= X[j] * m_LeftColumn[l]; } // get the current predictor coefficients row A = m_LowerTriangle[i]; // update the solution vector G = Inner * m_Diagonal[i]; for (j = 0; j <= i; j++) { X[j] += G * A[j]; } } return(X); }
private ComplexDoubleVector Pivot(IROComplexDoubleVector B) { ComplexDoubleVector ret = new ComplexDoubleVector(B.Length); for (int i = 0; i < pivots.Length; i++) { ret.data[i] = B[pivots[i]]; } return(ret); }
///<summary>Solves a system on linear equations, AX=B, where A is the factored matrixed.</summary> ///<param name="B">RHS side of the system.</param> ///<returns>the solution vector, X.</returns> ///<exception cref="ArgumentNullException">B is null.</exception> ///<exception cref="NotPositiveDefiniteException">A is not positive definite.</exception> ///<exception cref="ArgumentException">The number of rows of A and the length of B must be the same.</exception> public ComplexDoubleVector Solve(IROComplexDoubleVector B) { if (B == null) { throw new System.ArgumentNullException("B cannot be null."); } Compute(); if (!ispd) { throw new NotPositiveDefiniteException(); } else { if (B.Length != order) { throw new System.ArgumentException("The length of B must be the same as the order of the matrix."); } #if MANAGED // Copy right hand side. var X = new ComplexDoubleVector(B); // Solve L*Y = B; for (int i = 0; i < order; i++) { Complex sum = B[i]; for (int k = i - 1; k >= 0; k--) { sum -= l.data[i][k] * X.data[k]; } X.data[i] = sum / l.data[i][i]; } // Solve L'*X = Y; for (int i = order - 1; i >= 0; i--) { Complex sum = X.data[i]; for (int k = i + 1; k < order; k++) { sum -= ComplexMath.Conjugate(l.data[k][i]) * X.data[k]; } X.data[i] = sum / ComplexMath.Conjugate(l.data[i][i]); } return(X); #else Complex[] rhs = ComplexDoubleMatrix.ToLinearComplexArray(B); Lapack.Potrs.Compute(Lapack.UpLo.Lower, order, 1, l.data, order, rhs, B.Length); ComplexDoubleVector ret = new ComplexDoubleVector(order, B.Length); ret.data = rhs; return(ret); #endif } }
/// <summary> /// This algorithm determines the mean backward prediction error using the model stored in this instance. See remarks for details. /// </summary> /// <param name="x">Signal for which to determine the mean backward prediction error.</param> /// <returns>Mean backward prediction error.</returns> /// <remarks> /// 1. The prediction is done non recursively, i.e. part of the signal (the signal window) is used to predict the signal value before, and this predicted signal value is /// then compared with the original signal value stored in x to build the sum of errors. But the predicted signal value is <b>not</b> used to make further predictions. /// Instead, the signal window is moved by one point to the left and another prediction is made, with the original signal in x. This is repeated until the first point (index 0) /// is predicted. The return value is the square root of the sum of squared differences between predicted signal values and original values, divided by the number of predicted values. /// The number of predicted values is the length of the signal x minus the number of coefficents of the model. /// </remarks> public double GetMeanPredictionErrorNonrecursivelyBackward(IROComplexDoubleVector x) { int last = x.Length - _numberOfCoefficients; double sumsqr = 0; for (int i = last - 1; i >= 0; i--) { Complex sum = 0; for (int k = 1; k <= _numberOfCoefficients; k++) // note that Ak[0] is always 1 for technical reasons, thus we start here with index 1 { sum -= _Ak[k].GetConjugate() * x[i + k]; } sumsqr += (x[i] - sum).GetModulusSquared(); } return(Math.Sqrt(sumsqr / (last))); }
/// <overloads> /// Solve a square Toeplitz system. /// </overloads> /// <summary> /// Solve a square Toeplitz system with a right-side vector. /// </summary> /// <param name="Y">The right-hand side of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// Parameter <B>Y</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of Y is not equal to the number of rows in the Toeplitz matrix. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member solves the linear system <B>TX</B> = <B>Y</B>, where <B>T</B> is /// the square Toeplitz matrix, <B>X</B> is the unknown solution vector /// and <B>Y</B> is a known vector. /// <para> /// The class implicitly decomposes the inverse Toeplitz matrix into a <b>UDL</b> factorisation /// using the Levinson algorithm, before calculating the solution vector. /// </para> /// </remarks> public ComplexDoubleVector Solve(IROComplexDoubleVector Y) { ComplexDoubleVector X; Complex Inner; int i, j; // check parameters if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (m_Order != Y.Length) { throw new RankException("The length of Y is not equal to the number of rows in the Toeplitz matrix."); } Compute(); if (m_IsSingular == true) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // allocate memory for solution Complex[] A, B; X = new ComplexDoubleVector(m_Order); for (i = 0; i < m_Order; i++) { A = m_LowerTriangle[i]; B = m_UpperTriangle[i]; Inner = Y[i]; for (j = 0; j < i; j++) { Inner += A[j] * Y[j]; } Inner *= m_Diagonal[i]; X[i] = Inner; for (j = 0; j < i; j++) { X[j] += Inner * B[j]; } } return(X); }
/// <summary> /// Invert a symmetric square Toeplitz matrix. /// </summary> /// <param name="T">The left-most column of the symmetric Toeplitz matrix.</param> /// <returns>The inverse matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> must be greater than zero. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This static member combines the <b>UDL</b> decomposition and Trench's algorithm into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// <para> /// Trench's algorithm requires <b>N</b> squared FLOPS, compared to <b>N</b> cubed FLOPS /// if we simply solved a linear Toeplitz system with a right-side identity matrix (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleMatrix Inverse(IROComplexDoubleVector T) { ComplexDoubleMatrix X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (T.Length < 1) { throw new System.RankException("The length of T must be greater than zero."); } else if (T.Length == 1) { X = new ComplexDoubleMatrix(1) {
///<summary>Solves a system on linear equations, AX=B, where A is the factored matrixed.</summary> ///<param name="B">RHS side of the system.</param> ///<returns>the solution vector, X.</returns> ///<exception cref="ArgumentNullException">B is null.</exception> ///<exception cref="SingularMatrixException">A is singular.</exception> ///<exception cref="ArgumentException">The number of rows of A and the length of B must be the same.</exception> public ComplexDoubleVector Solve(IROComplexDoubleVector B) { if (B == null) { throw new System.ArgumentNullException("B cannot be null."); } Compute(); if (singular) { throw new SingularMatrixException(); } else { if (B.Length != order) { throw new System.ArgumentException("The length of B must be the same as the order of the matrix."); } #if MANAGED // Copy right hand side with pivoting ComplexDoubleVector X = Pivot(B); // Solve L*Y = B(piv,:) for (int k = 0; k < order; k++) { for (int i = k + 1; i < order; i++) { X[i] -= X[k] * factor[i][k]; } } // Solve U*X = Y; for (int k = order - 1; k >= 0; k--) { X[k] /= factor[k][k]; for (int i = 0; i < k; i++) { X[i] -= X[k] * factor[i][k]; } } return(X); #else Complex[] rhs = ComplexDoubleMatrix.ToLinearComplexArray(B); Lapack.Getrs.Compute(Lapack.Transpose.NoTrans, order, 1, factor, order, pivots, rhs, rhs.Length); return(new ComplexDoubleVector(rhs)); #endif } }
/// <summary> /// This algorithm determines the mean forward prediction error using the model stored in this instance. See remarks for details. /// </summary> /// <param name="x">Signal for which to determine the mean forward prediction error.</param> /// <returns>Mean backward prediction error.</returns> /// <remarks> /// 1. The prediction is done non recursively, i.e. part of the signal (the signal window) is used to predict the signal value immediately after the window, and this predicted signal value is /// then compared with the original signal value stored in x to build the sum of errors. But the predicted signal value is <b>not</b> used to make further predictions. /// Instead, the signal window is moved by one point to the right and another prediction is made, with the original signal in x. This is repeated until the last point /// is predicted. The return value is the square root of the sum of squared differences between predicted signal values and original values, divided by the number of predicted values. /// The number of predicted values is the length of the signal x minus the number of coefficents of the model. /// </remarks> public double GetMeanPredictionErrorNonrecursivelyForward(IROComplexDoubleVector x) { int first = _numberOfCoefficients; int last = x.Length; double sumsqr = 0; for (int i = first; i < last; i++) { Complex sum = 0; for (int k = 1; k <= _numberOfCoefficients; k++) // note that Ak[0] is always 1 for technical reasons, thus we start here with index 1 { sum -= _Ak[k] * x[i - k]; } sumsqr += (x[i] - sum).GetModulusSquared(); } return(Math.Sqrt(sumsqr / (last - first))); }
/// <summary> /// Constructor with <c>ComplexDoubleVector</c> parameters. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <exception cref="ArgumentNullException"> /// <B>col</B> is a null reference, /// <para>or</para> /// <para><B>row</B> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length col <B>col</B> is zero, /// <para>or</para> /// <para>the length of <B>col</B> does not match that of <B>row</B>.</para> /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <B>col</B> and <B>row</B> are not equal. /// </exception> public ComplexDoubleLevinson(IROComplexDoubleVector col, IROComplexDoubleVector row) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } // save the vectors m_LeftColumn = new ComplexDoubleVector(col); m_TopRow = new ComplexDoubleVector(row); m_Order = m_LeftColumn.Length; // allocate memory for lower triangular matrix m_LowerTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_LowerTriangle[i] = new Complex[i + 1]; } // allocate memory for diagonal m_Diagonal = new Complex[m_Order]; // allocate memory for upper triangular matrix m_UpperTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_UpperTriangle[i] = new Complex[i + 1]; } }
///<summary>Constructor for <c>ComplexDoubleVector</c> to deep copy from a <see cref="IROComplexDoubleVector" /></summary> ///<param name="src"><c>ComplexDoubleVector</c> to deep copy into <c>ComplexDoubleVector</c>.</param> ///<exception cref="ArgumentNullException">Exception thrown if null passed as 'src' parameter.</exception> public ComplexDoubleVector(IROComplexDoubleVector src) { if (src == null) { throw new ArgumentNullException("IROComplexDoubleVector cannot be null"); } if (src is ComplexDoubleVector) { data = (Complex[])(((ComplexDoubleVector)src).data.Clone()); } else { data = new Complex[src.Length]; for (int i = 0; i < src.Length; ++i) { data[i] = src[i]; } } }
public static IComplexDoubleMatrix UA(IROComplexDoubleVector u, IComplexDoubleMatrix A, int r1, int r2, int c1, int c2, IComplexDoubleVector v) { if (r2 < r1 || c2 < c1) { return(A); } if (r2 - r1 + 1 > u.Length) { throw new ArgumentException("Householder vector too short.", "u"); } if (c2 - c1 + 1 > v.Length) { throw new ArgumentException("Work vector too short.", "v"); } for (int j = c1; j <= c2; j++) { v[j - c1] = Complex.Zero; } for (int i = r1; i <= r2; i++) { for (int j = c1; j <= c2; j++) { v[j - c1] = new Complex(v[j - c1].Real + u[i - r1].Real * A[i, j].Real + u[i - r1].Imag * A[i, j].Imag, v[j - c1].Imag + u[i - r1].Real * A[i, j].Imag - u[i - r1].Imag * A[i, j].Real); } } for (int i = r1; i <= r2; i++) { for (int j = c1; j <= c2; j++) { A[i, j] = new Complex(A[i, j].Real - u[i - r1].Real * v[j - c1].Real + u[i - r1].Imag * v[j - c1].Imag, A[i, j].Imag - u[i - r1].Real * v[j - c1].Imag - u[i - r1].Imag * v[j - c1].Real); } } return(A); }
/// <summary> /// Transforms from a compact complex representation (nyquist frequency value put in imaginary part of first element) to real representation. /// </summary> /// <param name="src">Stores the complex spectrum.</param> /// <param name="destination">After return, stores the spectrum in normalized real representation. The length of the vector has to be equal to the length of the FFT. </param> public static void FromRepresentationCompactComplexToReal(IROComplexDoubleVector src, IVector <double> destination) { bool isEven = 0 == (destination.Length % 2); int destLen2; if (isEven) { destLen2 = destination.Length / 2; destination[0] = src[0].Re; destination[destLen2] = src[0].Im; ; } else // odd { destLen2 = (destination.Length - 1) / 2; destination[0] = src[0].Re; } for (int i = 1, j = destination.Length - 1; i < j; i++, j--) { destination[i] = src[i].Re; destination[j] = src[i].Im; } }
/// <summary> /// Invert a symmetric square Toeplitz matrix. /// </summary> /// <param name="T">The left-most column of the symmetric Toeplitz matrix.</param> /// <returns>The inverse matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> must be greater than zero. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This static member combines the <b>UDL</b> decomposition and Trench's algorithm into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// <para> /// Trench's algorithm requires <b>N</b> squared FLOPS, compared to <b>N</b> cubed FLOPS /// if we simply solved a linear Toeplitz system with a right-side identity matrix (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleMatrix Inverse(IROComplexDoubleVector T) { ComplexDoubleMatrix X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (T.Length < 1) { throw new System.RankException("The length of T must be greater than zero."); } else if (T.Length == 1) { X = new ComplexDoubleMatrix(1); X[0, 0] = Complex.One / T[0]; } else { int N = T.Length; Complex f, g; int i, j, l, k, m, n; X = new ComplexDoubleMatrix(N); // calculate the predictor coefficients ComplexDoubleVector Y = ComplexDoubleSymmetricLevinson.YuleWalker(T); // calculate gamma f = T[0]; for (i = 1, j = 0; i < N; i++, j++) { f += T[i] * Y[j]; } g = Complex.One / f; // calculate first row of inverse X[0, 0] = g; for (i = 1, j = 0; i < N; i++, j++) { X[0, i] = g * Y[j]; } // calculate successive rows of upper wedge for (i = 0, j = 1, k = N - 2; i < N / 2; i++, j++, k--) { for (l = j, m = i, n = N-1-j; l < N - j; l++, m++, n--) { X[j, l] = X[i, m] + g * (Y[i] * Y[m] - Y[k] * Y[n]); } } // this is symmetric matrix ... for (i = 0; i <= N / 2; i++) { for (j = i + 1; j < N - i; j++) { X[j, i] = X[i, j]; } } // and a persymmetric matrix. for (i = 0, j = N - 1; i < N; i++, j--) { for (k = 0, l = N - 1; k < j; k++, l--) { X[l, j] = X[i, k]; } } } return X; }
/// <overloads> /// Solve a symmetric square Toeplitz system. /// </overloads> /// <summary> /// Solve a symmetric square Toeplitz system with a right-side vector. /// </summary> /// <param name="Y">The right-hand side of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// Parameter <B>Y</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>Y</B> is not equal to the number of rows in the Toeplitz matrix. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member solves the linear system <B>TX</B> = <B>Y</B>, where <B>T</B> is /// the symmetric square Toeplitz matrix, <B>X</B> is the unknown solution vector /// and <B>Y</B> is a known vector. /// <para> /// The class implicitly decomposes the inverse Toeplitz matrix into a <b>UDL</b> factorisation /// using the Levinson algorithm, and then calculates the solution vector. /// </para> /// </remarks> public ComplexDoubleVector Solve(IROComplexDoubleVector Y) { ComplexDoubleVector X; // check parameters if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (m_Order != Y.Length) { throw new RankException("The length of Y is not equal to the number of rows in the Toeplitz matrix."); } Compute(); if (m_IsSingular == true) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } int i, j, l; // index/loop variables Complex Inner; // inner product Complex G; // scaling constant Complex[] A; // reference to current order coefficients // allocate memory for solution X = new ComplexDoubleVector(m_Order); // setup zero order solution X[0] = Y[0] / m_LeftColumn[0]; // solve systems of increasing order for (i = 1; i < m_Order; i++) { // calculate inner product Inner = Y[i]; for (j = 0, l = i; j < i; j++, l--) { Inner -= X[j] * m_LeftColumn[l]; } // get the current predictor coefficients row A = m_LowerTriangle[i]; // update the solution vector G = Inner * m_Diagonal[i]; for (j = 0; j <= i; j++) { X[j] += G * A[j]; } } return X; }
///<summary>Solves a system on linear equations, AX=B, where A is the factored matrixed.</summary> ///<param name="B">RHS side of the system.</param> ///<returns>the solution vector, X.</returns> ///<exception cref="ArgumentNullException">B is null.</exception> ///<exception cref="NotPositiveDefiniteException">A is not positive definite.</exception> ///<exception cref="ArgumentException">The number of rows of A and the length of B must be the same.</exception> public ComplexDoubleVector Solve (IROComplexDoubleVector B) { if ( B == null ) { throw new System.ArgumentNullException("B cannot be null."); } Compute(); if ( !ispd ) { throw new NotPositiveDefiniteException(); } else { if ( B.Length != order ) { throw new System.ArgumentException("The length of B must be the same as the order of the matrix." ); } #if MANAGED // Copy right hand side. ComplexDoubleVector X = new ComplexDoubleVector(B); // Solve L*Y = B; for (int i = 0; i < order; i++) { Complex sum = B[i]; for (int k = i-1; k >= 0; k--) { sum -= l.data[i][k] * X.data[k]; } X.data[i] = sum / l.data[i][i]; } // Solve L'*X = Y; for (int i =order-1; i >= 0; i--) { Complex sum = X.data[i]; for (int k = i+1; k < order; k++) { sum -= ComplexMath.Conjugate(l.data[k][i]) * X.data[k]; } X.data[i] = sum / ComplexMath.Conjugate(l.data[i][i]); } return X; #else Complex[] rhs = ComplexDoubleMatrix.ToLinearComplexArray(B); Lapack.Potrs.Compute(Lapack.UpLo.Lower,order,1,l.data,order,rhs,B.Length); ComplexDoubleVector ret = new ComplexDoubleVector(order,B.Length); ret.data = rhs; return ret; #endif } }
/// <summary> /// Uses th signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> public void Execute(IROComplexDoubleVector x, IComplexDoubleVector coefficients) { _meanSquareError = Execution(x, coefficients, null, null, this); }
public static IComplexDoubleMatrix UA(IROComplexDoubleVector u, IComplexDoubleMatrix A, int r1, int r2, int c1, int c2) { if (c1 > c2) { return A; } return UA(u, A, r1, r2, c1, c2, new ComplexDoubleVector(c2 - c1 + 1)); }
/// <summary> /// Invert a square Toeplitz matrix. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <returns>The inverse matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>col</B> is a null reference. /// <para>or</para> /// <para><B>row</B> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length of <B>col</B> is 0, /// <para>or</para> /// <para>the lengths of <B>col</B> and <B>row</B> are not equal.</para> /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <B>col</B> and <B>row</B> are not equal. /// </exception> /// <remarks> /// This static member combines the <b>UDL</b> decomposition and Trench's algorithm into a /// single algorithm. It requires minimal data storage, compared to the non-static member /// and suffers from no speed penalty in comparision. /// <para> /// Trench's algorithm requires <b>N</b> squared FLOPS, compared to <b>N</b> cubed FLOPS /// if we simply solved a linear Toeplitz system with a right-side identity matrix (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleMatrix Inverse(IROComplexDoubleVector col, IROComplexDoubleVector row) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } // check if leading diagonal is zero if (col[0] == Complex.Zero) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // decompose matrix int order = col.Length; Complex[] A = new Complex[order]; Complex[] B = new Complex[order]; Complex[] Z = new Complex[order]; Complex Q, S, Ke, Kr, e; int i, j, k, l; // setup the zero order solution A[0] = Complex.One; B[0] = Complex.One; e = Complex.One / col[0]; for (i = 1; i < order; i++) { // calculate inner products Q = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { Q += col[l] * A[j]; } S = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { S += row[l] * B[j]; } // reflection coefficients Kr = -S * e; Ke = -Q * e; // update lower triangle (in temporary storage) Z[0] = Complex.Zero; Array.Copy(A, 0, Z, 1, i); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] += Ke * B[l]; } // update upper triangle for (j = i; j > 0; j--) { B[j] = B[j - 1]; } B[0] = Complex.Zero; for (j = 0, l = i - 1; j < i; j++, l--) { B[j] += Kr * A[l]; } // copy from temporary storage to lower triangle Array.Copy(Z, 0, A, 0, i + 1); // check for singular sub-matrix) if (Ke * Kr == Complex.One) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // update diagonal e = e / (Complex.One - Ke * Kr); } // calculate the inverse ComplexDoubleMatrix I = new ComplexDoubleMatrix(order); // the solution matrix Complex A1, B1; #if MANAGED Complex[] current, previous; // references to rows in the solution // setup the first row in wedge current = I.data[0]; for (i = 0, j = order - 1; i < order; i++, j--) { current[i] = e * B[j]; } // calculate values in the rest of the wedge for (i = 1; i < order; i++) { previous = current; current = I.data[i]; A1 = e * A[order - i - 1]; B1 = e * B[i - 1]; current[0] = A1; for (j = 1, k = 0, l = order - 2; j < order - i; j++, k++, l--) { current[j] = previous[k] + A1 * B[l] - B1 * A[k]; } } #else // setup the first row in wedge for (i = 0, j = order - 1; i < order; i++, j--) { I[0, i] = e * B[j]; } // calculate values in the rest of the wedge for (i = 1; i < order; i++) { A1 = e * A[order - i - 1]; B1 = e * B[i - 1]; I[i, 0] = A1; for (j = 1, k = 0, l = order - 2; j < order - i; j++, k++, l--) { I[i, j] = I[i - 1, k] + A1 * B[l] - B1 * A[k]; } } #endif // inverse is a persymmetric matrix. for (i = 0, j = order - 1; i < order; i++, j--) { for (k = 0, l = order - 1; k < j; k++, l--) { I[l, j] = I[i, k]; } } return(I); }
///<summary>Constructor for <c>ComplexDoubleVector</c> to deep copy from a <see cref="IROComplexDoubleVector" /></summary> ///<param name="src"><c>ComplexDoubleVector</c> to deep copy into <c>ComplexDoubleVector</c>.</param> ///<exception cref="ArgumentNullException">Exception thrown if null passed as 'src' parameter.</exception> public ComplexDoubleVector(IROComplexDoubleVector src) { if (src == null) { throw new ArgumentNullException("IROComplexDoubleVector cannot be null"); } if (src is ComplexDoubleVector) { data = (Complex[])(((ComplexDoubleVector)src).data.Clone()); } else { data = new Complex[src.Length]; for (int i = 0; i < src.Length; ++i) { data[i] = src[i]; } } }
/// <overloads> /// Solve a symmetric square Toeplitz system. /// </overloads> /// <summary> /// Solve a symmetric square Toeplitz system with a right-side vector. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <param name="Y">The right-side vector of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> and/or <B>Y</B> are null references /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> does not match the length of <B>Y</B>. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a symmetric square Toeplitz matrix, <B>X</B> is an unknown /// vector and <B>Y</B> is a known vector. /// <para> /// This static member combines the <b>UDL</b> decomposition and the calculation of the solution into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// </para> /// </remarks> public static ComplexDoubleVector Solve(IROComplexDoubleVector T, IROComplexDoubleVector Y) { ComplexDoubleVector X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (T.Length != Y.Length) { throw new RankException("The length of T and Y are not equal."); } else { // allocate memory int N = T.Length; X = new ComplexDoubleVector(N); // solution vector Complex e; // prediction error // setup zero order solution e = T[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } X[0] = Y[0] / T[0]; if (N > 1) { ComplexDoubleVector a = new ComplexDoubleVector(N - 1); // prediction coefficients ComplexDoubleVector Z = new ComplexDoubleVector(N - 1); // temporary storage vector Complex g; // reflection coefficient Complex inner; // inner product Complex k; int i, j, l; // calculate solution for successive orders for (i = 1; i < N; i++) { // calculate first inner product inner = T[i]; for (j = 0, l = i - 1; j < i - 1; j++, l--) { inner += a[j] * T[l]; } // update predictor coefficients g = -(inner / e); for (j = 0, l = i - 2; j < i - 1; j++, l--) { Z[j] = a[j] + g * a[l]; } // copy vector for (j = 0; j < i - 1; j++) { a[j] = Z[j]; } a[i - 1] = g; e *= (Complex.One - g * g); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // calculate second inner product inner = Y[i]; for (j = 0, l = i; j < i; j++, l--) { inner -= X[j] * T[l]; } // update solution vector k = inner / e; for (j = 0, l = i - 1; j < i; j++, l--) { X[j] = X[j] + k * a[l]; } X[j] = k; } } } return(X); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> /// <param name="tempStorage">Instance of this class used to hold the temporary arrays.</param> /// <returns>The mean square error of backward and forward prediction.</returns> private static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector <double> errors, IComplexDoubleVector reflectionCoefficients, BurgAlgorithmComplex tempStorage) { int N = x.Length - 1; int m = coefficients.Length; Complex[] Ak; // Prediction coefficients, Ak[0] is always 1 Complex[] b; // backward prediction errors Complex[] f; // forward prediction errors if (null != tempStorage) { tempStorage.EnsureAllocation(x.Length, coefficients.Length); Ak = tempStorage._Ak; b = tempStorage._b; f = tempStorage._f; for (int i = 1; i <= coefficients.Length; i++) { Ak[i] = 0; } } else { Ak = new Complex[coefficients.Length + 1]; b = new Complex[x.Length]; f = new Complex[x.Length]; } Ak[0] = 1; // Initialize forward and backward prediction errors with x for (int i = 0; i <= N; i++) { f[i] = b[i] = x[i]; } double Dk = 0; for (int i = 0; i <= N; i++) { Dk += 2 * f[i].GetModulusSquared(); } Dk -= f[0].GetModulusSquared() + b[N].GetModulusSquared(); // Burg recursion int k; double sumE = 0; // error sum for (k = 0; (k < m) && (Dk > 0); k++) { // Compute mu Complex mu = 0; for (int n = 0; n < N - k; n++) { mu += f[n + k + 1] * b[n].GetConjugate(); } mu *= (-2 / Dk); // Update Ak for (int n = 0; n <= (k + 1) / 2; n++) { Complex t1 = Ak[n] + mu * Ak[k + 1 - n].GetConjugate(); Complex t2 = Ak[k + 1 - n] + mu * Ak[n].GetConjugate(); Ak[n] = t1; Ak[k + 1 - n] = t2; } if (null != reflectionCoefficients) { reflectionCoefficients[k] = Ak[k + 1]; } // update forward and backward predition error with simultaneous total error calculation sumE = 0; for (int n = 0; n < N - k; n++) { Complex t1 = f[n + k + 1] + mu * b[n]; Complex t2 = b[n] + mu.GetConjugate() * f[n + k + 1]; f[n + k + 1] = t1; b[n] = t2; sumE += t1.GetModulusSquared() + t2.GetModulusSquared(); } if (null != errors) { errors[k] = sumE / (2 * (N - k)); } // Update Dk // Note that it is possible to update Dk without total error calculation because sumE = Dk*(1-mu.GetModulusSquared()) // but this will render the algorithm numerically unstable especially for higher orders and low noise Dk = sumE - (f[k + 1].GetModulusSquared() + b[N - k - 1].GetModulusSquared()); } // Assign coefficients for (int i = 0; i < m; i++) { coefficients[i] = Ak[i + 1]; } // Assign the rest of reflection coefficients and errors with zero // if not all stages could be calculated because Dk was zero or because of rounding effects smaller than zero for (int i = k + 1; i < m; i++) { if (null != reflectionCoefficients) { reflectionCoefficients[i] = 0; } if (null != errors) { errors[i] = 0; } } return(sumE / (2 * (N - k))); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="numberOfCoefficients">Number of coefficients of the model.</param> public void Execute(IROComplexDoubleVector x, int numberOfCoefficients) { EnsureAllocation(x.Length, numberOfCoefficients); _meanSquareError = Execution(x, _AkWrapper, null, null, this); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> /// <returns>The mean square error of backward and forward prediction.</returns> public static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector <double> errors, IComplexDoubleVector reflectionCoefficients) { return(Execution(x, coefficients, errors, reflectionCoefficients, null)); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <returns>The mean square error of backward and forward prediction.</returns> public static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients) { return(Execution(x, coefficients, null, null, null)); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> /// <returns>The mean square error of backward and forward prediction.</returns> public static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector errors, IComplexDoubleVector reflectionCoefficients) { return Execution(x, coefficients, errors, reflectionCoefficients, null); }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="numberOfCoefficients">Number of coefficients of the model.</param> public void Execute(IROComplexDoubleVector x, int numberOfCoefficients) { EnsureAllocation(x.Length, numberOfCoefficients); _meanSquareError = Execution(x, _AkWrapper, null, null, this); }
public static IComplexDoubleMatrix AU(IComplexDoubleMatrix A, IROComplexDoubleVector u, int r1, int r2, int c1, int c2) { if (r2 < r1) { return A; } return AU(A, u, r1, r2, c1, c2, new ComplexDoubleVector(r2 - r1 + 1)); }
/// <summary> /// This algorithm determines the mean forward prediction error using the model stored in this instance. See remarks for details. /// </summary> /// <param name="x">Signal for which to determine the mean forward prediction error.</param> /// <returns>Mean backward prediction error.</returns> /// <remarks> /// 1. The prediction is done non recursively, i.e. part of the signal (the signal window) is used to predict the signal value immediately after the window, and this predicted signal value is /// then compared with the original signal value stored in x to build the sum of errors. But the predicted signal value is <b>not</b> used to make further predictions. /// Instead, the signal window is moved by one point to the right and another prediction is made, with the original signal in x. This is repeated until the last point /// is predicted. The return value is the square root of the sum of squared differences between predicted signal values and original values, divided by the number of predicted values. /// The number of predicted values is the length of the signal x minus the number of coefficents of the model. /// </remarks> public double GetMeanPredictionErrorNonrecursivelyForward(IROComplexDoubleVector x) { int first = _numberOfCoefficients; int last = x.Length; double sumsqr = 0; for (int i = first; i < last; i++) { Complex sum = 0; for (int k = 1; k <= _numberOfCoefficients; k++) // note that Ak[0] is always 1 for technical reasons, thus we start here with index 1 { sum -= _Ak[k] * x[i - k]; } sumsqr += (x[i] - sum).GetModulusSquared(); } return Math.Sqrt(sumsqr / (last - first)); }
/// <summary> /// Constructor with <c>ComplexDoubleVector</c> parameters. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <exception cref="ArgumentNullException"> /// <B>col</B> is a null reference, /// <para>or</para> /// <para><B>row</B> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length col <B>col</B> is zero, /// <para>or</para> /// <para>the length of <B>col</B> does not match that of <B>row</B>.</para> /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <B>col</B> and <B>row</B> are not equal. /// </exception> public ComplexDoubleLevinson(IROComplexDoubleVector col, IROComplexDoubleVector row) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } // save the vectors m_LeftColumn = new ComplexDoubleVector(col); m_TopRow = new ComplexDoubleVector(row); m_Order = m_LeftColumn.Length; // allocate memory for lower triangular matrix m_LowerTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_LowerTriangle[i] = new Complex[i + 1]; } // allocate memory for diagonal m_Diagonal = new Complex[m_Order]; // allocate memory for upper triangular matrix m_UpperTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_UpperTriangle[i] = new Complex[i + 1]; } }
/// <summary> /// Solve a square Toeplitz system with a right-side matrix. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <param name="Y">The right-side matrix of the system.</param> /// <returns>The solution matrix.</returns> /// <exception cref="ArgumentNullException"> /// <EM>col</EM> is a null reference, /// <para>or</para> /// <para><EM>row</EM> is a null reference,</para> /// <para>or</para> /// <para><EM>Y</EM> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length of <EM>col</EM> is 0, /// <para>or</para> /// <para>the lengths of <EM>col</EM> and <EM>row</EM> are not equal,</para> /// <para>or</para> /// <para>the number of rows in <EM>Y</EM> does not the length of <EM>col</EM> and <EM>row</EM>.</para> /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <EM>col</EM> and <EM>row</EM> are not equal. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a square Toeplitz matrix, <B>X</B> is an unknown /// matrix and <B>Y</B> is a known matrix. /// <para> /// The classic Levinson algorithm is used to solve the system. The algorithm /// assumes that all the leading sub-matrices of the Toeplitz matrix are /// non-singular. When a sub-matrix is near singular, accuracy will /// be degraded. This member requires approximately <B>N</B> squared /// FLOPS to calculate a solution, where <B>N</B> is the matrix order. /// </para> /// <para> /// This static method has minimal storage requirements as it combines /// the <b>UDL</b> decomposition with the calculation of the solution vector /// in a single algorithm. /// </para> /// </remarks> public static ComplexDoubleMatrix Solve(IROComplexDoubleVector col, IROComplexDoubleVector row, IROComplexDoubleMatrix Y) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (col.Length != Y.Columns) { throw new RankException("The numer of rows in Y does not match the length of col and row."); } // check if leading diagonal is zero if (col[0] == Complex.Zero) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // decompose matrix int order = col.Length; Complex[] A = new Complex[order]; Complex[] B = new Complex[order]; Complex[] Z = new Complex[order]; ComplexDoubleMatrix X = new ComplexDoubleMatrix(order); Complex Q, S, Ke, Kr, e; Complex Inner; int i, j, l; // setup the zero order solution A[0] = Complex.One; B[0] = Complex.One; e = Complex.One / col[0]; X.SetRow(0, e * ComplexDoubleVector.GetRow(Y, 0)); for (i = 1; i < order; i++) { // calculate inner products Q = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { Q += col[l] * A[j]; } S = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { S += row[l] * B[j]; } // reflection coefficients Kr = -S * e; Ke = -Q * e; // update lower triangle (in temporary storage) Z[0] = Complex.Zero; Array.Copy(A, 0, Z, 1, i); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] += Ke * B[l]; } // update upper triangle for (j = i; j > 0; j--) { B[j] = B[j - 1]; } B[0] = Complex.Zero; for (j = 0, l = i - 1; j < i; j++, l--) { B[j] += Kr * A[l]; } // copy from temporary storage to lower triangle Array.Copy(Z, 0, A, 0, i + 1); // check for singular sub-matrix) if (Ke * Kr == Complex.One) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // update diagonal e = e / (Complex.One - Ke * Kr); for (l = 0; l < Y.Rows; l++) { ComplexDoubleVector W = X.GetColumn(l); ComplexDoubleVector M = ComplexDoubleVector.GetColumn(Y, l); Inner = M[i]; for (j = 0; j < i; j++) { Inner += A[j] * M[j]; } Inner *= e; W[i] = Inner; for (j = 0; j < i; j++) { W[j] += Inner * B[j]; } X.SetColumn(l, W); } } return(X); }
/// <summary> /// Invert a square Toeplitz matrix. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <returns>The inverse matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>col</B> is a null reference. /// <para>or</para> /// <para><B>row</B> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length of <B>col</B> is 0, /// <para>or</para> /// <para>the lengths of <B>col</B> and <B>row</B> are not equal.</para> /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <B>col</B> and <B>row</B> are not equal. /// </exception> /// <remarks> /// This static member combines the <b>UDL</b> decomposition and Trench's algorithm into a /// single algorithm. It requires minimal data storage, compared to the non-static member /// and suffers from no speed penalty in comparision. /// <para> /// Trench's algorithm requires <b>N</b> squared FLOPS, compared to <b>N</b> cubed FLOPS /// if we simply solved a linear Toeplitz system with a right-side identity matrix (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleMatrix Inverse(IROComplexDoubleVector col, IROComplexDoubleVector row) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } // check if leading diagonal is zero if (col[0] == Complex.Zero) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // decompose matrix int order = col.Length; Complex[] A = new Complex[order]; Complex[] B = new Complex[order]; Complex[] Z = new Complex[order]; Complex Q, S, Ke, Kr, e; int i, j, k, l; // setup the zero order solution A[0] = Complex.One; B[0] = Complex.One; e = Complex.One / col[0]; for (i = 1; i < order; i++) { // calculate inner products Q = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { Q += col[l] * A[j]; } S = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { S += row[l] * B[j]; } // reflection coefficients Kr = -S * e; Ke = -Q * e; // update lower triangle (in temporary storage) Z[0] = Complex.Zero; Array.Copy(A, 0, Z, 1, i); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] += Ke * B[l]; } // update upper triangle for (j = i; j > 0; j--) { B[j] = B[j - 1]; } B[0] = Complex.Zero; for (j = 0, l = i - 1; j < i; j++, l--) { B[j] += Kr * A[l]; } // copy from temporary storage to lower triangle Array.Copy(Z, 0, A, 0, i + 1); // check for singular sub-matrix) if (Ke * Kr == Complex.One) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // update diagonal e = e / (Complex.One - Ke * Kr); } // calculate the inverse ComplexDoubleMatrix I = new ComplexDoubleMatrix(order); // the solution matrix Complex A1, B1; #if MANAGED Complex[] current, previous; // references to rows in the solution // setup the first row in wedge current = I.data[0]; for (i = 0, j = order - 1; i < order; i++, j--) { current[i] = e * B[j]; } // calculate values in the rest of the wedge for (i = 1; i < order; i++) { previous = current; current = I.data[i]; A1 = e * A[order - i - 1]; B1 = e * B[i - 1]; current[0] = A1; for (j = 1, k = 0, l = order - 2; j < order - i; j++, k++, l--) { current[j] = previous[k] + A1 * B[l] - B1 * A[k]; } } #else // setup the first row in wedge for (i = 0, j = order - 1; i < order; i++, j--) { I[0, i] = e * B[j]; } // calculate values in the rest of the wedge for (i = 1; i < order; i++) { A1 = e * A[order - i - 1]; B1 = e * B[i - 1]; I[i, 0] = A1; for (j = 1, k = 0, l = order - 2; j < order - i; j++, k++, l--) { I[i, j] = I[i - 1, k] + A1 * B[l] - B1 * A[k]; } } #endif // inverse is a persymmetric matrix. for (i = 0, j = order - 1; i < order; i++, j--) { for (k = 0, l = order - 1; k < j; k++, l--) { I[l, j] = I[i, k]; } } return I; }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> public void Execute(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector errors, IComplexDoubleVector reflectionCoefficients) { _meanSquareError = Execution(x, coefficients, errors, reflectionCoefficients, this); }
public static IComplexDoubleMatrix AU(IComplexDoubleMatrix A, IROComplexDoubleVector u, int r1, int r2, int c1, int c2, IComplexDoubleVector v) { if (r2 < r1 || c2 < c1) { return A; } if (c2 - c1 + 1 > u.Length) { throw new ArgumentException("Householder vector too short.", "u"); } if (r2 - r1 + 1 > v.Length) { throw new ArgumentException("Work vector too short.", "v"); } for (int i = r1; i <= r2; i++) { v[i - r1] = Complex.Zero; for (int j = c1; j <= c2; j++) { v[i - r1] = new Complex(v[i - r1].Real + A[i, j].Real * u[j - c1].Real - A[i, j].Imag * u[j - c1].Imag, v[i - r1].Imag + A[i, j].Real * u[j - c1].Imag + A[i, j].Imag * u[j - c1].Real); } } for (int i = r1; i <= r2; i++) { for (int j = c1; j <= c2; j++) { A[i, j] = new Complex(A[i, j].Real - v[i - r1].Real * u[j - c1].Real - v[i - r1].Imag * u[j - c1].Imag, A[i, j].Imag + v[i - r1].Real * u[j - c1].Imag - v[i - r1].Imag * u[j - c1].Real); } } return A; }
public void Test(double[] arr) { double[] re = (double[])arr.Clone(); double[] im = new double[arr.Length]; double sum = 0; for (int i = 0; i < arr.Length; i++) { sum += (arr[i] * arr[i]); } sum = Math.Sqrt(sum / arr.Length); double tol = sum * arr.Length * 1E-14; double tol2 = arr.Length * 1E-14; // We transform the array var rft = new RealFourierTransform(arr.Length); rft.Transform(arr, FourierDirection.Forward); var wrapper = new RealFFTResultWrapper(arr); // we transform the re and im NativeFourierMethods.FourierTransformation(re, im, FourierDirection.Forward); // now compare the results // first the realpart var realpart = wrapper.RealPart; for (int i = 0; i < realpart.Length; i++) { Assert.AreEqual(re[i], realpart[i], tol, string.Format("Testing realpart (len={0}, i={1})", arr.Length, i)); } // now the imaginary part var imagpart = wrapper.ImaginaryPart; for (int i = 0; i < imagpart.Length; i++) { Assert.AreEqual(im[i], imagpart[i], tol, string.Format("Testing imagpart (len={0}, i={1})", arr.Length, i)); } // now the complex result IROComplexDoubleVector reimpart = wrapper.ComplexResult; for (int i = 0; i < reimpart.Length; i++) { Assert.AreEqual(re[i], reimpart[i].Re, tol, string.Format("Testing ComplexResult.Re (len={0}, i={1})", arr.Length, i)); Assert.AreEqual(im[i], reimpart[i].Im, tol, string.Format("Testing ComplexResult.Im (len={0}, i={1})", arr.Length, i)); } // now the amplitude part var amppart = wrapper.Amplitude; for (int i = 0; i < imagpart.Length; i++) { double expected = Altaxo.Calc.RMath.Hypot(re[i], im[i]); Assert.AreEqual(expected, amppart[i], tol, string.Format("Testing amplitude (len={0}, i={1})", arr.Length, i)); } // now the phase part var phasepart = wrapper.Phase; for (int i = 0; i < imagpart.Length; i++) { double ampl = Altaxo.Calc.RMath.Hypot(re[i], im[i]); if (ampl < 1E-14 * arr.Length) { continue; } double expected = Math.Atan2(im[i], re[i]); double actual = phasepart[i]; if (Math.Abs(Math.Sin(expected) - Math.Sin(actual)) > tol2 || Math.Abs(Math.Cos(expected) - Math.Cos(actual)) > tol2) { Assert.Fail(string.Format("Testing phase (len={0}, i={1}, Expected={2}, Actual={3})", arr.Length, i, expected, actual)); } } }
/// <summary> /// Solve a symmetric square Toeplitz system with a right-side matrix. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <param name="Y">The right-side matrix of the system.</param> /// <returns>The solution matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> and/or <B>Y</B> are null references /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> does not match the number of rows in <B>Y</B>. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a symmetric square Toeplitz matrix, <B>X</B> is an unknown /// matrix and <B>Y</B> is a known matrix. /// <para> /// This static member combines the <b>UDL</b> decomposition and the calculation of the solution into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// </para> /// </remarks> public static ComplexDoubleMatrix Solve(IROComplexDoubleVector T, IROComplexDoubleMatrix Y) { ComplexDoubleMatrix X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (T.Length != Y.Columns) { throw new RankException("The length of T and Y are not equal."); } else { // allocate memory int N = T.Length; int M = Y.Rows; X = new ComplexDoubleMatrix(N, M); // solution matrix ComplexDoubleVector Z = new ComplexDoubleVector(N); // temporary storage vector Complex e; // prediction error int i, j, l, m; // setup zero order solution e = T[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } for (m = 0; m < M; m++) { X[0, m] = Y[0,m] / T[0]; } if (N > 1) { ComplexDoubleVector a = new ComplexDoubleVector(N - 1); // prediction coefficients Complex p; // reflection coefficient Complex inner; // inner product Complex k; // calculate solution for successive orders for (i = 1; i < N; i++) { // calculate first inner product inner = T[i]; for (j = 0, l = i - 1; j < i - 1; j++, l--) { inner += a[j] * T[l]; } // update predictor coefficients p = -(inner / e); for (j = 0, l = i - 2; j < i - 1; j++, l--) { Z[j] = a[j] + p * a[l]; } // copy vector for (j = 0; j < i - 1; j++) { a[j] = Z[j]; } a[i - 1] = p; e *= (Complex.One - p * p); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // update the solution matrix for (m = 0; m < M; m++) { // retrieve a copy of solution column for (j = 0; j < i; j++) { Z[j] = X[j, m]; } // calculate second inner product inner = Y[i, m]; for (j = 0, l = i; j < i; j++, l--) { inner -= Z[j] * T[l]; } // update solution vector k = inner / e; for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] = Z[j] + k * a[l]; } Z[j] = k; // store solution column in matrix for (j = 0; j <= i; j++) { X[j, m] = Z[j]; } } } } } return X; }
/// <summary> /// Solve a square Toeplitz system with a right-side matrix. /// </summary> /// <param name="col">The left-most column of the Toeplitz matrix.</param> /// <param name="row">The top-most row of the Toeplitz matrix.</param> /// <param name="Y">The right-side matrix of the system.</param> /// <returns>The solution matrix.</returns> /// <exception cref="ArgumentNullException"> /// <EM>col</EM> is a null reference, /// <para>or</para> /// <para><EM>row</EM> is a null reference,</para> /// <para>or</para> /// <para><EM>Y</EM> is a null reference.</para> /// </exception> /// <exception cref="RankException"> /// The length of <EM>col</EM> is 0, /// <para>or</para> /// <para>the lengths of <EM>col</EM> and <EM>row</EM> are not equal,</para> /// <para>or</para> /// <para>the number of rows in <EM>Y</EM> does not the length of <EM>col</EM> and <EM>row</EM>.</para> /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <exception cref="ArithmeticException"> /// The values of the first element of <EM>col</EM> and <EM>row</EM> are not equal. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a square Toeplitz matrix, <B>X</B> is an unknown /// matrix and <B>Y</B> is a known matrix. /// <para> /// The classic Levinson algorithm is used to solve the system. The algorithm /// assumes that all the leading sub-matrices of the Toeplitz matrix are /// non-singular. When a sub-matrix is near singular, accuracy will /// be degraded. This member requires approximately <B>N</B> squared /// FLOPS to calculate a solution, where <B>N</B> is the matrix order. /// </para> /// <para> /// This static method has minimal storage requirements as it combines /// the <b>UDL</b> decomposition with the calculation of the solution vector /// in a single algorithm. /// </para> /// </remarks> public static ComplexDoubleMatrix Solve(IROComplexDoubleVector col, IROComplexDoubleVector row, IROComplexDoubleMatrix Y) { // check parameters if (col == null) { throw new System.ArgumentNullException("col"); } else if (col.Length == 0) { throw new RankException("The length of col is zero."); } else if (row == null) { throw new System.ArgumentNullException("row"); } else if (col.Length != row.Length) { throw new RankException("The lengths of col and row are not equal."); } else if (col[0] != row[0]) { throw new ArithmeticException("The values of the first element of col and row are not equal."); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (col.Length != Y.Columns) { throw new RankException("The numer of rows in Y does not match the length of col and row."); } // check if leading diagonal is zero if (col[0] == Complex.Zero) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // decompose matrix int order = col.Length; Complex[] A = new Complex[order]; Complex[] B = new Complex[order]; Complex[] Z = new Complex[order]; ComplexDoubleMatrix X = new ComplexDoubleMatrix(order); Complex Q, S, Ke, Kr, e; Complex Inner; int i, j, l; // setup the zero order solution A[0] = Complex.One; B[0] = Complex.One; e = Complex.One / col[0]; X.SetRow(0, e * ComplexDoubleVector.GetRow(Y, 0)); for (i = 1; i < order; i++) { // calculate inner products Q = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { Q += col[l] * A[j]; } S = Complex.Zero; for (j = 0, l = 1; j < i; j++, l++) { S += row[l] * B[j]; } // reflection coefficients Kr = -S * e; Ke = -Q * e; // update lower triangle (in temporary storage) Z[0] = Complex.Zero; Array.Copy(A, 0, Z, 1, i); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] += Ke * B[l]; } // update upper triangle for (j = i; j > 0; j--) { B[j] = B[j - 1]; } B[0] = Complex.Zero; for (j = 0, l = i - 1; j < i; j++, l--) { B[j] += Kr * A[l]; } // copy from temporary storage to lower triangle Array.Copy(Z, 0, A, 0, i + 1); // check for singular sub-matrix) if (Ke * Kr == Complex.One) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // update diagonal e = e / (Complex.One - Ke * Kr); for (l = 0; l < Y.Rows; l++) { ComplexDoubleVector W = X.GetColumn(l); ComplexDoubleVector M = ComplexDoubleVector.GetColumn(Y, l); Inner = M[i]; for (j = 0; j < i; j++) { Inner += A[j] * M[j]; } Inner *= e; W[i] = Inner; for (j = 0; j < i; j++) { W[j] += Inner * B[j]; } X.SetColumn(l, W); } } return X; }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> public void Execute(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector <double> errors, IComplexDoubleVector reflectionCoefficients) { _meanSquareError = Execution(x, coefficients, errors, reflectionCoefficients, this); }
/// <overloads> /// Solve a square Toeplitz system. /// </overloads> /// <summary> /// Solve a square Toeplitz system with a right-side vector. /// </summary> /// <param name="Y">The right-hand side of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// Parameter <B>Y</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of Y is not equal to the number of rows in the Toeplitz matrix. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member solves the linear system <B>TX</B> = <B>Y</B>, where <B>T</B> is /// the square Toeplitz matrix, <B>X</B> is the unknown solution vector /// and <B>Y</B> is a known vector. /// <para> /// The class implicitly decomposes the inverse Toeplitz matrix into a <b>UDL</b> factorisation /// using the Levinson algorithm, before calculating the solution vector. /// </para> /// </remarks> public ComplexDoubleVector Solve(IROComplexDoubleVector Y) { ComplexDoubleVector X; Complex Inner; int i, j; // check parameters if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (m_Order != Y.Length) { throw new RankException("The length of Y is not equal to the number of rows in the Toeplitz matrix."); } Compute(); if (m_IsSingular == true) { throw new SingularMatrixException("One of the leading sub-matrices is singular."); } // allocate memory for solution Complex[] A, B; X = new ComplexDoubleVector(m_Order); for (i = 0; i < m_Order; i++) { A = m_LowerTriangle[i]; B = m_UpperTriangle[i]; Inner = Y[i]; for (j = 0; j < i; j++) { Inner += A[j] * Y[j]; } Inner *= m_Diagonal[i]; X[i] = Inner; for (j = 0; j < i; j++) { X[j] += Inner * B[j]; } } return X; }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <returns>The mean square error of backward and forward prediction.</returns> public static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients) { return Execution(x, coefficients, null, null, null); }
/// <summary> /// Uses th signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> public void Execute(IROComplexDoubleVector x, IComplexDoubleVector coefficients) { _meanSquareError = Execution(x, coefficients, null, null, this); }
/// <summary> /// This algorithm determines the mean backward prediction error using the model stored in this instance. See remarks for details. /// </summary> /// <param name="x">Signal for which to determine the mean backward prediction error.</param> /// <returns>Mean backward prediction error.</returns> /// <remarks> /// 1. The prediction is done non recursively, i.e. part of the signal (the signal window) is used to predict the signal value before, and this predicted signal value is /// then compared with the original signal value stored in x to build the sum of errors. But the predicted signal value is <b>not</b> used to make further predictions. /// Instead, the signal window is moved by one point to the left and another prediction is made, with the original signal in x. This is repeated until the first point (index 0) /// is predicted. The return value is the square root of the sum of squared differences between predicted signal values and original values, divided by the number of predicted values. /// The number of predicted values is the length of the signal x minus the number of coefficents of the model. /// </remarks> public double GetMeanPredictionErrorNonrecursivelyBackward(IROComplexDoubleVector x) { int last = x.Length - _numberOfCoefficients; double sumsqr = 0; for (int i = last - 1; i >= 0; i--) { Complex sum = 0; for (int k = 1; k <= _numberOfCoefficients; k++) // note that Ak[0] is always 1 for technical reasons, thus we start here with index 1 { sum -= _Ak[k].GetConjugate() * x[i + k]; } sumsqr += (x[i] - sum).GetModulusSquared(); } return Math.Sqrt(sumsqr / (last)); }
/// <summary> /// Transforms from a compact complex representation (nyquist frequency value put in imaginary part of first element) to real representation. /// </summary> /// <param name="src">Stores the complex spectrum.</param> /// <param name="destination">After return, stores the spectrum in normalized real representation. The length of the vector has to be equal to the length of the FFT. </param> public static void FromRepresentationCompactComplexToReal(IROComplexDoubleVector src, IVector destination) { bool isEven = 0 == (destination.Length % 2); int destLen2; if (isEven) { destLen2 = destination.Length / 2; destination[0] = src[0].Re; destination[destLen2] = src[0].Im; ; } else // odd { destLen2 = (destination.Length - 1) / 2; destination[0] = src[0].Re; } for (int i = 1, j = destination.Length - 1; i < j; i++, j--) { destination[i] = src[i].Re; destination[j] = src[i].Im; } }
/// <summary> /// Solve a symmetric square Toeplitz system with a right-side matrix. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <param name="Y">The right-side matrix of the system.</param> /// <returns>The solution matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> and/or <B>Y</B> are null references /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> does not match the number of rows in <B>Y</B>. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a symmetric square Toeplitz matrix, <B>X</B> is an unknown /// matrix and <B>Y</B> is a known matrix. /// <para> /// This static member combines the <b>UDL</b> decomposition and the calculation of the solution into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// </para> /// </remarks> public static ComplexDoubleMatrix Solve(IROComplexDoubleVector T, IROComplexDoubleMatrix Y) { ComplexDoubleMatrix X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (T.Length != Y.Columns) { throw new RankException("The length of T and Y are not equal."); } else { // allocate memory int N = T.Length; int M = Y.Rows; X = new ComplexDoubleMatrix(N, M); // solution matrix ComplexDoubleVector Z = new ComplexDoubleVector(N); // temporary storage vector Complex e; // prediction error int i, j, l, m; // setup zero order solution e = T[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } for (m = 0; m < M; m++) { X[0, m] = Y[0, m] / T[0]; } if (N > 1) { ComplexDoubleVector a = new ComplexDoubleVector(N - 1); // prediction coefficients Complex p; // reflection coefficient Complex inner; // inner product Complex k; // calculate solution for successive orders for (i = 1; i < N; i++) { // calculate first inner product inner = T[i]; for (j = 0, l = i - 1; j < i - 1; j++, l--) { inner += a[j] * T[l]; } // update predictor coefficients p = -(inner / e); for (j = 0, l = i - 2; j < i - 1; j++, l--) { Z[j] = a[j] + p * a[l]; } // copy vector for (j = 0; j < i - 1; j++) { a[j] = Z[j]; } a[i - 1] = p; e *= (Complex.One - p * p); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // update the solution matrix for (m = 0; m < M; m++) { // retrieve a copy of solution column for (j = 0; j < i; j++) { Z[j] = X[j, m]; } // calculate second inner product inner = Y[i, m]; for (j = 0, l = i; j < i; j++, l--) { inner -= Z[j] * T[l]; } // update solution vector k = inner / e; for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] = Z[j] + k * a[l]; } Z[j] = k; // store solution column in matrix for (j = 0; j <= i; j++) { X[j, m] = Z[j]; } } } } } return(X); }
/// <summary> /// Solve the Yule-Walker equations for a symmetric square Toeplitz system /// </summary> /// <param name="R">The left-most column of the Toeplitz matrix.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// <B>R</B> is a null reference. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// The length of <B>R</B> must be greater than one. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member is used to solve the Yule-Walker system <B>AX</B> = -<B>a</B>, /// where <B>A</B> is a symmetric square Toeplitz matrix, constructed /// from the elements <B>R[0]</B>, ..., <B>R[N-2]</B> and /// the vector <B>a</B> is constructed from the elements /// <B>R[1]</B>, ..., <B>R[N-1]</B>. /// <para> /// Durbin's algorithm is used to solve the linear system. It requires /// approximately the <b>N</b> squared FLOPS to calculate the /// solution (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleVector YuleWalker(IROComplexDoubleVector R) { ComplexDoubleVector a; // check parameters if (R == null) { throw new System.ArgumentNullException("R"); } else if (R.Length < 2) { throw new System.ArgumentOutOfRangeException("R", "The length of R must be greater than 1."); } else { int N = R.Length - 1; a = new ComplexDoubleVector(N); // prediction coefficients ComplexDoubleVector Z = new ComplexDoubleVector(N); // temporary storage vector Complex e; // predictor error Complex inner; // inner product Complex g; // reflection coefficient int i, j, l; // setup first order solution e = R[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } g = -R[1] / R[0]; a[0] = g; // calculate solution for successive orders for (i = 1; i < N; i++) { e *= (Complex.One - g * g); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // calculate inner product inner = R[i + 1]; for (j = 0, l = i; j < i; j++, l--) { inner += a[j] * R[l]; } // update prediction coefficients g = -(inner / e); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] = a[j] + g * a[l]; } // copy vector for (j = 0; j < i; j++) { a[j] = Z[j]; } a[i] = g; } } return a; }
/// <summary> /// Solve the Yule-Walker equations for a symmetric square Toeplitz system /// </summary> /// <param name="R">The left-most column of the Toeplitz matrix.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// <B>R</B> is a null reference. /// </exception> /// <exception cref="ArgumentOutOfRangeException"> /// The length of <B>R</B> must be greater than one. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This member is used to solve the Yule-Walker system <B>AX</B> = -<B>a</B>, /// where <B>A</B> is a symmetric square Toeplitz matrix, constructed /// from the elements <B>R[0]</B>, ..., <B>R[N-2]</B> and /// the vector <B>a</B> is constructed from the elements /// <B>R[1]</B>, ..., <B>R[N-1]</B>. /// <para> /// Durbin's algorithm is used to solve the linear system. It requires /// approximately the <b>N</b> squared FLOPS to calculate the /// solution (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleVector YuleWalker(IROComplexDoubleVector R) { ComplexDoubleVector a; // check parameters if (R == null) { throw new System.ArgumentNullException("R"); } else if (R.Length < 2) { throw new System.ArgumentOutOfRangeException("R", "The length of R must be greater than 1."); } else { int N = R.Length - 1; a = new ComplexDoubleVector(N); // prediction coefficients ComplexDoubleVector Z = new ComplexDoubleVector(N); // temporary storage vector Complex e; // predictor error Complex inner; // inner product Complex g; // reflection coefficient int i, j, l; // setup first order solution e = R[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } g = -R[1] / R[0]; a[0] = g; // calculate solution for successive orders for (i = 1; i < N; i++) { e *= (Complex.One - g * g); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // calculate inner product inner = R[i + 1]; for (j = 0, l = i; j < i; j++, l--) { inner += a[j] * R[l]; } // update prediction coefficients g = -(inner / e); for (j = 0, l = i - 1; j < i; j++, l--) { Z[j] = a[j] + g * a[l]; } // copy vector for (j = 0; j < i; j++) { a[j] = Z[j]; } a[i] = g; } } return(a); }
/// <overloads> /// There are two permuations of the constructor, both require a parameter corresponding /// to the left-most column of a Toeplitz matrix. /// </overloads> /// <summary> /// Constructor with <c>ComplexDoubleVector</c> parameter. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <exception cref="ArgumentNullException"> /// <B>T</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> is zero. /// </exception> public ComplexDoubleSymmetricLevinson(IROComplexDoubleVector T) { // check parameter if (T == null) { throw new System.ArgumentNullException("T"); } else if (T.Length == 0) { throw new RankException("The length of T is zero."); } // save the vector m_LeftColumn = new ComplexDoubleVector(T); m_Order = m_LeftColumn.Length; // allocate memory for lower triangular matrix m_LowerTriangle = new Complex[m_Order][]; for (int i = 0; i < m_Order; i++) { m_LowerTriangle[i] = new Complex[i+1]; } // allocate memory for diagonal m_Diagonal = new Complex[m_Order]; }
/// <summary> /// Invert a symmetric square Toeplitz matrix. /// </summary> /// <param name="T">The left-most column of the symmetric Toeplitz matrix.</param> /// <returns>The inverse matrix.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> is a null reference. /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> must be greater than zero. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This static member combines the <b>UDL</b> decomposition and Trench's algorithm into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// <para> /// Trench's algorithm requires <b>N</b> squared FLOPS, compared to <b>N</b> cubed FLOPS /// if we simply solved a linear Toeplitz system with a right-side identity matrix (<b>N</b> is the matrix order). /// </para> /// </remarks> public static ComplexDoubleMatrix Inverse(IROComplexDoubleVector T) { ComplexDoubleMatrix X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (T.Length < 1) { throw new System.RankException("The length of T must be greater than zero."); } else if (T.Length == 1) { X = new ComplexDoubleMatrix(1); X[0, 0] = Complex.One / T[0]; } else { int N = T.Length; Complex f, g; int i, j, l, k, m, n; X = new ComplexDoubleMatrix(N); // calculate the predictor coefficients ComplexDoubleVector Y = ComplexDoubleSymmetricLevinson.YuleWalker(T); // calculate gamma f = T[0]; for (i = 1, j = 0; i < N; i++, j++) { f += T[i] * Y[j]; } g = Complex.One / f; // calculate first row of inverse X[0, 0] = g; for (i = 1, j = 0; i < N; i++, j++) { X[0, i] = g * Y[j]; } // calculate successive rows of upper wedge for (i = 0, j = 1, k = N - 2; i < N / 2; i++, j++, k--) { for (l = j, m = i, n = N - 1 - j; l < N - j; l++, m++, n--) { X[j, l] = X[i, m] + g * (Y[i] * Y[m] - Y[k] * Y[n]); } } // this is symmetric matrix ... for (i = 0; i <= N / 2; i++) { for (j = i + 1; j < N - i; j++) { X[j, i] = X[i, j]; } } // and a persymmetric matrix. for (i = 0, j = N - 1; i < N; i++, j--) { for (k = 0, l = N - 1; k < j; k++, l--) { X[l, j] = X[i, k]; } } } return(X); }
/// <overloads> /// Solve a symmetric square Toeplitz system. /// </overloads> /// <summary> /// Solve a symmetric square Toeplitz system with a right-side vector. /// </summary> /// <param name="T">The left-most column of the Toeplitz matrix.</param> /// <param name="Y">The right-side vector of the system.</param> /// <returns>The solution vector.</returns> /// <exception cref="ArgumentNullException"> /// <B>T</B> and/or <B>Y</B> are null references /// </exception> /// <exception cref="RankException"> /// The length of <B>T</B> does not match the length of <B>Y</B>. /// </exception> /// <exception cref="SingularMatrixException"> /// The Toeplitz matrix or one of the the leading sub-matrices is singular. /// </exception> /// <remarks> /// This method solves the linear system <B>AX</B> = <B>Y</B>. Where /// <B>T</B> is a symmetric square Toeplitz matrix, <B>X</B> is an unknown /// vector and <B>Y</B> is a known vector. /// <para> /// This static member combines the <b>UDL</b> decomposition and the calculation of the solution into a /// single algorithm. When compared to the non-static member it requires minimal data storage /// and suffers from no speed penalty. /// </para> /// </remarks> public static ComplexDoubleVector Solve(IROComplexDoubleVector T, IROComplexDoubleVector Y) { ComplexDoubleVector X; // check parameters if (T == null) { throw new System.ArgumentNullException("T"); } else if (Y == null) { throw new System.ArgumentNullException("Y"); } else if (T.Length != Y.Length) { throw new RankException("The length of T and Y are not equal."); } else { // allocate memory int N = T.Length; X = new ComplexDoubleVector(N); // solution vector Complex e; // prediction error // setup zero order solution e = T[0]; if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } X[0] = Y[0] / T[0]; if (N > 1) { ComplexDoubleVector a = new ComplexDoubleVector(N - 1); // prediction coefficients ComplexDoubleVector Z = new ComplexDoubleVector(N - 1); // temporary storage vector Complex g; // reflection coefficient Complex inner; // inner product Complex k; int i, j, l; // calculate solution for successive orders for (i = 1; i < N; i++) { // calculate first inner product inner = T[i]; for (j = 0, l = i - 1; j < i - 1; j++, l--) { inner += a[j] * T[l]; } // update predictor coefficients g = -(inner / e); for (j = 0, l = i - 2; j < i - 1; j++, l--) { Z[j] = a[j] + g * a[l]; } // copy vector for (j = 0; j < i - 1; j++) { a[j] = Z[j]; } a[i - 1] = g; e *= (Complex.One - g * g); if (e == Complex.Zero) { throw new SingularMatrixException("The Toeplitz matrix or one of the the leading sub-matrices is singular."); } // calculate second inner product inner = Y[i]; for (j = 0, l = i; j < i; j++, l--) { inner -= X[j] * T[l]; } // update solution vector k = inner / e; for (j = 0, l = i - 1; j < i; j++, l--) { X[j] = X[j] + k * a[l]; } X[j] = k; } } } return X; }
/// <summary> /// Uses the signal in vector x to build a model with <c>numberOfCoefficients</c> parameter. /// </summary> /// <param name="x">Signal for building the model.</param> /// <param name="coefficients">Vector to be filled with the coefficients of the model.</param> /// <param name="errors">Vector to be filled with the sum of forward and backward prediction error for every stage of the model.</param> /// <param name="reflectionCoefficients">Vector to be filled with the reflection coefficients.</param> /// <param name="tempStorage">Instance of this class used to hold the temporary arrays.</param> /// <returns>The mean square error of backward and forward prediction.</returns> private static double Execution(IROComplexDoubleVector x, IComplexDoubleVector coefficients, IVector errors, IComplexDoubleVector reflectionCoefficients, BurgAlgorithmComplex tempStorage) { int N = x.Length - 1; int m = coefficients.Length; Complex[] Ak; // Prediction coefficients, Ak[0] is always 1 Complex[] b; // backward prediction errors Complex[] f; // forward prediction errors if (null != tempStorage) { tempStorage.EnsureAllocation(x.Length, coefficients.Length); Ak = tempStorage._Ak; b = tempStorage._b; f = tempStorage._f; for (int i = 1; i <= coefficients.Length; i++) Ak[i] = 0; } else { Ak = new Complex[coefficients.Length + 1]; b = new Complex[x.Length]; f = new Complex[x.Length]; } Ak[0] = 1; // Initialize forward and backward prediction errors with x for (int i = 0; i <= N; i++) f[i] = b[i] = x[i]; double Dk = 0; for (int i = 0; i <= N; i++) Dk += 2 * f[i].GetModulusSquared(); Dk -= f[0].GetModulusSquared() + b[N].GetModulusSquared(); // Burg recursion int k; double sumE = 0; // error sum for (k = 0; (k < m) && (Dk > 0); k++) { // Compute mu Complex mu = 0; for (int n = 0; n < N - k; n++) mu += f[n + k + 1] * b[n].GetConjugate(); mu *= (-2 / Dk); // Update Ak for (int n = 0; n <= (k + 1) / 2; n++) { Complex t1 = Ak[n] + mu * Ak[k + 1 - n].GetConjugate(); Complex t2 = Ak[k + 1 - n] + mu * Ak[n].GetConjugate(); Ak[n] = t1; Ak[k + 1 - n] = t2; } if (null != reflectionCoefficients) reflectionCoefficients[k] = Ak[k + 1]; // update forward and backward predition error with simultaneous total error calculation sumE = 0; for (int n = 0; n < N - k; n++) { Complex t1 = f[n + k + 1] + mu * b[n]; Complex t2 = b[n] + mu.GetConjugate() * f[n + k + 1]; f[n + k + 1] = t1; b[n] = t2; sumE += t1.GetModulusSquared() + t2.GetModulusSquared(); } if (null != errors) errors[k] = sumE / (2 * (N - k)); // Update Dk // Note that it is possible to update Dk without total error calculation because sumE = Dk*(1-mu.GetModulusSquared()) // but this will render the algorithm numerically unstable especially for higher orders and low noise Dk = sumE - (f[k + 1].GetModulusSquared() + b[N - k - 1].GetModulusSquared()); } // Assign coefficients for (int i = 0; i < m; i++) coefficients[i] = Ak[i + 1]; // Assign the rest of reflection coefficients and errors with zero // if not all stages could be calculated because Dk was zero or because of rounding effects smaller than zero for (int i = k + 1; i < m; i++) { if (null != reflectionCoefficients) reflectionCoefficients[i] = 0; if (null != errors) errors[i] = 0; } return sumE / (2 * (N - k)); }