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