Mercurial > hg > jslab
view src/samer/maths/opt/ZeroCrossingSparsity.java @ 8:5e3cbbf173aa tip
Reorganise some more
author | samer |
---|---|
date | Fri, 05 Apr 2019 22:41:58 +0100 |
parents | bf79fb79ee13 |
children |
line wrap: on
line source
/* * 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(); } } } }