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    
018    package org.apache.commons.math3.optim;
019    
020    import org.apache.commons.math3.util.FastMath;
021    import org.apache.commons.math3.exception.NotStrictlyPositiveException;
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 for all vectors elements.
031     * <br/>
032     * The {@link #converged(int,PointVectorValuePair,PointVectorValuePair) converged}
033     * method will also return {@code true} if the number of iterations has been set
034     * (see {@link #SimpleVectorValueChecker(double,double,int) this constructor}).
035     *
036     * @version $Id: SimpleVectorValueChecker.java 1416643 2012-12-03 19:37:14Z tn $
037     * @since 3.0
038     */
039    public class SimpleVectorValueChecker
040        extends AbstractConvergenceChecker<PointVectorValuePair> {
041        /**
042         * If {@link #maxIterationCount} is set to this value, the number of
043         * iterations will never cause
044         * {@link #converged(int,PointVectorValuePair,PointVectorValuePair)}
045         * to return {@code true}.
046         */
047        private static final int ITERATION_CHECK_DISABLED = -1;
048        /**
049         * Number of iterations after which the
050         * {@link #converged(int,PointVectorValuePair,PointVectorValuePair)} method
051         * will return true (unless the check is disabled).
052         */
053        private final int maxIterationCount;
054    
055        /**
056         * Build an instance with specified thresholds.
057         *
058         * In order to perform only relative checks, the absolute tolerance
059         * must be set to a negative value. In order to perform only absolute
060         * checks, the relative tolerance must be set to a negative value.
061         *
062         * @param relativeThreshold relative tolerance threshold
063         * @param absoluteThreshold absolute tolerance threshold
064         */
065        public SimpleVectorValueChecker(final double relativeThreshold,
066                                        final double absoluteThreshold) {
067            super(relativeThreshold, absoluteThreshold);
068            maxIterationCount = ITERATION_CHECK_DISABLED;
069        }
070    
071        /**
072         * Builds an instance with specified tolerance thresholds and
073         * iteration count.
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 SimpleVectorValueChecker(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 times 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 arguments satify the convergence criterion.
112         */
113        @Override
114        public boolean converged(final int iteration,
115                                 final PointVectorValuePair previous,
116                                 final PointVectorValuePair current) {
117            if (maxIterationCount != ITERATION_CHECK_DISABLED) {
118                if (iteration >= maxIterationCount) {
119                    return true;
120                }
121            }
122    
123            final double[] p = previous.getValueRef();
124            final double[] c = current.getValueRef();
125            for (int i = 0; i < p.length; ++i) {
126                final double pi         = p[i];
127                final double ci         = c[i];
128                final double difference = FastMath.abs(pi - ci);
129                final double size       = FastMath.max(FastMath.abs(pi), FastMath.abs(ci));
130                if (difference > size * getRelativeThreshold() &&
131                    difference > getAbsoluteThreshold()) {
132                    return false;
133                }
134            }
135            return true;
136        }
137    }