/* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* Copyright (C) 2006 Klaus Spanderen This file is part of QuantLib, a free-software/open-source library for financial quantitative analysts and developers - http://quantlib.org/ QuantLib is free software: you can redistribute it and/or modify it under the terms of the QuantLib license. You should have received a copy of the license along with this program; if not, please email . The license is also available online at . This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the license for more details. */ /*! \file lsmbasissystem.cpp \brief utility classes for longstaff schwartz early exercise Monte Carlo */ #include #include #include #include #include #include #include #include using boost::bind; namespace QuantLib { namespace { class MonomialFct : public std::unary_function { public: MonomialFct(Size order) : order_(order) {} inline Real operator()(const Real x) const { Real ret = 1.0; for (Size i=0; i > LsmBasisSystem::pathBasisSystem(Size order, PolynomType polynomType) { std::vector > ret; for (Size i=0; i<=order; ++i) { switch (polynomType) { case Monomial: ret.push_back(MonomialFct(i)); break; case Laguerre: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussLaguerrePolynomial(), i, _1)); break; case Hermite: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussHermitePolynomial(), i, _1)); break; case Hyperbolic: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussHyperbolicPolynomial(), i, _1)); break; case Legendre: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussLegendrePolynomial(), i, _1)); break; case Chebyshev: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussChebyshevPolynomial(), i, _1)); break; case Chebyshev2th: ret.push_back( bind(&GaussianOrthogonalPolynomial::weightedValue, GaussChebyshev2thPolynomial(), i, _1)); break; default: QL_FAIL("unknown regression type"); } } return ret; } std::vector > LsmBasisSystem::multiPathBasisSystem(Size dim, Size order, PolynomType polynomType) { const std::vector > b = pathBasisSystem(order, polynomType); std::vector > ret; ret.push_back(constant(1.0)); for (Size i=1; i<=order; ++i) { const std::vector > a = w(dim, i, polynomType, b); for (std::vector >::const_iterator iter = a.begin(); iter < a.end(); ++iter) { ret.push_back(*iter); } } // remove-o-zap: now remove redundant functions. // usually we do have a lot of them due to the construction schema. // We use a more "hands on" method here. std::deque rm(ret.size(), true); Array x(dim), v(ret.size()); MersenneTwisterUniformRng rng(1234UL); for (Size i=0; i<10; ++i) { Size k; // calculate random x vector for (k=0; k(10*v[k]*QL_EPSILON), v[k], _1) ) == v.begin() + k) { // don't remove this item, it's unique! rm[k] = false; } } } std::vector >::iterator iter = ret.begin(); for (Size i=0; i < rm.size(); ++i) { if (rm[i]) { iter = ret.erase(iter); } else { ++iter; } } return ret; } std::vector > LsmBasisSystem::w(Size dim, Size order, PolynomType polynomType, const std::vector > & b) { std::vector > ret; for (Size i=order; i>=1; --i) { const std::vector > left = w(dim, order-i, polynomType, b); for (Size j=0; j a = bind(b[i], bind(f_workaround, _1, j)); if (i == order) { ret.push_back(a); } else { // add linear combinations for (Size j=0; j