SobolBrownianGenerator::SobolBrownianGenerator(
                                        Size factors,
                                        Size steps,
                                        Ordering ordering,
                                        unsigned long seed,
                                        SobolRsg::DirectionIntegers integers)
    : factors_(factors), steps_(steps), ordering_(ordering),
      generator_(SobolRsg(factors*steps, seed, integers),
                 InverseCumulativeNormal()),
      bridge_(steps), lastStep_(0),
      orderedIndices_(factors, std::vector<Size>(steps)),
      bridgedVariates_(factors, std::vector<Real>(steps)) {

        switch (ordering_) {
          case Factors:
            fillByFactor(orderedIndices_, factors_, steps_);
            break;
          case Steps:
            fillByStep(orderedIndices_, factors_, steps_);
            break;
          case Diagonal:
            fillByDiagonal(orderedIndices_, factors_, steps_);
            break;
          default:
            QL_FAIL("unknown ordering");
        }
    }
    FdmBlackScholesMultiStrikeMesher::FdmBlackScholesMultiStrikeMesher(
            Size size,
            const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
            Time maturity, const std::vector<Real>& strikes,
            Real eps, Real scaleFactor,
            const std::pair<Real, Real>& cPoint)
    : Fdm1dMesher(size) {

        const Real spot = process->x0();
        QL_REQUIRE(spot > 0.0, "negative or null underlying given");

        const DiscountFactor d =   process->dividendYield()->discount(maturity)
                                 / process->riskFreeRate()->discount(maturity);
        const Real minStrike= *std::min_element(strikes.begin(), strikes.end());
        const Real maxStrike= *std::max_element(strikes.begin(), strikes.end());
                
        const Real Fmin = spot*spot/maxStrike*d;
        const Real Fmax = spot*spot/minStrike*d;
        
        QL_REQUIRE(Fmin > 0.0, "negative forward given");

        // Set the grid boundaries
        const Real normInvEps = InverseCumulativeNormal()(1-eps);
        const Real sigmaSqrtTmin 
            = process->blackVolatility()->blackVol(maturity, minStrike)
                                                        *std::sqrt(maturity);
        const Real sigmaSqrtTmax 
            = process->blackVolatility()->blackVol(maturity, maxStrike)
                                                        *std::sqrt(maturity);
        
        const Real xMin
            = std::min(0.8*std::log(0.8*spot*spot/maxStrike),
                       std::log(Fmin) - sigmaSqrtTmin*normInvEps*scaleFactor
                                      - sigmaSqrtTmin*sigmaSqrtTmin/2.0);
        const Real xMax
            = std::max(1.2*std::log(0.8*spot*spot/minStrike),
                       std::log(Fmax) + sigmaSqrtTmax*normInvEps*scaleFactor
                                      - sigmaSqrtTmax*sigmaSqrtTmax/2.0);

        boost::shared_ptr<Fdm1dMesher> helper;
        if (   cPoint.first != Null<Real>() 
            && std::log(cPoint.first) >=xMin && std::log(cPoint.first) <=xMax) {
            
            helper = boost::shared_ptr<Fdm1dMesher>(
                new Concentrating1dMesher(xMin, xMax, size, 
                    std::pair<Real,Real>(std::log(cPoint.first),cPoint.second)));
        }
        else {
            helper = boost::shared_ptr<Fdm1dMesher>(
                                        new Uniform1dMesher(xMin, xMax, size));
            
        }

        locations_ = helper->locations();
        for (Size i=0; i < locations_.size(); ++i) {
            dplus_[i]  = helper->dplus(i);
            dminus_[i] = helper->dminus(i);
        }
    }            
void RandomBase::GetGaussian(std::vector<double>& variates)
{
	GetUniforms(variates);

	for (unsigned long i = 0; i < Dimensionality; i++)
	{
		double x = variates[i];
		variates[i] = InverseCumulativeNormal(x);
	}
}
    FdmBlackScholesMesher::FdmBlackScholesMesher(
            Size size,
            const boost::shared_ptr<GeneralizedBlackScholesProcess>& process,
            Time maturity, Real strike,
            Real xMinConstraint, Real xMaxConstraint, 
            Real eps, Real scaleFactor,
            const std::pair<Real, Real>& cPoint)
    : Fdm1dMesher(size) {

        const Real S = process->x0();
        QL_REQUIRE(S > 0.0, "negative or null underlying given");

        // Set the grid boundaries
        const Real normInvEps = InverseCumulativeNormal()(1-eps);
        const Real sigmaSqrtT 
            = process->blackVolatility()->blackVol(maturity, strike)
                                                        *std::sqrt(maturity);
        
        Real xMin = std::log(S) - sigmaSqrtT*normInvEps*scaleFactor;
        Real xMax = std::log(S) + sigmaSqrtT*normInvEps*scaleFactor;
                
        if (xMinConstraint != Null<Real>()) {
            xMin = xMinConstraint;
        }
        if (xMaxConstraint != Null<Real>()) {
            xMax = xMaxConstraint;
        }

        boost::shared_ptr<Fdm1dMesher> helper;
        if (   cPoint.first != Null<Real>() 
            && std::log(cPoint.first) >=xMin && std::log(cPoint.first) <=xMax) {
            
            helper = boost::shared_ptr<Fdm1dMesher>(
                new Concentrating1dMesher(xMin, xMax, size, 
                    std::pair<Real,Real>(std::log(cPoint.first),cPoint.second)));
        }
        else {
            helper = boost::shared_ptr<Fdm1dMesher>(
                                        new Uniform1dMesher(xMin, xMax, size));
            
        }
        
        locations_ = helper->locations();
        for (Size i=0; i < locations_.size(); ++i) {
            dplus_[i]  = helper->dplus(i);
            dminus_[i] = helper->dminus(i);
        }
    }
    void FdBlackScholesAsianEngine::calculate() const {

        QL_REQUIRE(arguments_.exercise->type() == Exercise::European,
                   "European exercise supported only");
        QL_REQUIRE(arguments_.averageType == Average::Arithmetic,
                   "Arithmetic averaging supported only");
        QL_REQUIRE(   arguments_.runningAccumulator == 0
                   || arguments_.pastFixings > 0,
                   "Running average requires at least one past fixing");

        // 1. Mesher
        const ext::shared_ptr<StrikedTypePayoff> payoff =
            ext::dynamic_pointer_cast<StrikedTypePayoff>(arguments_.payoff);
        const Time maturity = process_->time(arguments_.exercise->lastDate());
        const ext::shared_ptr<Fdm1dMesher> equityMesher(
            new FdmBlackScholesMesher(xGrid_, process_, maturity,
                                      payoff->strike()));

        const Real spot = process_->x0();
        QL_REQUIRE(spot > 0.0, "negative or null underlying given");

        const Real avg = (arguments_.runningAccumulator == 0)
                 ? spot : arguments_.runningAccumulator/arguments_.pastFixings;

        const Real normInvEps = InverseCumulativeNormal()(1-0.0001);
        const Real sigmaSqrtT 
            = process_->blackVolatility()->blackVol(maturity, payoff->strike())
                                                        *std::sqrt(maturity);
        const Real r = sigmaSqrtT*normInvEps;

        Real xMin = std::min(std::log(avg)  - 0.25*r, std::log(spot) - 1.5*r);
        Real xMax = std::max(std::log(avg)  + 0.25*r, std::log(spot) + 1.5*r);

        const ext::shared_ptr<Fdm1dMesher> averageMesher(
            new FdmBlackScholesMesher(aGrid_, process_, maturity,
                                      payoff->strike(), xMin, xMax));

        const ext::shared_ptr<FdmMesher> mesher (
            new FdmMesherComposite(equityMesher, averageMesher));

        // 2. Calculator
        ext::shared_ptr<FdmInnerValueCalculator> calculator(
                                new FdmLogInnerValue(payoff, mesher, 1));

        // 3. Step conditions
        std::list<ext::shared_ptr<StepCondition<Array> > > stepConditions;
        std::list<std::vector<Time> > stoppingTimes;

        // 3.1 Arithmetic average step conditions
        std::vector<Time> averageTimes;
        for (Size i=0; i<arguments_.fixingDates.size(); ++i) {
            Time t = process_->time(arguments_.fixingDates[i]);
            QL_REQUIRE(t >= 0, "Fixing dates must not contain past date");
            averageTimes.push_back(t);
        }
        stoppingTimes.push_back(std::vector<Time>(averageTimes));
        stepConditions.push_back(ext::shared_ptr<StepCondition<Array> >(
                new FdmArithmeticAverageCondition(
                        averageTimes, arguments_.runningAccumulator,
                        arguments_.pastFixings, mesher, 0)));

        ext::shared_ptr<FdmStepConditionComposite> conditions(
                new FdmStepConditionComposite(stoppingTimes, stepConditions));

        // 4. Boundary conditions
        const FdmBoundaryConditionSet boundaries;

        // 5. Solver
        FdmSolverDesc solverDesc = { mesher, boundaries, conditions,
                                     calculator, maturity, tGrid_, 0 };
        ext::shared_ptr<FdmSimple2dBSSolver> solver(
              new FdmSimple2dBSSolver(
                              Handle<GeneralizedBlackScholesProcess>(process_),
                              payoff->strike(), solverDesc, schemeDesc_));

        results_.value = solver->valueAt(spot, avg);
        results_.delta = solver->deltaAt(spot, avg, spot*0.01);
        results_.gamma = solver->gammaAt(spot, avg, spot*0.01);
    }
    FdmBlackScholesMesher::FdmBlackScholesMesher(
        Size size,
        const ext::shared_ptr<GeneralizedBlackScholesProcess>& process,
        Time maturity, Real strike,
        Real xMinConstraint, Real xMaxConstraint,
        Real eps, Real scaleFactor,
        const std::pair<Real, Real>& cPoint,
        const DividendSchedule& dividendSchedule)
    : Fdm1dMesher(size) {

        const Real S = process->x0();
        QL_REQUIRE(S > 0.0, "negative or null underlying given");

        std::vector<std::pair<Time, Real> > intermediateSteps;
        for (Size i=0; i < dividendSchedule.size()
            && process->time(dividendSchedule[i]->date()) <= maturity; ++i)
            intermediateSteps.push_back(
                std::make_pair(
                    process->time(dividendSchedule[i]->date()),
                    dividendSchedule[i]->amount()
                ) );

        const Size intermediateTimeSteps = std::max<Size>(2, Size(24.0*maturity));
        for (Size i=0; i < intermediateTimeSteps; ++i)
            intermediateSteps.push_back(
                std::make_pair((i+1)*(maturity/intermediateTimeSteps), 0.0));

        std::sort(intermediateSteps.begin(), intermediateSteps.end());

        const Handle<YieldTermStructure> rTS = process->riskFreeRate();
        const Handle<YieldTermStructure> qTS = process->dividendYield();

        Time lastDivTime = 0.0;
        Real fwd = S, mi = S, ma = S;

        for (Size i=0; i < intermediateSteps.size(); ++i) {
            const Time divTime = intermediateSteps[i].first;
            const Real divAmount = intermediateSteps[i].second;

            fwd = fwd / rTS->discount(divTime) * rTS->discount(lastDivTime)
                      * qTS->discount(divTime) / qTS->discount(lastDivTime);

            mi  = std::min(mi, fwd); ma = std::max(ma, fwd);

            fwd-= divAmount;

            mi  = std::min(mi, fwd); ma = std::max(ma, fwd);

            lastDivTime = divTime;
        }

        // Set the grid boundaries
        const Real normInvEps = InverseCumulativeNormal()(1-eps);
        const Real sigmaSqrtT 
            = process->blackVolatility()->blackVol(maturity, strike)
                                                        *std::sqrt(maturity);
        
        Real xMin = std::log(mi) - sigmaSqrtT*normInvEps*scaleFactor;
        Real xMax = std::log(ma) + sigmaSqrtT*normInvEps*scaleFactor;

        if (xMinConstraint != Null<Real>()) {
            xMin = xMinConstraint;
        }
        if (xMaxConstraint != Null<Real>()) {
            xMax = xMaxConstraint;
        }

        ext::shared_ptr<Fdm1dMesher> helper;
        if (   cPoint.first != Null<Real>() 
            && std::log(cPoint.first) >=xMin && std::log(cPoint.first) <=xMax) {
            
            helper = ext::shared_ptr<Fdm1dMesher>(
                new Concentrating1dMesher(xMin, xMax, size, 
                    std::pair<Real,Real>(std::log(cPoint.first),
                                         cPoint.second)));
        }
        else {
            helper = ext::shared_ptr<Fdm1dMesher>(
                                        new Uniform1dMesher(xMin, xMax, size));
            
        }
        
        locations_ = helper->locations();
        for (Size i=0; i < locations_.size(); ++i) {
            dplus_[i]  = helper->dplus(i);
            dminus_[i] = helper->dminus(i);
        }
    }