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
|