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; } } }
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_); }
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]; }
FdmHestonFwdOp::FdmHestonFwdOp( const boost::shared_ptr<FdmMesher>& mesher, const boost::shared_ptr<HestonProcess>& process) : 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)), correlation_(new NinePointLinearOp( SecondOrderMixedDerivativeOp(0, 1, mesher) .mult(rho_*sigma_*mesher->locations(1)))) { const boost::shared_ptr<FdmLinearOpLayout> layout = mesher->layout(); // 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]; } } }
void FdmRAStepCondition::applyTo(Array& a, Time t) const { if (std::find(accrualTimes_.begin(), accrualTimes_.end(), t) != accrualTimes_.end()) { boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { a[iter.index()] += calculator_->innerValue(iter, t); } } }
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); }
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; }
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; }
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]; }
void FdmExtendedOrnsteinUhlenbackOp::setTime(Time t1, Time t2) { const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate(); const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); Array drift(layout->size()); for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) { const Size i = iter.index(); drift[i] = process_->drift(0.5*(t1+t2), x_[i]); } mapX_.axpyb(drift, dxMap_, dxxMap_, Array(1, -r)); }
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)); } } }
void Fdm2dBlackScholesOp::setTime(Time t1, Time t2) { opX_.setTime(t1, t2); opY_.setTime(t1, t2); if (localVol1_) { const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); Array vol1(layout->size()), vol2(layout->size()); for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) { const Size i = iter.index(); if (illegalLocalVolOverwrite_ < 0.0) { vol1[i] = localVol1_->localVol(0.5*(t1+t2), x_[i], true); vol2[i] = localVol2_->localVol(0.5*(t1+t2), y_[i], true); } else { try { vol1[i] = localVol1_->localVol(0.5*(t1+t2), x_[i],true); } catch (Error&) { vol1[i] = illegalLocalVolOverwrite_; } try { vol2[i] = localVol2_->localVol(0.5*(t1+t2), y_[i],true); } catch (Error&) { vol2[i] = illegalLocalVolOverwrite_; } } } corrMapT_ = corrMapTemplate_.mult(vol1*vol2); } else { const Real vol1 = p1_ ->blackVolatility()->blackForwardVol(t1, t2, p1_->x0()); const Real vol2 = p2_ ->blackVolatility()->blackForwardVol(t1, t2, p2_->x0()); corrMapT_ = corrMapTemplate_ .mult(Array(mesher_->layout()->size(), vol1*vol2)); } currentForwardRate_ = p1_->riskFreeRate() ->forwardRate(t1, t2, Continuous).rate(); }
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_)); }
Fdm3DimSolver::Fdm3DimSolver( const FdmSolverDesc& solverDesc, const FdmSchemeDesc& schemeDesc, const boost::shared_ptr<FdmLinearOpComposite>& op) : solverDesc_(solverDesc), schemeDesc_(schemeDesc), op_(op), thetaCondition_(boost::make_shared<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()[2], Matrix(solverDesc.mesher->layout()->dim()[1], solverDesc.mesher->layout()->dim()[0])), interpolation_(solverDesc.mesher->layout()->dim()[2]) { 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]); z_.reserve(layout->dim()[2]); 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] && !iter.coordinates()[2]) { x_.push_back(mesher->location(iter, 0)); } if (!iter.coordinates()[0] && !iter.coordinates()[2]) { y_.push_back(mesher->location(iter, 1)); } if (!iter.coordinates()[0] && !iter.coordinates()[1]) { z_.push_back(mesher->location(iter, 2)); } } }
NinePointLinearOp::NinePointLinearOp( Size d0, Size d1, const boost::shared_ptr<FdmMesher>& mesher) : d0_(d0), d1_(d1), i00_(new Size[mesher->layout()->size()]), i10_(new Size[mesher->layout()->size()]), i20_(new Size[mesher->layout()->size()]), i01_(new Size[mesher->layout()->size()]), i21_(new Size[mesher->layout()->size()]), i02_(new Size[mesher->layout()->size()]), i12_(new Size[mesher->layout()->size()]), i22_(new Size[mesher->layout()->size()]), a00_(new Real[mesher->layout()->size()]), a10_(new Real[mesher->layout()->size()]), a20_(new Real[mesher->layout()->size()]), a01_(new Real[mesher->layout()->size()]), a11_(new Real[mesher->layout()->size()]), a21_(new Real[mesher->layout()->size()]), a02_(new Real[mesher->layout()->size()]), a12_(new Real[mesher->layout()->size()]), a22_(new Real[mesher->layout()->size()]), mesher_(mesher) { QL_REQUIRE( d0_ != d1_ && d0_ < mesher->layout()->dim().size() && d1_ < mesher->layout()->dim().size(), "inconsistent derivative directions"); 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(); i10_[i] = layout->neighbourhood(iter, d1_, -1); i01_[i] = layout->neighbourhood(iter, d0_, -1); i21_[i] = layout->neighbourhood(iter, d0_, 1); i12_[i] = layout->neighbourhood(iter, d1_, 1); i00_[i] = layout->neighbourhood(iter, d0_, -1, d1_, -1); i20_[i] = layout->neighbourhood(iter, d0_, 1, d1_, -1); i02_[i] = layout->neighbourhood(iter, d0_, -1, d1_, 1); i22_[i] = layout->neighbourhood(iter, d0_, 1, d1_, 1); } }
void FdmAutocallStepCondition::applyTo(Array& a, Time t) const { if (std::find(exerciseTimes_.begin(), exerciseTimes_.end(), t) != exerciseTimes_.end()) { boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); const Size dims = layout->dim().size(); Array locations(dims); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { for (Size i = 0; i < dims; ++i) locations[i] = std::exp(mesher_->location(iter, i)); if ((*condition_)(locations)) { Real innerValue = calculator_->innerValue(iter, t); a[iter.index()] = innerValue; } } } }
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(); }
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_)); }
void FdmBlackScholesOp::setTime(Time t1, Time t2) { const Rate r = rTS_->forwardRate(t1, t2, Continuous).rate(); const Rate q = qTS_->forwardRate(t1, t2, Continuous).rate(); if (localVol_) { const boost::shared_ptr<FdmLinearOpLayout> layout=mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); Array v(layout->size()); for (FdmLinearOpIterator iter = layout->begin(); iter!=endIter; ++iter) { const Size i = iter.index(); if (illegalLocalVolOverwrite_ < 0.0) { v[i] = square<Real>()( localVol_->localVol(0.5*(t1+t2), x_[i], true)); } else { try { v[i] = square<Real>()( localVol_->localVol(0.5*(t1+t2), x_[i], true)); } catch (Error&) { v[i] = square<Real>()(illegalLocalVolOverwrite_); } } } mapT_.axpyb(r - q - 0.5*v, dxMap_, dxxMap_.mult(0.5*v), Array(1, -r)); } else { const Real v = volTS_->blackForwardVariance(t1, t2, strike_)/(t2-t1); mapT_.axpyb(Array(1, r - q - 0.5*v), dxMap_, dxxMap_.mult(0.5*Array(mesher_->layout()->size(), v)), Array(1, -r)); } }
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]; } }
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); }
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 }
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); } } }
Disposable<Array> FdmHestonGreensFct::get(Time t, Algorithm algorithm) const { const Rate r = process_->riskFreeRate()->forwardRate(0, t, Continuous); const Rate q = process_->dividendYield()->forwardRate(0,t, Continuous); const Real s0 = process_->s0()->value(); const Real v0 = process_->v0(); const Real x0 = std::log(s0) + (r-q-0.5*v0*l0_*l0_)*t; const Real rho = process_->rho(); const Real theta = process_->theta(); const Real kappa = process_->kappa(); const Real sigma = process_->sigma(); const boost::shared_ptr<FdmLinearOpLayout> layout = mesher_->layout(); const FdmLinearOpIterator endIter = layout->end(); Array p(mesher_->layout()->size()); for (FdmLinearOpIterator iter = layout->begin(); iter != endIter; ++iter) { const Real x = mesher_->location(iter, 0); const Real v = (trafoType_ != FdmSquareRootFwdOp::Log) ? mesher_->location(iter, 1) : std::exp(mesher_->location(iter, 1)); Real retVal; switch (algorithm) { case ZeroCorrelation: { const Real sd_x = l0_*std::sqrt(v0*t); const Real p_x = M_1_SQRTPI*M_SQRT1_2/sd_x * std::exp(-0.5*square<Real>()((x - x0)/sd_x)); const Real p_v = SquareRootProcessRNDCalculator( v0, kappa, theta, sigma).pdf(v, t); retVal = p_v*p_x; } break; case SemiAnalytical: retVal = process_->pdf(x, v, t, 1e-4); break; case Gaussian: { const Real sd_x = l0_*std::sqrt(v0*t); const Real sd_v = sigma*std::sqrt(v0*t); const Real z0 = v0 + kappa*(theta - v0)*t; retVal = 1.0/(M_TWOPI*sd_x*sd_v*std::sqrt(1-rho*rho)) *std::exp(-( square<Real>()((x-x0)/sd_x) + square<Real>()((v-z0)/sd_v) - 2*rho*(x-x0)*(v-z0)/(sd_x*sd_v)) /(2*(1-rho*rho)) ); } break; default: QL_FAIL("unknown algorithm"); } switch (trafoType_) { case FdmSquareRootFwdOp::Log: retVal*=v; break; case FdmSquareRootFwdOp::Plain: break; case FdmSquareRootFwdOp::Power: retVal*=std::pow(v, 1.0 - 2*kappa*theta/(sigma*sigma)); break; default: QL_FAIL("unknown transformation type"); } p[iter.index()] = retVal; } return p; }