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    package org.apache.commons.math3.optim.univariate;
018    
019    import org.apache.commons.math3.util.FastMath;
020    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
021    import org.apache.commons.math3.optim.AbstractConvergenceChecker;
022    
023    /**
024     * Simple implementation of the
025     * {@link org.apache.commons.math3.optimization.ConvergenceChecker} interface
026     * that uses only objective function values.
027     *
028     * Convergence is considered to have been reached if either the relative
029     * difference between the objective function values is smaller than a
030     * threshold or if either the absolute difference between the objective
031     * function values is smaller than another threshold.
032     * <br/>
033     * The {@link #converged(int,UnivariatePointValuePair,UnivariatePointValuePair)
034     * converged} method will also return {@code true} if the number of iterations
035     * has been set (see {@link #SimpleUnivariateValueChecker(double,double,int)
036     * this constructor}).
037     *
038     * @version $Id: SimpleUnivariateValueChecker.java 1413171 2012-11-24 11:11:10Z erans $
039     * @since 3.1
040     */
041    public class SimpleUnivariateValueChecker
042        extends AbstractConvergenceChecker<UnivariatePointValuePair> {
043        /**
044         * If {@link #maxIterationCount} is set to this value, the number of
045         * iterations will never cause
046         * {@link #converged(int,UnivariatePointValuePair,UnivariatePointValuePair)}
047         * to return {@code true}.
048         */
049        private static final int ITERATION_CHECK_DISABLED = -1;
050        /**
051         * Number of iterations after which the
052         * {@link #converged(int,UnivariatePointValuePair,UnivariatePointValuePair)}
053         * method will return true (unless the check is disabled).
054         */
055        private final int maxIterationCount;
056    
057        /** Build an instance with specified thresholds.
058         *
059         * In order to perform only relative checks, the absolute tolerance
060         * must be set to a negative value. In order to perform only absolute
061         * checks, the relative tolerance must be set to a negative value.
062         *
063         * @param relativeThreshold relative tolerance threshold
064         * @param absoluteThreshold absolute tolerance threshold
065         */
066        public SimpleUnivariateValueChecker(final double relativeThreshold,
067                                            final double absoluteThreshold) {
068            super(relativeThreshold, absoluteThreshold);
069            maxIterationCount = ITERATION_CHECK_DISABLED;
070        }
071    
072        /**
073         * Builds an instance with specified thresholds.
074         *
075         * In order to perform only relative checks, the absolute tolerance
076         * must be set to a negative value. In order to perform only absolute
077         * checks, the relative tolerance must be set to a negative value.
078         *
079         * @param relativeThreshold relative tolerance threshold
080         * @param absoluteThreshold absolute tolerance threshold
081         * @param maxIter Maximum iteration count.
082         * @throws NotStrictlyPositiveException if {@code maxIter <= 0}.
083         *
084         * @since 3.1
085         */
086        public SimpleUnivariateValueChecker(final double relativeThreshold,
087                                            final double absoluteThreshold,
088                                            final int maxIter) {
089            super(relativeThreshold, absoluteThreshold);
090    
091            if (maxIter <= 0) {
092                throw new NotStrictlyPositiveException(maxIter);
093            }
094            maxIterationCount = maxIter;
095        }
096    
097        /**
098         * Check if the optimization algorithm has converged considering the
099         * last two points.
100         * This method may be called several time from the same algorithm
101         * iteration with different points. This can be detected by checking the
102         * iteration number at each call if needed. Each time this method is
103         * called, the previous and current point correspond to points with the
104         * same role at each iteration, so they can be compared. As an example,
105         * simplex-based algorithms call this method for all points of the simplex,
106         * not only for the best or worst ones.
107         *
108         * @param iteration Index of current iteration
109         * @param previous Best point in the previous iteration.
110         * @param current Best point in the current iteration.
111         * @return {@code true} if the algorithm has converged.
112         */
113        @Override
114        public boolean converged(final int iteration,
115                                 final UnivariatePointValuePair previous,
116                                 final UnivariatePointValuePair current) {
117            if (maxIterationCount != ITERATION_CHECK_DISABLED) {
118                if (iteration >= maxIterationCount) {
119                    return true;
120                }
121            }
122    
123            final double p = previous.getValue();
124            final double c = current.getValue();
125            final double difference = FastMath.abs(p - c);
126            final double size = FastMath.max(FastMath.abs(p), FastMath.abs(c));
127            return difference <= size * getRelativeThreshold() ||
128                difference <= getAbsoluteThreshold();
129        }
130    }