public HybridAssetLIBORModelMonteCarloSimulationInterface getHybridAssetLIBORModel(
			final LIBORModelMonteCarloSimulationInterface baseModel,
			final BrownianMotionInterface brownianMotion,
			final double[] initialValues,
			final double riskFreeRate,
			final double[][] correlations,
			final double[] maturities,
			final double[] strikes,
			final double[] volatilities,
			final DiscountCurveInterface discountCurve) throws CalculationException {

		OptimizerInterface optimizer = new LevenbergMarquardt(volatilities /*initialParameters*/, volatilities /*targetValues*/, 100 /*maxIteration*/, 1 /*numberOfThreads*/) {
			private static final long serialVersionUID = -9199565564991442848L;

			@Override
			public void setValues(double[] parameters, double[] values) throws SolverException {
				AssetModelMonteCarloSimulationInterface model = new MonteCarloMultiAssetBlackScholesModel(brownianMotion, initialValues, riskFreeRate, parameters, correlations);
				HybridAssetLIBORModelMonteCarloSimulation hybridModel = new HybridAssetLIBORModelMonteCarloSimulation(baseModel, model);

				try {
					for(int assetIndex=0; assetIndex<values.length; assetIndex++) {
						double df = hybridModel.getNumeraire(maturities[assetIndex]).invert().getAverage();
						double spot = hybridModel.getAssetValue(0.0, assetIndex).getAverage();
						EuropeanOption option = new EuropeanOption(maturities[assetIndex], strikes[assetIndex], assetIndex);
						double valueOptoin = option.getValue(hybridModel);
						double impliedVol = AnalyticFormulas.blackScholesOptionImpliedVolatility(spot/df, maturities[assetIndex]/*optionMaturity*/, strikes[assetIndex]/*optionStrike*/, df /*payoffUnit*/, valueOptoin);
						values[assetIndex] = impliedVol;
					}
				} catch (CalculationException e) {
					throw new SolverException(e);
				}
			}
		};

		try {
			optimizer.run();
		} catch (SolverException e) {
			if(e.getCause() instanceof CalculationException) {
				throw (CalculationException)e.getCause();
			} else {
				throw new CalculationException(e);
			}
		}

		AssetModelMonteCarloSimulationInterface model = new MonteCarloMultiAssetBlackScholesModel(brownianMotion, initialValues, riskFreeRate, optimizer.getBestFitParameters(), correlations);

		/*
		 * Test calibration
		 */
		HybridAssetLIBORModelMonteCarloSimulation hybridModelWithoutDiscountAdjustment = new HybridAssetLIBORModelMonteCarloSimulation(baseModel, model, null);
		for(int assetIndex=0; assetIndex<volatilities.length; assetIndex++) {
			double df = hybridModelWithoutDiscountAdjustment.getNumeraire(maturities[assetIndex]).invert().getAverage();
			double spot = hybridModelWithoutDiscountAdjustment.getAssetValue(0.0, assetIndex).getAverage();
			EuropeanOption option = new EuropeanOption(maturities[assetIndex], strikes[assetIndex], assetIndex);
			double valueOptoin = option.getValue(hybridModelWithoutDiscountAdjustment);
			double impliedVol = AnalyticFormulas.blackScholesOptionImpliedVolatility(spot/df, maturities[assetIndex]/*optionMaturity*/, strikes[assetIndex]/*optionStrike*/, df /*payoffUnit*/, valueOptoin);
			if(Math.abs(impliedVol - volatilities[assetIndex]) > 0.01) {
				throw new CalculationException("Calibration failed");
			}
		}

		/*
		 * Construct model with discounting (options will then use the discounting spread adjustment).
		 */
		HybridAssetLIBORModelMonteCarloSimulation hybridModel = new HybridAssetLIBORModelMonteCarloSimulation(baseModel, model, discountCurve);
		return hybridModel;
	}
