/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.math.curve;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.ObjectUtils;
import org.joda.beans.Bean;
import org.joda.beans.BeanBuilder;
import org.joda.beans.BeanDefinition;
import org.joda.beans.JodaBeanUtils;
import org.joda.beans.MetaProperty;
import org.joda.beans.Property;
import org.joda.beans.PropertyDefinition;
import org.joda.beans.impl.direct.DirectBeanBuilder;
import org.joda.beans.impl.direct.DirectMetaProperty;
import org.joda.beans.impl.direct.DirectMetaPropertyMap;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.util.ArgumentChecker;
/**
* Class defining a spread curve, i.e. a curve that is the result of a mathematical operation
* (see {@link CurveSpreadFunction}) on two or more curves.
* For example, a simple spread curve could be <i>C = A - B</i>. As this curve is in the same
* hierarchy as the other curves, a spread curve can be defined on another spread curve,
* e.g. <i>E = C * D = D * (A - B)</i>.
*/
@BeanDefinition
public class SpreadDoublesCurve
extends DoublesCurve {
/**
* The spread function.
*/
@PropertyDefinition(get = "private", set = "private")
private CurveSpreadFunction _spreadFunction;
/**
* The evaluated function.
*/
@PropertyDefinition(get = "private", set = "private")
private Function<Double, Double> _f;
/**
* The curves.
*/
@PropertyDefinition(get = "private", set = "private")
private DoublesCurve[] _curves;
//-------------------------------------------------------------------------
/**
* Takes an array of curves that are to be operated on by the spread function.
* The name of the spread curve is automatically generated.
*
* @param spreadFunction the spread function, not null
* @param curves the curves, not null
* @return the spread curve, not null
*/
public static SpreadDoublesCurve from(final CurveSpreadFunction spreadFunction, final DoublesCurve... curves) {
return new SpreadDoublesCurve(spreadFunction, curves);
}
/**
* Takes an array of curves that are to be operated on by the spread function.
*
* @param spreadFunction the spread function, not null
* @param name the name of the curve, not null
* @param curves the curves, not null
* @return the spread curve, not null
*/
public static SpreadDoublesCurve from(final CurveSpreadFunction spreadFunction, final String name, final DoublesCurve... curves) {
return new SpreadDoublesCurve(spreadFunction, name, curves);
}
//-------------------------------------------------------------------------
/**
* Constructor for Joda-Beans.
*/
protected SpreadDoublesCurve() {
}
/**
* Creates a spread curve.
*
* @param spreadFunction the spread function, not null
* @param curves the curves, not null, contains more than one curve, not null
*/
public SpreadDoublesCurve(final CurveSpreadFunction spreadFunction, final DoublesCurve... curves) {
super();
ArgumentChecker.notNull(curves, "curves");
ArgumentChecker.isTrue(curves.length > 1, "curves");
ArgumentChecker.notNull(spreadFunction, "spread operator");
_curves = curves;
_spreadFunction = spreadFunction;
_f = spreadFunction.evaluate(curves);
}
/**
* Creates a spread curve.
*
* @param spreadFunction the spread function, not null
* @param name the name of the curve, not null
* @param curves the curves, not null, contains more than one curve, not null
*/
public SpreadDoublesCurve(final CurveSpreadFunction spreadFunction, final String name, final DoublesCurve... curves) {
super(name);
ArgumentChecker.notNull(curves, "curves");
ArgumentChecker.isTrue(curves.length > 1, "curves");
ArgumentChecker.notNull(spreadFunction, "spread operator");
_curves = curves;
_spreadFunction = spreadFunction;
_f = spreadFunction.evaluate(curves);
}
//-------------------------------------------------------------------------
/**
* Returns a set of the <b>unique</b> names of the curves that were used to construct this curve.
* If a constituent curve is a spread curve, then all of its underlyings are included.
*
* @return the set of underlying names, not null
*/
public Set<String> getUnderlyingNames() {
final Set<String> result = new HashSet<>();
for (final Curve<Double, Double> curve : _curves) {
if (curve instanceof SpreadDoublesCurve) {
result.addAll(((SpreadDoublesCurve) curve).getUnderlyingNames());
} else {
result.add(curve.getName());
}
}
return result;
}
/**
* Returns a string that represents the mathematical form of this curve.
* For example, <i>D = (A + (B / C))</i>.
*
* @return the long name of this curve, not null
*/
public String getLongName() {
final StringBuilder buf = new StringBuilder(getName());
buf.append("=");
int i = 0;
buf.append("(");
for (final Curve<Double, Double> curve : _curves) {
if (curve instanceof SpreadDoublesCurve) {
buf.append(((SpreadDoublesCurve) curve).getLongName().substring(2));
} else {
buf.append(curve.getName());
}
if (i != _curves.length - 1) {
buf.append(_spreadFunction.getOperationName());
}
i++;
}
buf.append(")");
return buf.toString();
}
/**
* Gets the underlying curves.
*
* @return the underlying curves, not null
*/
public DoublesCurve[] getUnderlyingCurves() {
return _curves;
}
/**
* Throws an exception as there is no <i>x</i> data.
*
* @return throws UnsupportedOperationException
* @throws UnsupportedOperationException always
*/
@Override
public Double[] getXData() {
throw new UnsupportedOperationException();
}
/**
* Throws an exception as there is no <i>y</i> data.
*
* @return throws UnsupportedOperationException
* @throws UnsupportedOperationException always
*/
@Override
public Double[] getYData() {
throw new UnsupportedOperationException();
}
@Override
public Double getYValue(final Double x) {
ArgumentChecker.notNull(x, "x");
return _f.evaluate(x);
}
@Override
public Double[] getYValueParameterSensitivity(final Double x) {
if (_curves.length == 2) {
if (_curves[0] instanceof InterpolatedDoublesCurve && _curves[1] instanceof ConstantDoublesCurve) {
return _curves[0].getYValueParameterSensitivity(x);
} else if (_curves[1] instanceof InterpolatedDoublesCurve && _curves[0] instanceof ConstantDoublesCurve) {
return _curves[1].getYValueParameterSensitivity(x);
}
}
throw new UnsupportedOperationException("Parameter sensitivity not supported yet for SpreadDoublesCurve");
}
@Override
public double getDyDx(final double x) {
throw new NotImplementedException();
}
/**
* Throws an exception as there is no <i>x</i> or <i>y</i> data.
*
* @return throws UnsupportedOperationException
* @throws UnsupportedOperationException always
*/
@Override
public int size() {
int size = 0;
for (final DoublesCurve underlying : _curves) {
if (underlying instanceof InterpolatedDoublesCurve || underlying instanceof NodalDoublesCurve || underlying instanceof SpreadDoublesCurve) {
size += underlying.size();
}
}
if (size != 0) {
return size;
}
throw new UnsupportedOperationException("Size not supported for SpreadDoublesCurve " + getLongName());
}
//-------------------------------------------------------------------------
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SpreadDoublesCurve other = (SpreadDoublesCurve) obj;
if (!Arrays.equals(_curves, other._curves)) {
return false;
}
return ObjectUtils.equals(_spreadFunction, other._spreadFunction);
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
result = prime * result + Arrays.hashCode(_curves);
result = prime * result + _spreadFunction.hashCode();
return result;
}
//------------------------- AUTOGENERATED START -------------------------
///CLOVER:OFF
/**
* The meta-bean for {@code SpreadDoublesCurve}.
* @return the meta-bean, not null
*/
public static SpreadDoublesCurve.Meta meta() {
return SpreadDoublesCurve.Meta.INSTANCE;
}
static {
JodaBeanUtils.registerMetaBean(SpreadDoublesCurve.Meta.INSTANCE);
}
@Override
public SpreadDoublesCurve.Meta metaBean() {
return SpreadDoublesCurve.Meta.INSTANCE;
}
//-----------------------------------------------------------------------
/**
* Gets the spread function.
* @return the value of the property
*/
private CurveSpreadFunction getSpreadFunction() {
return _spreadFunction;
}
/**
* Sets the spread function.
* @param spreadFunction the new value of the property
*/
private void setSpreadFunction(CurveSpreadFunction spreadFunction) {
this._spreadFunction = spreadFunction;
}
/**
* Gets the the {@code spreadFunction} property.
* @return the property, not null
*/
public final Property<CurveSpreadFunction> spreadFunction() {
return metaBean().spreadFunction().createProperty(this);
}
//-----------------------------------------------------------------------
/**
* Gets the evaluated function.
* @return the value of the property
*/
private Function<Double, Double> getF() {
return _f;
}
/**
* Sets the evaluated function.
* @param f the new value of the property
*/
private void setF(Function<Double, Double> f) {
this._f = f;
}
/**
* Gets the the {@code f} property.
* @return the property, not null
*/
public final Property<Function<Double, Double>> f() {
return metaBean().f().createProperty(this);
}
//-----------------------------------------------------------------------
/**
* Gets the curves.
* @return the value of the property
*/
private DoublesCurve[] getCurves() {
return _curves;
}
/**
* Sets the curves.
* @param curves the new value of the property
*/
private void setCurves(DoublesCurve[] curves) {
this._curves = curves;
}
/**
* Gets the the {@code curves} property.
* @return the property, not null
*/
public final Property<DoublesCurve[]> curves() {
return metaBean().curves().createProperty(this);
}
//-----------------------------------------------------------------------
@Override
public SpreadDoublesCurve clone() {
return JodaBeanUtils.cloneAlways(this);
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder(128);
buf.append("SpreadDoublesCurve{");
int len = buf.length();
toString(buf);
if (buf.length() > len) {
buf.setLength(buf.length() - 2);
}
buf.append('}');
return buf.toString();
}
@Override
protected void toString(StringBuilder buf) {
super.toString(buf);
buf.append("spreadFunction").append('=').append(JodaBeanUtils.toString(getSpreadFunction())).append(',').append(' ');
buf.append("f").append('=').append(JodaBeanUtils.toString(getF())).append(',').append(' ');
buf.append("curves").append('=').append(JodaBeanUtils.toString(getCurves())).append(',').append(' ');
}
//-----------------------------------------------------------------------
/**
* The meta-bean for {@code SpreadDoublesCurve}.
*/
public static class Meta extends DoublesCurve.Meta {
/**
* The singleton instance of the meta-bean.
*/
static final Meta INSTANCE = new Meta();
/**
* The meta-property for the {@code spreadFunction} property.
*/
private final MetaProperty<CurveSpreadFunction> _spreadFunction = DirectMetaProperty.ofReadWrite(
this, "spreadFunction", SpreadDoublesCurve.class, CurveSpreadFunction.class);
/**
* The meta-property for the {@code f} property.
*/
@SuppressWarnings({"unchecked", "rawtypes" })
private final MetaProperty<Function<Double, Double>> _f = DirectMetaProperty.ofReadWrite(
this, "f", SpreadDoublesCurve.class, (Class) Function.class);
/**
* The meta-property for the {@code curves} property.
*/
private final MetaProperty<DoublesCurve[]> _curves = DirectMetaProperty.ofReadWrite(
this, "curves", SpreadDoublesCurve.class, DoublesCurve[].class);
/**
* The meta-properties.
*/
private final Map<String, MetaProperty<?>> _metaPropertyMap$ = new DirectMetaPropertyMap(
this, (DirectMetaPropertyMap) super.metaPropertyMap(),
"spreadFunction",
"f",
"curves");
/**
* Restricted constructor.
*/
protected Meta() {
}
@Override
protected MetaProperty<?> metaPropertyGet(String propertyName) {
switch (propertyName.hashCode()) {
case -872176021: // spreadFunction
return _spreadFunction;
case 102: // f
return _f;
case -1349116572: // curves
return _curves;
}
return super.metaPropertyGet(propertyName);
}
@Override
public BeanBuilder<? extends SpreadDoublesCurve> builder() {
return new DirectBeanBuilder<SpreadDoublesCurve>(new SpreadDoublesCurve());
}
@Override
public Class<? extends SpreadDoublesCurve> beanType() {
return SpreadDoublesCurve.class;
}
@Override
public Map<String, MetaProperty<?>> metaPropertyMap() {
return _metaPropertyMap$;
}
//-----------------------------------------------------------------------
/**
* The meta-property for the {@code spreadFunction} property.
* @return the meta-property, not null
*/
public final MetaProperty<CurveSpreadFunction> spreadFunction() {
return _spreadFunction;
}
/**
* The meta-property for the {@code f} property.
* @return the meta-property, not null
*/
public final MetaProperty<Function<Double, Double>> f() {
return _f;
}
/**
* The meta-property for the {@code curves} property.
* @return the meta-property, not null
*/
public final MetaProperty<DoublesCurve[]> curves() {
return _curves;
}
//-----------------------------------------------------------------------
@Override
protected Object propertyGet(Bean bean, String propertyName, boolean quiet) {
switch (propertyName.hashCode()) {
case -872176021: // spreadFunction
return ((SpreadDoublesCurve) bean).getSpreadFunction();
case 102: // f
return ((SpreadDoublesCurve) bean).getF();
case -1349116572: // curves
return ((SpreadDoublesCurve) bean).getCurves();
}
return super.propertyGet(bean, propertyName, quiet);
}
@SuppressWarnings("unchecked")
@Override
protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) {
switch (propertyName.hashCode()) {
case -872176021: // spreadFunction
((SpreadDoublesCurve) bean).setSpreadFunction((CurveSpreadFunction) newValue);
return;
case 102: // f
((SpreadDoublesCurve) bean).setF((Function<Double, Double>) newValue);
return;
case -1349116572: // curves
((SpreadDoublesCurve) bean).setCurves((DoublesCurve[]) newValue);
return;
}
super.propertySet(bean, propertyName, newValue, quiet);
}
}
///CLOVER:ON
//-------------------------- AUTOGENERATED END --------------------------
}