Пример #1
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);
        }
Пример #2
0
        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);
        }
Пример #3
0
        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);
        }
Пример #4
0
        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);
            }
        }
Пример #5
0
        // 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");
            }
        }
Пример #6
0
        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");
            }
        }
Пример #7
0
 protected void initializeOperator()
 {
     finiteDifferenceOperator_ = OperatorFactory.getOperator(process_, intrinsicValues_.grid(),
                                                             getResidualTime(), timeDependent_);
 }
Пример #8
0
        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_;
        }
Пример #9
0
        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;
        }
Пример #10
0
 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;
 }
Пример #11
0
        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_);
        }
Пример #12
0
      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)));
         }
      }
Пример #13
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)));
            }
        }
Пример #14
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)));
            }
        }
Пример #15
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)));
            }
        }
Пример #16
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;
 }
Пример #17
0
        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)));
            }
        }