1 /*******************************************************************************
2 * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
9 * VTT Technical Research Centre of Finland - initial API and implementation
10 *******************************************************************************/
11 package org.simantics.history.util;
13 import java.util.Formatter;
15 import java.util.Map.Entry;
16 import java.util.TreeMap;
18 import org.simantics.databoard.primitives.MutableInteger;
21 * This class gives a rough distribution classification for double values.
23 * It calculates the frequency of values in each class. All values are
24 * accounted. There is a value between two samples.
25 * n(sample intervals) = n(samples) - 1 <p>
27 * Classes are derieved using logarithmic scale.
28 * Each class accounts all values within a range [ base ^ class .. base ^ (class-1) ).
30 * Example for classes of base number 2.0
33 * -10 [ 0,98ms .. 1,95ms )
34 * -9 [ 1,95ms .. 3,91ms )
35 * -8 [ 3,91ms .. 7,81ms )
36 * -7 [ 7,81ms .. 15,63ms )
37 * -6 [ 15,63ms .. 31,25ms )
38 * -5 [ 31,25ms .. 62,50ms )
39 * -4 [ 62,50ms .. 125,00ms )
40 * -3 [ 125,00ms .. 250,00ms )
41 * -2 [ 250,00ms .. 500,00ms )
42 * -1 [ 500,00ms .. 1 000,00ms )
43 * 0 [ 1 000,00ms .. 2 000,00ms )
44 * +1 [ 2 000,00ms .. 4 000,00ms )
45 * +2 [ 4 000,00ms .. 8 000,00ms )
46 * +3 [ 8 000,00ms .. 16 000,00ms )
47 * +4 [ 16 000,00ms .. 32 000,00ms )
48 * +5 [ 32 000,00ms .. 64 000,00ms )
49 * +6 [ 64 000,00ms .. 128 000,00ms )
50 * +7 [ 128 000,00ms .. 256 000,00ms )
51 * +8 [ 256 000,00ms .. 512 000,00ms )
52 * +9 [ 512 000,00ms .. 1 024 000,00ms )
53 * +10 [ 1 024 000,00ms .. 2 048 000,00ms )
55 * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
57 public class ClassDistribution {
59 // Optimization that tries to cirumvent slow Math.log
60 // previously entered value and its class is remembered
61 private transient double lastEnteredValue;
62 private transient int lastClass;
65 private transient double log_base;
68 TreeMap<Integer, MutableInteger> distribution;
70 public ClassDistribution() {
74 public ClassDistribution(double base) {
76 log_base = Math.log( base );
77 lastEnteredValue = 0.001;
78 lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );
79 distribution = new TreeMap<Integer, MutableInteger>();
82 public ClassDistribution(double base, TreeMap<Integer, MutableInteger> initialBreakdown) {
84 log_base = Math.log( base );
85 lastEnteredValue = 0.001;
86 lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );
87 distribution = new TreeMap<Integer, MutableInteger>( initialBreakdown );
90 public double getBase() {
94 public void setBase(double base) {
96 log_base = Math.log( base );
99 public double getSmallest() {
100 if (distribution.isEmpty()) return 1.0;
101 int clazz = distribution.firstKey();
102 return getClassAvg(clazz);
110 public double getMedian() {
113 for (MutableInteger v : distribution.values()) n += v.value;
115 double median = (double) n/2;
117 for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
118 sum += e.getValue().value;
121 Integer nextC = distribution.higherKey( c );
123 return getClassMax( c );
125 return ( getClassMax( c ) + getClassMin( nextC ) ) /2;
129 return getClassAvg( c );
136 * Get an index to the class with highest frequency.
138 * @return interval class or 0 if there are no samples
140 public int getLargestClassIndex() {
143 for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
144 if (e.getValue().value > nResult) {
145 nResult = e.getValue().value;
153 * Write distribution with user given map.
155 * @param result map where breakdown is written to
157 public void getDistribution(Map<Integer, Integer> result) {
159 for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
160 result.put( e.getKey(), Integer.valueOf(e.getValue().value));
164 public void setDistribution(Map<Integer, Integer> map) {
165 this.distribution.clear();
166 for (Entry<Integer, Integer> e : map.entrySet()) {
167 distribution.put( e.getKey(), new MutableInteger(e.getValue()) );
172 * Create a snapshot copy of the distribution.
174 * @return a histogram
176 public TreeMap<Integer, Integer> getDistribution() {
177 TreeMap<Integer, Integer> result = new TreeMap<Integer, Integer>();
178 getDistribution(result);
184 * Add new value to the distribution.
188 public void addValue(double value) {
189 Integer k = Integer.valueOf( getClassIndex(value) );
190 MutableInteger r = distribution.get(k);
192 r = new MutableInteger();
193 distribution.put(k, r);
199 * Get lowest value of a class
201 * @param intervalClass
204 public double getClassMin(int intervalClass) {
205 return Math.pow(base, intervalClass);
209 * Get highest value of a class
211 * @param intervalClass
214 public double getClassMax(int intervalClass) {
215 return Math.pow(base, intervalClass+1);
219 * Get average value of a class
221 * @param intervalClass
222 * @return average interval
224 public double getClassAvg(int intervalClass) {
225 double min = getClassMin(intervalClass);
226 double max = getClassMax(intervalClass);
227 return (max-min)/2+min;
231 * Get class index for a value
233 * @return class index
235 public int getClassIndex(double interval) {
236 if (interval == lastEnteredValue) return lastClass;
237 lastClass = (int) Math.floor( Math.log(interval) / log_base );
238 lastEnteredValue = interval;
243 public String toString() {
244 StringBuilder sb = new StringBuilder();
245 Formatter f = new Formatter(sb);
246 sb.append("Index Range Count\n");
247 for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
249 double start = getClassMin(ic);
250 double end = getClassMax(ic);
251 double avg = getClassAvg(ic);
252 int count = e.getValue().value;
258 format = " %+3d [ %(,8fm .. %(,8fm ) = %d, avg = %(,8fm\n";
264 format = " %+3d [ %(,8.2fm .. %(,8.2fm ) = %d, avg = %(,8.2fm\n";
266 format = " %+3d [ %(9.0f .. %(9.0f ) = %d, avg = %(8.1f\n";
268 f.format(format , ic, start, end, count, avg);
270 return sb.toString();