/* * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. * * Created on 28.05.2004 */ package net.finmath.integration; import net.finmath.compatibility.java.util.function.DoubleUnaryOperator; /** * A simple integrator using the trapezoidal rule. * * @author Christian Fries */ public class TrapezoidalRealIntegrator extends AbstractRealIntegral{ private int numberOfEvaluationPoints; private double[] evaluationPoints; /** * Create an integrator using the trapezoidal rule. * * @param lowerBound Lower bound of the integral. * @param upperBound Upper bound of the integral. * @param evaluationPoints An ordered array of the inner evaluation points to use. */ public TrapezoidalRealIntegrator(double lowerBound, double upperBound, double[] evaluationPoints) { super(lowerBound, upperBound); this.evaluationPoints = evaluationPoints; } /** * Create an integrator using the trapezoidal rule and an equi-distant grid of evaluation points. * The minimum number of evaluation points (<code>numberOfEvaluationPoints</code>) is 2, since the * trapezoidal rule operates on intervals. That is, lowerBound and upperBound are always evaluated. For * <code>numberOfEvaluationPoints > 2</code> additional inner points will be evaluated. * * @param lowerBound Lower bound of the integral. * @param upperBound Upper bound of the integral. * @param numberOfEvaluationPoints Number of evaluation points (that is calls to the applyAsDouble of integrand). Has to be > 2; */ public TrapezoidalRealIntegrator(double lowerBound, double upperBound, int numberOfEvaluationPoints) { super(lowerBound, upperBound); this.numberOfEvaluationPoints = numberOfEvaluationPoints; if(numberOfEvaluationPoints < 2) throw new IllegalArgumentException("Invalid numberOfEvaluationPoints (minumum admissible value is 2)."); } @Override public double integrate(DoubleUnaryOperator integrand) { double lowerBound = getLowerBound(); double upperBound = getUpperBound(); double sum = 0.0; if(evaluationPoints != null) { /* * Trapezoidal integration on a possibly non-equi-distant grid. */ int i = 0; while(i<evaluationPoints.length && evaluationPoints[i] < lowerBound) i++; double pointLeft = lowerBound; double valueLeft = integrand.applyAsDouble(lowerBound); for(;i<evaluationPoints.length && evaluationPoints[i]<upperBound; i++) { double pointRight = evaluationPoints[i]; double valueRight = integrand.applyAsDouble(pointRight); sum += (valueRight + valueLeft) * (pointRight - pointLeft); pointLeft = pointRight; valueLeft = valueRight; } double pointRight = upperBound; double valueRight = integrand.applyAsDouble(pointRight); sum += (valueRight + valueLeft) * (pointRight - pointLeft); sum /= 2.0; } else { /* * Trapezoidal integration on an equi-distant grid. */ double intervall = (upperBound-lowerBound) / (numberOfEvaluationPoints-1); // Sum of inner points for(int i=1; i<numberOfEvaluationPoints-1; i++) { double point = lowerBound + i * intervall; sum += integrand.applyAsDouble(point) * intervall; } // Sum of boundary points sum += (integrand.applyAsDouble(lowerBound) + integrand.applyAsDouble(upperBound)) / 2.0 * intervall; } return sum; } }