/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.provider.sensitivity.multicurve;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.DoublesPair;
import com.opengamma.util.tuple.Triple;
/**
* Utilities to manipulate present value sensitivities.
* <p>
* This is a thread-safe static utility class.
*/
public class MulticurveSensitivityUtils {
/**
* Restricted constructor.
*/
protected MulticurveSensitivityUtils() {
super();
}
/**
* Clean a map by sorting the times and adding the values at duplicated times.
* @param map The map.
* @return The cleaned map.
*/
public static Map<String, List<DoublesPair>> cleaned(final Map<String, List<DoublesPair>> map) {
//TODO: improve the sorting algorithm.
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : map.entrySet()) {
final List<DoublesPair> list = entry.getValue();
final List<DoublesPair> listClean = new ArrayList<>();
final Set<Double> set = new TreeSet<>();
for (final DoublesPair pair : list) {
set.add(pair.getFirst());
}
for (final Double time : set) {
double sensi = 0;
for (int looplist = 0; looplist < list.size(); looplist++) {
if (Double.doubleToLongBits(list.get(looplist).getFirst()) == Double.doubleToLongBits(time)) {
sensi += list.get(looplist).second;
}
}
listClean.add(DoublesPair.of(time.doubleValue(), sensi));
}
result.put(entry.getKey(), listClean);
}
return result;
}
/**
* Clean a map by sorting the times and adding the values at duplicated times. The total value below the tolerance threshold are removed.
* @param map The map.
* @param tolerance The tolerance.
* @return The cleaned map.
*/
public static Map<String, List<DoublesPair>> cleaned(final Map<String, List<DoublesPair>> map, final double tolerance) {
//TODO: improve the sorting algorithm.
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : map.entrySet()) {
final List<DoublesPair> list = entry.getValue();
final List<DoublesPair> listClean = new ArrayList<>();
final Set<Double> set = new TreeSet<>();
for (final DoublesPair pair : list) {
set.add(pair.getFirst());
}
for (final Double time : set) {
double sensi = 0;
for (int looplist = 0; looplist < list.size(); looplist++) {
if (Double.doubleToLongBits(list.get(looplist).getFirstDouble()) == Double.doubleToLongBits(time)) {
sensi += list.get(looplist).second;
}
}
if (Math.abs(sensi) > tolerance) {
listClean.add(DoublesPair.of(time.doubleValue(), sensi));
}
}
result.put(entry.getKey(), listClean);
}
return result;
}
public static Map<String, List<ForwardSensitivity>> cleanedFwd(final Map<String, List<ForwardSensitivity>> map) {
//TODO: improve the sorting algorithm.
final Map<String, List<ForwardSensitivity>> result = new HashMap<>();
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map.entrySet()) {
final List<ForwardSensitivity> list = entry.getValue();
final List<ForwardSensitivity> listClean = new ArrayList<>();
final Set<Triple<Double, Double, Double>> set = new TreeSet<>();
for (final ForwardSensitivity pair : list) {
set.add(Triple.of(pair.getStartTime(), pair.getEndTime(), pair.getAccrualFactor()));
}
for (final Triple<Double, Double, Double> time : set) {
double sensi = 0;
for (int looplist = 0; looplist < list.size(); looplist++) {
final ForwardSensitivity fwdSensitivity = list.get(looplist);
final Triple<Double, Double, Double> triple = Triple.of(fwdSensitivity.getStartTime(), fwdSensitivity.getEndTime(), fwdSensitivity.getAccrualFactor());
if (triple.equals(time)) {
sensi += list.get(looplist).getValue();
}
}
listClean.add(new SimplyCompoundedForwardSensitivity(time.getFirst(), time.getSecond(), time.getThird(), sensi));
}
result.put(entry.getKey(), listClean);
}
return result;
}
public static Map<String, List<ForwardSensitivity>> cleanedFwd(final Map<String, List<ForwardSensitivity>> map, final double tolerance) {
//TODO: improve the sorting algorithm.
final Map<String, List<ForwardSensitivity>> result = new HashMap<>();
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map.entrySet()) {
final List<ForwardSensitivity> list = entry.getValue();
final List<ForwardSensitivity> listClean = new ArrayList<>();
final Set<Triple<Double, Double, Double>> set = new TreeSet<>();
for (final ForwardSensitivity pair : list) {
set.add(Triple.of(pair.getStartTime(), pair.getEndTime(), pair.getAccrualFactor()));
}
for (final Triple<Double, Double, Double> time : set) {
double sensi = 0;
for (int looplist = 0; looplist < list.size(); looplist++) {
final ForwardSensitivity fwdSensitivity = list.get(looplist);
final Triple<Double, Double, Double> triple = Triple.of(fwdSensitivity.getStartTime(), fwdSensitivity.getEndTime(), fwdSensitivity.getAccrualFactor());
if (triple.equals(time)) {
sensi += list.get(looplist).getValue();
}
}
if (Math.abs(sensi) > tolerance) {
listClean.add(new SimplyCompoundedForwardSensitivity(time.getFirst(), time.getSecond(), time.getThird(), sensi));
}
}
result.put(entry.getKey(), listClean);
}
return result;
}
/**
* Add two list representing sensitivities into one. No attempt is made to net off sensitivities occurring at the same time - Use clean()
* to do this
* @param sensi1 First list of sensitivities
* @param sensi2 Second list of sensitivities
* @return combined list
*/
public static List<DoublesPair> plus(final List<DoublesPair> sensi1, final List<DoublesPair> sensi2) {
final List<DoublesPair> result = new ArrayList<>(sensi1);
result.addAll(sensi2);
return result;
}
//-------------------------------------------------------------------------
/**
* Add two maps representing sensitivities into one.
*
* @param sensi1 the first sensitivity, not null
* @param sensi2 the second sensitivity, not null
* @return the total sensitivity, not null
*/
public static Map<String, List<DoublesPair>> plus(final Map<String, List<DoublesPair>> sensi1, final Map<String, List<DoublesPair>> sensi2) {
ArgumentChecker.notNull(sensi1, "sensitivity");
ArgumentChecker.notNull(sensi2, "sensitivity");
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : sensi1.entrySet()) {
final String name = entry.getKey();
if (sensi2.containsKey(name)) {
result.put(name, plus(entry.getValue(), sensi2.get(name)));
} else {
result.put(name, entry.getValue());
}
}
for (final Map.Entry<String, List<DoublesPair>> entry : sensi2.entrySet()) {
final String name = entry.getKey();
if (!result.containsKey(name)) {
result.put(name, entry.getValue());
}
}
return result;
}
/**
* Add the list representing the sensitivity to one curve to the map of sensitivities to several curves.
* @param sensi The multi-curves sensitivity. Not null.
* @param curveName The name of the curve the sensitivity of which is added. Not null.
* @param list The sensitivity as a list. Not null.
* @return The total sensitivity, not null
*/
public static Map<String, List<DoublesPair>> plus(final Map<String, List<DoublesPair>> sensi, final String curveName, final List<DoublesPair> list) {
ArgumentChecker.notNull(sensi, "sensitivity");
ArgumentChecker.notNull(list, "sensitivity");
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : sensi.entrySet()) {
final String name = entry.getKey();
if (name.equals(curveName)) {
result.put(name, plus(entry.getValue(), list));
} else {
result.put(name, entry.getValue());
}
}
if (!result.containsKey(curveName)) {
result.put(curveName, list);
}
return result;
}
/**
* Add two maps links to forward curves.
* @param map1 The first map.
* @param map2 The second map.
* @return The sum.
*/
public static Map<String, List<ForwardSensitivity>> plusFwd(final Map<String, List<ForwardSensitivity>> map1, final Map<String, List<ForwardSensitivity>> map2) {
final Map<String, List<ForwardSensitivity>> result = new HashMap<>();
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map1.entrySet()) {
final List<ForwardSensitivity> temp = new ArrayList<>();
final String name = entry.getKey();
for (final ForwardSensitivity pair : entry.getValue()) {
temp.add(pair);
}
if (map2.containsKey(name)) {
for (final ForwardSensitivity pair : map2.get(name)) {
temp.add(pair);
}
}
result.put(name, temp);
}
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map2.entrySet()) {
final String name = entry.getKey();
if (!result.containsKey(name)) {
final List<ForwardSensitivity> temp = new ArrayList<>();
for (final ForwardSensitivity pair : entry.getValue()) {
temp.add(pair);
}
result.put(name, temp);
}
}
return result;
}
/**
* Multiply a sensitivity map by a common factor.
*
* @param sensitivity the original sensitivity, not null
* @param factor the multiplicative factor, not null
* @return the multiplied sensitivity, not null
*/
public static Map<String, List<DoublesPair>> multipliedBy(final Map<String, List<DoublesPair>> sensitivity, final double factor) {
ArgumentChecker.notNull(sensitivity, "sensitivity");
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : sensitivity.entrySet()) {
result.put(entry.getKey(), multipliedBy(entry.getValue(), factor));
}
return result;
}
public static List<DoublesPair> multipliedBy(final List<DoublesPair> sensitivity, final double factor) {
ArgumentChecker.notNull(sensitivity, "sensitivity");
final List<DoublesPair> curveSensi = new ArrayList<>();
for (final DoublesPair pair : sensitivity) {
curveSensi.add(DoublesPair.of(pair.first, pair.second * factor));
}
return curveSensi;
}
/**
* Product of two sensitivities
*
* @param sensi1 the original sensitivity, not null
* @param sensi2 the other sensitivity, not null
* @return the product sensitivity, not null
*/
public static Map<String, List<DoublesPair>> productOf(final Map<String, List<DoublesPair>> sensi1, final Map<String, List<DoublesPair>> sensi2) {
ArgumentChecker.notNull(sensi1, "sensitivity");
ArgumentChecker.notNull(sensi2, "sensitivity");
final Map<String, List<DoublesPair>> result = new HashMap<>();
for (final Map.Entry<String, List<DoublesPair>> entry : sensi1.entrySet()) {
final String name = entry.getKey();
if (sensi2.containsKey(name)) {
result.put(name, productOf(entry.getValue(), sensi2.get(name)));
}
}
return result;
}
public static List<DoublesPair> productOf(final List<DoublesPair> sensi1, final List<DoublesPair> sensi2) {
final List<DoublesPair> curveSensi = new ArrayList<>();
final int length2 = sensi2.size();
for (final DoublesPair pair : sensi1) {
for (int i = 0; i < length2; ++i) {
if (pair.first == sensi2.get(i).first) {
curveSensi.add(DoublesPair.of(pair.first, pair.second * sensi2.get(i).second));
}
}
}
return curveSensi;
}
public static Map<String, List<ForwardSensitivity>> multipliedByFwd(final Map<String, List<ForwardSensitivity>> map, final double factor) {
final Map<String, List<ForwardSensitivity>> result = new HashMap<>();
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map.entrySet()) {
final List<ForwardSensitivity> curveSensi = new ArrayList<>();
for (final ForwardSensitivity pair : entry.getValue()) {
curveSensi.add(new SimplyCompoundedForwardSensitivity(pair.getStartTime(), pair.getEndTime(), pair.getAccrualFactor(), pair.getValue() * factor));
}
result.put(entry.getKey(), curveSensi);
}
return result;
}
/**
* Product of two sensitivities
* @param map1 the original sensitivity
* @param map2 the other sensitivity
* @return the new sensitivity
*/
public static Map<String, List<ForwardSensitivity>> productOfFwd(final Map<String, List<ForwardSensitivity>> map1, final Map<String, List<ForwardSensitivity>> map2) {
final Map<String, List<ForwardSensitivity>> result = new HashMap<>();
for (final Map.Entry<String, List<ForwardSensitivity>> entry : map1.entrySet()) {
final List<ForwardSensitivity> curveSensi = new ArrayList<>();
final String name = entry.getKey();
if (map2.containsKey(name)) {
final int length2 = map2.size();
for (final ForwardSensitivity pair1 : entry.getValue()) {
for (int i = 0; i < length2; ++i) {
if (pair1.getStartTime() == map2.get(name).get(i).getStartTime() && pair1.getEndTime() == map2.get(name).get(i).getEndTime()) {
curveSensi.add(new SimplyCompoundedForwardSensitivity(pair1.getStartTime(), pair1.getEndTime(), pair1.getAccrualFactor(), pair1.getValue() * map2.get(name).get(i).getValue()));
}
}
}
}
result.put(entry.getKey(), curveSensi);
}
return result;
}
}