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]; }
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; } } }
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; }
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]; } } } }
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]; }
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)); } } }
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; }
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; } }
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_); }
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; }
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_]]; }
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)); } } }
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); } }
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; }
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_)); }
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); }
// 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; }
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_)); }
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); }
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]; } }
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); } } }
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 }