<commit_before>/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.provider.description.interestrate;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ObjectUtils;

import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.ForwardSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.DoublesPair;

/**
 * Class describing a "market" with discounting, forward, price index and credit curves.
 * The forward rate are computed as the ratio of discount factors stored in {@link YieldAndDiscountCurve}.
 */
public class MulticurveProviderDiscount implements MulticurveProviderInterface {

  /**
   * A map with one (discounting) curve by currency.
   */
  private final Map<Currency, YieldAndDiscountCurve> _discountingCurves;
  /**
   * A map with one (forward) curve by ON index.
   */
  private final Map<IndexON, YieldAndDiscountCurve> _forwardONCurves;
  /**
   * A map with one (forward) curve by Ibor index.
   */
  private final Map<IborIndex, YieldAndDiscountCurve> _forwardIborCurves;
  /**
   * The matrix containing the exchange rates.
   */
  private FXMatrix _fxMatrix;
  /**
   * Map of all curves used in the provider. The order is ???
   */
  private Map<String, YieldAndDiscountCurve> _allCurves;
  /**
   * Map of curve names to currencies.
   */
  private Map<String, Currency> _namesToCurrency;
  /**
   * Map of curve names to ibor indices.
   */
  private Map<String, IborIndex> _namesToIborIndex;
  /**
   * Map of curve names to overnight indices.
   */
  private Map<String, IndexON> _namesToONIndex;

  /**
   * Constructor with empty maps for discounting, forward and price index.
   */
  public MulticurveProviderDiscount() {
    // TODO: Do we need a LinkedHashMap or a more efficient Map could be used?
    _discountingCurves = new LinkedHashMap<>();
    _forwardIborCurves = new LinkedHashMap<>();
    _forwardONCurves = new LinkedHashMap<>();
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = new FXMatrix();
    setAllCurves();
  }

  /**
   * Constructor with empty maps for discounting, forward and price index.
   * @param fxMatrix The FXMatrix, not null
   */
  public MulticurveProviderDiscount(final FXMatrix fxMatrix) {
    ArgumentChecker.notNull(fxMatrix, "FX matrix");
    _discountingCurves = new LinkedHashMap<>();
    _forwardIborCurves = new LinkedHashMap<>();
    _forwardONCurves = new LinkedHashMap<>();
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = fxMatrix;
    setAllCurves();
  }

  /**
   * Constructor from an existing market. The given market maps are used for the new market (the same maps are used, not copied).
   * @param discountingCurves A map with one (discounting) curve by currency, not null
   * @param forwardIborCurves A map with one (forward) curve by Ibor index, not null
   * @param forwardONCurves A map with one (forward) curve by ON index, not null
   * @param fxMatrix The FXMatrix, not null
   */
  public MulticurveProviderDiscount(final Map<Currency, YieldAndDiscountCurve> discountingCurves, final Map<IborIndex, YieldAndDiscountCurve> forwardIborCurves,
      final Map<IndexON, YieldAndDiscountCurve> forwardONCurves, final FXMatrix fxMatrix) {
    ArgumentChecker.notNull(discountingCurves, "discounting curve");
    ArgumentChecker.notNull(forwardIborCurves, "forward ibor curve");
    ArgumentChecker.notNull(forwardONCurves, "forward overnight curve");
    ArgumentChecker.notNull(fxMatrix, "FX matrix");
    _discountingCurves = discountingCurves;
    _forwardIborCurves = forwardIborCurves;
    _forwardONCurves = forwardONCurves;
    _fxMatrix = fxMatrix;
    setAllCurves();
  }

  /**
   * Constructor from exiting maps. The given maps are used for the new market (the same maps are used, not copied).
   * @param market The existing market, not null
   */
  public MulticurveProviderDiscount(final MulticurveProviderDiscount market) {
    ArgumentChecker.notNull(market, "market");
    _discountingCurves = market._discountingCurves;
    _forwardIborCurves = market._forwardIborCurves;
    _forwardONCurves = market._forwardONCurves;
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = market._fxMatrix;
    setAllCurves();
  }

  @Override
  public MulticurveProviderInterface getMulticurveProvider() {
    return this;
  }

