예제 #1
0
    Size FdmLinearOpLayout::neighbourhood(const FdmLinearOpIterator& iterator,
                                          Size i1, Integer offset1,
                                          Size i2, Integer offset2) const {

        Size myIndex = iterator.index()
            - iterator.coordinates()[i1]*spacing_[i1]
            - iterator.coordinates()[i2]*spacing_[i2];

        Integer coorOffset1 = Integer(iterator.coordinates()[i1])+offset1;
        if (coorOffset1 < 0) {
            coorOffset1=-coorOffset1;
        }
        else if (Size(coorOffset1) >= dim_[i1]) {
            coorOffset1 = 2*(dim_[i1]-1) - coorOffset1;
        }

        Integer coorOffset2 = Integer(iterator.coordinates()[i2])+offset2;
        if (coorOffset2 < 0) {
            coorOffset2=-coorOffset2;
        }
        else if (Size(coorOffset2) >= dim_[i2]) {
            coorOffset2 = 2*(dim_[i2]-1) - coorOffset2;
        }

        return myIndex + coorOffset1*spacing_[i1]+coorOffset2*spacing_[i2];
    }
예제 #2
0
FirstDerivativeOp::FirstDerivativeOp(
    Size direction,
    const boost::shared_ptr<FdmMesher>& mesher)
    : TripleBandLinearOp(direction, mesher) {

    const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
    const FdmLinearOpIterator endIter = layout->end();

    for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) {
        const Size i = iter.index();
        const Real hm = mesher->dminus(iter, direction_);
        const Real hp = mesher->dplus(iter, direction_);

        const Real zetam1 = hm*(hm+hp);
        const Real zeta0  = hm*hp;
        const Real zetap1 = hp*(hm+hp);

        if (iter.coordinates()[direction_] == 0) {
            //upwinding scheme
            lower_[i] = 0.0;
            diag_[i]  = -(upper_[i] = 1/hp);
        }
        else if (   iter.coordinates()[direction_]
                    == layout->dim()[direction]-1) {
            // downwinding scheme
            lower_[i] = -(diag_[i] = 1/hm);
            upper_[i] = 0.0;
        }
        else {
            lower_[i] = -hp/zetam1;
            diag_[i]  = (hp-hm)/zeta0;
            upper_[i] = hm/zetap1;
        }
    }
}
예제 #3
0
    Disposable<Array> FdmHestonEquityPart::getLeverageFctSlice(Time t1, Time t2)
    const {
        const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
        Array v(layout->size(), 1.0);

        if (!leverageFct_) {
            return v;
        }
        const Real t = 0.5*(t1+t2);
        const Time time = std::min(leverageFct_->maxTime(), t);

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin();
             iter!=endIter; ++iter) {
            const Size nx = iter.coordinates()[0];

            if (iter.coordinates()[1] == 0) {
                const Real x = std::exp(mesher_->location(iter, 0));
                const Real spot = std::min(leverageFct_->maxStrike(),
                                           std::max(leverageFct_->minStrike(), x));
                v[nx] = std::max(0.01, leverageFct_->localVol(time, spot, true));
            }
            else {
                v[iter.index()] = v[nx];
            }
        }
        return v;
    }
예제 #4
0
    FdmHestonFwdOp::FdmHestonFwdOp(
            const boost::shared_ptr<FdmMesher>& mesher,
            const boost::shared_ptr<HestonProcess>& process,
            FdmSquareRootFwdOp::TransformationType type)
    : type_ (type),
      kappa_(process->kappa()),
      theta_(process->theta()),
      sigma_(process->sigma()),
      rho_  (process->rho()),
      v0_   (process->v0()),
      rTS_  (process->riskFreeRate().currentLink()),
      qTS_  (process->dividendYield().currentLink()),
      varianceValues_(0.5*mesher->locations(1)),
      dxMap_ (new FirstDerivativeOp(0, mesher)),
      dxxMap_(new ModTripleBandLinearOp(TripleBandLinearOp(
          SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))))),
      mapX_  (new TripleBandLinearOp(0, mesher)),
      mapY_  (new FdmSquareRootFwdOp(mesher,kappa_,theta_,sigma_, 1, type)),
      correlation_(new NinePointLinearOp(
          SecondOrderMixedDerivativeOp(0, 1, mesher)
              .mult(rho_*sigma_*mesher->locations(1))))
    {
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();

        if (type_ == FdmSquareRootFwdOp::Plain) {
            // zero flux boundary condition
            const Size n = layout->dim()[1];
            const Real alpha = 2*rho_*mapY_->v(0)/sigma_*mapY_->f0();
            const Real beta  = 2*rho_*mapY_->v(n)/sigma_*mapY_->f1();
            ModTripleBandLinearOp fDx(FirstDerivativeOp(0, mesher));

            const FdmLinearOpIterator endIter = layout->end();
            for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
                    ++iter) {
                if (iter.coordinates()[1] == 0) {
                    const Size idx = iter.index();

                    dxxMap_->upper()[idx] += alpha*fDx.upper()[idx];
                    dxxMap_->diag()[idx]  += alpha*fDx.diag()[idx];
                    dxxMap_->lower()[idx] += alpha*fDx.lower()[idx];
                }
                else if (iter.coordinates()[1] == n-1) {
                    const Size idx = iter.index();

                    dxxMap_->upper()[idx] += beta*fDx.upper()[idx];
                    dxxMap_->diag()[idx]  += beta*fDx.diag()[idx];
                    dxxMap_->lower()[idx] += beta*fDx.lower()[idx];
                }
            }
        }
    }