public HybridAssetLIBORModelMonteCarloSimulationInterface getHybridAssetLIBORModel ( final LIBORModelMonteCarloSimulationInterface baseModel , final BrownianMotionInterface brownianMotion , final double [ ] initialValues , final double riskFreeRate , final double [ ] [ ] correlations , final double [ ] maturities , final double [ ] strikes , final double [ ] volatilities , final DiscountCurveInterface discountCurve ) throws CalculationException { OptimizerInterface optimizer = new LevenbergMarquardt ( volatilities , volatilities , 100 , 1 ) { private static final long serialVersionUID = - 9199565564991442848L ; @ Override public void setValues ( double [ ] parameters , double [ ] values ) throws SolverException { AssetModelMonteCarloSimulationInterface model = new MonteCarloMultiAssetBlackScholesModel ( brownianMotion , initialValues , riskFreeRate , parameters , correlations ) ; HybridAssetLIBORModelMonteCarloSimulation hybridModel = new HybridAssetLIBORModelMonteCarloSimulation ( baseModel , model ) ; try { for ( int assetIndex = 0 ; assetIndex < values . length ; assetIndex ++ ) { double df = hybridModel . getNumeraire ( maturities [ assetIndex ] ) . invert ( ) . getAverage ( ) ; double spot = hybridModel . getAssetValue ( 0.0 , assetIndex ) . getAverage ( ) ; EuropeanOption option = new EuropeanOption ( maturities [ assetIndex ] , strikes [ assetIndex ] , assetIndex ) ; double valueOptoin = option . getValue ( hybridModel ) ; double impliedVol = AnalyticFormulas . blackScholesOptionImpliedVolatility ( spot / df , maturities [ assetIndex ] , strikes [ assetIndex ] , df , valueOptoin ) ; values [ assetIndex ] = impliedVol ; } } catch ( CalculationException e ) { throw new SolverException ( e ) ; } } } ; try { optimizer . run ( ) ; } catch ( SolverException e ) { if ( e . getCause ( ) instanceof CalculationException ) { throw ( CalculationException ) e . getCause ( ) ; } else { throw new CalculationException ( e ) ; } } AssetModelMonteCarloSimulationInterface model = new MonteCarloMultiAssetBlackScholesModel ( brownianMotion , initialValues , riskFreeRate , optimizer . getBestFitParameters ( ) , correlations ) ; HybridAssetLIBORModelMonteCarloSimulation hybridModelWithoutDiscountAdjustment = new HybridAssetLIBORModelMonteCarloSimulation ( baseModel , model , null ) ; for ( int assetIndex = 0 ; assetIndex < volatilities . length ; assetIndex ++ ) { double df = hybridModelWithoutDiscountAdjustment . getNumeraire ( maturities [ assetIndex ] ) . invert ( ) . getAverage ( ) ; double spot = hybridModelWithoutDiscountAdjustment . getAssetValue ( 0.0 , assetIndex ) . getAverage ( ) ; EuropeanOption option = new EuropeanOption ( maturities [ assetIndex ] , strikes [ assetIndex ] , assetIndex ) ; double valueOptoin = option . getValue ( hybridModelWithoutDiscountAdjustment ) ; double impliedVol = AnalyticFormulas . blackScholesOptionImpliedVolatility ( spot / df , maturities [ assetIndex ] , strikes [ assetIndex ] , df , valueOptoin ) ; if ( Math . abs ( impliedVol - volatilities [ assetIndex ] ) > 0.01 ) { throw new CalculationException ( "Calibration failed" ) ; } } HybridAssetLIBORModelMonteCarloSimulation hybridModel = new HybridAssetLIBORModelMonteCarloSimulation ( baseModel , model , discountCurve ) ; return hybridModel ; }
Create a simple equity hybrid LIBOR market model with a calibration of the equity processes
to a given Black-Scholes implied volatility.

@param baseModel LIBOR model providing the stochastic numeraire.
@param brownianMotion {@link BrownianMotionInterface} for the asset process.
@param initialValues Initial value of the asset process.
@param riskFreeRate Not used (internally used to generate paths, will be later adjusted)
@param correlations Correlation of the asset processes.
@param maturities Maturities of the options (one for each asset process).
@param strikes Strikes of the options (one for each asset process).
@param volatilities Implied volatilities of the options (one for each asset process).
@param discountCurve Discount curve used for the final hybrid model (not used in calibration).
@return An object implementing {@link HybridAssetLIBORModelMonteCarloSimulationInterface}, where each asset process is calibrated to a given option.
@throws CalculationException Thrown if calibration fails.