com.opengamma.strata.math.impl.integration.AdaptiveCompositeIntegrator1D 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) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.strata.math.impl.integration;
import java.util.function.Function;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.opengamma.strata.collect.ArgChecker;
/**
* Adaptive composite integrator: step size is set to be small if functional variation of integrand is large
* The integrator in individual intervals (base integrator) should be specified by constructor.
*/
public class AdaptiveCompositeIntegrator1D extends Integrator1D {
private static final Logger log = LoggerFactory.getLogger(AdaptiveCompositeIntegrator1D.class);
private final Integrator1D integrator;
private static final int MAX_IT = 15;
private final double gain;
private final double tol;
/**
* Creates an instance.
*
* @param integrator The base integrator
*/
public AdaptiveCompositeIntegrator1D(Integrator1D integrator) {
ArgChecker.notNull(integrator, "integrator");
this.integrator = integrator;
this.gain = 15.;
this.tol = 1.e-13;
}
/**
* Creates an instance.
*
* @param integrator The base integrator.
* @param gain The gain ratio
* @param tol The tolerance
*/
public AdaptiveCompositeIntegrator1D(Integrator1D integrator, double gain, double tol) {
ArgChecker.notNull(integrator, "integrator");
this.integrator = integrator;
this.gain = gain;
this.tol = tol;
}
@Override
public Double integrate(Function f, Double lower, Double upper) {
ArgChecker.notNull(f, "f");
ArgChecker.notNull(lower, "lower bound");
ArgChecker.notNull(upper, "upper bound");
try {
if (lower < upper) {
return integration(f, lower, upper);
}
log.info("Upper bound was less than lower bound; swapping bounds and negating result");
return -integration(f, upper, lower);
} catch (Exception e) {
throw new IllegalStateException("function evaluation returned NaN or Inf");
}
}
private Double integration(Function f, Double lower, Double upper) {
double res = integrator.integrate(f, lower, upper);
return integrationRec(f, lower, upper, res, MAX_IT);
}
private double integrationRec(Function f, double lower, double upper, double res, double counter) {
double localTol = gain * tol;
double half = 0.5 * (lower + upper);
double newResDw = integrator.integrate(f, lower, half);
double newResUp = integrator.integrate(f, half, upper);
double newRes = newResUp + newResDw;
if (Math.abs(res - newRes) < localTol || counter == 0 ||
(Math.abs(res) < 1.e-14 && Math.abs(newResUp) < 1.e-14 && Math.abs(newResDw) < 1.e-14)) {
return newRes + (newRes - res) / gain;
}
return integrationRec(f, lower, half, newResDw, counter - 1) +
integrationRec(f, half, upper, newResUp, counter - 1);
}
@Override
public int hashCode() {
int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(gain);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + integrator.hashCode();
temp = Double.doubleToLongBits(tol);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof AdaptiveCompositeIntegrator1D)) {
return false;
}
AdaptiveCompositeIntegrator1D other = (AdaptiveCompositeIntegrator1D) obj;
if (Double.doubleToLongBits(this.gain) != Double.doubleToLongBits(other.gain)) {
return false;
}
if (!this.integrator.equals(other.integrator)) {
return false;
}
if (Double.doubleToLongBits(this.tol) != Double.doubleToLongBits(other.tol)) {
return false;
}
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy