/** * Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.curve.inflation.generator; import java.util.Arrays; import com.opengamma.analytics.financial.interestrate.InstrumentDerivative; import com.opengamma.analytics.financial.model.interestrate.curve.PriceIndexCurve; import com.opengamma.analytics.financial.model.interestrate.curve.PriceIndexCurveAddPriceIndexSpreadCurve; import com.opengamma.analytics.financial.model.interestrate.curve.PriceIndexCurveSimple; import com.opengamma.analytics.financial.provider.description.inflation.InflationProviderInterface; import com.opengamma.util.ArgumentChecker; /** * Store the details and generate the required curve. The curve is the sum (or difference) of two (or more) curves * (operation on the price index): an existing curve referenced by its name and a new curve. * The generated curve is a PriceIndexCurveAddPriceIndexSpreadCurve. */ public class GeneratorPriceIndexCurveAddPriceIndex extends GeneratorPriceIndexCurve { /** * The array of generators describing the different parts of the spread curve. */ private final GeneratorPriceIndexCurve[] _generators; /** * If true, the rate of all curves, except the first one, will be subtracted from the first one. If false, all the rates are added. */ private final boolean _substract; /** * The number of generators. */ private final int _nbGenerators; /** * Constructor. * @param generators The array of constructors for the component curves. * @param substract If true, the rate of all curves, except the first one, will be subtracted from the first one. If false, all the rates are added. */ public GeneratorPriceIndexCurveAddPriceIndex(GeneratorPriceIndexCurve[] generators, boolean substract) { ArgumentChecker.notNull(generators, "Generators"); _generators = generators; _nbGenerators = generators.length; _substract = substract; } @Override public int getNumberOfParameter() { int nbParam = 0; for (int loopgen = 0; loopgen < _nbGenerators; loopgen++) { nbParam += _generators[loopgen].getNumberOfParameter(); } return nbParam; } @Override public PriceIndexCurve generateCurve(String name, double[] x) { ArgumentChecker.notNull(name, "Name"); ArgumentChecker.isTrue(x.length == getNumberOfParameter(), "Incorrect number of parameters"); PriceIndexCurve[] underlyingCurves = new PriceIndexCurveSimple[_nbGenerators]; int index = 0; for (int loopgen = 0; loopgen < _nbGenerators; loopgen++) { double[] paramCurve = Arrays.copyOfRange(x, index, index + _generators[loopgen].getNumberOfParameter()); index += _generators[loopgen].getNumberOfParameter(); underlyingCurves[loopgen] = _generators[loopgen].generateCurve(name + "-" + loopgen, paramCurve); } return new PriceIndexCurveAddPriceIndexSpreadCurve(name, _substract, underlyingCurves); } @Override public PriceIndexCurve generateCurve(String name, InflationProviderInterface inflation, double[] parameters) { return generateCurve(name, parameters); } /** * All generator but the last should have a known number of parameters. * The number of data corresponding to each known generator is eliminated and only the last part is used to create the final generator version. * If several generators had a unknown number of parameters, it would be unclear which instrument correspond to which generator. * In the last generator, the previous instrument is passed to create the anchor. * @param data The array of instrument used to construct the curve. * @return The final generator. */ @Override public GeneratorPriceIndexCurve finalGenerator(Object data) { ArgumentChecker.isTrue(data instanceof InstrumentDerivative[], "data should be an array of InstrumentDerivative"); InstrumentDerivative[] instruments = (InstrumentDerivative[]) data; GeneratorPriceIndexCurve[] finalGenerator = new GeneratorPriceIndexCurve[_nbGenerators]; int nbDataUsed = 0; int nbParam = 0; for (int loopgen = 0; loopgen < _nbGenerators - 1; loopgen++) { nbParam = _generators[loopgen].getNumberOfParameter(); InstrumentDerivative[] instrumentsLoop = new InstrumentDerivative[nbParam]; System.arraycopy(instruments, nbDataUsed, instrumentsLoop, 0, nbParam); finalGenerator[loopgen] = _generators[loopgen].finalGenerator(instrumentsLoop); nbDataUsed += nbParam; } InstrumentDerivative[] instrumentsLast = new InstrumentDerivative[instruments.length - nbDataUsed + 1]; instrumentsLast[0] = instruments[nbDataUsed - 1]; // Implementation note: The anchor is the previous instrument. System.arraycopy(instruments, nbDataUsed, instrumentsLast, 1, instruments.length - nbDataUsed); finalGenerator[_nbGenerators - 1] = _generators[_nbGenerators - 1].finalGenerator(instrumentsLast); return new GeneratorPriceIndexCurveAddPriceIndex(finalGenerator, _substract); } @Override public double[] initialGuess(double[] rates) { double[] guess = new double[rates.length]; int nbDataUsed = 0; int nbParam = 0; for (int loopgen = 0; loopgen < _nbGenerators; loopgen++) { nbParam = _generators[loopgen].getNumberOfParameter(); double[] tmp = new double[nbParam]; System.arraycopy(rates, nbDataUsed, tmp, 0, nbParam); System.arraycopy(_generators[loopgen].initialGuess(tmp), 0, guess, nbDataUsed, nbParam); nbDataUsed += nbParam; } return guess; } }