annotate src/samer/units/Histogram.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 * Histogram.java
samer@0 3 *
samer@0 4 * Copyright (c) 2000, Samer Abdallah, King's College London.
samer@0 5 * All rights reserved.
samer@0 6 *
samer@0 7 * This software is provided AS iS and WITHOUT ANY WARRANTY;
samer@0 8 * without even the implied warranty of MERCHANTABILITY or
samer@0 9 * FITNESS FOR A PARTICULAR PURPOSE.
samer@0 10 */
samer@0 11
samer@0 12 package samer.units;
samer@0 13
samer@0 14 import samer.core.*;
samer@0 15 import samer.core.types.*;
samer@0 16 import samer.core.util.*;
samer@0 17 import samer.core.Agent.*;
samer@0 18 import samer.tools.*;
samer@0 19 import samer.maths.*;
samer@0 20 import java.util.*;
samer@0 21
samer@0 22 /**
samer@0 23 This actually builds several histograms in parallel: one
samer@0 24 for each element of a Vec or double array. A IMap provides
samer@0 25 the mapping from element values to histogram bins.
samer@0 26 The result is a <i>Matrix</i>, each <i>row</i> of which
samer@0 27 is the histogram for the corresponding element of the
samer@0 28 input vector.
samer@0 29 */
samer@0 30
samer@0 31 public class Histogram extends Viewable implements Task, Agent
samer@0 32 {
samer@0 33 private Vec input;
samer@0 34 private Matrix bins;
samer@0 35 private VMap map;
samer@0 36 private double[][] binArray;
samer@0 37 private double[] lbw; // log of bin widths
samer@0 38 private VVector L;
samer@0 39 private VDouble sumL;
samer@0 40 private int N, count;
samer@0 41 private double[] x;
samer@0 42
samer@0 43 public Histogram( Vec input, int binCount)
samer@0 44 {
samer@0 45 super("histogram");
samer@0 46
samer@0 47 Shell.push(getNode());
samer@0 48
samer@0 49 N = input.size();
samer@0 50 Shell.setAutoRegister(false);
samer@0 51 bins = new Matrix("bins",N,binCount);
samer@0 52 map = new VMap(new LinearMap(binCount));
samer@0 53 L = new VVector("likelihood",N);
samer@0 54 sumL = new VDouble("sumL");
samer@0 55 Shell.setAutoRegister(true);
samer@0 56 count=0; x=input.array();
samer@0 57 lbw = new double[binCount];
samer@0 58 Shell.pop();
samer@0 59
samer@0 60 setAgent(this);
samer@0 61 binArray = bins.getArray();
samer@0 62 Shell.registerViewable(this);
samer@0 63 }
samer@0 64
samer@0 65 public Matrix getBinMatrix() { return bins; }
samer@0 66 public VVector getLikelihoodVector() { return L; }
samer@0 67 public VDouble getLikelihoodSignal() { return sumL; }
samer@0 68
samer@0 69 public void starting() {}
samer@0 70 public void stopping() {}
samer@0 71 public void run()
samer@0 72 {
samer@0 73 IMap binmap=map.getMap();
samer@0 74 double [] l=L.array();
samer@0 75
samer@0 76 if (x!=null) {
samer@0 77 for(int k=0; k<N; k++) {
samer@0 78 int j=binmap.clipInt(x[k]);
samer@0 79 l[k] = -Math.log(++binArray[k][j]) + lbw[j];
samer@0 80 }
samer@0 81 } else {
samer@0 82 Vec.Iterator i=input.iterator();
samer@0 83 for(int k=0; i.more(); k++) {
samer@0 84 int j=binmap.clipInt(i.next());
samer@0 85 l[k] = -Math.log(++binArray[k][j]) + lbw[j];
samer@0 86 }
samer@0 87 }
samer@0 88
samer@0 89 count++;
samer@0 90 Mathx.add(l,Math.log(count));
samer@0 91 sumL.value=Mathx.sum(l);
samer@0 92
samer@0 93 L.changed();
samer@0 94 sumL.changed();
samer@0 95 bins.changed();
samer@0 96 }
samer@0 97
samer@0 98 public void clear() { bins.zero(); bins.changed(); count=0; }
samer@0 99 public double[] normalise() {
samer@0 100 count=(int)Mathx.sum(binArray[0]);
samer@0 101 Shell.print("Histogram: count="+count);
samer@0 102 Shell.print("Computing bin widths...");
samer@0 103 IMap binmap=map.getMap();
samer@0 104
samer@0 105 for (int i=0; i<lbw.length; i++) {
samer@0 106 lbw[i]=Math.log(binmap.inverseFromInt(i+1) - binmap.inverseFromInt(i));
samer@0 107 }
samer@0 108 return lbw;
samer@0 109 }
samer@0 110
samer@0 111 public void dispose() {
samer@0 112 bins.dispose();
samer@0 113 map.dispose();
samer@0 114 L.dispose();
samer@0 115 super.dispose();
samer@0 116 }
samer@0 117
samer@0 118 public Viewer getViewer() {
samer@0 119 DefaultViewer vwr=new DefaultViewer(this);
samer@0 120 vwr.add(bins.viewable());
samer@0 121 vwr.add(L);
samer@0 122 vwr.add(sumL);
samer@0 123 return vwr;
samer@0 124 }
samer@0 125
samer@0 126 public void getCommands(Registry r) {
samer@0 127 r.add("clear").add("normalise");
samer@0 128 r.group(); map.getCommands(r);
samer@0 129 }
samer@0 130
samer@0 131 public void execute(String cmd, Environment env) throws Exception {
samer@0 132 if (cmd.equals("clear")) clear();
samer@0 133 else if (cmd.equals("normalise")) normalise();
samer@0 134 map.execute(cmd,env);
samer@0 135 }
samer@0 136
samer@0 137 public Equaliser getEqualiser() { return new Equaliser(); }
samer@0 138
samer@0 139 /** This is a function which uses a cumulative probability function
samer@0 140 derived from the histogram to compute a transformation that
samer@0 141 results in a uniformly distributed variable. It takes a SNAPSHOT
samer@0 142 of the current histogram map and bin counts. You must update()
samer@0 143 to update from current histogram.
samer@0 144 */
samer@0 145 public class Equaliser extends VectorFunctionOfVector
samer@0 146 {
samer@0 147 IMap map;
samer@0 148 int N, M;
samer@0 149 Matrix C;
samer@0 150 double K;
samer@0 151 double [][]P;
samer@0 152
samer@0 153 public Equaliser() {
samer@0 154 N=bins.getRowDimension();
samer@0 155 M=bins.getColumnDimension();
samer@0 156 C=new Matrix("cumulative",N,M);
samer@0 157 P=C.getArray();
samer@0 158 update();
samer@0 159 }
samer@0 160
samer@0 161 public void dispose() { C.dispose(); }
samer@0 162 public void update() {
samer@0 163 map=Histogram.this.map.getMap();
samer@0 164 K=map.getIntRange();
samer@0 165 for (int i=0; i<N; i++) {
samer@0 166 double T=0;
samer@0 167 for (int j=0; j<M; j++) {
samer@0 168 P[i][j]=(T+=binArray[i][j]);
samer@0 169 }
samer@0 170 Mathx.mul(P[i],1/T);
samer@0 171 }
samer@0 172 C.changed();
samer@0 173 }
samer@0 174
samer@0 175 public void apply(double [] x) { apply(x,x); }
samer@0 176 public void apply(double[] x, double[] y) {
samer@0 177 for (int i=0; i<N; i++) {
samer@0 178 double z=K*map.map(x[i]);
samer@0 179 int j=(int)z;
samer@0 180 if (j<0) y[i]=0;
samer@0 181 else if (j>=M) y[i]=1;
samer@0 182 else {
samer@0 183 // linearly interpolate
samer@0 184 double P1=P[i][j];
samer@0 185 double P0=(j==0)? 0 : P[i][j-1];
samer@0 186 double d=z-j;
samer@0 187 y[i]=(1-d)*P0 + d*P1;
samer@0 188 }
samer@0 189 }
samer@0 190 }
samer@0 191 }
samer@0 192 }
samer@0 193