예제 #5
0
    Size FdmLinearOpLayout::neighbourhood(const FdmLinearOpIterator& iterator,
                                          Size i, Integer offset) const {
        Size myIndex = iterator.index()
            - iterator.coordinates()[i]*spacing_[i];

        Integer coorOffset = Integer(iterator.coordinates()[i])+offset;
        if (coorOffset < 0) {
            coorOffset=-coorOffset;
        }
        else if (Size(coorOffset) >= dim_[i]) {
            coorOffset = 2*(dim_[i]-1) - coorOffset;
        }
        return myIndex + coorOffset*spacing_[i];
    }
예제 #6
0
    FdmHestonSolver::FdmHestonSolver(
        const Handle<HestonProcess>& process,
        const boost::shared_ptr<FdmMesher>& mesher,
        const FdmBoundaryConditionSet& bcSet,
        const boost::shared_ptr<FdmStepConditionComposite> & condition,
        const boost::shared_ptr<FdmInnerValueCalculator>& calculator,
        const Time maturity,
        const Size timeSteps,
        Size dampingSteps,
        FdmBackwardSolver::FdmSchemeType schemeType,
        Real theta, Real mu,
        const Handle<FdmQuantoHelper>& quantoHelper)
    : process_(process),
      mesher_(mesher),
      bcSet_(bcSet),
      thetaCondition_(new FdmSnapshotCondition(
        0.99*std::min(1.0/365.0,
                      condition->stoppingTimes().empty() ? maturity :
                                 condition->stoppingTimes().front()))),
      condition_(addCondition(thetaCondition_, condition)),
      maturity_(maturity),
      timeSteps_(timeSteps),
      dampingSteps_(dampingSteps),
      schemeType_(schemeType),
      theta_(theta),
      mu_(mu),
      quantoHelper_(quantoHelper),
      initialValues_(mesher->layout()->size()),
      resultValues_(mesher->layout()->dim()[1], mesher->layout()->dim()[0]) {
        registerWith(process_);
        registerWith(quantoHelper_);

        x_.reserve(mesher->layout()->dim()[0]);
        v_.reserve(mesher->layout()->dim()[1]);

        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
             ++iter) {
            initialValues_[iter.index()] = calculator->avgInnerValue(iter);

            if (!iter.coordinates()[1]) {
                x_.push_back(mesher->location(iter, 0));
            }
            if (!iter.coordinates()[0]) {
                v_.push_back(mesher->location(iter, 1));
            }
        }
    }
예제 #7
0
    FdmHestonEquityPart::FdmHestonEquityPart(
        const boost::shared_ptr<FdmMesher>& mesher,
        const boost::shared_ptr<YieldTermStructure>& rTS,
        const boost::shared_ptr<YieldTermStructure>& qTS,
        const boost::shared_ptr<FdmQuantoHelper>& quantoHelper,
        const boost::shared_ptr<LocalVolTermStructure>& leverageFct)
    : varianceValues_(0.5*mesher->locations(1)),
      dxMap_ (FirstDerivativeOp(0, mesher)),
      dxxMap_(SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))),
      mapT_  (0, mesher),
      mesher_(mesher),
      rTS_(rTS),
      qTS_(qTS),
      quantoHelper_(quantoHelper),
      leverageFct_(leverageFct) {

        // on the boundary s_min and s_max the second derivative
        // d^2V/dS^2 is zero and due to Ito's Lemma the variance term
        // in the drift should vanish.
        boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
        FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
            if (   iter.coordinates()[0] == 0
                || iter.coordinates()[0] == layout->dim()[0]-1) {
                varianceValues_[iter.index()] = 0.0;
            }
        }
        volatilityValues_ = Sqrt(2*varianceValues_);
    }
    void FdmSimpleSwingCondition::applyTo(Array& a, Time t) const {
        const std::vector<Time>::const_iterator iter
            = std::find(exerciseTimes_.begin(), exerciseTimes_.end(), t);
        const Size maxExerciseValue=mesher_->layout()->dim()[swingDirection_]-1;

        if (iter != exerciseTimes_.end()) {
            Array retVal= a;

            const Size d = std::distance(iter, exerciseTimes_.end());

            const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
            const FdmLinearOpIterator endIter = layout->end();
            
            for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
                 ++iter) {
                
                const std::vector<Size>& coor = iter.coordinates();
                
                const Size exercisesUsed = coor[swingDirection_];
                
                if (exercisesUsed < maxExerciseValue) {
                    const Real cashflow = calculator_->innerValue(iter, t);
                    const Real currentValue = a[iter.index()];
                    const Real valuePlusOneExercise
                         = a[layout->neighbourhood(iter, swingDirection_, 1)];
                    
                    if (   currentValue < valuePlusOneExercise + cashflow
                        || exercisesUsed + d <=  minExercises_) {
                        retVal[iter.index()] = valuePlusOneExercise + cashflow;
                    }
                }
            }
            a = retVal;
        }
    }
Real FdmLogInnerValue::avgInnerValueCalc(const FdmLinearOpIterator& iter) {
    const Size dim = mesher_->layout()->dim()[direction_];
    const Size coord = iter.coordinates()[direction_];
    const Real loc = mesher_->location(iter,direction_);
    Real a = loc;
    Real b = loc;
    if (coord > 0) {
        a -= mesher_->dminus(iter, direction_)/2.0;
    }
    if (coord < dim-1) {
        b += mesher_->dplus(iter, direction_)/2.0;
    }
    boost::function1<Real, Real> f = compose(
                                         std::bind1st(std::mem_fun(&Payoff::operator()), payoff_.get()),
                                         std::ptr_fun<Real,Real>(std::exp));

    Real retVal;
    try {
        const Real acc
            = ((f(a) != 0.0 || f(b) != 0.0) ? (f(a)+f(b))*5e-5 : 1e-4);
        retVal = SimpsonIntegral(acc, 8)(f, a, b)/(b-a);
    }
    catch (Error&) {
        // use default value
        retVal = innerValue(iter);
    }

    return retVal;
}
예제 #10
0
    TripleBandLinearOp::TripleBandLinearOp(
        Size direction,
        const boost::shared_ptr<FdmMesher>& mesher)
    : direction_(direction),
      i0_       (new Size[mesher->layout()->size()]),
      i2_       (new Size[mesher->layout()->size()]),
      reverseIndex_ (new Size[mesher->layout()->size()]),
      lower_    (new Real[mesher->layout()->size()]),
      diag_     (new Real[mesher->layout()->size()]),
      upper_    (new Real[mesher->layout()->size()]),
      mesher_(mesher) {

        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
        const FdmLinearOpIterator endIter = layout->end();

        std::vector<Size> newDim(layout->dim());
        std::iter_swap(newDim.begin(), newDim.begin()+direction_);
        std::vector<Size> newSpacing = FdmLinearOpLayout(newDim).spacing();
        std::iter_swap(newSpacing.begin(), newSpacing.begin()+direction_);

        for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) {
            const Size i = iter.index();

            i0_[i] = layout->neighbourhood(iter, direction, -1);
            i2_[i] = layout->neighbourhood(iter, direction,  1);

            const std::vector<Size>& coordinates = iter.coordinates();
            const Size newIndex =
                  std::inner_product(coordinates.begin(), coordinates.end(),
                                     newSpacing.begin(), Size(0));
            reverseIndex_[newIndex] = i;
        }
    }
