View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.math4.legacy.linear;
18  
19  import org.apache.commons.math4.legacy.core.IntegerSequence;
20  
21  import java.util.Collection;
22  import java.util.concurrent.CopyOnWriteArrayList;
23  
24  /**
25   * This abstract class provides a general framework for managing iterative
26   * algorithms. The maximum number of iterations can be set, and methods are
27   * provided to monitor the current iteration count. A lightweight event
28   * framework is also provided.
29   *
30   */
31  public class IterationManager {
32      /** The collection of all listeners attached to this iterative algorithm. */
33      private final Collection<IterationListener> listeners;
34      /** Maximum number of iterations. */
35      private final int maxIterations;
36      /** Callback. */
37      private final IntegerSequence.Incrementor.MaxCountExceededCallback callback;
38      /** Keeps a count of the number of iterations. */
39      private IntegerSequence.Incrementor iterations;
40  
41      /**
42       * Creates a new instance of this class.
43       *
44       * @param maxIterations Maximum number of iterations.
45       * {@link org.apache.commons.math4.legacy.exception.MaxCountExceededException}
46       * will be raised at counter exhaustion.
47       */
48      public IterationManager(final int maxIterations) {
49          this(maxIterations, null);
50      }
51  
52      /**
53       * Creates a new instance of this class.
54       *
55       * @param maxIterations the maximum number of iterations
56       * @param callback the function to be called when the maximum number of
57       * iterations has been reached.
58       * If {@code null}, {@link org.apache.commons.math4.legacy.exception.MaxCountExceededException}
59       * will be raised at counter exhaustion.
60       *
61       * @since 3.1
62       */
63      public IterationManager(final int maxIterations,
64                              final IntegerSequence.Incrementor.MaxCountExceededCallback callback) {
65          this.maxIterations = maxIterations;
66          this.callback = callback;
67          this.listeners = new CopyOnWriteArrayList<>();
68          resetCounter();
69      }
70  
71      /**
72       * Attaches a listener to this manager.
73       *
74       * @param listener A {@code IterationListener} object.
75       */
76      public void addIterationListener(final IterationListener listener) {
77          listeners.add(listener);
78      }
79  
80      /**
81       * Informs all registered listeners that the initial phase (prior to the
82       * main iteration loop) has been completed.
83       *
84       * @param e The {@link IterationEvent} object.
85       */
86      public void fireInitializationEvent(final IterationEvent e) {
87          for (IterationListener l : listeners) {
88              l.initializationPerformed(e);
89          }
90      }
91  
92      /**
93       * Informs all registered listeners that a new iteration (in the main
94       * iteration loop) has been performed.
95       *
96       * @param e The {@link IterationEvent} object.
97       */
98      public void fireIterationPerformedEvent(final IterationEvent e) {
99          for (IterationListener l : listeners) {
100             l.iterationPerformed(e);
101         }
102     }
103 
104     /**
105      * Informs all registered listeners that a new iteration (in the main
106      * iteration loop) has been started.
107      *
108      * @param e The {@link IterationEvent} object.
109      */
110     public void fireIterationStartedEvent(final IterationEvent e) {
111         for (IterationListener l : listeners) {
112             l.iterationStarted(e);
113         }
114     }
115 
116     /**
117      * Informs all registered listeners that the final phase (post-iterations)
118      * has been completed.
119      *
120      * @param e The {@link IterationEvent} object.
121      */
122     public void fireTerminationEvent(final IterationEvent e) {
123         for (IterationListener l : listeners) {
124             l.terminationPerformed(e);
125         }
126     }
127 
128     /**
129      * Returns the number of iterations of this solver, 0 if no iterations has
130      * been performed yet.
131      *
132      * @return the number of iterations.
133      */
134     public int getIterations() {
135         return iterations.getCount();
136     }
137 
138     /**
139      * Returns the maximum number of iterations.
140      *
141      * @return the maximum number of iterations.
142      */
143     public int getMaxIterations() {
144         return iterations.getMaximalCount();
145     }
146 
147     /**
148      * Increments the iteration count by one, and throws an exception if the
149      * maximum number of iterations is reached. This method should be called at
150      * the beginning of a new iteration.
151      *
152      * @throws org.apache.commons.math4.legacy.exception.MaxCountExceededException
153      * if the maximum number of iterations is reached.
154      */
155     public void incrementIterationCount() {
156         iterations.increment();
157     }
158 
159     /**
160      * Removes the specified iteration listener from the list of listeners
161      * currently attached to {@code this} object. Attempting to remove a
162      * listener which was <em>not</em> previously registered does not cause any
163      * error.
164      *
165      * @param listener The {@link IterationListener} to be removed.
166      */
167     public void removeIterationListener(final IterationListener listener) {
168         listeners.remove(listener);
169     }
170 
171     /**
172      * Sets the iteration count to 0. This method must be called during the
173      * initial phase.
174      */
175     public void resetIterationCount() {
176         resetCounter();
177     }
178 
179     /** Reset counter. */
180     private void resetCounter() {
181         iterations = IntegerSequence.Incrementor.create()
182             .withMaximalCount(maxIterations);
183         if (callback != null) {
184             iterations = iterations.withCallback(callback);
185         }
186     }
187 }