All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.math.impl.integration.AdaptiveCompositeIntegrator1D Maven / Gradle / Ivy

There is a newer version: 2.12.46
Show newest version
/*
 * 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