class EuropeanMonteCarloOptionModel extends MonteCarloOptionModel<OptionDefinition, StandardOptionDataBundle> {

  @Override
  public Function1D<StandardOptionDataBundle, Double> getPricingFunction(final OptionDefinition definition) {
    Validate.notNull(definition, "definition");
    final OptionPayoffFunction<StandardOptionDataBundle> payoffFunction = definition.getPayoffFunction();
    final int steps = getSteps();
    final int n = getN();
    final RandomNumberGenerator randomNumbers = getGenerator();
    final StochasticProcess<OptionDefinition, StandardOptionDataBundle> process = getProcess();
    final Function2D<Double, Double> accumulator = process.getPathAccumulationFunction();
    return new Function1D<StandardOptionDataBundle, Double>() {

      @Override
      public Double evaluate(final StandardOptionDataBundle data) {
        Validate.notNull(data, "data");
        final Function1D<Double, Double> generator = process.getPathGeneratingFunction(definition, data, steps);
        double[] e;
        final double s0 = process.getInitialValue(definition, data);
        double st;
        double sum = 0;
        for (int i = 0; i < n; i++) {
          e = randomNumbers.getVector(steps);
          st = s0;
          for (int j = 0; j < steps; j++) {
            st = accumulator.evaluate(generator.evaluate(e[j]), st);
          }
          sum += payoffFunction.getPayoff(data.withSpot(process.getFinalValue(st)), 0.);
        }
        final double t = definition.getTimeToExpiry(data.getDate());
        final double r = data.getInterestRate(t);
        return Math.exp(-r * t) * sum / n;
      }
    };
  }

  public  EuropeanMonteCarloOptionModel(final int n, final int steps, final StochasticProcess<OptionDefinition, StandardOptionDataBundle> process, final RandomNumberGenerator generator);

}