QLNet.TridiagonalOperator.solveFor C# (CSharp) Метод

solveFor() публичный Метод

public solveFor ( Vector rhs ) : Vector
rhs Vector
Результат Vector
        public Vector solveFor(Vector rhs)
        {
            if (rhs.Count != size()) throw new ApplicationException("rhs has the wrong size");

            Vector result = new Vector(size()), tmp = new Vector(size());

            double bet = diagonal_[0];
            if (bet == 0.0) throw new ApplicationException("division by zero");
            result[0] = rhs[0] / bet;

            for (int j = 1; j < size(); j++) {
                tmp[j] = upperDiagonal_[j - 1] / bet;
                bet = diagonal_[j] - lowerDiagonal_[j - 1] * tmp[j];
                if (bet == 0.0) throw new ApplicationException("division by zero");
                result[j] = (rhs[j] - lowerDiagonal_[j - 1] * result[j - 1]) / bet;
            }
            // cannot be j>=0 with Size j
            for (int j = size() - 2; j > 0; --j)
                result[j] -= tmp[j + 1] * result[j + 1];
            result[0] -= tmp[1] * result[1];
            return result;
        }

Usage Example

Пример #1
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)));
            }
        }
All Usage Examples Of QLNet.TridiagonalOperator::solveFor