001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.math4.optim;
019
020import org.apache.commons.math4.exception.NotStrictlyPositiveException;
021import org.apache.commons.math4.util.FastMath;
022
023/**
024 * Simple implementation of the {@link ConvergenceChecker} interface using
025 * only objective function values.
026 *
027 * Convergence is considered to have been reached if either the relative
028 * difference between the objective function values is smaller than a
029 * threshold or if either the absolute difference between the objective
030 * function values is smaller than another threshold.
031 * <br>
032 * The {@link #converged(int,PointValuePair,PointValuePair) converged}
033 * method will also return {@code true} if the number of iterations has been set
034 * (see {@link #SimpleValueChecker(double,double,int) this constructor}).
035 *
036 * @since 3.0
037 */
038public class SimpleValueChecker
039    extends AbstractConvergenceChecker<PointValuePair> {
040    /**
041     * If {@link #maxIterationCount} is set to this value, the number of
042     * iterations will never cause
043     * {@link #converged(int,PointValuePair,PointValuePair)}
044     * to return {@code true}.
045     */
046    private static final int ITERATION_CHECK_DISABLED = -1;
047    /**
048     * Number of iterations after which the
049     * {@link #converged(int,PointValuePair,PointValuePair)} method
050     * will return true (unless the check is disabled).
051     */
052    private final int maxIterationCount;
053
054    /** Build an instance with specified thresholds.
055     *
056     * In order to perform only relative checks, the absolute tolerance
057     * must be set to a negative value. In order to perform only absolute
058     * checks, the relative tolerance must be set to a negative value.
059     *
060     * @param relativeThreshold relative tolerance threshold
061     * @param absoluteThreshold absolute tolerance threshold
062     */
063    public SimpleValueChecker(final double relativeThreshold,
064                              final double absoluteThreshold) {
065        super(relativeThreshold, absoluteThreshold);
066        maxIterationCount = ITERATION_CHECK_DISABLED;
067    }
068
069    /**
070     * Builds an instance with specified thresholds.
071     *
072     * In order to perform only relative checks, the absolute tolerance
073     * must be set to a negative value. In order to perform only absolute
074     * checks, the relative tolerance must be set to a negative value.
075     *
076     * @param relativeThreshold relative tolerance threshold
077     * @param absoluteThreshold absolute tolerance threshold
078     * @param maxIter Maximum iteration count.
079     * @throws NotStrictlyPositiveException if {@code maxIter <= 0}.
080     *
081     * @since 3.1
082     */
083    public SimpleValueChecker(final double relativeThreshold,
084                              final double absoluteThreshold,
085                              final int maxIter) {
086        super(relativeThreshold, absoluteThreshold);
087
088        if (maxIter <= 0) {
089            throw new NotStrictlyPositiveException(maxIter);
090        }
091        maxIterationCount = maxIter;
092    }
093
094    /**
095     * Check if the optimization algorithm has converged considering the
096     * last two points.
097     * This method may be called several time from the same algorithm
098     * iteration with different points. This can be detected by checking the
099     * iteration number at each call if needed. Each time this method is
100     * called, the previous and current point correspond to points with the
101     * same role at each iteration, so they can be compared. As an example,
102     * simplex-based algorithms call this method for all points of the simplex,
103     * not only for the best or worst ones.
104     *
105     * @param iteration Index of current iteration
106     * @param previous Best point in the previous iteration.
107     * @param current Best point in the current iteration.
108     * @return {@code true} if the algorithm has converged.
109     */
110    @Override
111    public boolean converged(final int iteration,
112                             final PointValuePair previous,
113                             final PointValuePair current) {
114        if (maxIterationCount != ITERATION_CHECK_DISABLED && iteration >= maxIterationCount) {
115            return true;
116        }
117
118        final double p = previous.getValue();
119        final double c = current.getValue();
120        final double difference = FastMath.abs(p - c);
121        final double size = FastMath.max(FastMath.abs(p), FastMath.abs(c));
122        return difference <= size * getRelativeThreshold() ||
123            difference <= getAbsoluteThreshold();
124    }
125}