예제 #11
0
    FdmHestonHullWhiteEquityPart::FdmHestonHullWhiteEquityPart(
        const boost::shared_ptr<FdmMesher>& mesher,
        const boost::shared_ptr<HullWhite>& hwModel,
        const boost::shared_ptr<YieldTermStructure>& qTS)
    : x_(mesher->locations(2)),
      varianceValues_(0.5*mesher->locations(1)),
      dxMap_ (FirstDerivativeOp(0, mesher)),
      dxxMap_(SecondDerivativeOp(0, mesher).mult(0.5*mesher->locations(1))),
      mapT_   (0, mesher),
      hwModel_(hwModel),
      mesher_ (mesher),
      qTS_(qTS) {

        // on the boundary s_min and s_max the second derivative
        // d²V/dS² is zero and due to Ito's Lemma the variance term
        // in the drift should vanish.
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
            if (   iter.coordinates()[0] == 0
                || iter.coordinates()[0] == layout->dim()[0]-1) {
                varianceValues_[iter.index()] = 0.0;
            }
        }
        volatilityValues_ = Sqrt(2*varianceValues_);
    }
예제 #12
0
    Disposable<Array> UniformGridMesher::locations(Size d) const {
        Array retVal(layout_->size());

        const FdmLinearOpIterator endIter = layout_->end();
        for (FdmLinearOpIterator iter = layout_->begin();
            iter != endIter; ++iter) {
            retVal[iter.index()] = locations_[d][iter.coordinates()[d]];
        }

        return retVal;
    }
예제 #13
0
    Disposable<Array> FdmMesherComposite::locations(Size direction) const {
        Array retVal(layout_->size());

        const FdmLinearOpIterator endIter = layout_->end();
        for (FdmLinearOpIterator iter = layout_->begin();
             iter != endIter; ++iter) {
            retVal[iter.index()] =
                mesher_[direction]->locations()[iter.coordinates()[direction]];
        }

        return retVal;
    }
예제 #14
0
Real FdmLogInnerValue::avgInnerValue(const FdmLinearOpIterator& iter) {

    if (avgInnerValues_.empty()) {
        // calculate caching values
        avgInnerValues_.resize(mesher_->layout()->dim()[direction_]);
        std::deque<bool> initialized(avgInnerValues_.size(), false);

        const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout();
        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
                ++iter) {
            const Size xn = iter.coordinates()[direction_];
            if (!initialized[xn]) {
                initialized[xn]     = true;
                avgInnerValues_[xn] = avgInnerValueCalc(iter);
            }
        }
    }

    return avgInnerValues_[iter.coordinates()[direction_]];
}
예제 #15
0
    Fdm2DimSolver::Fdm2DimSolver(
                             const FdmSolverDesc& solverDesc,
                             const FdmSchemeDesc& schemeDesc,
                             const boost::shared_ptr<FdmLinearOpComposite>& op)
    : solverDesc_(solverDesc),
      schemeDesc_(schemeDesc),
      op_(op),
      thetaCondition_(new FdmSnapshotCondition(
        0.99*std::min(1.0/365.0,
           solverDesc.condition->stoppingTimes().empty()
                    ? solverDesc.maturity
                    : solverDesc.condition->stoppingTimes().front()))),
      conditions_(FdmStepConditionComposite::joinConditions(thetaCondition_,
                                                         solverDesc.condition)),
      initialValues_(solverDesc.mesher->layout()->size()),
      resultValues_ (solverDesc.mesher->layout()->dim()[1],
                     solverDesc.mesher->layout()->dim()[0]) {

        const boost::shared_ptr<FdmMesher> mesher = solverDesc.mesher;
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();

        x_.reserve(layout->dim()[0]);
        y_.reserve(layout->dim()[1]);

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
             ++iter) {
            initialValues_[iter.index()]
                 = solverDesc_.calculator->avgInnerValue(iter,
                                                         solverDesc.maturity);

            if (!iter.coordinates()[1]) {
                x_.push_back(mesher->location(iter, 0));
            }
            if (!iter.coordinates()[0]) {
                y_.push_back(mesher->location(iter, 1));
            }
        }
    }
예제 #16
0
    Real FdmVPPStepCondition::evolve(
                               const FdmLinearOpIterator& iter, Time t) const {

        const Size state = iter.coordinates()[stateDirection_];

        if (stateEvolveFcts_[state].empty()) {
            return 0.0;
        }
        else {
            const Real sparkSpread = sparkSpreadPrice_->innerValue(iter, t);
            return stateEvolveFcts_[state](sparkSpread);
        }
    }