  @Override
  public MulticurveProviderDiscount copy() {
    final LinkedHashMap<Currency, YieldAndDiscountCurve> discountingCurves = new LinkedHashMap<>(_discountingCurves);
    final LinkedHashMap<IborIndex, YieldAndDiscountCurve> forwardIborCurves = new LinkedHashMap<>(_forwardIborCurves);
    final LinkedHashMap<IndexON, YieldAndDiscountCurve> forwardONCurves = new LinkedHashMap<>(_forwardONCurves);
    final FXMatrix fxMatrix = new FXMatrix(_fxMatrix);
    return new MulticurveProviderDiscount(discountingCurves, forwardIborCurves, forwardONCurves, fxMatrix);
  }

  /**
   * Adds all curves to a single map containing (curve name, curve) elements.
   */
  private void setAllCurves() {
    _allCurves = new LinkedHashMap<>();
    final Set<Currency> ccySet = _discountingCurves.keySet();
    for (final Currency ccy : ccySet) {
      final String name = _discountingCurves.get(ccy).getName();
      _allCurves.put(name, _discountingCurves.get(ccy));
      if (_namesToCurrency == null) {
        _namesToCurrency = new HashMap<>();
      }
      _namesToCurrency.put(name, ccy);
    }
    final Set<IborIndex> indexSet = _forwardIborCurves.keySet();
    for (final IborIndex index : indexSet) {
      final String name = _forwardIborCurves.get(index).getName();
      _allCurves.put(name, _forwardIborCurves.get(index));
      if (_namesToIborIndex == null) {
        _namesToIborIndex = new HashMap<>();
      }
      _namesToIborIndex.put(name, index);
    }
    final Set<IndexON> indexONSet = _forwardONCurves.keySet();
    for (final IndexON index : indexONSet) {
      final String name = _forwardONCurves.get(index).getName();
      _allCurves.put(name, _forwardONCurves.get(index));
      if (_namesToONIndex == null) {
        _namesToONIndex = new HashMap<>();
      }
      _namesToONIndex.put(name, index);
    }
  }

