//! compute vector of derivatives of the least square function public void gradient(ref Vector grad_f, Vector x) { // size of target and function to fit vectors Vector target = new Vector(lsp_.size()); Vector fct2fit = new Vector(lsp_.size()); // size of gradient matrix Matrix grad_fct2fit = new Matrix(lsp_.size(), x.size()); // compute its values lsp_.targetValueAndGradient(x, ref grad_fct2fit, ref target, ref fct2fit); // do the difference Vector diff = target - fct2fit; // compute derivative grad_f = -2.0 * (Matrix.transpose(grad_fct2fit) * diff); }
protected override void generateArguments() { double rho = arguments_[0].value(0.0); double beta = arguments_[1].value(0.0); for (int i = 0; i < size_; ++i) { for (int j = i; j < size_; ++j) { corrMatrix_[i, j] = corrMatrix_[j, i] = rho + (1 - rho) * Math.Exp(-beta * Math.Abs((double)i - (double)j)); } } pseudoSqrt_ = MatrixUtilitites.rankReducedSqrt(corrMatrix_, factors_, 1.0, MatrixUtilitites.SalvagingAlgorithm.None); corrMatrix_ = pseudoSqrt_ * Matrix.transpose(pseudoSqrt_); }
//! compute value and gradient of the least square function public double valueAndGradient(ref Vector grad_f, Vector x) { // size of target and function to fit vectors Vector target = new Vector(lsp_.size()); Vector fct2fit = new Vector(lsp_.size()); // size of gradient matrix Matrix grad_fct2fit = new Matrix(lsp_.size(), x.size()); // compute its values lsp_.targetValueAndGradient(x, ref grad_fct2fit, ref target, ref fct2fit); // do the difference Vector diff = target - fct2fit; // compute derivative grad_f = -2.0 * (Matrix.transpose(grad_fct2fit) * diff); // and compute the scalar product (square of the norm) return(Vector.DotProduct(diff, diff)); }
// Take a matrix and make all the eigenvalues non-negative private static Matrix projectToPositiveSemidefiniteMatrix(Matrix M) { int size = M.rows(); Utils.QL_REQUIRE(size == M.columns(), () => "matrix not square"); Matrix diagonal = new Matrix(size, size); SymmetricSchurDecomposition jd = new SymmetricSchurDecomposition(M); for (int i = 0; i < size; ++i) { diagonal[i, i] = Math.Max(jd.eigenvalues()[i], 0.0); } Matrix result = jd.eigenvectors() * diagonal * Matrix.transpose(jd.eigenvectors()); return(result); }
//! QR Solve /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * Given an m by n matrix A, an n by n diagonal matrix d, * and an m-vector b, the problem is to determine an x which * solves the system * * A*x = b , d*x = 0 , * * in the least squares sense. * * d is an input array of length n which must contain the * diagonal elements of the matrix d. * * See lmdiff.cpp for further details. */ public static Vector qrSolve(Matrix a, Vector b, bool pivot = true, Vector d = null) { int m = a.rows(); int n = a.columns(); if (d == null) { d = new Vector(); } Utils.QL_REQUIRE(b.Count == m, () => "dimensions of A and b don't match"); Utils.QL_REQUIRE(d.Count == n || d.empty(), () => "dimensions of A and d don't match"); Matrix q = new Matrix(m, n), r = new Matrix(n, n); List <int> lipvt = MatrixUtilities.qrDecomposition(a, ref q, ref r, pivot); List <int> ipvt = new List <int>(n); ipvt = lipvt; //std::copy(lipvt.begin(), lipvt.end(), ipvt.get()); Matrix aT = Matrix.transpose(a); Matrix rT = Matrix.transpose(r); Vector sdiag = new Vector(n); Vector wa = new Vector(n); Vector ld = new Vector(n, 0.0); if (!d.empty()) { ld = d; //std::copy(d.begin(), d.end(), ld.begin()); } Vector x = new Vector(n); Vector qtb = Matrix.transpose(q) * b; MINPACK.qrsolv(n, rT, n, ipvt, ld, qtb, x, sdiag, wa); return(x); }
public Matrix jacFcn(int m, int n, Vector x, int iflag) { Vector xt = new Vector(x); Matrix fjac; // constraint handling needs some improvement in the future: // starting point should not be close to a constraint violation if (currentProblem_.constraint().test(xt)) { Matrix tmp = new Matrix(m, n); currentProblem_.costFunction().jacobian(tmp, xt); Matrix tmpT = Matrix.transpose(tmp); fjac = new Matrix(tmpT); } else { Matrix tmpT = Matrix.transpose(initJacobian_); fjac = new Matrix(tmpT); } return(fjac); }
public void updateInterpolators() { for (int k = 0; k < nLayers_; ++k) { transposedPoints_[k] = Matrix.transpose(points_[k]); Interpolation2D interpolation; if (k <= 4 && backwardFlat_) { interpolation = new BackwardflatLinearInterpolation( optionTimes_, optionTimes_.Count, swapLengths_, swapLengths_.Count, transposedPoints_[k]); } else { interpolation = new BilinearInterpolation( optionTimes_, optionTimes_.Count, swapLengths_, swapLengths_.Count, transposedPoints_[k]); } interpolators_[k] = new FlatExtrapolator2D(interpolation); interpolators_[k].enableExtrapolation(); } }
public override double value(Vector x) { int i, j, k; currentRoot_.fill(1); if (lowerDiagonal_) { for (i = 0; i < size_; i++) { for (k = 0; k < size_; k++) { if (k > i) { currentRoot_[i, k] = 0; } else { for (j = 0; j <= k; j++) { if (j == k && k != i) { currentRoot_[i, k] *= Math.Cos(x[i * (i - 1) / 2 + j]); } else if (j != i) { currentRoot_[i, k] *= Math.Sin(x[i * (i - 1) / 2 + j]); } } } } } } else { for (i = 0; i < size_; i++) { for (k = 0; k < size_; k++) { for (j = 0; j <= k; j++) { if (j == k && k != size_ - 1) { currentRoot_[i, k] *= Math.Cos(x[j * size_ + i]); } else if (j != size_ - 1) { currentRoot_[i, k] *= Math.Sin(x[j * size_ + i]); } } } } } double temp, error = 0; tempMatrix_ = Matrix.transpose(currentRoot_); currentMatrix_ = currentRoot_ * tempMatrix_; for (i = 0; i < size_; i++) { for (j = 0; j < size_; j++) { temp = currentMatrix_[i, j] * targetVariance_[i] * targetVariance_[j] - targetMatrix_[i, j]; error += temp * temp; } } return(error); }
// Optimization function for hypersphere and lower-diagonal algorithm private static Matrix hypersphereOptimize(Matrix targetMatrix, Matrix currentRoot, bool lowerDiagonal) { int i, j, k, size = targetMatrix.rows(); Matrix result = new Matrix(currentRoot); Vector variance = new Vector(size); for (i = 0; i < size; i++) { variance[i] = Math.Sqrt(targetMatrix[i, i]); } if (lowerDiagonal) { Matrix approxMatrix = result * Matrix.transpose(result); result = MatrixUtilities.CholeskyDecomposition(approxMatrix, true); for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] /= Math.Sqrt(approxMatrix[i, i]); } } } else { for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] /= variance[i]; } } } ConjugateGradient optimize = new ConjugateGradient(); EndCriteria endCriteria = new EndCriteria(100, 10, 1e-8, 1e-8, 1e-8); HypersphereCostFunction costFunction = new HypersphereCostFunction(targetMatrix, variance, lowerDiagonal); NoConstraint constraint = new NoConstraint(); // hypersphere vector optimization if (lowerDiagonal) { Vector theta = new Vector(size * (size - 1) / 2); const double eps = 1e-16; for (i = 1; i < size; i++) { for (j = 0; j < i; j++) { theta[i * (i - 1) / 2 + j] = result[i, j]; if (theta[i * (i - 1) / 2 + j] > 1 - eps) { theta[i * (i - 1) / 2 + j] = 1 - eps; } if (theta[i * (i - 1) / 2 + j] < -1 + eps) { theta[i * (i - 1) / 2 + j] = -1 + eps; } for (k = 0; k < j; k++) { theta[i * (i - 1) / 2 + j] /= Math.Sin(theta[i * (i - 1) / 2 + k]); if (theta[i * (i - 1) / 2 + j] > 1 - eps) { theta[i * (i - 1) / 2 + j] = 1 - eps; } if (theta[i * (i - 1) / 2 + j] < -1 + eps) { theta[i * (i - 1) / 2 + j] = -1 + eps; } } theta[i * (i - 1) / 2 + j] = Math.Acos(theta[i * (i - 1) / 2 + j]); if (j == i - 1) { if (result[i, i] < 0) { theta[i * (i - 1) / 2 + j] = -theta[i * (i - 1) / 2 + j]; } } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta = p.currentValue(); result.fill(1); for (i = 0; i < size; i++) { for (k = 0; k < size; k++) { if (k > i) { result[i, k] = 0; } else { for (j = 0; j <= k; j++) { if (j == k && k != i) { result[i, k] *= Math.Cos(theta[i * (i - 1) / 2 + j]); } else if (j != i) { result[i, k] *= Math.Sin(theta[i * (i - 1) / 2 + j]); } } } } } } else { Vector theta = new Vector(size * (size - 1)); const double eps = 1e-16; for (i = 0; i < size; i++) { for (j = 0; j < size - 1; j++) { theta[j * size + i] = result[i, j]; if (theta[j * size + i] > 1 - eps) { theta[j * size + i] = 1 - eps; } if (theta[j * size + i] < -1 + eps) { theta[j * size + i] = -1 + eps; } for (k = 0; k < j; k++) { theta[j * size + i] /= Math.Sin(theta[k * size + i]); if (theta[j * size + i] > 1 - eps) { theta[j * size + i] = 1 - eps; } if (theta[j * size + i] < -1 + eps) { theta[j * size + i] = -1 + eps; } } theta[j * size + i] = Math.Acos(theta[j * size + i]); if (j == size - 2) { if (result[i, j + 1] < 0) { theta[j * size + i] = -theta[j * size + i]; } } } } Problem p = new Problem(costFunction, constraint, theta); optimize.minimize(p, endCriteria); theta = p.currentValue(); result.fill(1); for (i = 0; i < size; i++) { for (k = 0; k < size; k++) { for (j = 0; j <= k; j++) { if (j == k && k != size - 1) { result[i, k] *= Math.Cos(theta[j * size + i]); } else if (j != size - 1) { result[i, k] *= Math.Sin(theta[j * size + i]); } } } } } for (i = 0; i < size; i++) { for (j = 0; j < size; j++) { result[i, j] *= variance[i]; } } return(result); }
public Matrix correlation() { return(sqrtCorrelation_ * Matrix.transpose(sqrtCorrelation_)); }
public override Matrix covariance(double t0, Vector x0, double dt) { Matrix tmp = stdDeviation(t0, x0, dt); return(tmp * Matrix.transpose(tmp)); }
public SVD(Matrix M) { Matrix A; /* The implementation requires that rows > columns. * If this is not the case, we decompose M^T instead. * Swapping the resulting U and V gives the desired * result for M as * * M^T = U S V^T (decomposition of M^T) * * M = (U S V^T)^T (transpose) * * M = (V^T^T S^T U^T) ((AB)^T = B^T A^T) * * M = V S U^T (idempotence of transposition, * symmetry of diagonal matrix S) */ if (M.rows() >= M.columns()) { A = new Matrix(M); transpose_ = false; } else { A = Matrix.transpose(M); transpose_ = true; } m_ = A.rows(); n_ = A.columns(); // we're sure that m_ >= n_ s_ = new Vector(n_); U_ = new Matrix(m_, n_); V_ = new Matrix(n_, n_); Vector e = new Vector(n_); Vector work = new Vector(m_); int i, j, k; // Reduce A to bidiagonal form, storing the diagonal elements // in s and the super-diagonal elements in e. int nct = Math.Min(m_ - 1, n_); int nrt = Math.Max(0, n_ - 2); for (k = 0; k < Math.Max(nct, nrt); k++) { if (k < nct) { // Compute the transformation for the k-th column and // place the k-th diagonal in s[k]. // Compute 2-norm of k-th column without under/overflow. s_[k] = 0; for (i = k; i < m_; i++) { s_[k] = hypot(s_[k], A[i, k]); } if (s_[k] != 0.0) { if (A[k, k] < 0.0) { s_[k] = -s_[k]; } for (i = k; i < m_; i++) { A[i, k] /= s_[k]; } A[k, k] += 1.0; } s_[k] = -s_[k]; } for (j = k + 1; j < n_; j++) { if ((k < nct) && (s_[k] != 0.0)) { // Apply the transformation. double t = 0; for (i = k; i < m_; i++) { t += A[i, k] * A[i, j]; } t = -t / A[k, k]; for (i = k; i < m_; i++) { A[i, j] += t * A[i, k]; } } // Place the k-th row of A into e for the // subsequent calculation of the row transformation. e[j] = A[k, j]; } if (k < nct) { // Place the transformation in U for subsequent back multiplication. for (i = k; i < m_; i++) { U_[i, k] = A[i, k]; } } if (k < nrt) { // Compute the k-th row transformation and place the k-th super-diagonal in e[k]. // Compute 2-norm without under/overflow. e[k] = 0; for (i = k + 1; i < n_; i++) { e[k] = hypot(e[k], e[i]); } if (e[k] != 0.0) { if (e[k + 1] < 0.0) { e[k] = -e[k]; } for (i = k + 1; i < n_; i++) { e[i] /= e[k]; } e[k + 1] += 1.0; } e[k] = -e[k]; if ((k + 1 < m_) & (e[k] != 0.0)) { // Apply the transformation. for (i = k + 1; i < m_; i++) { work[i] = 0.0; } for (j = k + 1; j < n_; j++) { for (i = k + 1; i < m_; i++) { work[i] += e[j] * A[i, j]; } } for (j = k + 1; j < n_; j++) { double t = -e[j] / e[k + 1]; for (i = k + 1; i < m_; i++) { A[i, j] += t * work[i]; } } } // Place the transformation in V for subsequent back multiplication. for (i = k + 1; i < n_; i++) { V_[i, k] = e[i]; } } } // Set up the final bidiagonal matrix or order n. if (nct < n_) { s_[nct] = A[nct, nct]; } if (nrt + 1 < n_) { e[nrt] = A[nrt, n_ - 1]; } e[n_ - 1] = 0.0; // generate U for (j = nct; j < n_; j++) { for (i = 0; i < m_; i++) { U_[i, j] = 0.0; } U_[j, j] = 1.0; } for (k = nct - 1; k >= 0; --k) { if (s_[k] != 0.0) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k; i < m_; i++) { t += U_[i, k] * U_[i, j]; } t = -t / U_[k, k]; for (i = k; i < m_; i++) { U_[i, j] += t * U_[i, k]; } } for (i = k; i < m_; i++) { U_[i, k] = -U_[i, k]; } U_[k, k] = 1.0 + U_[k, k]; for (i = 0; i < k - 1; i++) { U_[i, k] = 0.0; } } else { for (i = 0; i < m_; i++) { U_[i, k] = 0.0; } U_[k, k] = 1.0; } } // generate V for (k = n_ - 1; k >= 0; --k) { if ((k < nrt) & (e[k] != 0.0)) { for (j = k + 1; j < n_; ++j) { double t = 0; for (i = k + 1; i < n_; i++) { t += V_[i, k] * V_[i, j]; } t = -t / V_[k + 1, k]; for (i = k + 1; i < n_; i++) { V_[i, j] += t * V_[i, k]; } } } for (i = 0; i < n_; i++) { V_[i, k] = 0.0; } V_[k, k] = 1.0; } // Main iteration loop for the singular values. int p = n_, pp = p - 1; int iter = 0; double eps = Math.Pow(2.0, -52.0); while (p > 0) { int kase; // Here is where a test for too many iterations would go. // This section of the program inspects for // negligible elements in the s and e arrays. On // completion the variables kase and k are set as follows. // kase = 1 if s(p) and e[k-1] are negligible and k<p // kase = 2 if s(k) is negligible and k<p // kase = 3 if e[k-1] is negligible, k<p, and // s(k), ..., s(p) are not negligible (qr step). // kase = 4 if e(p-1) is negligible (convergence). for (k = p - 2; k >= -1; --k) { if (k == -1) { break; } if (Math.Abs(e[k]) <= eps * (Math.Abs(s_[k]) + Math.Abs(s_[k + 1]))) { e[k] = 0.0; break; } } if (k == p - 2) { kase = 4; } else { int ks; for (ks = p - 1; ks >= k; --ks) { if (ks == k) { break; } double t = (ks != p ? Math.Abs(e[ks]) : 0) + (ks != k + 1 ? Math.Abs(e[ks - 1]) : 0); if (Math.Abs(s_[ks]) <= eps * t) { s_[ks] = 0.0; break; } } if (ks == k) { kase = 3; } else if (ks == p - 1) { kase = 1; } else { kase = 2; k = ks; } } k++; // Perform the task indicated by kase. switch (kase) { // Deflate negligible s(p). case 1: { double f = e[p - 2]; e[p - 2] = 0.0; for (j = p - 2; j >= k; --j) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; if (j != k) { f = -sn * e[j - 1]; e[j - 1] = cs * e[j - 1]; } for (i = 0; i < n_; i++) { t = cs * V_[i, j] + sn * V_[i, p - 1]; V_[i, p - 1] = -sn * V_[i, j] + cs * V_[i, p - 1]; V_[i, j] = t; } } } break; // Split at negligible s(k). case 2: { double f = e[k - 1]; e[k - 1] = 0.0; for (j = k; j < p; j++) { double t = hypot(s_[j], f); double cs = s_[j] / t; double sn = f / t; s_[j] = t; f = -sn * e[j]; e[j] = cs * e[j]; for (i = 0; i < m_; i++) { t = cs * U_[i, j] + sn * U_[i, k - 1]; U_[i, k - 1] = -sn * U_[i, j] + cs * U_[i, k - 1]; U_[i, j] = t; } } } break; // Perform one qr step. case 3: { // Calculate the shift. double scale = Math.Max( Math.Max( Math.Max( Math.Max(Math.Abs(s_[p - 1]), Math.Abs(s_[p - 2])), Math.Abs(e[p - 2])), Math.Abs(s_[k])), Math.Abs(e[k])); double sp = s_[p - 1] / scale; double spm1 = s_[p - 2] / scale; double epm1 = e[p - 2] / scale; double sk = s_[k] / scale; double ek = e[k] / scale; double b = ((spm1 + sp) * (spm1 - sp) + epm1 * epm1) / 2.0; double c = (sp * epm1) * (sp * epm1); double shift = 0.0; if ((b != 0.0) | (c != 0.0)) { shift = Math.Sqrt(b * b + c); if (b < 0.0) { shift = -shift; } shift = c / (b + shift); } double f = (sk + sp) * (sk - sp) + shift; double g = sk * ek; // Chase zeros. for (j = k; j < p - 1; j++) { double t = hypot(f, g); double cs = f / t; double sn = g / t; if (j != k) { e[j - 1] = t; } f = cs * s_[j] + sn * e[j]; e[j] = cs * e[j] - sn * s_[j]; g = sn * s_[j + 1]; s_[j + 1] = cs * s_[j + 1]; for (i = 0; i < n_; i++) { t = cs * V_[i, j] + sn * V_[i, j + 1]; V_[i, j + 1] = -sn * V_[i, j] + cs * V_[i, j + 1]; V_[i, j] = t; } t = hypot(f, g); cs = f / t; sn = g / t; s_[j] = t; f = cs * e[j] + sn * s_[j + 1]; s_[j + 1] = -sn * e[j] + cs * s_[j + 1]; g = sn * e[j + 1]; e[j + 1] = cs * e[j + 1]; if (j < m_ - 1) { for (i = 0; i < m_; i++) { t = cs * U_[i, j] + sn * U_[i, j + 1]; U_[i, j + 1] = -sn * U_[i, j] + cs * U_[i, j + 1]; U_[i, j] = t; } } } e[p - 2] = f; iter = iter + 1; } break; // Convergence. case 4: { // Make the singular values positive. if (s_[k] <= 0.0) { s_[k] = (s_[k] < 0.0 ? -s_[k] : 0.0); for (i = 0; i <= pp; i++) { V_[i, k] = -V_[i, k]; } } // Order the singular values. while (k < pp) { if (s_[k] >= s_[k + 1]) { break; } s_.swap(k, k + 1); if (k < n_ - 1) { for (i = 0; i < n_; i++) { V_.swap(i, k, i, k + 1); } } if (k < m_ - 1) { for (i = 0; i < m_; i++) { U_.swap(i, k, i, k + 1); } } k++; } iter = 0; --p; } break; } } }
public LfmHullWhiteParameterization( LiborForwardModelProcess process, OptionletVolatilityStructure capletVol, Matrix correlation, int factors) : base(process.size(), factors) { diffusion_ = new Matrix(size_ - 1, factors_); fixingTimes_ = process.fixingTimes(); Matrix sqrtCorr = new Matrix(size_ - 1, factors_, 1.0); if (correlation.empty()) { if (!(factors_ == 1)) { throw new ApplicationException("correlation matrix must be given for " + "multi factor models"); } } else { if (!(correlation.rows() == size_ - 1 && correlation.rows() == correlation.columns())) { throw new ApplicationException("wrong dimesion of the correlation matrix"); } if (!(factors_ <= size_ - 1)) { throw new ApplicationException("too many factors for given LFM process"); } Matrix tmpSqrtCorr = MatrixUtilitites.pseudoSqrt(correlation, MatrixUtilitites.SalvagingAlgorithm.Spectral); // reduce to n factor model // "Reconstructing a valid correlation matrix from invalid data" // (<http://www.quarchome.org/correlationmatrix.pdf>) for (int i = 0; i < size_ - 1; ++i) { double d = 0; tmpSqrtCorr.row(i).GetRange(0, factors_).ForEach((ii, vv) => d += vv * tmpSqrtCorr.row(i)[ii]); //sqrtCorr.row(i).GetRange(0, factors_).ForEach((ii, vv) => sqrtCorr.row(i)[ii] = tmpSqrtCorr.row(i).GetRange(0, factors_)[ii] / Math.Sqrt(d)); for (int k = 0; k < factors_; ++k) { sqrtCorr[i, k] = tmpSqrtCorr.row(i).GetRange(0, factors_)[k] / Math.Sqrt(d); } } } List <double> lambda = new List <double>(); DayCounter dayCounter = process.index().dayCounter(); List <double> fixingTimes = process.fixingTimes(); List <Date> fixingDates = process.fixingDates(); for (int i = 1; i < size_; ++i) { double cumVar = 0.0; for (int j = 1; j < i; ++j) { cumVar += lambda[i - j - 1] * lambda[i - j - 1] * (fixingTimes[j + 1] - fixingTimes[j]); } double vol = capletVol.volatility(fixingDates[i], 0.0, false); double var = vol * vol * capletVol.dayCounter().yearFraction(fixingDates[0], fixingDates[i]); lambda.Add(Math.Sqrt((var - cumVar) / (fixingTimes[1] - fixingTimes[0]))); for (int q = 0; q < factors_; ++q) { diffusion_[i - 1, q] = sqrtCorr[i - 1, q] * lambda.Last(); } } covariance_ = diffusion_ * Matrix.transpose(diffusion_); }
public override void update() { Vector tmp = new Vector(size_); List <double> dx = new InitializedList <double>(size_ - 1), S = new InitializedList <double>(size_ - 1); for (int i = 0; i < size_ - 1; ++i) { dx[i] = xBegin_[i + 1] - xBegin_[i]; S[i] = (yBegin_[i + 1] - yBegin_[i]) / dx[i]; } // first derivative approximation if (da_ == CubicInterpolation.DerivativeApprox.Spline) { TridiagonalOperator L = new TridiagonalOperator(size_); for (int i = 1; i < size_ - 1; ++i) { L.setMidRow(i, dx[i], 2.0 * (dx[i] + dx[i - 1]), dx[i - 1]); tmp[i] = 3.0 * (dx[i] * S[i - 1] + dx[i - 1] * S[i]); } // left boundary condition switch (leftType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setFirstRow(dx[1] * (dx[1] + dx[0]), (dx[0] + dx[1]) * (dx[0] + dx[1])); tmp[0] = S[0] * dx[1] * (2.0 * dx[1] + 3.0 * dx[0]) + S[1] * dx[0] * dx[0]; break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0 * S[0] - leftValue_ * dx[0] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); case CubicInterpolation.BoundaryCondition.Lagrange: L.setFirstRow(1.0, 0.0); tmp[0] = cubicInterpolatingPolynomialDerivative( this.xBegin_[0], this.xBegin_[1], this.xBegin_[2], this.xBegin_[3], this.yBegin_[0], this.yBegin_[1], this.yBegin_[2], this.yBegin_[3], this.xBegin_[0]); break; default: throw new ArgumentException("unknown end condition"); } // right boundary condition switch (rightType_) { case CubicInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[size_ - 2] + dx[size_ - 3]) * (dx[size_ - 2] + dx[size_ - 3]), -dx[size_ - 3] * (dx[size_ - 3] + dx[size_ - 2])); tmp[size_ - 1] = -S[size_ - 3] * dx[size_ - 2] * dx[size_ - 2] - S[size_ - 2] * dx[size_ - 3] * (3.0 * dx[size_ - 2] + 2.0 * dx[size_ - 3]); break; case CubicInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[size_ - 1] = rightValue_; break; case CubicInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[size_ - 1] = 3.0 * S[size_ - 2] + rightValue_ * dx[size_ - 2] / 2.0; break; case CubicInterpolation.BoundaryCondition.Periodic: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); case CubicInterpolation.BoundaryCondition.Lagrange: L.setLastRow(0.0, 1.0); tmp[size_ - 1] = cubicInterpolatingPolynomialDerivative( this.xBegin_[size_ - 4], this.xBegin_[size_ - 3], this.xBegin_[size_ - 2], this.xBegin_[size_ - 1], this.yBegin_[size_ - 4], this.yBegin_[size_ - 3], this.yBegin_[size_ - 2], this.yBegin_[size_ - 1], this.xBegin_[size_ - 1]); break; default: throw new ArgumentException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); } else if (da_ == CubicInterpolation.DerivativeApprox.SplineOM1) { Matrix T_ = new Matrix(size_ - 2, size_, 0.0); for (int i = 0; i < size_ - 2; ++i) { T_[i, i] = dx[i] / 6.0; T_[i, i + 1] = (dx[i + 1] + dx[i]) / 3.0; T_[i, i + 2] = dx[i + 1] / 6.0; } Matrix S_ = new Matrix(size_ - 2, size_, 0.0); for (int i = 0; i < size_ - 2; ++i) { S_[i, i] = 1.0 / dx[i]; S_[i, i + 1] = -(1.0 / dx[i + 1] + 1.0 / dx[i]); S_[i, i + 2] = 1.0 / dx[i + 1]; } Matrix Up_ = new Matrix(size_, 2, 0.0); Up_[0, 0] = 1; Up_[size_ - 1, 1] = 1; Matrix Us_ = new Matrix(size_, size_ - 2, 0.0); for (int i = 0; i < size_ - 2; ++i) { Us_[i + 1, i] = 1; } Matrix Z_ = Us_ * Matrix.inverse(T_ * Us_); Matrix I_ = new Matrix(size_, size_, 0.0); for (int i = 0; i < size_; ++i) { I_[i, i] = 1; } Matrix V_ = (I_ - Z_ * T_) * Up_; Matrix W_ = Z_ * S_; Matrix Q_ = new Matrix(size_, size_, 0.0); Q_[0, 0] = 1.0 / (size_ - 1) * dx[0] * dx[0] * dx[0]; Q_[0, 1] = 7.0 / 8 * 1.0 / (size_ - 1) * dx[0] * dx[0] * dx[0]; for (int i = 1; i < size_ - 1; ++i) { Q_[i, i - 1] = 7.0 / 8 * 1.0 / (size_ - 1) * dx[i - 1] * dx[i - 1] * dx[i - 1]; Q_[i, i] = 1.0 / (size_ - 1) * dx[i] * dx[i] * dx[i] + 1.0 / (size_ - 1) * dx[i - 1] * dx[i - 1] * dx[i - 1]; Q_[i, i + 1] = 7.0 / 8 * 1.0 / (size_ - 1) * dx[i] * dx[i] * dx[i]; } Q_[size_ - 1, size_ - 2] = 7.0 / 8 * 1.0 / (size_ - 1) * dx[size_ - 2] * dx[size_ - 2] * dx[size_ - 2]; Q_[size_ - 1, size_ - 1] = 1.0 / (size_ - 1) * dx[size_ - 2] * dx[size_ - 2] * dx[size_ - 2]; Matrix J_ = (I_ - V_ * Matrix.inverse(Matrix.transpose(V_) * Q_ * V_) * Matrix.transpose(V_) * Q_) * W_; Vector Y_ = new Vector(size_); for (int i = 0; i < size_; ++i) { Y_[i] = this.yBegin_[i]; } Vector D_ = J_ * Y_; for (int i = 0; i < size_ - 1; ++i) { tmp[i] = (Y_[i + 1] - Y_[i]) / dx[i] - (2.0 * D_[i] + D_[i + 1]) * dx[i] / 6.0; } tmp[size_ - 1] = tmp[size_ - 2] + D_[size_ - 2] * dx[size_ - 2] + (D_[size_ - 1] - D_[size_ - 2]) * dx[size_ - 2] / 2.0; } else if (da_ == CubicInterpolation.DerivativeApprox.SplineOM2) { Matrix T_ = new Matrix(size_ - 2, size_, 0.0); for (int i = 0; i < size_ - 2; ++i) { T_[i, i] = dx[i] / 6.0; T_[i, i + 1] = (dx[i] + dx[i + 1]) / 3.0; T_[i, i + 2] = dx[i + 1] / 6.0; } Matrix S_ = new Matrix(size_ - 2, size_, 0.0); for (int i = 0; i < size_ - 2; ++i) { S_[i, i] = 1.0 / dx[i]; S_[i, i + 1] = -(1.0 / dx[i + 1] + 1.0 / dx[i]); S_[i, i + 2] = 1.0 / dx[i + 1]; } Matrix Up_ = new Matrix(size_, 2, 0.0); Up_[0, 0] = 1; Up_[size_ - 1, 1] = 1; Matrix Us_ = new Matrix(size_, size_ - 2, 0.0); for (int i = 0; i < size_ - 2; ++i) { Us_[i + 1, i] = 1; } Matrix Z_ = Us_ * Matrix.inverse(T_ * Us_); Matrix I_ = new Matrix(size_, size_, 0.0); for (int i = 0; i < size_; ++i) { I_[i, i] = 1; } Matrix V_ = (I_ - Z_ * T_) * Up_; Matrix W_ = Z_ * S_; Matrix Q_ = new Matrix(size_, size_, 0.0); Q_[0, 0] = 1.0 / (size_ - 1) * dx[0]; Q_[0, 1] = 1.0 / 2 * 1.0 / (size_ - 1) * dx[0]; for (int i = 1; i < size_ - 1; ++i) { Q_[i, i - 1] = 1.0 / 2 * 1.0 / (size_ - 1) * dx[i - 1]; Q_[i, i] = 1.0 / (size_ - 1) * dx[i] + 1.0 / (size_ - 1) * dx[i - 1]; Q_[i, i + 1] = 1.0 / 2 * 1.0 / (size_ - 1) * dx[i]; } Q_[size_ - 1, size_ - 2] = 1.0 / 2 * 1.0 / (size_ - 1) * dx[size_ - 2]; Q_[size_ - 1, size_ - 1] = 1.0 / (size_ - 1) * dx[size_ - 2]; Matrix J_ = (I_ - V_ * Matrix.inverse(Matrix.transpose(V_) * Q_ * V_) * Matrix.transpose(V_) * Q_) * W_; Vector Y_ = new Vector(size_); for (int i = 0; i < size_; ++i) { Y_[i] = this.yBegin_[i]; } Vector D_ = J_ * Y_; for (int i = 0; i < size_ - 1; ++i) { tmp[i] = (Y_[i + 1] - Y_[i]) / dx[i] - (2.0 * D_[i] + D_[i + 1]) * dx[i] / 6.0; } tmp[size_ - 1] = tmp[size_ - 2] + D_[size_ - 2] * dx[size_ - 2] + (D_[size_ - 1] - D_[size_ - 2]) * dx[size_ - 2] / 2.0; } else { // local schemes if (size_ == 2) { tmp[0] = tmp[1] = S[0]; } else { switch (da_) { case CubicInterpolation.DerivativeApprox.FourthOrder: throw new NotImplementedException("FourthOrder not implemented yet"); case CubicInterpolation.DerivativeApprox.Parabolic: // intermediate points for (int i = 1; i < size_ - 1; ++i) { tmp[i] = (dx[i - 1] * S[i] + dx[i] * S[i - 1]) / (dx[i] + dx[i - 1]); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.FritschButland: // intermediate points for (int i = 1; i < size_ - 1; ++i) { double Smin = Math.Min(S[i - 1], S[i]); double Smax = Math.Max(S[i - 1], S[i]); tmp[i] = 3.0 * Smin * Smax / (Smax + 2.0 * Smin); } // end points tmp[0] = ((2.0 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[0] + dx[1]); tmp[size_ - 1] = ((2.0 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 2] + dx[size_ - 3]); break; case CubicInterpolation.DerivativeApprox.Akima: tmp[0] = (Math.Abs(S[1] - S[0]) * 2 * S[0] * S[1] + Math.Abs(2 * S[0] * S[1] - 4 * S[0] * S[0] * S[1]) * S[0]) / (Math.Abs(S[1] - S[0]) + Math.Abs(2 * S[0] * S[1] - 4 * S[0] * S[0] * S[1])); tmp[1] = (Math.Abs(S[2] - S[1]) * S[0] + Math.Abs(S[0] - 2 * S[0] * S[1]) * S[1]) / (Math.Abs(S[2] - S[1]) + Math.Abs(S[0] - 2 * S[0] * S[1])); for (int i = 2; i < size_ - 2; ++i) { if ((S[i - 2].IsEqual(S[i - 1])) && (S[i].IsNotEqual(S[i + 1]))) { tmp[i] = S[i - 1]; } else if ((S[i - 2].IsNotEqual(S[i - 1])) && (S[i].IsEqual(S[i + 1]))) { tmp[i] = S[i]; } else if (S[i].IsEqual(S[i - 1])) { tmp[i] = S[i]; } else if ((S[i - 2].IsEqual(S[i - 1])) && (S[i - 1].IsNotEqual(S[i])) && (S[i].IsEqual(S[i + 1]))) { tmp[i] = (S[i - 1] + S[i]) / 2.0; } else { tmp[i] = (Math.Abs(S[i + 1] - S[i]) * S[i - 1] + Math.Abs(S[i - 1] - S[i - 2]) * S[i]) / (Math.Abs(S[i + 1] - S[i]) + Math.Abs(S[i - 1] - S[i - 2])); } } tmp[size_ - 2] = (Math.Abs(2 * S[size_ - 2] * S[size_ - 3] - S[size_ - 2]) * S[size_ - 3] + Math.Abs(S[size_ - 3] - S[size_ - 4]) * S[size_ - 2]) / (Math.Abs(2 * S[size_ - 2] * S[size_ - 3] - S[size_ - 2]) + Math.Abs(S[size_ - 3] - S[size_ - 4])); tmp[size_ - 1] = (Math.Abs(4 * S[size_ - 2] * S[size_ - 2] * S[size_ - 3] - 2 * S[size_ - 2] * S[size_ - 3]) * S[size_ - 2] + Math.Abs(S[size_ - 2] - S[size_ - 3]) * 2 * S[size_ - 2] * S[size_ - 3]) / (Math.Abs(4 * S[size_ - 2] * S[size_ - 2] * S[size_ - 3] - 2 * S[size_ - 2] * S[size_ - 3]) + Math.Abs(S[size_ - 2] - S[size_ - 3])); break; case CubicInterpolation.DerivativeApprox.Kruger: // intermediate points for (int i = 1; i < size_ - 1; ++i) { if (S[i - 1] * S[i] < 0.0) { // slope changes sign at point tmp[i] = 0.0; } else { // slope will be between the slopes of the adjacent // straight lines and should approach zero if the // slope of either line approaches zero tmp[i] = 2.0 / (1.0 / S[i - 1] + 1.0 / S[i]); } } // end points tmp[0] = (3.0 * S[0] - tmp[1]) / 2.0; tmp[size_ - 1] = (3.0 * S[size_ - 2] - tmp[size_ - 2]) / 2.0; break; case CubicInterpolation.DerivativeApprox.Harmonic: // intermediate points for (int i = 1; i < size_ - 1; ++i) { double w1 = 2 * dx[i] + dx[i - 1]; double w2 = dx[i] + 2 * dx[i - 1]; if (S[i - 1] * S[i] <= 0.0) { // slope changes sign at point tmp[i] = 0.0; } else { // weighted harmonic mean of S[i] and S[i-1] if they // have the same sign; otherwise 0 tmp[i] = (w1 + w2) / (w1 / S[i - 1] + w2 / S[i]); } } // end points [0] tmp[0] = ((2 * dx[0] + dx[1]) * S[0] - dx[0] * S[1]) / (dx[1] + dx[0]); if (tmp[0] * S[0] < 0.0) { tmp[0] = 0; } else if (S[0] * S[1] < 0) { if (Math.Abs(tmp[0]) > Math.Abs(3 * S[0])) { tmp[0] = 3 * S[0]; } } // end points [n-1] tmp[size_ - 1] = ((2 * dx[size_ - 2] + dx[size_ - 3]) * S[size_ - 2] - dx[size_ - 2] * S[size_ - 3]) / (dx[size_ - 3] + dx[size_ - 2]); if (tmp[size_ - 1] * S[size_ - 2] < 0.0) { tmp[size_ - 1] = 0; } else if (S[size_ - 2] * S[size_ - 3] < 0) { if (Math.Abs(tmp[size_ - 1]) > Math.Abs(3 * S[size_ - 2])) { tmp[size_ - 1] = 3 * S[size_ - 2]; } } break; default: throw new ArgumentException("unknown scheme"); } } } monotonicityAdjustments_.Erase(); // Hyman monotonicity constrained filter if (monotonic_) { double correction; double pm, pu, pd, M; for (int i = 0; i < size_; ++i) { if (i == 0) { if (tmp[i] * S[0] > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[0])); } else { correction = 0.0; } if (correction.IsNotEqual(tmp[i])) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else if (i == size_ - 1) { if (tmp[i] * S[size_ - 2] > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[size_ - 2])); } else { correction = 0.0; } if (correction.IsNotEqual(tmp[i])) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } else { pm = (S[i - 1] * dx[i] + S[i] * dx[i - 1]) / (dx[i - 1] + dx[i]); M = 3.0 * Math.Min(Math.Min(Math.Abs(S[i - 1]), Math.Abs(S[i])), Math.Abs(pm)); if (i > 1) { if ((S[i - 1] - S[i - 2]) * (S[i] - S[i - 1]) > 0.0) { pd = (S[i - 1] * (2.0 * dx[i - 1] + dx[i - 2]) - S[i - 2] * dx[i - 1]) / (dx[i - 2] + dx[i - 1]); if (pm * pd > 0.0 && pm * (S[i - 1] - S[i - 2]) > 0.0) { M = Math.Max(M, 1.5 * Math.Min( Math.Abs(pm), Math.Abs(pd))); } } } if (i < size_ - 2) { if ((S[i] - S[i - 1]) * (S[i + 1] - S[i]) > 0.0) { pu = (S[i] * (2.0 * dx[i] + dx[i + 1]) - S[i + 1] * dx[i]) / (dx[i] + dx[i + 1]); if (pm * pu > 0.0 && -pm * (S[i] - S[i - 1]) > 0.0) { M = Math.Max(M, 1.5 * Math.Min( Math.Abs(pm), Math.Abs(pu))); } } } if (tmp[i] * pm > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), M); } else { correction = 0.0; } if (correction.IsNotEqual(tmp[i])) { tmp[i] = correction; monotonicityAdjustments_[i] = true; } } } } // cubic coefficients for (int i = 0; i < size_ - 1; ++i) { a_[i] = tmp[i]; b_[i] = (3.0 * S[i] - tmp[i + 1] - 2.0 * tmp[i]) / dx[i]; c_[i] = (tmp[i + 1] + tmp[i] - 2.0 * S[i]) / (dx[i] * dx[i]); } primitiveConst_[0] = 0.0; for (int i = 1; i < size_ - 1; ++i) { primitiveConst_[i] = primitiveConst_[i - 1] + dx[i - 1] * (yBegin_[i - 1] + dx[i - 1] * (a_[i - 1] / 2.0 + dx[i - 1] * (b_[i - 1] / 3.0 + dx[i - 1] * c_[i - 1] / 4.0))); } }
//! QR decompoisition /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * This subroutine uses householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix A. That is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that A*p = q*r. * * Return value ipvt is an integer array of length n, which * defines the permutation matrix p such that A*p = q*r. * Column j of p is column ipvt(j) of the identity matrix. * * See lmdiff.cpp for further details. */ //public static List<int> qrDecomposition(Matrix A, Matrix q, Matrix r, bool pivot = true) { public static List <int> qrDecomposition(Matrix M, Matrix q, Matrix r, bool pivot) { Matrix mT = Matrix.transpose(M); int m = M.rows(); int n = M.columns(); List <int> lipvt = new InitializedList <int>(n); Vector rdiag = new Vector(n); Vector wa = new Vector(n); MINPACK.qrfac(m, n, mT, 0, (pivot)?1:0, ref lipvt, n, ref rdiag, ref rdiag, wa); if (r.columns() != n || r.rows() != n) { r = new Matrix(n, n); } for (int i = 0; i < n; ++i) { // std::fill(r.row_begin(i), r.row_begin(i)+i, 0.0); r[i, i] = rdiag[i]; if (i < m) { // std::copy(mT.column_begin(i)+i+1, mT.column_end(i), // r.row_begin(i)+i+1); } else { // std::fill(r.row_begin(i)+i+1, r.row_end(i), 0.0); } } if (q.rows() != m || q.columns() != n) { q = new Matrix(m, n); } Vector w = new Vector(m); //for (int k=0; k < m; ++k) { // std::fill(w.begin(), w.end(), 0.0); // w[k] = 1.0; // for (int j=0; j < Math.Min(n, m); ++j) { // double t3 = mT[j,j]; // if (t3 != 0.0) { // double t // = std::inner_product(mT.row_begin(j)+j, mT.row_end(j), // w.begin()+j, 0.0)/t3; // for (int i=j; i<m; ++i) { // w[i]-=mT[j,i]*t; // } // } // q[k,j] = w[j]; // } // std::fill(q.row_begin(k) + Math.Min(n, m), q.row_end(k), 0.0); //} List <int> ipvt = new InitializedList <int>(n); //if (pivot) { // std::copy(lipvt.get(), lipvt.get()+n, ipvt.begin()); //} //else { // for (int i=0; i < n; ++i) // ipvt[i] = i; //} return(ipvt); }
//! QR decompoisition /*! This implementation is based on MINPACK * (<http://www.netlib.org/minpack>, * <http://www.netlib.org/cephes/linalg.tgz>) * * This subroutine uses householder transformations with column * pivoting (optional) to compute a qr factorization of the * m by n matrix A. That is, qrfac determines an orthogonal * matrix q, a permutation matrix p, and an upper trapezoidal * matrix r with diagonal elements of nonincreasing magnitude, * such that A*p = q*r. * * Return value ipvt is an integer array of length n, which * defines the permutation matrix p such that A*p = q*r. * Column j of p is column ipvt(j) of the identity matrix. * * See lmdiff.cpp for further details. */ //public static List<int> qrDecomposition(Matrix A, Matrix q, Matrix r, bool pivot = true) { public static List <int> qrDecomposition(Matrix M, ref Matrix q, ref Matrix r, bool pivot) { Matrix mT = Matrix.transpose(M); int m = M.rows(); int n = M.columns(); List <int> lipvt = new InitializedList <int>(n); Vector rdiag = new Vector(n); Vector wa = new Vector(n); MINPACK.qrfac(m, n, mT, 0, (pivot)?1:0, ref lipvt, n, ref rdiag, ref rdiag, wa); if (r.columns() != n || r.rows() != n) { r = new Matrix(n, n); } for (int i = 0; i < n; ++i) { r[i, i] = rdiag[i]; if (i < m) { for (int j = i; j < mT.rows() - 1; j++) { r[i, j + 1] = mT[j + 1, i]; } } } if (q.rows() != m || q.columns() != n) { q = new Matrix(m, n); } Vector w = new Vector(m); for (int k = 0; k < m; ++k) { w.Erase(); w[k] = 1.0; for (int j = 0; j < Math.Min(n, m); ++j) { double t3 = mT[j, j]; if (t3 != 0.0) { double t = 0; for (int kk = j; kk < mT.columns(); kk++) { t += (mT[j, kk] * w[kk]) / t3; } for (int i = j; i < m; ++i) { w[i] -= mT[j, i] * t; } } q[k, j] = w[j]; } } List <int> ipvt = new InitializedList <int>(n); if (pivot) { for (int i = 0; i < n; ++i) { ipvt[i] = lipvt[i]; } } else { for (int i = 0; i < n; ++i) { ipvt[i] = i; } } return(ipvt); }