public override Vector evolve(double t0, Vector x0, double dt, Vector dw) { /* predictor-corrector step to reduce discretization errors. * * Short - but slow - solution would be * * Array rnd_0 = stdDeviation(t0, x0, dt)*dw; * Array drift_0 = discretization_->drift(*this, t0, x0, dt); * * return apply(x0, ( drift_0 + discretization_ * ->drift(*this,t0,apply(x0, drift_0 + rnd_0),dt) )*0.5 + rnd_0); * * The following implementation does the same but is faster. */ int m = nextIndexReset(t0); double sdt = Math.Sqrt(dt); Vector f = new Vector(x0); Matrix diff = lfmParam_.diffusion(t0, x0); Matrix covariance = lfmParam_.covariance(t0, x0); for (int k = m; k < size_; ++k) { double y = accrualPeriod_[k] * x0[k]; m1[k] = y / (1 + y); double d = 0; m1.GetRange(m, k + 1 - m).ForEach( (ii, vv) => d += vv * covariance.column(k).GetRange(m, covariance.rows() - m)[ii]); d = (d - 0.5 * covariance[k, k]) * dt; double r = 0; diff.row(k).ForEach((kk, vv) => r += vv * dw[kk]); r *= sdt; double x = y * Math.Exp(d + r); m2[k] = x / (1 + x); double inner_product = 0; m2.GetRange(m, k + 1 - m).ForEach( (ii, vv) => inner_product += vv * covariance.column(k).GetRange(m, covariance.rows() - m)[ii]); f[k] = x0[k] * Math.Exp(0.5 * (d + (inner_product - 0.5 * covariance[k, k]) * dt) + r); } return(f); }
public override Vector evolve(double t0, Vector x0, double dt, Vector dw) { // predictor-corrector step to reduce discretization errors. int m = nextIndexReset(t0); double sdt = Math.Sqrt(dt); Vector f = new Vector(x0); Matrix diff = lfmParam_.diffusion(t0, x0); Matrix covariance = lfmParam_.covariance(t0, x0); for (int k = m; k < size_; ++k) { double y = accrualPeriod_[k] * x0[k]; m1[k] = y / (1 + y); double d = 0; m1.GetRange(m, k + 1 - m).ForEach( (ii, vv) => d += vv * covariance.column(k).GetRange(m, covariance.rows() - m)[ii]); d = (d - 0.5 * covariance[k, k]) * dt; double r = 0; diff.row(k).ForEach((kk, vv) => r += vv * dw[kk]); r *= sdt; double x = y * Math.Exp(d + r); m2[k] = x / (1 + x); double inner_product = 0; m2.GetRange(m, k + 1 - m).ForEach( (ii, vv) => inner_product += vv * covariance.column(k).GetRange(m, covariance.rows() - m)[ii]); f[k] = x0[k] * Math.Exp(0.5 * (d + (inner_product - 0.5 * covariance[k, k]) * dt) + r); } return(f); }
public override Vector drift(double t, Vector x) { Vector f = new Vector(size_, 0.0); Matrix covariance = lfmParam_.covariance(t, x); int m = nextIndexReset(t); for (int k = m; k < size_; ++k) { m1[k] = accrualPeriod_[k] * x[k] / (1 + accrualPeriod_[k] * x[k]); double inner_product = 0; m1.GetRange(m, k + 1 - m).ForEach( (ii, vv) => inner_product += vv * covariance.column(k).GetRange(m, covariance.rows() - m)[ii]); f[k] = inner_product - 0.5 * covariance[k, k]; } return(f); }
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]; } } }
/*! \pre s must be symmetric */ public SymmetricSchurDecomposition(Matrix s) { diagonal_ = new Vector(s.rows()); eigenVectors_ = new Matrix(s.rows(), s.columns(), 0.0); if (!(s.rows() > 0 && s.columns() > 0)) throw new ApplicationException( "null matrix given"); if (s.rows()!=s.columns()) throw new ApplicationException( "input matrix must be square"); int size = s.rows(); for (int q=0; q<size; q++) { diagonal_[q] = s[q,q]; eigenVectors_[q,q] = 1.0; } Matrix ss = new Matrix(s); Vector tmpDiag = new Vector(diagonal_); Vector tmpAccumulate = new Vector(size, 0.0); double threshold, epsPrec = 1e-15; bool keeplooping = true; int maxIterations = 100, ite = 1; do { //main loop double sum = 0; for (int a=0; a<size-1; a++) { for (int b=a+1; b<size; b++) { sum += Math.Abs(ss[a,b]); } } if (sum==0) { keeplooping = false; } else { /* To speed up computation a threshold is introduced to make sure it is worthy to perform the Jacobi rotation */ if (ite<5) threshold = 0.2*sum/(size*size); else threshold = 0.0; int j, k, l; for (j=0; j<size-1; j++) { for (k=j+1; k<size; k++) { double sine, rho, cosin, heig, tang, beta; double smll = Math.Abs(ss[j,k]); if(ite> 5 && smll<epsPrec*Math.Abs(diagonal_[j]) && smll<epsPrec*Math.Abs(diagonal_[k])) { ss[j,k] = 0; } else if (Math.Abs(ss[j,k])>threshold) { heig = diagonal_[k]-diagonal_[j]; if (smll<epsPrec*Math.Abs(heig)) { tang = ss[j,k]/heig; } else { beta = 0.5*heig/ss[j,k]; tang = 1.0/(Math.Abs(beta)+ Math.Sqrt(1+beta*beta)); if (beta<0) tang = -tang; } cosin = 1/Math.Sqrt(1+tang*tang); sine = tang*cosin; rho = sine/(1+cosin); heig = tang*ss[j,k]; tmpAccumulate[j] -= heig; tmpAccumulate[k] += heig; diagonal_[j] -= heig; diagonal_[k] += heig; ss[j,k] = 0.0; for (l=0; l+1<=j; l++) jacobiRotate_(ss, rho, sine, l, j, l, k); for (l=j+1; l<=k-1; l++) jacobiRotate_(ss, rho, sine, j, l, l, k); for (l=k+1; l<size; l++) jacobiRotate_(ss, rho, sine, j, l, k, l); for (l=0; l<size; l++) jacobiRotate_(eigenVectors_, rho, sine, l, j, l, k); } } } for (k=0; k<size; k++) { tmpDiag[k] += tmpAccumulate[k]; diagonal_[k] = tmpDiag[k]; tmpAccumulate[k] = 0.0; } } } while (++ite<=maxIterations && keeplooping); if(!(ite<=maxIterations)) throw new ApplicationException("Too many iterations (" + maxIterations + ") reached"); // sort (eigenvalues, eigenvectors) List<KeyValuePair<double, Vector>> temp = new InitializedList<KeyValuePair<double, Vector>>(size); int row, col; for (col=0; col<size; col++) { Vector eigenVector = new Vector(size); eigenVectors_.column(col).ForEach((ii, xx) => eigenVector[ii] = xx); temp[col] = new KeyValuePair<double,Vector>(diagonal_[col], eigenVector); } // sort descending: std::greater temp.Sort((x, y) => y.Key.CompareTo(x.Key)); double maxEv = temp[0].Key; for (col=0; col<size; col++) { // check for round-off errors diagonal_[col] = (Math.Abs(temp[col].Key/maxEv)<1e-16 ? 0.0 : temp[col].Key); double sign = 1.0; if (temp[col].Value[0]<0.0) sign = -1.0; for (row=0; row<size; row++) { eigenVectors_[row,col] = sign * temp[col].Value[row]; } } }
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]; } } }
/*! \pre s must be symmetric */ public SymmetricSchurDecomposition(Matrix s) { diagonal_ = new Vector(s.rows()); eigenVectors_ = new Matrix(s.rows(), s.columns(), 0.0); if (!(s.rows() > 0 && s.columns() > 0)) { throw new ApplicationException("null matrix given"); } if (s.rows() != s.columns()) { throw new ApplicationException("input matrix must be square"); } int size = s.rows(); for (int q = 0; q < size; q++) { diagonal_[q] = s[q, q]; eigenVectors_[q, q] = 1.0; } Matrix ss = new Matrix(s); Vector tmpDiag = new Vector(diagonal_); Vector tmpAccumulate = new Vector(size, 0.0); double threshold, epsPrec = 1e-15; bool keeplooping = true; int maxIterations = 100, ite = 1; do { //main loop double sum = 0; for (int a = 0; a < size - 1; a++) { for (int b = a + 1; b < size; b++) { sum += Math.Abs(ss[a, b]); } } if (sum == 0) { keeplooping = false; } else { /* To speed up computation a threshold is introduced to * make sure it is worthy to perform the Jacobi rotation */ if (ite < 5) { threshold = 0.2 * sum / (size * size); } else { threshold = 0.0; } int j, k, l; for (j = 0; j < size - 1; j++) { for (k = j + 1; k < size; k++) { double sine, rho, cosin, heig, tang, beta; double smll = Math.Abs(ss[j, k]); if (ite > 5 && smll < epsPrec * Math.Abs(diagonal_[j]) && smll < epsPrec * Math.Abs(diagonal_[k])) { ss[j, k] = 0; } else if (Math.Abs(ss[j, k]) > threshold) { heig = diagonal_[k] - diagonal_[j]; if (smll < epsPrec * Math.Abs(heig)) { tang = ss[j, k] / heig; } else { beta = 0.5 * heig / ss[j, k]; tang = 1.0 / (Math.Abs(beta) + Math.Sqrt(1 + beta * beta)); if (beta < 0) { tang = -tang; } } cosin = 1 / Math.Sqrt(1 + tang * tang); sine = tang * cosin; rho = sine / (1 + cosin); heig = tang * ss[j, k]; tmpAccumulate[j] -= heig; tmpAccumulate[k] += heig; diagonal_[j] -= heig; diagonal_[k] += heig; ss[j, k] = 0.0; for (l = 0; l + 1 <= j; l++) { jacobiRotate_(ss, rho, sine, l, j, l, k); } for (l = j + 1; l <= k - 1; l++) { jacobiRotate_(ss, rho, sine, j, l, l, k); } for (l = k + 1; l < size; l++) { jacobiRotate_(ss, rho, sine, j, l, k, l); } for (l = 0; l < size; l++) { jacobiRotate_(eigenVectors_, rho, sine, l, j, l, k); } } } } for (k = 0; k < size; k++) { tmpDiag[k] += tmpAccumulate[k]; diagonal_[k] = tmpDiag[k]; tmpAccumulate[k] = 0.0; } } } while (++ite <= maxIterations && keeplooping); if (!(ite <= maxIterations)) { throw new ApplicationException("Too many iterations (" + maxIterations + ") reached"); } // sort (eigenvalues, eigenvectors) List <KeyValuePair <double, Vector> > temp = new InitializedList <KeyValuePair <double, Vector> >(size); int row, col; for (col = 0; col < size; col++) { Vector eigenVector = new Vector(size); eigenVectors_.column(col).ForEach((ii, xx) => eigenVector[ii] = xx); temp[col] = new KeyValuePair <double, Vector>(diagonal_[col], eigenVector); } // sort descending: std::greater temp.Sort((x, y) => y.Key.CompareTo(x.Key)); double maxEv = temp[0].Key; for (col = 0; col < size; col++) { // check for round-off errors diagonal_[col] = (Math.Abs(temp[col].Key / maxEv) < 1e-16 ? 0.0 : temp[col].Key); double sign = 1.0; if (temp[col].Value[0] < 0.0) { sign = -1.0; } for (row = 0; row < size; row++) { eigenVectors_[row, col] = sign * temp[col].Value[row]; } } }