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.util;
018    
019    import java.util.Collection;
020    import java.util.concurrent.CopyOnWriteArrayList;
021    
022    import org.apache.commons.math3.exception.MaxCountExceededException;
023    
024    /**
025     * This abstract class provides a general framework for managing iterative
026     * algorithms. The maximum number of iterations can be set, and methods are
027     * provided to monitor the current iteration count. A lightweight event
028     * framework is also provided.
029     *
030     * @version $Id: IterationManager.java 1422313 2012-12-15 18:53:41Z psteitz $
031     */
032    public class IterationManager {
033    
034        /** Keeps a count of the number of iterations. */
035        private final Incrementor iterations;
036    
037        /** The collection of all listeners attached to this iterative algorithm. */
038        private final Collection<IterationListener> listeners;
039    
040        /**
041         * Creates a new instance of this class.
042         *
043         * @param maxIterations the maximum number of iterations
044         */
045        public IterationManager(final int maxIterations) {
046            this.iterations = new Incrementor(maxIterations);
047            this.listeners = new CopyOnWriteArrayList<IterationListener>();
048        }
049    
050        /**
051         * Creates a new instance of this class.
052         *
053         * @param maxIterations the maximum number of iterations
054         * @param callBack the function to be called when the maximum number of
055         * iterations has been reached
056         * @throws org.apache.commons.math3.exception.NullArgumentException if {@code callBack} is {@code null}
057         * @since 3.1
058         */
059        public IterationManager(final int maxIterations,
060                                final Incrementor.MaxCountExceededCallback callBack) {
061            this.iterations = new Incrementor(maxIterations, callBack);
062            this.listeners = new CopyOnWriteArrayList<IterationListener>();
063        }
064    
065        /**
066         * Attaches a listener to this manager.
067         *
068         * @param listener A {@code IterationListener} object.
069         */
070        public void addIterationListener(final IterationListener listener) {
071            listeners.add(listener);
072        }
073    
074        /**
075         * Informs all registered listeners that the initial phase (prior to the
076         * main iteration loop) has been completed.
077         *
078         * @param e The {@link IterationEvent} object.
079         */
080        public void fireInitializationEvent(final IterationEvent e) {
081            for (IterationListener l : listeners) {
082                l.initializationPerformed(e);
083            }
084        }
085    
086        /**
087         * Informs all registered listeners that a new iteration (in the main
088         * iteration loop) has been performed.
089         *
090         * @param e The {@link IterationEvent} object.
091         */
092        public void fireIterationPerformedEvent(final IterationEvent e) {
093            for (IterationListener l : listeners) {
094                l.iterationPerformed(e);
095            }
096        }
097    
098        /**
099         * Informs all registered listeners that a new iteration (in the main
100         * iteration loop) has been started.
101         *
102         * @param e The {@link IterationEvent} object.
103         */
104        public void fireIterationStartedEvent(final IterationEvent e) {
105            for (IterationListener l : listeners) {
106                l.iterationStarted(e);
107            }
108        }
109    
110        /**
111         * Informs all registered listeners that the final phase (post-iterations)
112         * has been completed.
113         *
114         * @param e The {@link IterationEvent} object.
115         */
116        public void fireTerminationEvent(final IterationEvent e) {
117            for (IterationListener l : listeners) {
118                l.terminationPerformed(e);
119            }
120        }
121    
122        /**
123         * Returns the number of iterations of this solver, 0 if no iterations has
124         * been performed yet.
125         *
126         * @return the number of iterations.
127         */
128        public int getIterations() {
129            return iterations.getCount();
130        }
131    
132        /**
133         * Returns the maximum number of iterations.
134         *
135         * @return the maximum number of iterations.
136         */
137        public int getMaxIterations() {
138            return iterations.getMaximalCount();
139        }
140    
141        /**
142         * Increments the iteration count by one, and throws an exception if the
143         * maximum number of iterations is reached. This method should be called at
144         * the beginning of a new iteration.
145         *
146         * @throws MaxCountExceededException if the maximum number of iterations is
147         * reached.
148         */
149        public void incrementIterationCount()
150            throws MaxCountExceededException {
151            iterations.incrementCount();
152        }
153    
154        /**
155         * Removes the specified iteration listener from the list of listeners
156         * currently attached to {@code this} object. Attempting to remove a
157         * listener which was <em>not</em> previously registered does not cause any
158         * error.
159         *
160         * @param listener The {@link IterationListener} to be removed.
161         */
162        public void removeIterationListener(final IterationListener listener) {
163            listeners.remove(listener);
164        }
165    
166        /**
167         * Sets the iteration count to 0. This method must be called during the
168         * initial phase.
169         */
170        public void resetIterationCount() {
171            iterations.resetCount();
172        }
173    }