/*
 * Roby Joehanes
 * 
 * Copyright 2007 Roby Joehanes
 * This file is distributed under the GNU General Public License version 2.0.
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 2 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */
/**
 * 
 */
package jdistlib.math.opt;

import static java.lang.Math.*;
import static jdistlib.math.Constants.*;

import jdistlib.math.UnivariateFunction;
import jdistlib.util.Debug;

/**
 * Function optimization routines. Currently only Brent's minimization routine.
 * Maybe I'll add Nelder-Meade or other fancier methods.
 * 
 * @author Roby Joehanes
 *
 */
public class Optimization {
	/**
	 * Brent's minimization function with default tolerance (1e-10)
	 * @param f
	 * @param ax
	 * @param bx
	 * @return the x at which f(x) is the minimum value
	 */
	public static final strictfp double optimize(UnivariateFunction f, double ax, double bx)
	{	return optimize(f, ax, bx, 1e-10, 1000); }

	/**
	 * Richard Brent's function minimization routine.
* Wikipedia's link
* Adapted from Netlib's fmin.
* Also looked at Numerical Methods in C, 2nd ed. Chapter 10 section 1 and 2. * * @param f the function to minimize * @param ax lower bound * @param bx upper bound * @param tol tolerance * @param maxiter the maximum number of iterations */ public static final strictfp double optimize(UnivariateFunction f, double ax, double bx, double tol, int maxiter) { // Local variables double a = ax, b = bx, v = a + kInvGoldRatio * (b - a), w = v, x = v, d = 0.0, e = 0.0, fu, fv, fw, fx, tol3; int iterNo = 0; fv = fw = fx = f.eval(x); tol3 = tol / 3.0; // main loop starts here for(;;) { iterNo++; double xm = (a + b) * 0.5, tol1 = SQRT_DBL_EPSILON * abs(x) + tol3, t2 = tol1 * 2.0; // check stopping criterion if (abs(x - xm) <= t2 - (b - a) * .5) break; double p = 0.0, q = 0.0, r = 0.0; if (abs(e) > tol1) { // fit parabola r = (x - w) * (fx - fv); q = (x - v) * (fx - fw); p = (x - v) * q - (x - w) * r; q = (q - r) * 2.0; if (q > 0.0) p = -p; else q = -q; r = e; e = d; } if (abs(p) >= abs(q * 0.5 * r) || p <= q * (a - x) || p >= q * (b - x)) { // a golden-section step e = x < xm ? b - x : a - x; d = kInvGoldRatio * e; } else { // a parabolic-interpolation step d = p / q; double u = x + d; // f must not be evaluated too close to ax or bx if (u - a < t2 || b - u < t2) d = x >= xm ? -tol1 : tol1; } // f must not be evaluated too close to x double u = abs(d) >= tol1 ? x + d : (d > 0 ? x + tol1 : x - tol1); fu = f.eval(u); // update a, b, v, w, and x if (fu <= fx) { if (u < x) b = x; else a = x; v = w; w = x; x = u; fv = fw; fw = fx; fx = fu; } else { if (u < x) a = u; else b = u; if (fu <= fw || w == x) { v = w; fv = fw; w = u; fw = fu; } else if (fu <= fv || v == x || v == w) { v = u; fv = fu; } } if (iterNo >= maxiter) { System.err.println("Warning: Convergence failure in optimize function!"); if (Debug.warningAsError) throw new RuntimeException("Warning: Convergence failure in optimize function!"); break; } } // end of main loop return x; } /**
************************************************************************
	 *			    C math library
	 * function ZEROIN - obtain a function zero within the given range
	 *
	 * Output
	 *	Zeroin returns an estimate for the root with accuracy
	 *	4*EPSILON*abs(x) + tol
	 *
	 * Algorithm
	 *	G.Forsythe, M.Malcolm, C.Moler, Computer methods for mathematical
	 *	computations. M., Mir, 1980, p.180 of the Russian edition
	 *
	 *	The function makes use of the bisection procedure combined with
	 *	the linear or quadric inverse interpolation.
	 *	At every step program operates on three abscissae - a, b, and c.
	 *	b - the last and the best approximation to the root
	 *	a - the last but one approximation
	 *	c - the last but one or even earlier approximation than a that
	 *		1) |f(b)| <= |f(c)|
	 *		2) f(b) and f(c) have opposite signs, i.e., b and c confine
	 *		   the root
	 *	At every step Zeroin selects one of the two new approximations, the
	 *	former being obtained by the bisection procedure and the latter
	 *	resulting in the interpolation (if a,b, and c are all different
	 *	the quadric interpolation is utilized, otherwise the linear one).
	 *	If the latter (i.e. obtained by the interpolation) point is
	 *	reasonable (i.e. lies within the current interval [b,c] not being
	 *	too close to the boundaries) it is accepted. The bisection result
	 *	is used in the other case. Therefore, the range of uncertainty is
	 *	ensured to be reduced at least by the factor 1.6
	 *
	 ************************************************************************
	 *
	 * NOTE:  uniroot() --> do_zeroin2()  --- in  ../main/optimize.c
	 *					      ~~~~~~~~~~~~~~~~~~
	 * 
