public TqrEigenDecomposition(Vector diag, Vector sub, EigenVectorCalculation calc = EigenVectorCalculation.WithEigenVector, ShiftStrategy strategy = ShiftStrategy.CloseEigenValue) { iter_ = 0; d_ = new Vector(diag); int row = calc == EigenVectorCalculation.WithEigenVector ? d_.size() : calc == EigenVectorCalculation.WithoutEigenVector ? 0 : 1; ev_ = new Matrix(row, d_.size(), 0.0); int n = diag.size(); Utils.QL_REQUIRE(n == sub.size() + 1, () => "Wrong dimensions"); Vector e = new Vector(n, 0.0); int i; for (i = 1; i < e.Count; ++i) { e[i] = sub[i - 1]; } for (i = 0; i < ev_.rows(); ++i) { ev_[i, i] = 1.0; } for (int k = n - 1; k >= 1; --k) { while (!offDiagIsZero(k, e)) { int l = k; while (--l > 0 && !offDiagIsZero(l, e)) { ; } iter_++; double q = d_[l]; if (strategy != ShiftStrategy.NoShift) { // calculated eigenvalue of 2x2 sub matrix of // [ d_[k-1] e_[k] ] // [ e_[k] d_[k] ] // which is closer to d_[k+1]. // FLOATING_POINT_EXCEPTION double t1 = Math.Sqrt( 0.25 * (d_[k] * d_[k] + d_[k - 1] * d_[k - 1]) - 0.5 * d_[k - 1] * d_[k] + e[k] * e[k]); double t2 = 0.5 * (d_[k] + d_[k - 1]); double lambda = (Math.Abs(t2 + t1 - d_[k]) < Math.Abs(t2 - t1 - d_[k]))? t2 + t1 : t2 - t1; if (strategy == ShiftStrategy.CloseEigenValue) { q -= lambda; } else { q -= ((k == n - 1) ? 1.25 : 1.0) * lambda; } } // the QR transformation double sine = 1.0; double cosine = 1.0; double u = 0.0; bool recoverUnderflow = false; for (i = l + 1; i <= k && !recoverUnderflow; ++i) { double h = cosine * e[i]; double p = sine * e[i]; e[i - 1] = Math.Sqrt(p * p + q * q); if (e[i - 1].IsNotEqual(0.0)) { sine = p / e[i - 1]; cosine = q / e[i - 1]; double g = d_[i - 1] - u; double t = (d_[i] - g) * sine + 2 * cosine * h; u = sine * t; d_[i - 1] = g + u; q = cosine * t - h; for (int j = 0; j < ev_.rows(); ++j) { double tmp = ev_[j, i - 1]; ev_[j, i - 1] = sine * ev_[j, i] + cosine * tmp; ev_[j, i] = cosine * ev_[j, i] - sine * tmp; } } else { // recover from underflow d_[i - 1] -= u; e[l] = 0.0; recoverUnderflow = true; } } if (!recoverUnderflow) { d_[k] -= u; e[k] = q; e[l] = 0.0; } } } // sort (eigenvalues, eigenvectors), // code taken from symmetricSchureDecomposition.cpp List <KeyValuePair <double, List <double> > > temp = new InitializedList <KeyValuePair <double, List <double> > >(n); List <double> eigenVector = new InitializedList <double>(ev_.rows()); for (i = 0; i < n; i++) { if (ev_.rows() > 0) { eigenVector = ev_.column(i); } temp[i] = new KeyValuePair <double, List <double> >(d_[i], eigenVector); } temp.Sort(KeyValuePairCompare); // first element is positive for (i = 0; i < n; i++) { d_[i] = temp[i].Key; double sign = 1.0; if (ev_.rows() > 0 && temp[i].Value[0] < 0.0) { sign = -1.0; } for (int j = 0; j < ev_.rows(); ++j) { ev_[j, i] = sign * temp[i].Value[j]; } } }
public TqrEigenDecomposition(Vector diag, Vector sub, EigenVectorCalculation calc = EigenVectorCalculation.WithEigenVector, ShiftStrategy strategy = ShiftStrategy.CloseEigenValue) { iter_ = 0; d_ = new Vector(diag); int row = calc == EigenVectorCalculation.WithEigenVector ? d_.size() : calc == EigenVectorCalculation.WithoutEigenVector ? 0 : 1; ev_ = new Matrix(row, d_.size(), 0.0); int n = diag.size(); Utils.QL_REQUIRE( n == sub.size() + 1, () => "Wrong dimensions" ); Vector e = new Vector(sub); int i; for (i=0; i < ev_.rows(); ++i) { ev_[i,i] = 1.0; } for (int k=n-1; k >=1; --k) { while (!offDiagIsZero(k, e)) { int l = k; while (--l > 0 && !offDiagIsZero(l,e)); iter_++; double q = d_[l]; if (strategy != ShiftStrategy.NoShift) { // calculated eigenvalue of 2x2 sub matrix of // [ d_[k-1] e_[k] ] // [ e_[k] d_[k] ] // which is closer to d_[k+1]. // FLOATING_POINT_EXCEPTION double t1 = Math.Sqrt( 0.25*(d_[k]*d_[k] + d_[k-1]*d_[k-1]) - 0.5*d_[k-1]*d_[k] + e[k]*e[k]); double t2 = 0.5*(d_[k]+d_[k-1]); double lambda = (Math.Abs(t2+t1 - d_[k]) < Math.Abs(t2-t1 - d_[k]))? t2+t1 : t2-t1; if (strategy == ShiftStrategy.CloseEigenValue) { q-=lambda; } else { q-=((k==n-1)? 1.25 : 1.0)*lambda; } } // the QR transformation double sine = 1.0; double cosine = 1.0; double u = 0.0; bool recoverUnderflow = false; for (i=l+1; i <= k && !recoverUnderflow; ++i) { double h = cosine*e[i]; double p = sine*e[i]; e[i-1] = Math.Sqrt(p*p+q*q); if (e[i-1] != 0.0) { sine = p/e[i-1]; cosine = q/e[i-1]; double g = d_[i-1]-u; double t = (d_[i]-g)*sine+2*cosine*h; u = sine*t; d_[i-1] = g + u; q = cosine*t - h; for (int j=0; j < ev_.rows(); ++j) { double tmp = ev_[j,i-1]; ev_[j,i-1] = sine*ev_[j,i] + cosine*tmp; ev_[j,i] = cosine*ev_[j,i] - sine*tmp; } } else { // recover from underflow d_[i-1] -= u; e[l] = 0.0; recoverUnderflow = true; } } if (!recoverUnderflow) { d_[k] -= u; e[k] = q; e[l] = 0.0; } } } // sort (eigenvalues, eigenvectors), // code taken from symmetricSchureDecomposition.cpp List<KeyValuePair<double, List<double> > > temp = new List<KeyValuePair<double,List<double>>>(n); List<double> eigenVector = new List<double>(ev_.rows()); for (i=0; i<n; i++) { if (ev_.rows() > 0) //std::copy(ev_.column_begin(i),ev_.column_end(i), eigenVector.begin()); eigenVector = ev_.column(i) ; temp[i] = new KeyValuePair<double,List<double>>(d_[i], eigenVector); } //std::sort(temp.begin(), temp.end(), std::greater<std::pair<Real, std::vector<Real> > >()); temp.Sort(); // first element is positive for (i=0; i<n; i++) { d_[i] = temp[i].Key; double sign = 1.0; if (ev_.rows() > 0 && temp[i].Value[0]<0.0) sign = -1.0; for (int j=0; j<ev_.rows(); ++j) { ev_[j,i] = sign * temp[i].Value[j]; } } }