예제 #17
0
    Disposable<Array>
    TripleBandLinearOp::solve_splitting(const Array& r, Real a, Real b) const {
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
        QL_REQUIRE(r.size() == layout->size(), "inconsistent size of rhs");

#ifdef QL_EXTRA_SAFETY_CHECKS
        for (FdmLinearOpIterator iter = layout->begin();
             iter!=layout->end(); ++iter) {
            const std::vector<Size>& coordinates = iter.coordinates();
            QL_REQUIRE(   coordinates[direction_] != 0
                       || lower_[iter.index()] == 0,"removing non zero entry!");
            QL_REQUIRE(   coordinates[direction_] != layout->dim()[direction_]-1
                       || upper_[iter.index()] == 0,"removing non zero entry!");
        }
#endif

        Array retVal(r.size()), tmp(r.size());

        const Real* lptr = lower_.get();
        const Real* dptr = diag_.get();
        const Real* uptr = upper_.get();

        // Thomson algorithm to solve a tridiagonal system.
        // Example code taken from Tridiagonalopertor and
        // changed to fit for the triple band operator.
        Size rim1 = reverseIndex_[0];
        Real bet=1.0/(a*dptr[rim1]+b);
        QL_REQUIRE(bet != 0.0, "division by zero");
        retVal[reverseIndex_[0]] = r[rim1]*bet;

        for (Size j=1; j<=layout->size()-1; j++){
            const Size ri = reverseIndex_[j];
            tmp[j] = a*uptr[rim1]*bet;

            bet=b+a*(dptr[ri]-tmp[j]*lptr[ri]);
            QL_ENSURE(bet != 0.0, "division by zero");
            bet=1.0/bet;

            retVal[ri] = (r[ri]-a*lptr[ri]*retVal[rim1])*bet;
            rim1 = ri;
        }
        // cannot be j>=0 with Size j
        for (Size j=layout->size()-2; j>0; --j)
            retVal[reverseIndex_[j]] -= tmp[j+1]*retVal[reverseIndex_[j+1]];
        retVal[reverseIndex_[0]] -= tmp[1]*retVal[reverseIndex_[1]];

        return retVal;
    }
예제 #18
0
    template <Size N> inline
    FdmNdimSolver<N>::FdmNdimSolver(
                        const FdmSolverDesc& solverDesc,
                        const FdmSchemeDesc& schemeDesc,
                        const boost::shared_ptr<FdmLinearOpComposite>& op)
    : solverDesc_(solverDesc),
      schemeDesc_(schemeDesc),
      op_(op),
      thetaCondition_(new FdmSnapshotCondition(
        0.99*std::min(1.0/365.0,
                solverDesc.condition->stoppingTimes().empty()
                ? solverDesc.maturity :
                  solverDesc.condition->stoppingTimes().front()))),
      conditions_(FdmStepConditionComposite::joinConditions(thetaCondition_,
                                                        solverDesc.condition)),
      x_            (solverDesc.mesher->layout()->dim().size()),
      initialValues_(solverDesc.mesher->layout()->size()),
      extrapolation_(std::vector<bool>(N, true)) {

        const boost::shared_ptr<FdmMesher> mesher = solverDesc.mesher;
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();

        QL_REQUIRE(layout->dim().size() == N, "solver dim " << N
                    << "does not fit to layout dim " << layout->size());

        for (Size i=0; i < N; ++i) {
            x_[i].reserve(layout->dim()[i]);
        }

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
             ++iter) {

            initialValues_[iter.index()] = solverDesc_.calculator
                                ->avgInnerValue(iter, solverDesc.maturity);

            const std::vector<Size>& c = iter.coordinates();
            for (Size i=0; i < N; ++i) {
                if (!(std::accumulate(c.begin(), c.end(), 0)-c[i])) {
                    x_[i].push_back(mesher->location(iter, i));
                }
            }
        }

        f_ = boost::shared_ptr<data_table>(new data_table(x_));
    }
