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)));
}
}