/* * Copyright (c) 2003, the JUNG Project and the Regents of the University * of California * All rights reserved. * * This software is open-source under the BSD license; see either * "license.txt" or * http://jung.sourceforge.net/license.txt for a description. */ package edu.uci.ics.jung.algorithms.util; /** * Provides basic infrastructure for iterative algorithms. Services provided * include: * <ul> * <li>storage of current and max iteration count</li> * <li>framework for initialization, iterative evaluation, and finalization</li> * <li>test for convergence</li> * <li>etc.</li> * </ul> * <p> * Algorithms that subclass this class are typically used in the following way: * <br> * * <pre> * FooAlgorithm foo = new FooAlgorithm(...) * foo.setMaximumIterations(100); //set up conditions * ... * foo.evaluate(); //key method which initiates iterative process * foo.getSomeResult(); * </pre> * * @author Scott White (originally written by Didier Besset) */ public abstract class IterativeProcess implements IterativeContext { /** * Number of iterations performed. */ private int iterations; /** * Maximum allowed number of iterations. */ private int maximumIterations = 50; /** * Desired precision. */ private double desiredPrecision = Double.MIN_VALUE; /** * Achieved precision. */ private double precision; /** * Generic constructor. */ public IterativeProcess() { } /** * Performs the iterative process. Note: this method does not return * anything because Java does not allow mixing double, int, or objects */ public void evaluate() { iterations = 0; initializeIterations(); while (iterations++ < maximumIterations) { step(); precision = getPrecision(); if (hasConverged()) { break; } } finalizeIterations(); } /** * Evaluate the result of the current iteration. */ @Override abstract public void step(); /** * Perform eventual clean-up operations (must be implement by subclass when * needed). */ protected void finalizeIterations() { } /** * Returns the desired precision. */ public double getDesiredPrecision() { return desiredPrecision; } /** * Returns the number of iterations performed. */ public int getIterations() { return iterations; } /** * Returns the maximum allowed number of iterations. */ public int getMaximumIterations() { return maximumIterations; } /** * Returns the attained precision. */ public double getPrecision() { return precision; } /** * @param precision * the precision to set */ public void setPrecision(double precision) { this.precision = precision; } /** * * Check to see if the result has been attained. * * @return boolean */ public boolean hasConverged() { return precision < desiredPrecision; } @Override public boolean done() { return hasConverged(); } /** * Initializes internal parameters to start the iterative process. */ protected void initializeIterations() { } /** * */ public void reset() { } /** * @return double * @param epsilon * double * @param x * double */ public double relativePrecision(double epsilon, double x) { return x > desiredPrecision ? epsilon / x : epsilon; } /** * Defines the desired precision. */ public void setDesiredPrecision(double prec) throws IllegalArgumentException { if (prec <= 0) { throw new IllegalArgumentException( "Non-positive precision: " + prec); } desiredPrecision = prec; } /** * Defines the maximum allowed number of iterations. */ public void setMaximumIterations(int maxIter) throws IllegalArgumentException { if (maxIter < 1) { throw new IllegalArgumentException( "Non-positive maximum iteration: " + maxIter); } maximumIterations = maxIter; } }