예제 #19
0
Disposable<Array> FdmExtOUJumpOp::integro(const Array& r) const {
    Array integral(r.size());
    const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
    const Size extraDims=layout->size()/(layout->dim()[0]*layout->dim()[1]);

    std::vector<Array>  y(extraDims, Array(layout->dim()[1]));
    std::vector<Matrix> f(extraDims,
                          Matrix(layout->dim()[1], layout->dim()[0]));

    const FdmLinearOpIterator endIter = layout->end();
    for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
        const Size i = iter.coordinates()[0];
        const Size j = iter.coordinates()[1];
        const Size k = iter.index() / (layout->dim()[0]*layout->dim()[1]);

        y[k][j]    = mesher_->location(iter, 1);
        f[k][j][i] = r[iter.index()];
    }
    std::vector<std::vector<boost::shared_ptr<LinearInterpolation> > >
    interpl(extraDims, std::vector<
            boost::shared_ptr<LinearInterpolation> >(f[0].columns()));

    for (Size k=0; k < extraDims; ++k) {
        for (Size i=0; i < f[k].columns(); ++i) {
            interpl[k][i] = boost::shared_ptr<LinearInterpolation>(
                                new LinearInterpolation(y[k].begin(), y[k].end(),
                                        f[k].column_begin(i)));
        }
    }

    const Real eta = process_->eta();

    for (FdmLinearOpIterator iter=layout->begin(); iter!=endIter; ++iter) {
        const Size i = iter.coordinates()[0];
        const Size j = iter.coordinates()[1];
        const Size k = iter.index() / (layout->dim()[0]*layout->dim()[1]);

        integral[iter.index()] = gaussLaguerreIntegration_(
                                     IntegroIntegrand(interpl[k][i], bcSet_, y[k][j], eta));
    }

    return process_->jumpIntensity()*(integral-r);
}
예제 #20
0
    // smart but sometimes too slow
    Disposable<FdmLinearOpIterator> FdmLinearOpLayout::iter_neighbourhood(
        const FdmLinearOpIterator& iterator, Size i, Integer offset) const {

        std::vector<Size> coordinates = iterator.coordinates();

        Integer coorOffset = Integer(coordinates[i])+offset;
        if (coorOffset < 0) {
            coorOffset=-coorOffset;
        }
        else if (Size(coorOffset) >= dim_[i]) {
            coorOffset = 2*(dim_[i]-1) - coorOffset;
        }
        coordinates[i] = Size(coorOffset);

        FdmLinearOpIterator retVal(dim_, coordinates,
                                   index(coordinates));

        return retVal;
    }
예제 #21
0
    template <Size N> inline
    Real FdmNdimSolver<N>::thetaAt(const std::vector<Real>& x) const {
        QL_REQUIRE(conditions_->stoppingTimes().front() > 0.0,
                   "stopping time at zero-> can't calculate theta");
        calculate();
        const Array& rhs = thetaCondition_->getValues();
        const boost::shared_ptr<FdmLinearOpLayout> layout
                                            = solverDesc_.mesher->layout();

        data_table f(x_);

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
             ++iter) {
            setValue(f, iter.coordinates(), rhs[iter.index()]);
        }

        return (MultiCubicSpline<N>(x_, f)(x)
                        - interpolateAt(x)) / thetaCondition_->getTime();
    }
예제 #22
0
    template <Size N> inline
    void FdmNdimSolver<N>::performCalculations() const {
        Array rhs(initialValues_.size());
        std::copy(initialValues_.begin(), initialValues_.end(), rhs.begin());

        FdmBackwardSolver(op_, solverDesc_.bcSet, conditions_, schemeDesc_)
                 .rollback(rhs, solverDesc_.maturity, 0.0,
                           solverDesc_.timeSteps, solverDesc_.dampingSteps);

        const boost::shared_ptr<FdmLinearOpLayout> layout
                                               = solverDesc_.mesher->layout();

        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
             ++iter) {
            setValue(*f_, iter.coordinates(), rhs[iter.index()]);
        }

        interp_ = boost::shared_ptr<MultiCubicSpline<N> >(
            new MultiCubicSpline<N>(x_, *f_, extrapolation_));
    }
예제 #23
0
    Disposable<Array> FdmBatesOp::integro(const Array& r) const {
        const shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
        
        QL_REQUIRE(layout->dim().size() == 2, "invalid layout dimension");

        Array x(layout->dim()[0]);
        Matrix f(layout->dim()[1], layout->dim()[0]);
        
        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
            const Size i = iter.coordinates()[0];
            const Size j = iter.coordinates()[1];
            
            x[i]    = mesher_->location(iter, 0);
            f[j][i] = r[iter.index()];
            
        }
        std::vector<shared_ptr<LinearInterpolation> > interpl(f.rows());
        for (Size i=0; i < f.rows(); ++i) {
            interpl[i] = shared_ptr<LinearInterpolation>(
                new LinearInterpolation(x.begin(), x.end(), f.row_begin(i)));
        }
        
        Array integral(r.size());
        for (FdmLinearOpIterator iter=layout->begin(); iter!=endIter; ++iter) {
            const Size i = iter.coordinates()[0];
            const Size j = iter.coordinates()[1];

            integral[iter.index()] = M_1_SQRTPI* 
                gaussHermiteIntegration_(
                      IntegroIntegrand(interpl[j], bcSet_, x[i], delta_, nu_));
        }

        return lambda_*(integral-r);
    }