  @Override
  public double[] parameterSensitivity(final String name, final List<DoublesPair> pointSensitivity) {
    final YieldAndDiscountCurve curve = _allCurves.get(name);
    final int nbParameters = curve.getNumberOfParameters();
    final double[] result = new double[nbParameters];
    if (pointSensitivity != null && pointSensitivity.size() > 0) {
      for (final DoublesPair timeAndS : pointSensitivity) {
        final double[] sensi1Point = curve.getInterestRateParameterSensitivity(timeAndS.getFirst());
        for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
          result[loopparam] += timeAndS.getSecond() * sensi1Point[loopparam];
        }
      }
    }
    return result;
  }

  @Override
  public double[] parameterForwardSensitivity(final String name, final List<ForwardSensitivity> pointSensitivity) {
    final YieldAndDiscountCurve curve = _allCurves.get(name);
    final int nbParameters = curve.getNumberOfParameters();
    final double[] result = new double[nbParameters];
    if (pointSensitivity != null && pointSensitivity.size() > 0) {
      for (final ForwardSensitivity timeAndS : pointSensitivity) {
        final double startTime = timeAndS.getStartTime();
        final double endTime = timeAndS.getEndTime();
        final double accrualFactor = timeAndS.getAccrualFactor();
        final double forwardBar = timeAndS.getValue();
        // Implementation note: only the sensitivity to the forward is available. The sensitivity to the pseudo-discount factors need to be computed.
        final double dfForwardStart = curve.getDiscountFactor(startTime);
        final double dfForwardEnd = curve.getDiscountFactor(endTime);
        final double dFwddyStart = -startTime * dfForwardStart / (dfForwardEnd * accrualFactor);
        final double dFwddyEnd = endTime * dfForwardStart / (dfForwardEnd * accrualFactor);
        final double[] sensiPtStart = curve.getInterestRateParameterSensitivity(startTime);
        final double[] sensiPtEnd = curve.getInterestRateParameterSensitivity(endTime);
        for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
          result[loopparam] += dFwddyStart * sensiPtStart[loopparam] * forwardBar;
          result[loopparam] += dFwddyEnd * sensiPtEnd[loopparam] * forwardBar;
        }
      }
    }
    return result;
  }

  @Override
  public Integer getNumberOfParameters(final String name) {
    return _allCurves.get(name).getNumberOfParameters();
  }

  @Override
  public List<String> getUnderlyingCurvesNames(final String name) {
    return _allCurves.get(name).getUnderlyingCurvesNames();
  }

  /**
   * Gets a named curve.
   * @param name The name
   * @return The curve, null if not found
   */
  public YieldAndDiscountCurve getCurve(final String name) {
    return _allCurves.get(name);
  }

  /**
   * Gets the currency of a named discounting curve. If there is no curve with
   * this name in this provider, returns null.
   * @param name The name of a curve
   * @return The currency, null if not found
   */
  public Currency getCurrencyForName(final String name) {
    return _namesToCurrency.get(name);
  }

  /**
   * Gets the ibor index of a named forward ibor index curve. If there is no
   * curve with this name in this provider, returns null.
   * @param name The name of a curve
   * @return The ibor index, null if not found
   */
  public IborIndex getIborIndexForName(final String name) {
    return _namesToIborIndex.get(name);
  }

  /**
   * Gets the overnight index of a named overnight index curve. If there is
   * no curve with this name in this provider, returns null.
   * @param name The name of a curve
   * @return The overnight index, null if not found
   */
  public IndexON getOvernightIndexForName(final String name) {
    return _namesToONIndex.get(name);
  }

  @Override
  public double getDiscountFactor(final Currency ccy, final Double time) {
    if (_discountingCurves.containsKey(ccy)) {
      return _discountingCurves.get(ccy).getDiscountFactor(time);
    }
    throw new IllegalArgumentException("Currency discounting curve not found: " + ccy);
  }

  @Override
  public String getName(final Currency ccy) {
    if (_discountingCurves.containsKey(ccy)) {
      return _discountingCurves.get(ccy).getName();
    }
    throw new IllegalArgumentException("Currency discounting curve not found: " + ccy);
  }

  @Override
  public Set<Currency> getCurrencies() {
    return _discountingCurves.keySet();
  }

  @Override
  public double getForwardRate(final IborIndex index, final double startTime, final double endTime, final double accrualFactor) {
    if (_forwardIborCurves.containsKey(index)) {
      return (_forwardIborCurves.get(index).getDiscountFactor(startTime) / _forwardIborCurves.get(index).getDiscountFactor(endTime) - 1) / accrualFactor;
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public double getForwardRate(final IborIndex index, final double startTime, final double endTime) {
    ArgumentChecker.isFalse(startTime == endTime, "sart time should be different from end time");
    if (_forwardIborCurves.containsKey(index)) {
      return (_forwardIborCurves.get(index).getDiscountFactor(startTime) / _forwardIborCurves.get(index).getDiscountFactor(endTime) - 1) / (endTime - startTime);
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public String getName(final IborIndex index) {
    if (_forwardIborCurves.containsKey(index)) {
      return _forwardIborCurves.get(index).getName();
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public Set<IborIndex> getIndexesIbor() {
    return _forwardIborCurves.keySet();
  }

  @Override
  public double getForwardRate(final IndexON index, final double startTime, final double endTime, final double accrualFactor) {
    if (_forwardONCurves.containsKey(index)) {
      return (_forwardONCurves.get(index).getDiscountFactor(startTime) / _forwardONCurves.get(index).getDiscountFactor(endTime) - 1) / accrualFactor;
    }
    throw new IllegalArgumentException("Forward ON curve not found: " + index);
  }

  @Override
  public double getForwardRate(final IndexON index, final double startTime, final double endTime) {
    ArgumentChecker.isFalse(startTime == endTime, "sart time should be different from end time");
    if (_forwardIborCurves.containsKey(index)) {
      return (_forwardIborCurves.get(index).getDiscountFactor(startTime) / _forwardIborCurves.get(index).getDiscountFactor(endTime) - 1) / (endTime - startTime);
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public String getName(final IndexON index) {
    if (_forwardONCurves.containsKey(index)) {
      return _forwardONCurves.get(index).getName();
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public Set<IndexON> getIndexesON() {
    return _forwardONCurves.keySet();
  }

  /**<commit_msg>PLAT-5298 - MulticurveProviderDiscount.getForwardRate uses wrong underlying collection<commit_after>/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.provider.description.interestrate;

import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.ObjectUtils;

import com.opengamma.analytics.financial.forex.method.FXMatrix;
import com.opengamma.analytics.financial.instrument.index.IborIndex;
import com.opengamma.analytics.financial.instrument.index.IndexON;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.ForwardSensitivity;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.Currency;
import com.opengamma.util.tuple.DoublesPair;

/**
 * Class describing a "market" with discounting, forward, price index and credit curves.
 * The forward rate are computed as the ratio of discount factors stored in {@link YieldAndDiscountCurve}.
 */
public class MulticurveProviderDiscount implements MulticurveProviderInterface {

  /**
   * A map with one (discounting) curve by currency.
   */
  private final Map<Currency, YieldAndDiscountCurve> _discountingCurves;
  /**
   * A map with one (forward) curve by ON index.
   */
  private final Map<IndexON, YieldAndDiscountCurve> _forwardONCurves;
  /**
   * A map with one (forward) curve by Ibor index.
   */
  private final Map<IborIndex, YieldAndDiscountCurve> _forwardIborCurves;
  /**
   * The matrix containing the exchange rates.
   */
  private FXMatrix _fxMatrix;
  /**
   * Map of all curves used in the provider. The order is ???
   */
  private Map<String, YieldAndDiscountCurve> _allCurves;
  /**
   * Map of curve names to currencies.
   */
  private Map<String, Currency> _namesToCurrency;
  /**
   * Map of curve names to ibor indices.
   */
  private Map<String, IborIndex> _namesToIborIndex;
  /**
   * Map of curve names to overnight indices.
   */
  private Map<String, IndexON> _namesToONIndex;

  /**
   * Constructor with empty maps for discounting, forward and price index.
   */
  public MulticurveProviderDiscount() {
    // TODO: Do we need a LinkedHashMap or a more efficient Map could be used?
    _discountingCurves = new LinkedHashMap<>();
    _forwardIborCurves = new LinkedHashMap<>();
    _forwardONCurves = new LinkedHashMap<>();
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = new FXMatrix();
    setAllCurves();
  }

  /**
   * Constructor with empty maps for discounting, forward and price index.
   * @param fxMatrix The FXMatrix, not null
   */
  public MulticurveProviderDiscount(final FXMatrix fxMatrix) {
    ArgumentChecker.notNull(fxMatrix, "FX matrix");
    _discountingCurves = new LinkedHashMap<>();
    _forwardIborCurves = new LinkedHashMap<>();
    _forwardONCurves = new LinkedHashMap<>();
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = fxMatrix;
    setAllCurves();
  }

  /**
   * Constructor from an existing market. The given market maps are used for the new market (the same maps are used, not copied).
   * @param discountingCurves A map with one (discounting) curve by currency, not null
   * @param forwardIborCurves A map with one (forward) curve by Ibor index, not null
   * @param forwardONCurves A map with one (forward) curve by ON index, not null
   * @param fxMatrix The FXMatrix, not null
   */
  public MulticurveProviderDiscount(final Map<Currency, YieldAndDiscountCurve> discountingCurves, final Map<IborIndex, YieldAndDiscountCurve> forwardIborCurves,
      final Map<IndexON, YieldAndDiscountCurve> forwardONCurves, final FXMatrix fxMatrix) {
    ArgumentChecker.notNull(discountingCurves, "discounting curve");
    ArgumentChecker.notNull(forwardIborCurves, "forward ibor curve");
    ArgumentChecker.notNull(forwardONCurves, "forward overnight curve");
    ArgumentChecker.notNull(fxMatrix, "FX matrix");
    _discountingCurves = discountingCurves;
    _forwardIborCurves = forwardIborCurves;
    _forwardONCurves = forwardONCurves;
    _fxMatrix = fxMatrix;
    setAllCurves();
  }

  /**
   * Constructor from exiting maps. The given maps are used for the new market (the same maps are used, not copied).
   * @param market The existing market, not null
   */
  public MulticurveProviderDiscount(final MulticurveProviderDiscount market) {
    ArgumentChecker.notNull(market, "market");
    _discountingCurves = market._discountingCurves;
    _forwardIborCurves = market._forwardIborCurves;
    _forwardONCurves = market._forwardONCurves;
    _namesToCurrency = new HashMap<>();
    _namesToIborIndex = new HashMap<>();
    _namesToONIndex = new HashMap<>();
    _fxMatrix = market._fxMatrix;
    setAllCurves();
  }

  @Override
  public MulticurveProviderInterface getMulticurveProvider() {
    return this;
  }

  @Override
  public MulticurveProviderDiscount copy() {
    final LinkedHashMap<Currency, YieldAndDiscountCurve> discountingCurves = new LinkedHashMap<>(_discountingCurves);
    final LinkedHashMap<IborIndex, YieldAndDiscountCurve> forwardIborCurves = new LinkedHashMap<>(_forwardIborCurves);
    final LinkedHashMap<IndexON, YieldAndDiscountCurve> forwardONCurves = new LinkedHashMap<>(_forwardONCurves);
    final FXMatrix fxMatrix = new FXMatrix(_fxMatrix);
    return new MulticurveProviderDiscount(discountingCurves, forwardIborCurves, forwardONCurves, fxMatrix);
  }

  /**
   * Adds all curves to a single map containing (curve name, curve) elements.
   */
  private void setAllCurves() {
    _allCurves = new LinkedHashMap<>();
    final Set<Currency> ccySet = _discountingCurves.keySet();
    for (final Currency ccy : ccySet) {
      final String name = _discountingCurves.get(ccy).getName();
      _allCurves.put(name, _discountingCurves.get(ccy));
      if (_namesToCurrency == null) {
        _namesToCurrency = new HashMap<>();
      }
      _namesToCurrency.put(name, ccy);
    }
    final Set<IborIndex> indexSet = _forwardIborCurves.keySet();
    for (final IborIndex index : indexSet) {
      final String name = _forwardIborCurves.get(index).getName();
      _allCurves.put(name, _forwardIborCurves.get(index));
      if (_namesToIborIndex == null) {
        _namesToIborIndex = new HashMap<>();
      }
      _namesToIborIndex.put(name, index);
    }
    final Set<IndexON> indexONSet = _forwardONCurves.keySet();
    for (final IndexON index : indexONSet) {
      final String name = _forwardONCurves.get(index).getName();
      _allCurves.put(name, _forwardONCurves.get(index));
      if (_namesToONIndex == null) {
        _namesToONIndex = new HashMap<>();
      }
      _namesToONIndex.put(name, index);
    }
  }

  @Override
  public double[] parameterSensitivity(final String name, final List<DoublesPair> pointSensitivity) {
    final YieldAndDiscountCurve curve = _allCurves.get(name);
    final int nbParameters = curve.getNumberOfParameters();
    final double[] result = new double[nbParameters];
    if (pointSensitivity != null && pointSensitivity.size() > 0) {
      for (final DoublesPair timeAndS : pointSensitivity) {
        final double[] sensi1Point = curve.getInterestRateParameterSensitivity(timeAndS.getFirst());
        for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
          result[loopparam] += timeAndS.getSecond() * sensi1Point[loopparam];
        }
      }
    }
    return result;
  }

  @Override
  public double[] parameterForwardSensitivity(final String name, final List<ForwardSensitivity> pointSensitivity) {
    final YieldAndDiscountCurve curve = _allCurves.get(name);
    final int nbParameters = curve.getNumberOfParameters();
    final double[] result = new double[nbParameters];
    if (pointSensitivity != null && pointSensitivity.size() > 0) {
      for (final ForwardSensitivity timeAndS : pointSensitivity) {
        final double startTime = timeAndS.getStartTime();
        final double endTime = timeAndS.getEndTime();
        final double accrualFactor = timeAndS.getAccrualFactor();
        final double forwardBar = timeAndS.getValue();
        // Implementation note: only the sensitivity to the forward is available. The sensitivity to the pseudo-discount factors need to be computed.
        final double dfForwardStart = curve.getDiscountFactor(startTime);
        final double dfForwardEnd = curve.getDiscountFactor(endTime);
        final double dFwddyStart = -startTime * dfForwardStart / (dfForwardEnd * accrualFactor);
        final double dFwddyEnd = endTime * dfForwardStart / (dfForwardEnd * accrualFactor);
        final double[] sensiPtStart = curve.getInterestRateParameterSensitivity(startTime);
        final double[] sensiPtEnd = curve.getInterestRateParameterSensitivity(endTime);
        for (int loopparam = 0; loopparam < nbParameters; loopparam++) {
          result[loopparam] += dFwddyStart * sensiPtStart[loopparam] * forwardBar;
          result[loopparam] += dFwddyEnd * sensiPtEnd[loopparam] * forwardBar;
        }
      }
    }
    return result;
  }

  @Override
  public Integer getNumberOfParameters(final String name) {
    return _allCurves.get(name).getNumberOfParameters();
  }

  @Override
  public List<String> getUnderlyingCurvesNames(final String name) {
    return _allCurves.get(name).getUnderlyingCurvesNames();
  }

  /**
   * Gets a named curve.
   * @param name The name
   * @return The curve, null if not found
   */
  public YieldAndDiscountCurve getCurve(final String name) {
    return _allCurves.get(name);
  }

  /**
   * Gets the currency of a named discounting curve. If there is no curve with
   * this name in this provider, returns null.
   * @param name The name of a curve
   * @return The currency, null if not found
   */
  public Currency getCurrencyForName(final String name) {
    return _namesToCurrency.get(name);
  }

  /**
   * Gets the ibor index of a named forward ibor index curve. If there is no
   * curve with this name in this provider, returns null.
   * @param name The name of a curve
   * @return The ibor index, null if not found
   */
  public IborIndex getIborIndexForName(final String name) {
    return _namesToIborIndex.get(name);
  }

  /**
   * Gets the overnight index of a named overnight index curve. If there is
   * no curve with this name in this provider, returns null.
   * @param name The name of a curve
   * @return The overnight index, null if not found
   */
  public IndexON getOvernightIndexForName(final String name) {
    return _namesToONIndex.get(name);
  }

  @Override
  public double getDiscountFactor(final Currency ccy, final Double time) {
    if (_discountingCurves.containsKey(ccy)) {
      return _discountingCurves.get(ccy).getDiscountFactor(time);
    }
    throw new IllegalArgumentException("Currency discounting curve not found: " + ccy);
  }

  @Override
  public String getName(final Currency ccy) {
    if (_discountingCurves.containsKey(ccy)) {
      return _discountingCurves.get(ccy).getName();
    }
    throw new IllegalArgumentException("Currency discounting curve not found: " + ccy);
  }

  @Override
  public Set<Currency> getCurrencies() {
    return _discountingCurves.keySet();
  }

  @Override
  public double getForwardRate(final IborIndex index, final double startTime, final double endTime, final double accrualFactor) {
    if (_forwardIborCurves.containsKey(index)) {
      return (_forwardIborCurves.get(index).getDiscountFactor(startTime) / _forwardIborCurves.get(index).getDiscountFactor(endTime) - 1) / accrualFactor;
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public double getForwardRate(final IborIndex index, final double startTime, final double endTime) {
    ArgumentChecker.isFalse(startTime == endTime, "Start time should be different from end time");
    double accrualFactor = endTime - startTime;
    return getForwardRate(index, startTime, endTime, accrualFactor);
  }

  @Override
  public String getName(final IborIndex index) {
    if (_forwardIborCurves.containsKey(index)) {
      return _forwardIborCurves.get(index).getName();
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public Set<IborIndex> getIndexesIbor() {
    return _forwardIborCurves.keySet();
  }

  @Override
  public double getForwardRate(final IndexON index, final double startTime, final double endTime, final double accrualFactor) {
    if (_forwardONCurves.containsKey(index)) {
      return (_forwardONCurves.get(index).getDiscountFactor(startTime) / _forwardONCurves.get(index).getDiscountFactor(endTime) - 1) / accrualFactor;
    }
    throw new IllegalArgumentException("Forward ON curve not found: " + index);
  }

  @Override
  public double getForwardRate(final IndexON index, final double startTime, final double endTime) {
    ArgumentChecker.isFalse(startTime == endTime, "Start time should be different from end time");
    double accrualFactor = endTime - startTime;
    return getForwardRate(index, startTime, endTime, accrualFactor);
  }

  @Override
  public String getName(final IndexON index) {
    if (_forwardONCurves.containsKey(index)) {
      return _forwardONCurves.get(index).getName();
    }
    throw new IllegalArgumentException("Forward curve not found: " + index);
  }

  @Override
  public Set<IndexON> getIndexesON() {
    return _forwardONCurves.keySet();
  }

  /**
{'fraction_non_alphanumeric': 0.09366559832907198, 'fraction_numerical': 0.0010803413878785696, 'mean_word_length': 4.0435888122048675, 'pattern_counts': {'":': 0, '<': 95, '<?xml version=': 0, '>': 95, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6039875', 'n_tokens_mistral': 8285, 'n_tokens_neox': 8258, 'n_words': 2217}