ArgumentChecker.notNull(forwardIborMap, "forward ibor map");
ArgumentChecker.notNull(forwardONMap, "forward overnight map");
ArgumentChecker.notNull(calculator, "calculator");
ArgumentChecker.notNull(sensitivityCalculator, "sensitivity calculator");
final int nbUnits = curveBundles.length;
final MulticurveProviderDiscount knownSoFarData = knownData.copy();
final List<InstrumentDerivative> instrumentsSoFar = new ArrayList<>();
final LinkedHashMap<String, GeneratorYDCurve> generatorsSoFar = new LinkedHashMap<>();
final LinkedHashMap<String, Pair<CurveBuildingBlock, DoubleMatrix2D>> unitBundleSoFar = new LinkedHashMap<>();
final List<Double> parametersSoFar = new ArrayList<>();
final LinkedHashMap<String, Pair<Integer, Integer>> unitMap = new LinkedHashMap<>();
int startUnit = 0;
for (int iUnits = 0; iUnits < nbUnits; iUnits++) {
final MultiCurveBundle<GeneratorYDCurve> curveBundle = curveBundles[iUnits];
final int nbCurve = curveBundle.size();
final int[] startCurve = new int[nbCurve]; // First parameter index of the curve in the unit.
final LinkedHashMap<String, GeneratorYDCurve> gen = new LinkedHashMap<>();
final int[] nbIns = new int[curveBundle.getNumberOfInstruments()];
int nbInsUnit = 0; // Number of instruments in the unit.
for (int iCurve = 0; iCurve < nbCurve; iCurve++) {
final SingleCurveBundle<GeneratorYDCurve> singleCurve = curveBundle.getCurveBundle(iCurve);
startCurve[iCurve] = nbInsUnit;
nbIns[iCurve] = singleCurve.size();
nbInsUnit += nbIns[iCurve];
instrumentsSoFar.addAll(Arrays.asList(singleCurve.getDerivatives()));
}
final InstrumentDerivative[] instrumentsUnit = new InstrumentDerivative[nbInsUnit];
final double[] parametersGuess = new double[nbInsUnit];
final InstrumentDerivative[] instrumentsSoFarArray = instrumentsSoFar.toArray(new InstrumentDerivative[instrumentsSoFar.size()]);
for (int iCurve = 0; iCurve < nbCurve; iCurve++) {
final SingleCurveBundle<GeneratorYDCurve> singleCurve = curveBundle.getCurveBundle(iCurve);
final InstrumentDerivative[] derivatives = singleCurve.getDerivatives();
System.arraycopy(derivatives, 0, instrumentsUnit, startCurve[iCurve], nbIns[iCurve]);
System.arraycopy(singleCurve.getStartingPoint(), 0, parametersGuess, startCurve[iCurve], nbIns[iCurve]);
final GeneratorYDCurve tmp = singleCurve.getCurveGenerator().finalGenerator(derivatives);
final String curveName = singleCurve.getCurveName();
gen.put(curveName, tmp);
generatorsSoFar.put(curveName, tmp);
unitMap.put(curveName, new ObjectsPair<>(startUnit + startCurve[iCurve], nbIns[iCurve]));
}
final Pair<MulticurveProviderDiscount, Double[]> unitCal = makeUnit(instrumentsUnit, parametersGuess, knownSoFarData,
discountingMap, forwardIborMap, forwardONMap, gen, calculator, sensitivityCalculator);
parametersSoFar.addAll(Arrays.asList(unitCal.getSecond()));
final DoubleMatrix2D[] mat = makeCurveMatrix(instrumentsSoFarArray, startUnit, nbIns, parametersSoFar.toArray(new Double[parametersSoFar.size()]), knownData, discountingMap,
forwardIborMap, forwardONMap, generatorsSoFar, sensitivityCalculator);
// TODO: should curve matrix be computed only once at the end? To save time
for (int iCurve = 0; iCurve < nbCurve; iCurve++) {
final SingleCurveBundle<GeneratorYDCurve> singleCurve = curveBundle.getCurveBundle(iCurve);
unitBundleSoFar.put(singleCurve.getCurveName(), new ObjectsPair<>(new CurveBuildingBlock(unitMap), mat[iCurve]));
}
knownSoFarData.setAll(unitCal.getFirst());
startUnit = startUnit + nbInsUnit;
}
return new ObjectsPair<>(knownSoFarData, new CurveBuildingBlockBundle(unitBundleSoFar));
}