예제 #24
0
    FdmDirichletBoundary::FdmDirichletBoundary(
                            const boost::shared_ptr<FdmMesher>& mesher,
                            Real valueOnBoundary, Size direction,
                            FdmDirichletBoundary::Side side)
    : side_(side),
      valueOnBoundary_(valueOnBoundary) {
                                
        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
                                
        std::vector<Size> newDim(layout->dim());
        newDim[direction] = 1;
        const Size hyperSize = std::accumulate(newDim.begin(), newDim.end(),
                                               Size(1), std::multiplies<Size>());
        indicies_.resize(hyperSize);

        Size i=0;
        const FdmLinearOpIterator endIter = layout->end();
        for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
            if (   (side == Lower && iter.coordinates()[direction] == 0)
                || (side == Upper && iter.coordinates()[direction] 
                                            == layout->dim()[direction]-1)) {

                QL_REQUIRE(hyperSize > i, "index missmatch");
                indicies_[i++] = iter.index();
            }
        }
        
        if (side_ == Lower) {
            xExtreme_ = mesher->locations(direction)[0];
        }
        else if (side_ == Upper) {
            xExtreme_ 
                = mesher->locations(direction)[layout->dim()[direction]-1];
        }
    }
예제 #25
0
 Real FdmMesherComposite::location(const FdmLinearOpIterator& iter,
                                   Size direction) const {
     return mesher_[direction]->location(iter.coordinates()[direction]);
 }
    SecondOrderMixedDerivativeOp::SecondOrderMixedDerivativeOp(
        Size d0, Size d1,
        const boost::shared_ptr<FdmMesher>& mesher)
    : NinePointLinearOp(d0, d1, mesher) {

        const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout();
        const FdmLinearOpIterator endIter = layout->end();

        for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) {
            const Size i = iter.index();
            const Real hm_d0 = mesher->dminus(iter, d0_);
            const Real hp_d0 = mesher->dplus(iter, d0_);
            const Real hm_d1 = mesher->dminus(iter, d1_);
            const Real hp_d1 = mesher->dplus(iter, d1_);

            const Real zetam1 = hm_d0*(hm_d0+hp_d0);
            const Real zeta0  = hm_d0*hp_d0;
            const Real zetap1 = hp_d0*(hm_d0+hp_d0);
            const Real phim1  = hm_d1*(hm_d1+hp_d1);
            const Real phi0   = hm_d1*hp_d1;
            const Real phip1  = hp_d1*(hm_d1+hp_d1);

            const Size c0 = iter.coordinates()[d0_];
            const Size c1 = iter.coordinates()[d1_];
            if (c0 == 0 && c1 == 0) {
                // lower left corner
                a00_[i] = a01_[i] = a02_[i] = a10_[i] = a20_[i] = 0.0;
                a21_[i] = a12_[i] = -(a11_[i] = a22_[i] = 1.0/(hp_d0*hp_d1));
            }
            else if (c0 == layout->dim()[d0_]-1 && c1 == 0) {
                // upper left corner
                a22_[i] = a21_[i] = a20_[i] = a10_[i] = a00_[i] = 0.0;
                a11_[i] = a02_[i] = -(a01_[i] = a12_[i] = 1.0/(hm_d0*hp_d1));
            }
            else if (c0 == 0 && c1 == layout->dim()[d1_]-1) {
                // lower right corner
                a00_[i] = a01_[i] = a02_[i] = a12_[i] = a22_[i] = 0.0;
                a20_[i] = a11_[i] = -(a10_[i] = a21_[i] = 1.0/(hp_d0*hm_d1));
            }
            else if (c0 == layout->dim()[d0_]-1 && c1 == layout->dim()[d1_]-1) {
                // upper right corner
                a20_[i] = a21_[i] = a22_[i] = a12_[i] = a02_[i] = 0.0;
                a10_[i] = a01_[i] = -(a00_[i] = a11_[i] = 1.0/(hm_d0*hm_d1));
            }
            else if (c0 == 0) {
                // lower side
                a00_[i] = a01_[i] = a02_[i] = 0.0;

                a20_[i] = -(a10_[i] = hp_d1/(hp_d0*phim1));
                a11_[i] = -(a21_[i] = (hp_d1-hm_d1)/(hp_d0*phi0));
                a12_[i] = -(a22_[i] = hm_d1/(hp_d0*phip1));
            }
            else if (c0 == layout->dim()[d0_]-1) {
                // upper side
                a20_[i] = a21_[i] = a22_[i] = 0.0;

                a10_[i] = -(a00_[i] = hp_d1/(hm_d0*phim1));
                a01_[i] = -(a11_[i] = (hp_d1-hm_d1)/(hm_d0*phi0));
                a02_[i] = -(a12_[i] = hm_d1/(hm_d0*phip1));
            }
            else if (c1 == 0) {
                // left side
                a00_[i] = a10_[i] = a20_[i] = 0.0;

                a02_[i] = -(a01_[i] = hp_d0/(zetam1*hp_d1));
                a11_[i] = -(a12_[i] = (hp_d0-hm_d0)/(zeta0*hp_d1));
                a21_[i] = -(a22_[i] = hm_d0/(zetap1*hp_d1));
            }
            else if (c1 == layout->dim()[d1_]-1) {
                // right side
                a22_[i] = a12_[i] = a02_[i] = 0.0;

                a01_[i] = -(a00_[i] = hp_d0/(zetam1*hm_d1));
                a10_[i] = -(a11_[i] = (hp_d0-hm_d0)/(zeta0*hm_d1));
                a20_[i] = -(a21_[i] = hm_d0/(zetap1*hm_d1));
            }
            else {
                a00_[i] =  hp_d0*hp_d1/(zetam1*phim1);
                a10_[i] = -(hp_d0-hm_d0)*hp_d1/(zeta0*phim1);
                a20_[i] = -hm_d0*hp_d1/(zetap1*phim1);
                a01_[i] = -hp_d0*(hp_d1-hm_d1)/(zetam1*phi0);
                a11_[i] = (hp_d0-hm_d0)*(hp_d1-hm_d1)/(zeta0*phi0);
                a21_[i] =  hm_d0*(hp_d1-hm_d1)/(zetap1*phi0);
                a02_[i] = -hp_d0*hm_d1/(zetam1*phip1);
                a12_[i] =  hm_d1*(hp_d0-hm_d0)/(zeta0*phip1);
                a22_[i] =  hm_d0*hm_d1/(zetap1*phip1);
            }
        }
    }
