samer@0: /* samer@0: * Copyright (c) 2000, Samer Abdallah, King's College London. samer@0: * All rights reserved. samer@0: * samer@0: * This software is provided AS iS and WITHOUT ANY WARRANTY; samer@0: * without even the implied warranty of MERCHANTABILITY or samer@0: * FITNESS FOR A PARTICULAR PURPOSE. samer@0: */ samer@0: samer@0: package samer.maths.opt; samer@0: import samer.maths.*; samer@0: import samer.core.*; samer@0: samer@0: /** samer@0: Line search from Numerical Recipes in C, pretty samer@0: much as supplied. samer@0: samer@0: I removed the max step and slope checking and made it the samer@0: responsibility of the calling code to check these. samer@0: Also, this works with ONE-DIMENSIONAL functions: the stuff samer@0: about vectors can be handled by a LineFunction object. samer@0: */ samer@0: samer@0: public class PolynomialLineSearch samer@0: { samer@0: State S; samer@0: samer@0: public PolynomialLineSearch(State s) { S=s; } samer@0: samer@0: /** samer@0: This assumes that the initial step has already been taken samer@0: @param alamin minimum step size samer@0: */ samer@0: samer@0: public void run(Condition termination) samer@0: { samer@0: double alam, alam2, f3; samer@0: double tmplam; samer@0: samer@0: // if initial step is ok... samer@0: if (termination.test()) return; samer@0: samer@0: // backtrack using quadratic interpolation samer@0: tmplam = -S.P1.s/(2*(S.P1.f-S.P2.f-S.P1.s)); samer@0: alam = S.alpha; samer@0: samer@0: for (;;) { samer@0: samer@0: // remember failed parameters samer@0: alam2=alam; f3=S.P2.f; samer@0: alam=Math.max(tmplam,0.1*alam); samer@0: samer@0: S.step(alam); samer@0: samer@0: // if step was ok... samer@0: if (termination.test()) return; samer@0: samer@0: // backtrack using cubic interpolation samer@0: double rhs1 = S.P2.f - S.P1.f - alam*S.P1.s; samer@0: double rhs2 = f3 - S.P1.f - alam2*S.P1.s; samer@0: double a = (rhs1/(alam*alam) - rhs2/(alam2*alam2)) / (alam-alam2); samer@0: double b = (-alam2*rhs1/(alam*alam)+alam*rhs2/(alam2*alam2))/(alam-alam2); samer@0: samer@0: if (a==0.0) tmplam = -S.P1.s/(2*b); samer@0: else { samer@0: double disc=b*b-2*a*S.P1.s; samer@0: if (disc<0) tmplam=alam/2; samer@0: else if (b<=0) tmplam=(-b+Math.sqrt(disc))/(3*a); samer@0: else tmplam=-S.P1.s/(b+Math.sqrt(disc)); samer@0: } samer@0: if (tmplam>alam/2) tmplam=alam/2; samer@0: } samer@0: } samer@0: }