//! identity instance public IOperator identity(int size) { TridiagonalOperator I = new TridiagonalOperator(new Vector(size - 1, 0.0), // lower diagonal new Vector(size, 1.0), // diagonal new Vector(size - 1, 0.0)); // upper diagonal return(I); }
public IOperator multiply(double a, IOperator o) { TridiagonalOperator D = o as TridiagonalOperator; Vector low = D.lowerDiagonal_ * a, mid = D.diagonal_ * a, high = D.upperDiagonal_ * a; TridiagonalOperator result = new TridiagonalOperator(low, mid, high); return(result); }
public IOperator subtract(IOperator A, IOperator B) { TridiagonalOperator D1 = A as TridiagonalOperator; TridiagonalOperator D2 = B as TridiagonalOperator; Vector low = D1.lowerDiagonal_ - D2.lowerDiagonal_, mid = D1.diagonal_ - D2.diagonal_, high = D1.upperDiagonal_ - D2.upperDiagonal_; TridiagonalOperator result = new TridiagonalOperator(low, mid, high); return(result); }
public void generateOperator(double t, TransformedGrid tg, TridiagonalOperator L) { for (int i = 1; i < tg.size() - 1; i++) { double sigma = diffusion(t, tg.grid(i)); double nu = drift(t, tg.grid(i)); double r = discount(t, tg.grid(i)); double sigma2 = sigma * sigma; double pd = -(sigma2 / tg.dxm(i) - nu) / tg.dx(i); double pu = -(sigma2 / tg.dxp(i) + nu) / tg.dx(i); double pm = sigma2 / (tg.dxm(i) * tg.dxp(i)) + r; L.setMidRow(i, pd, pm, pu); } }
// interface public override void applyBeforeApplying(IOperator o) { TridiagonalOperator L = o as TridiagonalOperator; switch (side_) { case Side.Lower: L.setFirstRow(-1.0, 1.0); break; case Side.Upper: L.setLastRow(-1.0, 1.0); break; default: throw new ArgumentException("unknown side for Neumann boundary condition"); } }
public override void applyBeforeSolving(IOperator o, Vector rhs) { TridiagonalOperator L = o as TridiagonalOperator; switch (side_) { case Side.Lower: L.setFirstRow(-1.0, 1.0); rhs[0] = value_; break; case Side.Upper: L.setLastRow(-1.0, 1.0); rhs[rhs.size() - 1] = value_; break; default: throw new ArgumentException("unknown side for Neumann boundary condition"); } }
protected void initializeOperator() { finiteDifferenceOperator_ = OperatorFactory.getOperator(process_, intrinsicValues_.grid(), getResidualTime(), timeDependent_); }
public override void calculate(IPricingEngineResults r) { OneAssetOption.Results results = r as OneAssetOption.Results; setGridLimits(); initializeInitialCondition(); initializeOperator(); initializeBoundaryConditions(); initializeStepCondition(); List <IOperator> operatorSet = new List <IOperator>(); List <Vector> arraySet = new List <Vector>(); BoundaryConditionSet bcSet = new BoundaryConditionSet(); StepConditionSet <Vector> conditionSet = new StepConditionSet <Vector>(); prices_ = (SampledCurve)intrinsicValues_.Clone(); controlPrices_ = (SampledCurve)intrinsicValues_.Clone(); controlOperator_ = (TridiagonalOperator)finiteDifferenceOperator_.Clone(); controlBCs_[0] = BCs_[0]; controlBCs_[1] = BCs_[1]; operatorSet.Add(finiteDifferenceOperator_); operatorSet.Add(controlOperator_); arraySet.Add(prices_.values()); arraySet.Add(controlPrices_.values()); bcSet.Add(BCs_); bcSet.Add(controlBCs_); conditionSet.Add(stepCondition_); conditionSet.Add(new NullCondition <Vector>()); var model = new FiniteDifferenceModel <ParallelEvolver <CrankNicolson <TridiagonalOperator> > >(operatorSet, bcSet); object temp = arraySet; model.rollback(ref temp, getResidualTime(), 0.0, timeSteps_, conditionSet); arraySet = (List <Vector>)temp; prices_.setValues(arraySet[0]); controlPrices_.setValues(arraySet[1]); StrikedTypePayoff striked_payoff = payoff_ as StrikedTypePayoff; Utils.QL_REQUIRE(striked_payoff != null, () => "non-striked payoff given"); double variance = process_.blackVolatility().link.blackVariance(exerciseDate_, striked_payoff.strike()); double dividendDiscount = process_.dividendYield().link.discount(exerciseDate_); double riskFreeDiscount = process_.riskFreeRate().link.discount(exerciseDate_); double spot = process_.stateVariable().link.value(); double forwardPrice = spot * dividendDiscount / riskFreeDiscount; BlackCalculator black = new BlackCalculator(striked_payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount); results.value = prices_.valueAtCenter() - controlPrices_.valueAtCenter() + black.value(); results.delta = prices_.firstDerivativeAtCenter() - controlPrices_.firstDerivativeAtCenter() + black.delta(spot); results.gamma = prices_.secondDerivativeAtCenter() - controlPrices_.secondDerivativeAtCenter() + black.gamma(spot); results.additionalResults["priceCurve"] = prices_; }
public IOperator subtract(IOperator A, IOperator B) { TridiagonalOperator D1 = A as TridiagonalOperator; TridiagonalOperator D2 = B as TridiagonalOperator; Vector low = D1.lowerDiagonal_-D2.lowerDiagonal_, mid = D1.diagonal_-D2.diagonal_, high = D1.upperDiagonal_-D2.upperDiagonal_; TridiagonalOperator result = new TridiagonalOperator(low,mid,high); return result; }
public IOperator multiply(double a, IOperator o) { TridiagonalOperator D = o as TridiagonalOperator; Vector low = D.lowerDiagonal_*a, mid = D.diagonal_*a, high = D.upperDiagonal_*a; TridiagonalOperator result = new TridiagonalOperator(low,mid,high); return result; }
public override void calculate(IPricingEngineResults r) { OneAssetOption.Results results = r as OneAssetOption.Results; setGridLimits(); initializeInitialCondition(); initializeOperator(); initializeBoundaryConditions(); initializeStepCondition(); // typedef StandardSystemFiniteDifferenceModel model_type; List<IOperator> operatorSet = new List<IOperator>(); List<Vector> arraySet = new List<Vector>(); BoundaryConditionSet bcSet = new BoundaryConditionSet(); StepConditionSet<Vector> conditionSet = new StepConditionSet<Vector>(); prices_ = (SampledCurve)intrinsicValues_.Clone(); controlPrices_ = (SampledCurve)intrinsicValues_.Clone(); controlOperator_ = (TridiagonalOperator)finiteDifferenceOperator_.Clone(); controlBCs_[0] = BCs_[0]; controlBCs_[1] = BCs_[1]; operatorSet.Add(finiteDifferenceOperator_); operatorSet.Add(controlOperator_); arraySet.Add(prices_.values()); arraySet.Add(controlPrices_.values()); bcSet.Add(BCs_); bcSet.Add(controlBCs_); conditionSet.Add(stepCondition_); conditionSet.Add(new NullCondition<Vector>()); var model = new FiniteDifferenceModel<ParallelEvolver<CrankNicolson<TridiagonalOperator>>>(operatorSet, bcSet); object temp = arraySet; model.rollback(ref temp, getResidualTime(), 0.0, timeSteps_, conditionSet); arraySet = (List<Vector>)temp; prices_.setValues(arraySet[0]); controlPrices_.setValues(arraySet[1]); StrikedTypePayoff striked_payoff = payoff_ as StrikedTypePayoff; if (striked_payoff == null) throw new ApplicationException("non-striked payoff given"); double variance = process_.blackVolatility().link.blackVariance(exerciseDate_, striked_payoff.strike()); double dividendDiscount = process_.dividendYield().link.discount(exerciseDate_); double riskFreeDiscount = process_.riskFreeRate().link.discount(exerciseDate_); double spot = process_.stateVariable().link.value(); double forwardPrice = spot * dividendDiscount / riskFreeDiscount; BlackCalculator black = new BlackCalculator(striked_payoff, forwardPrice, Math.Sqrt(variance), riskFreeDiscount); results.value = prices_.valueAtCenter() - controlPrices_.valueAtCenter() + black.value(); results.delta = prices_.firstDerivativeAtCenter() - controlPrices_.firstDerivativeAtCenter() + black.delta(spot); results.gamma = prices_.secondDerivativeAtCenter() - controlPrices_.secondDerivativeAtCenter() + black.gamma(spot); results.additionalResults.Add("priceCurve", prices_); }
public override void update() { TridiagonalOperator L = new TridiagonalOperator(cH_.n_); Array<double> tmp = new Array<double>(cH_.n_); var dx = new Array<double>(cH_.n_ - 1); var S = new Array<double>(cH_.n_ - 1); int i=0; dx[i] = this.xBegin_[i+1] - this.xBegin_[i]; S[i] = (this.yBegin_[i+1] - this.yBegin_[i])/dx[i]; for (i=1; i<cH_.n_-1; ++i) { dx[i] = this.xBegin_[i+1] - this.xBegin_[i]; S[i] = (this.yBegin_[i+1] - this.yBegin_[i])/dx[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]); } /**** BOUNDARY CONDITIONS ****/ // left condition switch (leftType_) { case CubicSplineInterpolation.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 CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0*S[0] - leftValue_*dx[0]/2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // right condition switch (rightType_) { case CubicSplineInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[cH_.n_-2]+dx[cH_.n_-3])*(dx[cH_.n_-2]+dx[cH_.n_-3]), -dx[cH_.n_-3]*(dx[cH_.n_-3]+dx[cH_.n_-2])); tmp[cH_.n_-1] = -S[cH_.n_-3]*dx[cH_.n_-2]*dx[cH_.n_-2] - S[cH_.n_-2]*dx[cH_.n_-3]*(3.0*dx[cH_.n_-2]+2.0*dx[cH_.n_-3]); break; case CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[cH_.n_-1] = rightValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[cH_.n_-1] = 3.0*S[cH_.n_-2] + rightValue_*dx[cH_.n_-2]/2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); for (int j = 0; i < cH_.monotonicityAdjustments_.Count; j++ ) cH_.monotonicityAdjustments_[j] = false; if (constrained_) { double correction; double pm, pu, pd, M; for (i=0; i<cH_.n_; ++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!=tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } else if (i==cH_.n_-1) { if (tmp[i]*S[cH_.n_-2]>0.0) { correction = tmp[i]/Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0*S[cH_.n_-2])); } else { correction = 0.0; } if (correction!=tmp[i]) { tmp[i] = correction; cH_.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<cH_.n_-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!=tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } } } for (i=0; i<cH_.n_-1; ++i) { cH_.a_[i] = tmp[i]; cH_.b_[i] = (3.0*S[i] - tmp[i+1] - 2.0*tmp[i])/dx[i]; cH_.c_[i] = (tmp[i+1] + tmp[i] - 2.0*S[i])/(dx[i]*dx[i]); } cH_.primitiveConst_[0] = 0.0; for (i=1; i<cH_.n_-1; ++i) { cH_.primitiveConst_[i] = cH_.primitiveConst_[i-1] + dx[i-1] * (this.yBegin_[i-1] + dx[i-1] * (cH_.a_[i-1]/2.0 + dx[i-1] * (cH_.b_[i-1]/3.0 + dx[i-1] * cH_.c_[i-1]/4.0))); } }
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 // 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] == S[i - 1]) && (S[i] != S[i + 1])) { tmp[i] = S[i - 1]; } else if ((S[i - 2] != S[i - 1]) && (S[i] == S[i + 1])) { tmp[i] = S[i]; } else if (S[i] == S[i - 1]) { tmp[i] = S[i]; } else if ((S[i - 2] == S[i - 1]) && (S[i - 1] != S[i]) && (S[i] == 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; 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 != 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 != 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 != 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))); } }
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))); } }
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: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); 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: case CubicInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new NotImplementedException("this end condition is not implemented yet"); default: throw new ArgumentException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); } 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"); break; 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; 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: throw new NotImplementedException("Akima not implemented yet"); // 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.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; 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!=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!=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!=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))); } }
//! identity instance public IOperator identity(int size) { TridiagonalOperator I = new TridiagonalOperator(new Vector(size - 1, 0.0), // lower diagonal new Vector(size, 1.0), // diagonal new Vector(size - 1, 0.0)); // upper diagonal return I; }
public override void update() { TridiagonalOperator L = new TridiagonalOperator(cH_.n_); Array <double> tmp = new Array <double>(cH_.n_); var dx = new Array <double>(cH_.n_ - 1); var S = new Array <double>(cH_.n_ - 1); int i = 0; dx[i] = this.xBegin_[i + 1] - this.xBegin_[i]; S[i] = (this.yBegin_[i + 1] - this.yBegin_[i]) / dx[i]; for (i = 1; i < cH_.n_ - 1; ++i) { dx[i] = this.xBegin_[i + 1] - this.xBegin_[i]; S[i] = (this.yBegin_[i + 1] - this.yBegin_[i]) / dx[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]); } /**** BOUNDARY CONDITIONS ****/ // left condition switch (leftType_) { case CubicSplineInterpolation.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 CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setFirstRow(1.0, 0.0); tmp[0] = leftValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setFirstRow(2.0, 1.0); tmp[0] = 3.0 * S[0] - leftValue_ * dx[0] / 2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // right condition switch (rightType_) { case CubicSplineInterpolation.BoundaryCondition.NotAKnot: // ignoring end condition value L.setLastRow(-(dx[cH_.n_ - 2] + dx[cH_.n_ - 3]) * (dx[cH_.n_ - 2] + dx[cH_.n_ - 3]), -dx[cH_.n_ - 3] * (dx[cH_.n_ - 3] + dx[cH_.n_ - 2])); tmp[cH_.n_ - 1] = -S[cH_.n_ - 3] * dx[cH_.n_ - 2] * dx[cH_.n_ - 2] - S[cH_.n_ - 2] * dx[cH_.n_ - 3] * (3.0 * dx[cH_.n_ - 2] + 2.0 * dx[cH_.n_ - 3]); break; case CubicSplineInterpolation.BoundaryCondition.FirstDerivative: L.setLastRow(0.0, 1.0); tmp[cH_.n_ - 1] = rightValue_; break; case CubicSplineInterpolation.BoundaryCondition.SecondDerivative: L.setLastRow(1.0, 2.0); tmp[cH_.n_ - 1] = 3.0 * S[cH_.n_ - 2] + rightValue_ * dx[cH_.n_ - 2] / 2.0; break; case CubicSplineInterpolation.BoundaryCondition.Periodic: case CubicSplineInterpolation.BoundaryCondition.Lagrange: // ignoring end condition value throw new ApplicationException("this end condition is not implemented yet"); default: throw new ApplicationException("unknown end condition"); } // solve the system tmp = L.solveFor(tmp); for (int j = 0; i < cH_.monotonicityAdjustments_.Count; j++) { cH_.monotonicityAdjustments_[j] = false; } if (constrained_) { double correction; double pm, pu, pd, M; for (i = 0; i < cH_.n_; ++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 != tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } else if (i == cH_.n_ - 1) { if (tmp[i] * S[cH_.n_ - 2] > 0.0) { correction = tmp[i] / Math.Abs(tmp[i]) * Math.Min(Math.Abs(tmp[i]), Math.Abs(3.0 * S[cH_.n_ - 2])); } else { correction = 0.0; } if (correction != tmp[i]) { tmp[i] = correction; cH_.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 < cH_.n_ - 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 != tmp[i]) { tmp[i] = correction; cH_.monotonicityAdjustments_[i] = true; } } } } for (i = 0; i < cH_.n_ - 1; ++i) { cH_.a_[i] = tmp[i]; cH_.b_[i] = (3.0 * S[i] - tmp[i + 1] - 2.0 * tmp[i]) / dx[i]; cH_.c_[i] = (tmp[i + 1] + tmp[i] - 2.0 * S[i]) / (dx[i] * dx[i]); } cH_.primitiveConst_[0] = 0.0; for (i = 1; i < cH_.n_ - 1; ++i) { cH_.primitiveConst_[i] = cH_.primitiveConst_[i - 1] + dx[i - 1] * (this.yBegin_[i - 1] + dx[i - 1] * (cH_.a_[i - 1] / 2.0 + dx[i - 1] * (cH_.b_[i - 1] / 3.0 + dx[i - 1] * cH_.c_[i - 1] / 4.0))); } }