com.opengamma.strata.math.impl.minimization.SingleRangeLimitTransform Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of strata-math Show documentation
Show all versions of strata-math Show documentation
Mathematic support for Strata
/*
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.minimization;
import com.opengamma.strata.collect.ArgChecker;
/**
* If a model parameter $x$ is constrained to be either above or below some
* level $a$ (i.e. $x > a$ or $x < a$), the function to transform it to an
* unconstrained variable $y$ is given by
* $$
* \begin{align*}
* y =
* \begin{cases}
* \ln(e^{x-a} - 1)\quad & x > a\\
* a - \ln(e^{a-x} - 1)\quad & x < a
* \end{cases}
* \end{align*}
* $$
* with inverse transform
* $$
* \begin{align*}
* x =
* \begin{cases}
* a + \ln(e^y + 1)\quad & x > a\\
* a - \ln(e^y + 1)\quad & x < a
* \end{cases}
* \end{align*}
* $$
* For large $y > 50$, this becomes
* $$
* \begin{align*}
* y =
* \begin{cases}
* x - a\quad & x > a\\
* a - x\quad & x < a
* \end{cases}
* \end{align*}
* $$
* with inverse transform
* $$
* \begin{align*}
* x =
* \begin{cases}
* a + y\quad & x > a\\
* a - y\quad & x < a
* \end{cases}
* \end{align*}
* $$
* so any value of $y$ will give a value of $x$.
*/
public class SingleRangeLimitTransform implements ParameterLimitsTransform {
private static final double EXP_MAX = 50.;
private final double _limit;
private final int _sign;
/**
* Creates an instance.
*
* @param a The limit level
* @param limitType Type of the limit for the parameter
*/
public SingleRangeLimitTransform(double a, LimitType limitType) {
_limit = a;
_sign = limitType == LimitType.GREATER_THAN ? 1 : -1;
}
/**
* {@inheritDoc}
*/
@Override
public double inverseTransform(double y) {
if (y > EXP_MAX) {
return _limit + _sign * y;
} else if (y < -EXP_MAX) {
return _limit;
}
return _limit + _sign * Math.log(Math.exp(y) + 1);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException If the value of $x$ is not consistent with the limit
* (e.g. the limit is $x > a$ and $x$ is less than $a$
*/
@Override
public double transform(double x) {
ArgChecker.isTrue(_sign * x >= _sign * _limit, "x not in limit");
if (x == _limit) {
return -EXP_MAX;
}
double r = _sign * (x - _limit);
if (r > EXP_MAX) {
return r;
}
return Math.log(Math.exp(r) - 1);
}
/**
* {@inheritDoc}
*/
@Override
public double inverseTransformGradient(double y) {
if (y > EXP_MAX) {
return _sign;
}
double temp = Math.exp(y);
return _sign * temp / (temp + 1);
}
/**
* {@inheritDoc}
* @throws IllegalArgumentException If the value of $x$ is not consistent with the limit
* (e.g. the limit is $x > a$ and $x$ is less than $a$
*/
@Override
public double transformGradient(double x) {
ArgChecker.isTrue(_sign * x >= _sign * _limit, "x not in limit");
double r = _sign * (x - _limit);
if (r > EXP_MAX) {
return 1.0;
}
double temp = Math.exp(r);
return _sign * temp / (temp - 1);
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(_limit);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + _sign;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SingleRangeLimitTransform other = (SingleRangeLimitTransform) obj;
if (Double.doubleToLongBits(_limit) != Double.doubleToLongBits(other._limit)) {
return false;
}
return _sign == other._sign;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy