annotate 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
rev   line source
samer@0 1 /*
samer@0 2 * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0 3 * All rights reserved.
samer@0 4 *
samer@0 5 * This software is provided AS iS and WITHOUT ANY WARRANTY;
samer@0 6 * without even the implied warranty of MERCHANTABILITY or
samer@0 7 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 8 */
samer@0 9
samer@0 10 package samer.maths.opt;
samer@0 11 import samer.maths.*;
samer@0 12 import samer.core.*;
samer@0 13 import samer.core.types.*;
samer@0 14 import java.util.*;
samer@0 15
samer@0 16 /**
samer@0 17 Constraints and line minimisations for functions with gradient
samer@0 18 discontinuity at co-ordinate zeros (hyperplanes).
samer@0 19 The ZeroCrossingSparsity class handles this by checking for
samer@0 20 zero crossings during the line search. If a gradient
samer@0 21 discontinuity causes a change of sign in the gradient,
samer@0 22 that dimension is constrained and becomes inactive (drops
samer@0 23 out of minimisation). It can later be reactivated if
samer@0 24 the algorithm determines that the gradient no longer
samer@0 25 changes sign at that point.
samer@0 26 */
samer@0 27
samer@0 28 public class ZeroCrossingSparsity extends Constraints
samer@0 29 {
samer@0 30 public double alphas[];
samer@0 31 public int crossings[];
samer@0 32 public int numcrossings;
samer@0 33 public int clipped=0;
samer@0 34 private int released, releasable;
samer@0 35 private double XEPS=1e-6, GEPS=1e-4;
samer@0 36 private double GTHRESH=1;
samer@0 37
samer@0 38 public static Factory factory() {
samer@0 39 return new Factory() {
samer@0 40 public Constraints build(MinimiserBase minimiser) {
samer@0 41 return new ZeroCrossingSparsity(minimiser);
samer@0 42 }
samer@0 43 };
samer@0 44 }
samer@0 45
samer@0 46 public ZeroCrossingSparsity(MinimiserBase minimiser)
samer@0 47 {
samer@0 48 super(minimiser);
samer@0 49 crossings=new int[n];
samer@0 50 alphas=new double[n];
samer@0 51
samer@0 52 minimiser.add(new VParameter("XEPS", new DoubleModel() {
samer@0 53 public void set(double t) { XEPS=t; }
samer@0 54 public double get() { return XEPS; }
samer@0 55 } )
samer@0 56 );
samer@0 57
samer@0 58 minimiser.add(new VParameter("GEPS", new DoubleModel() {
samer@0 59 public void set(double t) { GEPS=t; }
samer@0 60 public double get() { return GEPS; }
samer@0 61 } )
samer@0 62 );
samer@0 63
samer@0 64 try {
samer@0 65 final Object jump=Shell.get("ZeroCrossingSparsity.jump");
samer@0 66 if (jump instanceof Double) {
samer@0 67 GTHRESH=((Double)jump).doubleValue();
samer@0 68 Shell.print("Gradient jump="+GTHRESH);
samer@0 69 } else if (jump instanceof VDouble) {
samer@0 70 GTHRESH=((VDouble)jump).value;
samer@0 71 ((VDouble)jump).addObserver( new Observer() {
samer@0 72 public void update(Observable o, Object arg) {
samer@0 73 GTHRESH=((VDouble)jump).value;
samer@0 74 }
samer@0 75 } );
samer@0 76 Shell.print("Gradient jump in VDouble="+GTHRESH);
samer@0 77 }
samer@0 78 } catch (Exception ex) {
samer@0 79 Shell.print("*** no jump object found! ***");
samer@0 80 Shell.print(ex.toString());
samer@0 81 ex.printStackTrace();
samer@0 82 }
samer@0 83 }
samer@0 84
samer@0 85 public void setGThreshold(double gt) { GTHRESH=gt; }
samer@0 86
samer@0 87 /** constrain all dimensions which are currently set
samer@0 88 to zero.
samer@0 89 */
samer@0 90
samer@0 91 public void initialise()
samer@0 92 {
samer@0 93 int p=0, q=0;
samer@0 94
samer@0 95 for (int i=0; i<n; i++) {
samer@0 96 if (S.P1.x[i]==0) inactive[p++]=i;
samer@0 97 else active[q++]=i;
samer@0 98 }
samer@0 99 m=q;
samer@0 100 }
samer@0 101
samer@0 102
samer@0 103 /** find all the zero crossings */
samer@0 104
samer@0 105 private boolean check()
samer@0 106 {
samer@0 107 // got to find sign swappers
samer@0 108 numcrossings=0;
samer@0 109 for (int j=0; j<m; j++) {
samer@0 110 int i=active[j];
samer@0 111 if ( (S.P1.x[i]>XEPS && S.P2.x[i]<XEPS)
samer@0 112 || (S.P2.x[i]>-XEPS && S.P1.x[i]<-XEPS) ) {
samer@0 113 crossings[numcrossings]=i;
samer@0 114 alphas[numcrossings]=-S.P1.x[i]/S.h[i];
samer@0 115 numcrossings++;
samer@0 116 }
samer@0 117 }
samer@0 118 return numcrossings>0;
samer@0 119 }
samer@0 120
samer@0 121 public void report()
samer@0 122 {
samer@0 123 if (numcrossings>0) {
samer@0 124 Shell.trace("crossings: "+numcrossings);
samer@0 125 for (int i=0; i<numcrossings; i++) {
samer@0 126 Shell.trace("dim: "+crossings[i]+" alpha: "+alphas[i]);
samer@0 127 }
samer@0 128 }
samer@0 129 super.report();
samer@0 130 }
samer@0 131
samer@0 132
samer@0 133 /**
samer@0 134 This finds the constrained dimension with the
samer@0 135 largest gradient, and if that absolute value of
samer@0 136 that gradient is bigger than 1, then releases
samer@0 137 that dimension so that it can take part in the
samer@0 138 optimization
samer@0 139 */
samer@0 140
samer@0 141 public boolean release(Datum P)
samer@0 142 {
samer@0 143 if (m==n) return false; // all active
samer@0 144
samer@0 145 int imax=-1;
samer@0 146 double grad=GTHRESH+GEPS;
samer@0 147
samer@0 148 releasable=0;
samer@0 149 for (int k=0; k<(n-m); k++) {
samer@0 150 int j=inactive[k];
samer@0 151 if (Math.abs(P.g[j])>grad) {
samer@0 152 releasable++;
samer@0 153 grad=Math.abs(P.g[j]);
samer@0 154 imax=j;
samer@0 155 }
samer@0 156 }
samer@0 157
samer@0 158 if (imax!=-1) {
samer@0 159 activate(imax); released=imax;
samer@0 160 return true;
samer@0 161 }
samer@0 162 else return false;
samer@0 163 }
samer@0 164
samer@0 165 public int getReleasedDimension() { return released; }
samer@0 166 public int getReleasableDimensions() { return releasable; }
samer@0 167
samer@0 168 public void lineSearch(Condition convergence, CubicLineSearch ls, double beta0)
samer@0 169 {
samer@0 170 boolean zcdone=false;
samer@0 171
samer@0 172 step(beta0);
samer@0 173 eval2();
samer@0 174
samer@0 175 while (!convergence.test()) {
samer@0 176
samer@0 177 // formulate any other direction change conditions
samer@0 178
samer@0 179 if (S.P2.f<S.P1.f && S.P2.s<0) {
samer@0 180 double beta=ls.extrapolate();
samer@0 181 S.move();
samer@0 182 step(beta);
samer@0 183 eval2();
samer@0 184 zcdone=false;
samer@0 185 } else {
samer@0 186 /* couple of options here:
samer@0 187 we could check all the zero crossings in one go.
samer@0 188 if we find one that needs constraining, then
samer@0 189 we're done.
samer@0 190 otherwise, we don't need to check zero crossings
samer@0 191 again unless we extrapolate
samer@0 192
samer@0 193 other option is to backtrack one zero crossing
samer@0 194 at a time
samer@0 195
samer@0 196 OR find zero crossing just after (or before)
samer@0 197 expected minimum
samer@0 198
samer@0 199 */
samer@0 200
samer@0 201 // get cubic step
samer@0 202 double interp = ls.interpolate();
samer@0 203
samer@0 204 if (!zcdone) { check(); zcdone=true; }
samer@0 205
samer@0 206 // try to pick a good step length
samer@0 207 // bearing in mind the zero crossings we have
samer@0 208 if (numcrossings>0) {
samer@0 209
samer@0 210 // we are going to look at the alphas, and
samer@0 211 // find the smallest one that is between
samer@0 212 // interp and current alpha
samer@0 213
samer@0 214 int best=-1;
samer@0 215 double bestAlpha=S.alpha;
samer@0 216
samer@0 217 for (int k=0; k<numcrossings; k++) {
samer@0 218 double beta=alphas[k];
samer@0 219 if (beta>=interp && beta<bestAlpha) {
samer@0 220 best=k; bestAlpha=beta;
samer@0 221 }
samer@0 222 }
samer@0 223
samer@0 224 if (best!=-1) {
samer@0 225 int j=crossings[best];
samer@0 226
samer@0 227 // kth zero crossing of jth dimension
samer@0 228 step(bestAlpha);
samer@0 229 S.P2.x[j]=0;
samer@0 230 eval2();
samer@0 231 if (Math.abs(S.P2.g[j])<=GTHRESH-GEPS) {
samer@0 232 inactivate(j);
samer@0 233 // Shell.trace("- inactivating: "+j);
samer@0 234 return;
samer@0 235
samer@0 236 // what if SEVERAL dimensions
samer@0 237 // end up close to zero:
samer@0 238 // should we constrain them all?
samer@0 239 } else {
samer@0 240 // Shell.trace("truncating");
samer@0 241 // what?
samer@0 242 // should we stick with this point, or
samer@0 243 // move to interp?
samer@0 244 continue;
samer@0 245 }
samer@0 246 } // else fall through to ordinary step
samer@0 247 }
samer@0 248
samer@0 249 // no crossings, take ordinary step
samer@0 250 step(interp);
samer@0 251 eval2();
samer@0 252 }
samer@0 253 }
samer@0 254 }
samer@0 255 }
samer@0 256