Real ExponentialJump1dMesher::jumpSizeDistribution(Real x, Time t) const {
     const Real xmin = std::min(x, 1.0e-100);
     
     return GaussLobattoIntegral(1000000, 1e-12)(
         boost::bind(&ExponentialJump1dMesher::jumpSizeDensity, this, _1, t),
         xmin, std::max(x, xmin));
 }
    Real ExtendedOrnsteinUhlenbeckProcess::expectation(
                                          Time t0, Real x0, Time dt) const {
        switch (discretization_) {
          case MidPoint:
            return ouProcess_->expectation(t0, x0, dt)
                    + b_(t0+0.5*dt)*(1.0 - std::exp(-speed_*dt));
            break;
          case Trapezodial:
            {
              const Time t = t0+dt;
              const Time u = t0;
              const Real bt = b_(t);
              const Real bu = b_(u);
              const Real ex = std::exp(-speed_*dt);

              return ouProcess_->expectation(t0, x0, dt)
                    + bt-ex*bu - (bt-bu)/(speed_*dt)*(1-ex);
            }
            break;
          case GaussLobatto:
              return ouProcess_->expectation(t0, x0, dt)
                  + speed_*std::exp(-speed_*(t0+dt))
                  * GaussLobattoIntegral(100000, intEps_)(
                         boost::lambda::bind(b_, boost::lambda::_1)
                        *boost::lambda::bind(std::ptr_fun<Real, Real>(std::exp),
                                          speed_*boost::lambda::_1), t0, t0+dt);
            break;
          default:
            QL_FAIL("unknown discretization scheme");
        }
    }
    Real HestonRNDCalculator::cdf(Real x, Time t) const {
        return GaussLobattoIntegral(
            maxIntegrationIterations_, 0.1*integrationEps_)(
            boost::bind(&CpxPv_Helper::p0,
                CpxPv_Helper(getHestonParams(hestonProcess_), x_t(x,t),t),_1),
            0.0, 1.0)/M_TWOPI + 0.5;

    }
 Real ExponentialJump1dMesher::jumpSizeDistribution(Real x) const {
     const Real a    = jumpIntensity_/beta_;
     const Real xmin = std::min(x, QL_EPSILON);
     const Real gammaValue 
             = std::exp(GammaFunction().logValue(jumpIntensity_/beta_));
     
     const Real lowerEps = 
         (std::pow(xmin, a)/a - std::pow(xmin, a+1)/(a+1))/gammaValue;
     
     return lowerEps + GaussLobattoIntegral(10000, 1e-12)(
         boost::bind(&ExponentialJump1dMesher::jumpSizeDensity, this, _1),
         xmin/eta_, std::max(x, xmin/eta_));
 }
    Real AnalyticPDFHestonEngine::Pv(Real x_t, Time t) const {
        const Hestonp p = { model_->v0(),
                            model_->kappa(),
                            model_->theta(),
                            model_->sigma(),
                            model_->rho() };
        Real xMax = (xMax_ != Null<Real>()) ? xMax_
            : Brent().solve(boost::bind(&zero_pv, p, _1, x_t, t),
                            0.01, 1.0, 1.0);

        return GaussLobattoIntegral(nIterations_, 0.1*eps_)
               (boost::bind(&pv, p, _1, x_t, t), -xMax, xMax)/M_TWOPI;
    }
    void AnalyticPDFHestonEngine::calculate() const {
        // this is an European option pricer
        QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
                   "not an European option");

        const boost::shared_ptr<HestonProcess>& process = model_->process();

        const Time t = process->time(arguments_.exercise->lastDate());

        const Real xMax = 10 * std::sqrt(process->theta()*t);

        results_.value = GaussLobattoIntegral(nIterations_, eps_)
            (boost::bind(&AnalyticPDFHestonEngine::weightedPayoff, this,_1, t),
             -xMax, xMax);
    }
    FdmHestonVarianceMesher::FdmHestonVarianceMesher(
        Size size,
        const boost::shared_ptr<HestonProcess> & process,
        Time maturity, Size tAvgSteps, Real epsilon)
        : Fdm1dMesher(size) {

        std::vector<Real> vGrid(size, 0.0), pGrid(size, 0.0);
        const Real df  = 4*process->theta()*process->kappa()/
                            square<Real>()(process->sigma());
        try {
            std::multiset<std::pair<Real, Real> > grid;
            
            for (Size l=1; l<=tAvgSteps; ++l) {
                const Real t = (maturity*l)/tAvgSteps;
                const Real ncp = 4*process->kappa()*std::exp(-process->kappa()*t)
                    /(square<Real>()(process->sigma())
                    *(1-std::exp(-process->kappa()*t)))*process->v0();
                const Real k = square<Real>()(process->sigma())
                    *(1-std::exp(-process->kappa()*t))/(4*process->kappa());

                const Real qMin = 0.0; // v_min = 0.0;
                const Real qMax = std::max(process->v0(),
                    k*InverseNonCentralChiSquareDistribution(
                                            df, ncp, 1000,  1e-8)(1-epsilon));

                const Real minVStep=(qMax-qMin)/(50*size);
                Real ps,p = 0.0;

                Real vTmp = qMin;
                grid.insert(std::pair<Real, Real>(qMin, epsilon));
                
                for (Size i=1; i < size; ++i) {
                    ps = (1 - epsilon - p)/(size-i);
                    p += ps;
                    const Real tmp = k*InverseNonCentralChiSquareDistribution(
                        df, ncp, 1000, 1e-8)(p);

                    const Real vx = std::max(vTmp+minVStep, tmp);
                    p = NonCentralChiSquareDistribution(df, ncp)(vx/k);
                    vTmp=vx;
                    grid.insert(std::pair<Real, Real>(vx, p));
                }
            }
            QL_REQUIRE(grid.size() == size*tAvgSteps, 
                       "something wrong with the grid size");
            
            std::vector<std::pair<Real, Real> > tp(grid.begin(), grid.end());

            for (Size i=0; i < size; ++i) {
                const Size b = (i*tp.size())/size;
                const Size e = ((i+1)*tp.size())/size;
                for (Size j=b; j < e; ++j) {
                    vGrid[i]+=tp[j].first/(e-b);
                    pGrid[i]+=tp[j].second/(e-b);
                }
            }
        } 
        catch (const Error&) {
            // use default mesh
            const Real vol = process->sigma()*
                std::sqrt(process->theta()/(2*process->kappa()));

            const Real mean = process->theta();
            const Real upperBound = std::max(process->v0()+4*vol, mean+4*vol);
            const Real lowerBound
                = std::max(0.0, std::min(process->v0()-4*vol, mean-4*vol));

            for (Size i=0; i < size; ++i) {
                pGrid[i] = i/(size-1.0);
                vGrid[i] = lowerBound + i*(upperBound-lowerBound)/(size-1.0);
            }
        }

        Real skewHint = ((process->kappa() != 0.0) 
                ? std::max(1.0, process->sigma()/process->kappa()) : 1.0);

        std::sort(pGrid.begin(), pGrid.end());
        volaEstimate_ = GaussLobattoIntegral(100000, 1e-4)(
            boost::function1<Real, Real>(
                compose(std::ptr_fun<Real, Real>(std::sqrt),
                        LinearInterpolation(pGrid.begin(), pGrid.end(),
                        vGrid.begin()))),
            pGrid.front(), pGrid.back())*std::pow(skewHint, 1.5);
        
        const Real v0 = process->v0();
        for (Size i=1; i<vGrid.size(); ++i) {
            if (vGrid[i-1] <= v0 && vGrid[i] >= v0) {
                if (std::fabs(vGrid[i-1] - v0) < std::fabs(vGrid[i] - v0))
                    vGrid[i-1] = v0;
                else
                    vGrid[i] = v0;
            }
        }

        std::copy(vGrid.begin(), vGrid.end(), locations_.begin());

        for (Size i=0; i < size-1; ++i) {
            dminus_[i+1] = dplus_[i] = vGrid[i+1] - vGrid[i];
        }
        dplus_.back() = dminus_.front() = Null<Real>();
    }