예제 #27
0
FdmExtOUJumpOp::FdmExtOUJumpOp(
    const boost::shared_ptr<FdmMesher>& mesher,
    const boost::shared_ptr<ExtOUWithJumpsProcess>& process,
    const boost::shared_ptr<YieldTermStructure>& rTS,
    const FdmBoundaryConditionSet& bcSet,
    Size integroIntegrationOrder)
    : mesher_ (mesher),
      process_(process),
      rTS_    (rTS),
      bcSet_  (bcSet),
      gaussLaguerreIntegration_(integroIntegrationOrder),
      x_      (mesher->locations(0)),
      ouOp_   (new FdmExtendedOrnsteinUhlenbackOp(
                   mesher,
                   process->getExtendedOrnsteinUhlenbeckProcess(), rTS, bcSet)),
      dyMap_  (FirstDerivativeOp(1, mesher)
               .mult(-process->beta()*mesher->locations(1)))
{
#if !defined(QL_NO_UBLAS_SUPPORT)
    const Real eta     = process_->eta();
    const Real lambda  = process_->jumpIntensity();

    const Array yInt   = gaussLaguerreIntegration_.x();
    const Array weights= gaussLaguerreIntegration_.weights();

    integroPart_ = SparseMatrix(mesher_->layout()->size(),
                                mesher_->layout()->size());

    const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout();
    const FdmLinearOpIterator endIter = layout->end();

    Array yLoc(mesher_->layout()->dim()[1]);
    for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {
        yLoc[iter.coordinates()[1]] = mesher_->location(iter, 1);
    }

    for (FdmLinearOpIterator iter = layout->begin(); iter != endIter;
            ++iter) {

        const Size diag = iter.index();
        integroPart_(diag, diag) -= lambda;

        const Real y = mesher_->location(iter, 1);
        const Integer yIndex = iter.coordinates()[1];

        for (Size i=0; i < yInt.size(); ++i) {
            const Real weight = std::exp(-yInt[i])*weights[i];

            const Real ys = y + yInt[i]/eta;
            const Integer l = (ys > yLoc.back()) ? yLoc.size()-2
                              : std::upper_bound(yLoc.begin(),
                                                 yLoc.end()-1, ys) - yLoc.begin()-1;

            const Real s = (ys-yLoc[l])/(yLoc[l+1]-yLoc[l]);
            integroPart_(diag, layout->neighbourhood(iter, 1, l-yIndex))
            += weight*lambda*(1-s);
            integroPart_(diag, layout->neighbourhood(iter, 1, l+1-yIndex))
            += weight*lambda*s;
        }
    }
#endif
}