/** * Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.math.interpolation.data; import java.io.Serializable; import java.util.Arrays; import com.opengamma.analytics.math.MathException; import com.opengamma.util.ArgumentChecker; /** * */ public class Interpolator1DMonotonicIncreasingDataBundle implements Interpolator1DDataBundle, Serializable { private final Interpolator1DDataBundle _underlyingData; private final double[] _a; private final double[] _b; public Interpolator1DMonotonicIncreasingDataBundle(final Interpolator1DDataBundle underlyingData) { ArgumentChecker.notNull(underlyingData, "underlying data"); _underlyingData = underlyingData; final double[] x = _underlyingData.getKeys(); final double[] h = _underlyingData.getValues(); final int n = _underlyingData.size(); for (int i = 1; i < n; i++) { ArgumentChecker.isTrue(h[i] >= h[i - 1], "Data not increasing"); } final double[] dx = new double[n]; dx[0] = x[0]; for (int i = 1; i < n; i++) { dx[i] = x[i] - x[i - 1]; } _a = new double[n + 1]; _b = new double[n + 1]; _a[0] = _underlyingData.firstValue() / _underlyingData.firstKey(); for (int i = 1; i < n; i++) { _a[i] = _a[i - 1] * Math.exp(_b[i - 1] * dx[i - 1]); final double temp = ((h[i] - h[i - 1]) / _a[i] - dx[i]) * 2 / dx[i] / dx[i]; if (temp == 0) { _b[i] = 0.0; } else { _b[i] = solveForB(h[i - 1] - h[i], _a[i], dx[i], Math.max(-10, Math.min(10, temp))); } } _a[n] = _a[n - 1] * Math.exp(_b[n - 1] * dx[n - 1]); } private double solveForB(final double c, final double a, final double dx, final double startB) { final double eps = 1e-12; double f = c + a / startB * (Math.exp(startB * dx) - 1); double b = startB; int count = 0; while (Math.abs(f) > eps) { final double expB = Math.exp(b * dx); final double df = a * (dx * expB / b - (expB - 1) / b / b); b = b - f / df; f = c + a / b * (Math.exp(b * dx) - 1); if (count > 50) { throw new MathException("fail to solve for b"); } count++; } return b; } @Override public boolean containsKey(final Double key) { return _underlyingData.containsKey(key); } @Override public Double firstKey() { return _underlyingData.firstKey(); } @Override public Double firstValue() { return _underlyingData.firstValue(); } @Override public Double get(final Double key) { return _underlyingData.get(key); } @Override public InterpolationBoundedValues getBoundedValues(final Double key) { return _underlyingData.getBoundedValues(key); } @Override public double[] getKeys() { return _underlyingData.getKeys(); } @Override public int getLowerBoundIndex(final Double value) { final double[] keys = _underlyingData.getKeys(); final int n = _underlyingData.size(); if (value < keys[0]) { return 0; } if (value > keys[n - 1]) { return n; } int index = Arrays.binarySearch(keys, value); if (index >= 0) { // Fast break out if it's an exact match. return index; } if (index < 0) { index = -(index + 1); index--; } return index; } @Override public Double getLowerBoundKey(final Double value) { return _underlyingData.getLowerBoundKey(value); } @Override public double[] getValues() { return _underlyingData.getValues(); } @Override public Double higherKey(final Double key) { return _underlyingData.higherKey(key); } @Override public Double higherValue(final Double key) { return _underlyingData.higherValue(key); } @Override public Double lastKey() { return _underlyingData.lastKey(); } @Override public Double lastValue() { return _underlyingData.lastValue(); } @Override public int size() { return _underlyingData.size(); } @Override public void setYValueAtIndex(final int index, final double y) { } public double getA(final int index) { return _a[index]; } public double getB(final int index) { return _b[index]; } }