* @param f The function whose zero is sought * @param ax Root will be sought for within a range [ax,bx] * @param bx * @param tol Acceptable tolerance for the root value. May be specified as 0.0 to cause the program to find the root as accurate as possible. * @param maxiter Max. iterations * @return the x where f(x) == 0 */ public static final strictfp double zeroin(UnivariateFunction f, double ax, double bx, double tol, int maxiter) { double maxit = maxiter+1, a = ax, b = bx, c = a, fa = f.eval(ax), fb = f.eval(bx), fc = fa; // First test if we have found a root at an endpoint if (fa == 0) return a; if (fb == 0) return b; while(maxit-- > 0) // Main iteration loop { double prev_step = b-a; // Distance from the last but one to the last approximation double tol_act; // Actual tolerance double p, q; // Interpolation step is calculated in the form p/q; division operations is delayed until the last moment double new_step; // Step at this iteration if( abs(fc) < abs(fb) ) { a = b; b = c; c = a; //Swap data for b to be the best approximation fa=fb; fb=fc; fc=fa; } tol_act = 2*DBL_EPSILON*abs(b) + tol/2; new_step = (c-b)/2; if( abs(new_step) <= tol_act || fb == 0.0 ) return b; // Acceptable approx. is found // Decide if the interpolation can be tried if( abs(prev_step) >= tol_act // If prev_step was large enough && abs(fa) > abs(fb) ) { // and was in true direction, interpolation may be tried double t1,cb,t2; cb = c-b; if( a==c ) { // If we have only two distinct points linear interpolation can only be applied t1 = fb/fa; p = cb*t1; q = 1.0 - t1; } else { // Quadric inverse interpolation q = fa/fc; t1 = fb/fc; t2 = fb/fa; p = t2 * ( cb*q*(q-t1) - (b-a)*(t1-1.0) ); q = (q-1.0) * (t1-1.0) * (t2-1.0); } if( p > 0 ) // p was calculated with the opposite sign; make p positive q = -q; else // and assign possible minus to q p = -p; if( p < (0.75*cb*q-abs(tol_act*q)/2) // If b+p/q falls in [b,c] && p < abs(prev_step*q/2) ) // and isn't too large new_step = p/q; // it is accepted // If p/q is too large then the bisection procedure can reduce [b,c] range to more extent } if( abs(new_step) < tol_act) { // Adjust the step to be not less than tolerance if( new_step > 0 ) new_step = tol_act; else new_step = -tol_act; } a = b; fa = fb; // Save the previous approx. b += new_step; fb = f.eval(b); // Do step to a new approxim. if( (fb > 0 && fc > 0) || (fb < 0 && fc < 0) ) { c = a; fc = fa; // Adjust c for it to have a sign opposite to that of b } } System.err.println("Warning: Convergence failure in zeroin function!"); if (Debug.warningAsError) throw new RuntimeException("Warning: Convergence failure in zeroin function!"); return b; } public static void main(String[] args) { UnivariateFunction f = new UnivariateFunction() { public double eval(double x) { x = x - 1/3.0; return x * x; } public void setObjects(Object... obj) {} public void setParameters(double... params) {} }; System.out.println(optimize(f, 0, 1, 0.0001, 1000)); System.out.println(optimize(f, 0, 1, 0, 1000)); f = new UnivariateFunction() { public double eval(double x) { return x * (x * x - 1) + 0.5; } public void setObjects(Object... obj) {} public void setParameters(double... params) {} }; System.out.println(zeroin(f, -2, 2, 0.0001, 1000)); System.out.println(zeroin(f, -2, 2, 1e-10, 1000)); System.out.println(zeroin(f, -2, 2, 0, 1000)); } }

Ads help maintain this website.