/// <summary> /// Returns the Pearson correlation coefficient of two sets of values. /// </summary> /// <param name="a">An array of complex numbers.</param> /// <param name="b">An array of complex numbers.</param> /// <returns>The Pearson correlation coefficient of the elements of a and b.</returns> /// <exception cref="System.ArgumentException"> /// The length of the array a does not match the length of the array b. /// </exception> public static Complex Correlation(IList <Complex> a, IList <Complex> b) { if (a.Count != b.Count) { throw new ArgumentException("The lengths of the two arrays do not match."); } Complex mean_a = Mean(a); Complex mean_b = Mean(b); Complex sum = Complex.Zero; double sum1 = 0.0; double sum2 = 0.0; for (int i = 0; i < a.Count; i++) { Complex c1 = a[i] - mean_a; Complex c2 = b[i] - mean_b; sum += Complex.ConjugateMultiply(c2, c1); sum1 += Complex.AbsSquared(c1); sum2 += Complex.AbsSquared(c2); } return(sum / Math.Sqrt(sum1 * sum2)); }
/// <summary> /// Returns the population variance of the elements of an array. /// </summary> /// <param name="v">An array of complex numbers.</param> /// <returns>The population variance of the elements of v.</returns> public static double PopulationVariance(IEnumerable <Complex> v) { int count = 0; double sum = 0.0; Complex mean = Mean(v); foreach (Complex item in v) { sum += Complex.AbsSquared(item - mean); count++; } return(sum / count); }
/// <summary> /// Returns the sample variance of the elements of an array. /// </summary> /// <param name="v">An array of complex numbers.</param> /// <returns>The sample variance of the elements of v.</returns> public static double SampleVariance(IEnumerable <Complex> v) { int count = 0; double sum = 0.0; Complex mean = Mean(v); foreach (Complex item in v) { sum += Complex.AbsSquared(item - mean); count++; } if (count == 1) { return(0.0); } return(sum / (count - 1)); }
public static Complex InfiniteProduct(Func <Complex, Complex> term, int m, double relativeTolerance) { double tolsq = relativeTolerance * relativeTolerance; Complex product = Complex.One; Complex termValue; for (int i = m; i < _maxIters; i++) { termValue = term(i); product *= termValue; if (Complex.AbsSquared(termValue / product) <= tolsq) { return(product); } } throw new NotConvergenceException(); }
public static Complex InfiniteSummation(Func <Complex, Complex> term, int m, double relativeTolerance) { double tolsq = relativeTolerance * relativeTolerance; Complex sum = Complex.Zero; Complex termValue; for (int i = m; i <= _maxIters; i++) { termValue = term(i); sum += termValue; if (Complex.AbsSquared(termValue / sum) <= tolsq) { return(sum); } } throw new NotConvergenceException(); }
/// <summary> /// Reduces a complex hermitian matrix to a real symmetric tridiagonal matrix using unitary similarity transformations. /// </summary> /// <param name="matrixA">Source matrix to reduce</param> /// <param name="d">Output: Arrays for internal storage of real parts of eigenvalues</param> /// <param name="e">Output: Arrays for internal storage of imaginary parts of eigenvalues</param> /// <param name="tau">Output: Arrays that contains further information about the transformations.</param> /// <param name="order">Order of initial matrix</param> /// <remarks>This is derived from the Algol procedures HTRIDI by /// Smith, Boyle, Dongarra, Garbow, Ikebe, Klema, Moler, and Wilkinson, Handbook for /// Auto. Comp., Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutine in EISPACK.</remarks> internal static void SymmetricTridiagonalize(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 * order + i].Re; } // 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[k * order + i].Re) + Math.Abs(matrixA[k * order + i].Im); } if (scale == 0.0) { tau[i - 1] = Complex.One; e[i] = 0.0; } else { for (var k = 0; k < i; k++) { matrixA[k * order + i] /= scale; h += Complex.AbsSquared(matrixA[k * order + i]); } Complex g = Math.Sqrt(h); e[i] = scale * g.Re; Complex temp; var im1Oi = (i - 1) * order + i; var f = matrixA[im1Oi]; if (f.Modulus != 0) { temp = -(Complex.Conjugate(matrixA[im1Oi]) * Complex.Conjugate(tau[i])) / f.Modulus; h += f.Modulus * g.Re; g = 1.0 + (g / f.Modulus); matrixA[im1Oi] *= g; } else { temp = -Complex.Conjugate(tau[i]); matrixA[im1Oi] = g; } if ((f.Modulus == 0) || (i != 1)) { f = Complex.Zero; for (var j = 0; j < i; j++) { var tmp = Complex.Zero; var jO = j * order; // Form element of A*U. for (var k = 0; k <= j; k++) { tmp += matrixA[k * order + j] * Complex.Conjugate(matrixA[k * order + i]); } for (var k = j + 1; k <= i - 1; k++) { tmp += Complex.Conjugate(matrixA[jO + k]) * Complex.Conjugate(matrixA[k * order + i]); } // Form element of P tau[j] = tmp / h; f += (tmp / h) * matrixA[jO + i]; } hh = f.Re / (h + h); // Form the reduced A. for (var j = 0; j < i; j++) { f = Complex.Conjugate(matrixA[j * order + i]); g = tau[j] - (hh * f); tau[j] = Complex.Conjugate(g); for (var k = 0; k <= j; k++) { matrixA[k * order + j] -= (f * tau[k]) + (g * matrixA[k * order + i]); } } } for (var k = 0; k < i; k++) { matrixA[k * order + i] *= scale; } tau[i - 1] = Complex.Conjugate(temp); } hh = d[i]; d[i] = matrixA[i * order + i].Re; matrixA[i * order + i] = new Complex(hh, scale * Math.Sqrt(h)); } hh = d[0]; d[0] = matrixA[0].Re; matrixA[0] = hh; e[0] = 0.0; }
/// <summary> /// Nonsymmetric reduction to Hessenberg form. /// </summary> /// <param name="dataEv">Data array of matrix V (eigenvectors)</param> /// <param name="matrixH">Array for internal storage of nonsymmetric Hessenberg form.</param> /// <param name="order">Order of initial matrix</param> /// <remarks>This is derived from the Algol procedures orthes and ortran, /// by Martin and Wilkinson, Handbook for Auto. Comp., /// Vol.ii-Linear Algebra, and the corresponding /// Fortran subroutines in EISPACK.</remarks> internal static void NonsymmetricReduceToHessenberg(Complex[] dataEv, Complex[] matrixH, int order) { var ort = new Complex[order]; for (var m = 1; m < order - 1; m++) { // Scale column. var scale = 0.0; var mm1O = (m - 1) * order; for (var i = m; i < order; i++) { scale += Math.Abs(matrixH[mm1O + i].Re) + Math.Abs(matrixH[mm1O + i].Im); } if (scale != 0.0) { // Compute Householder transformation. var h = 0.0; for (var i = order - 1; i >= m; i--) { ort[i] = matrixH[mm1O + i] / scale; h += Complex.AbsSquared(ort[i]); } var g = Math.Sqrt(h); if (ort[m].Modulus != 0) { h = h + (ort[m].Modulus * g); g /= ort[m].Modulus; ort[m] = (1.0 + g) * ort[m]; } else { ort[m] = g; matrixH[mm1O + m] = scale; } // Apply Householder similarity transformation // H = (I-u*u'/h)*H*(I-u*u')/h) for (var j = m; j < order; j++) { var f = Complex.Zero; var jO = j * order; for (var i = order - 1; i >= m; i--) { f += Complex.Conjugate(ort[i]) * matrixH[jO + i]; } f = f / h; for (var i = m; i < order; i++) { matrixH[jO + i] -= f * ort[i]; } } for (var i = 0; i < order; i++) { var f = Complex.Zero; for (var j = order - 1; j >= m; j--) { f += ort[j] * matrixH[j * order + i]; } f = f / h; for (var j = m; j < order; j++) { matrixH[j * order + i] -= f * Complex.Conjugate(ort[j]); } } ort[m] = scale * ort[m]; matrixH[mm1O + m] *= -g; } } // Accumulate transformations (Algol's ortran). for (var i = 0; i < order; i++) { for (var j = 0; j < order; j++) { dataEv[(j * order) + i] = i == j ? Complex.One : Complex.Zero; } } for (var m = order - 2; m >= 1; m--) { var mm1O = (m - 1) * order; var mm1Om = mm1O + m; if (matrixH[mm1Om] != Complex.Zero && ort[m] != Complex.Zero) { var norm = (matrixH[mm1Om].Re * ort[m].Re) + (matrixH[mm1Om].Im * ort[m].Im); for (var i = m + 1; i < order; i++) { ort[i] = matrixH[mm1O + i]; } for (var j = m; j < order; j++) { var g = Complex.Zero; for (var i = m; i < order; i++) { g += Complex.Conjugate(ort[i]) * dataEv[(j * order) + i]; } // Double division avoids possible underflow g /= norm; for (var i = m; i < order; i++) { dataEv[(j * order) + i] += g * ort[i]; } } } } // Create real subdiagonal elements. for (var i = 1; i < order; i++) { var im1 = i - 1; var im1O = im1 * order; var im1Oi = im1O + i; var iO = i * order; if (matrixH[im1Oi].Im != 0.0) { var y = matrixH[im1Oi] / matrixH[im1Oi].Modulus; matrixH[im1Oi] = matrixH[im1Oi].Modulus; for (var j = i; j < order; j++) { matrixH[j * order + i] *= Complex.Conjugate(y); } for (var j = 0; j <= Math.Min(i + 1, order - 1); j++) { matrixH[iO + j] *= y; } for (var j = 0; j < order; j++) { dataEv[(i * order) + j] *= y; } } } }