Mercurial > hg > jslab
view 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 |
line wrap: on
line source
/* * Histogram.java * * 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.units; import samer.core.*; import samer.core.types.*; import samer.core.util.*; import samer.core.Agent.*; import samer.tools.*; import samer.maths.*; import java.util.*; /** This actually builds several histograms in parallel: one for each element of a Vec or double array. A IMap provides the mapping from element values to histogram bins. The result is a <i>Matrix</i>, each <i>row</i> of which is the histogram for the corresponding element of the input vector. */ public class Histogram extends Viewable implements Task, Agent { private Vec input; private Matrix bins; private VMap map; private double[][] binArray; private double[] lbw; // log of bin widths private VVector L; private VDouble sumL; private int N, count; private double[] x; public Histogram( Vec input, int binCount) { super("histogram"); Shell.push(getNode()); N = input.size(); Shell.setAutoRegister(false); bins = new Matrix("bins",N,binCount); map = new VMap(new LinearMap(binCount)); L = new VVector("likelihood",N); sumL = new VDouble("sumL"); Shell.setAutoRegister(true); count=0; x=input.array(); lbw = new double[binCount]; Shell.pop(); setAgent(this); binArray = bins.getArray(); Shell.registerViewable(this); } public Matrix getBinMatrix() { return bins; } public VVector getLikelihoodVector() { return L; } public VDouble getLikelihoodSignal() { return sumL; } public void starting() {} public void stopping() {} public void run() { IMap binmap=map.getMap(); double [] l=L.array(); if (x!=null) { for(int k=0; k<N; k++) { int j=binmap.clipInt(x[k]); l[k] = -Math.log(++binArray[k][j]) + lbw[j]; } } else { Vec.Iterator i=input.iterator(); for(int k=0; i.more(); k++) { int j=binmap.clipInt(i.next()); l[k] = -Math.log(++binArray[k][j]) + lbw[j]; } } count++; Mathx.add(l,Math.log(count)); sumL.value=Mathx.sum(l); L.changed(); sumL.changed(); bins.changed(); } public void clear() { bins.zero(); bins.changed(); count=0; } public double[] normalise() { count=(int)Mathx.sum(binArray[0]); Shell.print("Histogram: count="+count); Shell.print("Computing bin widths..."); IMap binmap=map.getMap(); for (int i=0; i<lbw.length; i++) { lbw[i]=Math.log(binmap.inverseFromInt(i+1) - binmap.inverseFromInt(i)); } return lbw; } public void dispose() { bins.dispose(); map.dispose(); L.dispose(); super.dispose(); } public Viewer getViewer() { DefaultViewer vwr=new DefaultViewer(this); vwr.add(bins.viewable()); vwr.add(L); vwr.add(sumL); return vwr; } public void getCommands(Registry r) { r.add("clear").add("normalise"); r.group(); map.getCommands(r); } public void execute(String cmd, Environment env) throws Exception { if (cmd.equals("clear")) clear(); else if (cmd.equals("normalise")) normalise(); map.execute(cmd,env); } public Equaliser getEqualiser() { return new Equaliser(); } /** This is a function which uses a cumulative probability function derived from the histogram to compute a transformation that results in a uniformly distributed variable. It takes a SNAPSHOT of the current histogram map and bin counts. You must update() to update from current histogram. */ public class Equaliser extends VectorFunctionOfVector { IMap map; int N, M; Matrix C; double K; double [][]P; public Equaliser() { N=bins.getRowDimension(); M=bins.getColumnDimension(); C=new Matrix("cumulative",N,M); P=C.getArray(); update(); } public void dispose() { C.dispose(); } public void update() { map=Histogram.this.map.getMap(); K=map.getIntRange(); for (int i=0; i<N; i++) { double T=0; for (int j=0; j<M; j++) { P[i][j]=(T+=binArray[i][j]); } Mathx.mul(P[i],1/T); } C.changed(); } public void apply(double [] x) { apply(x,x); } public void apply(double[] x, double[] y) { for (int i=0; i<N; i++) { double z=K*map.map(x[i]); int j=(int)z; if (j<0) y[i]=0; else if (j>=M) y[i]=1; else { // linearly interpolate double P1=P[i][j]; double P0=(j==0)? 0 : P[i][j-1]; double d=z-j; y[i]=(1-d)*P0 + d*P1; } } } } }