Mercurial > hg > jslab
diff src/samer/maths/opt/ZeroCrossingSparsity.java @ 0:bf79fb79ee13
Initial Mercurial check in.
author | samer |
---|---|
date | Tue, 17 Jan 2012 17:50:20 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/samer/maths/opt/ZeroCrossingSparsity.java Tue Jan 17 17:50:20 2012 +0000 @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2000, Samer Abdallah, King's College London. + * All rights reserved. + * + * This software is provided AS iS and WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + */ + +package samer.maths.opt; +import samer.maths.*; +import samer.core.*; +import samer.core.types.*; +import java.util.*; + +/** + Constraints and line minimisations for functions with gradient + discontinuity at co-ordinate zeros (hyperplanes). + The ZeroCrossingSparsity class handles this by checking for + zero crossings during the line search. If a gradient + discontinuity causes a change of sign in the gradient, + that dimension is constrained and becomes inactive (drops + out of minimisation). It can later be reactivated if + the algorithm determines that the gradient no longer + changes sign at that point. + */ + +public class ZeroCrossingSparsity extends Constraints +{ + public double alphas[]; + public int crossings[]; + public int numcrossings; + public int clipped=0; + private int released, releasable; + private double XEPS=1e-6, GEPS=1e-4; + private double GTHRESH=1; + + public static Factory factory() { + return new Factory() { + public Constraints build(MinimiserBase minimiser) { + return new ZeroCrossingSparsity(minimiser); + } + }; + } + + public ZeroCrossingSparsity(MinimiserBase minimiser) + { + super(minimiser); + crossings=new int[n]; + alphas=new double[n]; + + minimiser.add(new VParameter("XEPS", new DoubleModel() { + public void set(double t) { XEPS=t; } + public double get() { return XEPS; } + } ) + ); + + minimiser.add(new VParameter("GEPS", new DoubleModel() { + public void set(double t) { GEPS=t; } + public double get() { return GEPS; } + } ) + ); + + try { + final Object jump=Shell.get("ZeroCrossingSparsity.jump"); + if (jump instanceof Double) { + GTHRESH=((Double)jump).doubleValue(); + Shell.print("Gradient jump="+GTHRESH); + } else if (jump instanceof VDouble) { + GTHRESH=((VDouble)jump).value; + ((VDouble)jump).addObserver( new Observer() { + public void update(Observable o, Object arg) { + GTHRESH=((VDouble)jump).value; + } + } ); + Shell.print("Gradient jump in VDouble="+GTHRESH); + } + } catch (Exception ex) { + Shell.print("*** no jump object found! ***"); + Shell.print(ex.toString()); + ex.printStackTrace(); + } + } + + public void setGThreshold(double gt) { GTHRESH=gt; } + + /** constrain all dimensions which are currently set + to zero. + */ + + public void initialise() + { + int p=0, q=0; + + for (int i=0; i<n; i++) { + if (S.P1.x[i]==0) inactive[p++]=i; + else active[q++]=i; + } + m=q; + } + + + /** find all the zero crossings */ + + private boolean check() + { + // got to find sign swappers + numcrossings=0; + for (int j=0; j<m; j++) { + int i=active[j]; + if ( (S.P1.x[i]>XEPS && S.P2.x[i]<XEPS) + || (S.P2.x[i]>-XEPS && S.P1.x[i]<-XEPS) ) { + crossings[numcrossings]=i; + alphas[numcrossings]=-S.P1.x[i]/S.h[i]; + numcrossings++; + } + } + return numcrossings>0; + } + + public void report() + { + if (numcrossings>0) { + Shell.trace("crossings: "+numcrossings); + for (int i=0; i<numcrossings; i++) { + Shell.trace("dim: "+crossings[i]+" alpha: "+alphas[i]); + } + } + super.report(); + } + + + /** + This finds the constrained dimension with the + largest gradient, and if that absolute value of + that gradient is bigger than 1, then releases + that dimension so that it can take part in the + optimization + */ + + public boolean release(Datum P) + { + if (m==n) return false; // all active + + int imax=-1; + double grad=GTHRESH+GEPS; + + releasable=0; + for (int k=0; k<(n-m); k++) { + int j=inactive[k]; + if (Math.abs(P.g[j])>grad) { + releasable++; + grad=Math.abs(P.g[j]); + imax=j; + } + } + + if (imax!=-1) { + activate(imax); released=imax; + return true; + } + else return false; + } + + public int getReleasedDimension() { return released; } + public int getReleasableDimensions() { return releasable; } + + public void lineSearch(Condition convergence, CubicLineSearch ls, double beta0) + { + boolean zcdone=false; + + step(beta0); + eval2(); + + while (!convergence.test()) { + + // formulate any other direction change conditions + + if (S.P2.f<S.P1.f && S.P2.s<0) { + double beta=ls.extrapolate(); + S.move(); + step(beta); + eval2(); + zcdone=false; + } else { + /* couple of options here: + we could check all the zero crossings in one go. + if we find one that needs constraining, then + we're done. + otherwise, we don't need to check zero crossings + again unless we extrapolate + + other option is to backtrack one zero crossing + at a time + + OR find zero crossing just after (or before) + expected minimum + + */ + + // get cubic step + double interp = ls.interpolate(); + + if (!zcdone) { check(); zcdone=true; } + + // try to pick a good step length + // bearing in mind the zero crossings we have + if (numcrossings>0) { + + // we are going to look at the alphas, and + // find the smallest one that is between + // interp and current alpha + + int best=-1; + double bestAlpha=S.alpha; + + for (int k=0; k<numcrossings; k++) { + double beta=alphas[k]; + if (beta>=interp && beta<bestAlpha) { + best=k; bestAlpha=beta; + } + } + + if (best!=-1) { + int j=crossings[best]; + + // kth zero crossing of jth dimension + step(bestAlpha); + S.P2.x[j]=0; + eval2(); + if (Math.abs(S.P2.g[j])<=GTHRESH-GEPS) { + inactivate(j); + // Shell.trace("- inactivating: "+j); + return; + + // what if SEVERAL dimensions + // end up close to zero: + // should we constrain them all? + } else { + // Shell.trace("truncating"); + // what? + // should we stick with this point, or + // move to interp? + continue; + } + } // else fall through to ordinary step + } + + // no crossings, take ordinary step + step(interp); + eval2(); + } + } + } +} +