-/*******************************************************************************\r
- * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- * VTT Technical Research Centre of Finland - initial API and implementation\r
- *******************************************************************************/\r
-package org.simantics.history.util;\r
-\r
-import java.util.Formatter;\r
-import java.util.Map;\r
-import java.util.Map.Entry;\r
-import java.util.TreeMap;\r
-\r
-import org.simantics.databoard.primitives.MutableInteger;\r
-\r
-/**\r
- * This class gives a rough distribution classification for double values. \r
- * \r
- * It calculates the frequency of values in each class. All values are \r
- * accounted. There is a value between two samples. \r
- * n(sample intervals) = n(samples) - 1 <p>\r
- * \r
- * Classes are derieved using logarithmic scale. \r
- * Each class accounts all values within a range [ base ^ class .. base ^ (class-1) ).\r
- * \r
- * Example for classes of base number 2.0\r
- * \r
- * Class Ranges\r
- * -10 [ 0,98ms .. 1,95ms )\r
- * -9 [ 1,95ms .. 3,91ms )\r
- * -8 [ 3,91ms .. 7,81ms )\r
- * -7 [ 7,81ms .. 15,63ms )\r
- * -6 [ 15,63ms .. 31,25ms )\r
- * -5 [ 31,25ms .. 62,50ms )\r
- * -4 [ 62,50ms .. 125,00ms )\r
- * -3 [ 125,00ms .. 250,00ms )\r
- * -2 [ 250,00ms .. 500,00ms )\r
- * -1 [ 500,00ms .. 1 000,00ms )\r
- * 0 [ 1 000,00ms .. 2 000,00ms )\r
- * +1 [ 2 000,00ms .. 4 000,00ms )\r
- * +2 [ 4 000,00ms .. 8 000,00ms )\r
- * +3 [ 8 000,00ms .. 16 000,00ms )\r
- * +4 [ 16 000,00ms .. 32 000,00ms )\r
- * +5 [ 32 000,00ms .. 64 000,00ms )\r
- * +6 [ 64 000,00ms .. 128 000,00ms )\r
- * +7 [ 128 000,00ms .. 256 000,00ms )\r
- * +8 [ 256 000,00ms .. 512 000,00ms )\r
- * +9 [ 512 000,00ms .. 1 024 000,00ms )\r
- * +10 [ 1 024 000,00ms .. 2 048 000,00ms ) \r
- *\r
- * @author Toni Kalajainen <toni.kalajainen@vtt.fi>\r
- */\r
-public class ClassDistribution {\r
- \r
- // Optimization that tries to cirumvent slow Math.log\r
- // previously entered value and its class is remembered\r
- private transient double lastEnteredValue;\r
- private transient int lastClass;\r
- \r
- double base;\r
- private transient double log_base;\r
-\r
- /** Distribution */\r
- TreeMap<Integer, MutableInteger> distribution; \r
- \r
- public ClassDistribution() {\r
- this( 2.0 );\r
- }\r
- \r
- public ClassDistribution(double base) {\r
- this.base = base;\r
- log_base = Math.log( base );\r
- lastEnteredValue = 0.001;\r
- lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );\r
- distribution = new TreeMap<Integer, MutableInteger>();\r
- }\r
- \r
- public ClassDistribution(double base, TreeMap<Integer, MutableInteger> initialBreakdown) {\r
- this.base = base;\r
- log_base = Math.log( base );\r
- lastEnteredValue = 0.001;\r
- lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );\r
- distribution = new TreeMap<Integer, MutableInteger>( initialBreakdown );\r
- }\r
- \r
- public double getBase() {\r
- return base;\r
- }\r
- \r
- public void setBase(double base) {\r
- this.base = base;\r
- log_base = Math.log( base );\r
- }\r
-\r
- public double getSmallest() {\r
- if (distribution.isEmpty()) return 1.0;\r
- int clazz = distribution.firstKey();\r
- return getClassAvg(clazz);\r
- }\r
- \r
- /**\r
- * Get median value\r
- * \r
- * @return\r
- */\r
- public double getMedian() {\r
- // Count total\r
- int n = 0;\r
- for (MutableInteger v : distribution.values()) n += v.value;\r
- \r
- double median = (double) n/2;\r
- double sum = 0;\r
- for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {\r
- sum += e.getValue().value;\r
- if (sum==median) { \r
- int c = e.getKey();\r
- Integer nextC = distribution.higherKey( c );\r
- if (nextC == null)\r
- return getClassMax( c );\r
- \r
- return ( getClassMax( c ) + getClassMin( nextC ) ) /2; \r
- }\r
- if (sum>median) {\r
- int c = e.getKey();\r
- return getClassAvg( c );\r
- }\r
- } \r
- return 0;\r
- }\r
- \r
- /**\r
- * Get an index to the class with highest frequency.\r
- *\r
- * @return interval class or 0 if there are no samples\r
- */\r
- public int getLargestClassIndex() {\r
- int result = 0;\r
- int nResult = -1;\r
- for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {\r
- if (e.getValue().value > nResult) {\r
- nResult = e.getValue().value;\r
- result = e.getKey();\r
- }\r
- }\r
- return result;\r
- }\r
- \r
- /**\r
- * Write distribution with user given map.\r
- * \r
- * @param result map where breakdown is written to\r
- */\r
- public void getDistribution(Map<Integer, Integer> result) {\r
- result.clear();\r
- for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {\r
- result.put( e.getKey(), Integer.valueOf(e.getValue().value));\r
- }\r
- }\r
- \r
- public void setDistribution(Map<Integer, Integer> map) {\r
- this.distribution.clear();\r
- for (Entry<Integer, Integer> e : map.entrySet()) {\r
- distribution.put( e.getKey(), new MutableInteger(e.getValue()) );\r
- }\r
- }\r
- \r
- /**\r
- * Create a snapshot copy of the distribution.\r
- * \r
- * @return a histogram \r
- */\r
- public TreeMap<Integer, Integer> getDistribution() {\r
- TreeMap<Integer, Integer> result = new TreeMap<Integer, Integer>();\r
- getDistribution(result);\r
- return result;\r
- }\r
- \r
- \r
- /**\r
- * Add new value to the distribution.\r
- * \r
- * @param value\r
- */\r
- public void addValue(double value) { \r
- Integer k = Integer.valueOf( getClassIndex(value) );\r
- MutableInteger r = distribution.get(k);\r
- if ( r == null ) {\r
- r = new MutableInteger();\r
- distribution.put(k, r);\r
- }\r
- r.value ++;\r
- }\r
-\r
- /**\r
- * Get lowest value of a class\r
- * \r
- * @param intervalClass\r
- * @return min value\r
- */\r
- public double getClassMin(int intervalClass) {\r
- return Math.pow(base, intervalClass);\r
- }\r
-\r
- /**\r
- * Get highest value of a class \r
- * \r
- * @param intervalClass\r
- * @return max value\r
- */\r
- public double getClassMax(int intervalClass) {\r
- return Math.pow(base, intervalClass+1);\r
- }\r
- \r
- /**\r
- * Get average value of a class\r
- * \r
- * @param intervalClass\r
- * @return average interval\r
- */\r
- public double getClassAvg(int intervalClass) {\r
- double min = getClassMin(intervalClass);\r
- double max = getClassMax(intervalClass);\r
- return (max-min)/2+min;\r
- }\r
- \r
- /**\r
- * Get class index for a value\r
- * @param interval\r
- * @return class index\r
- */\r
- public int getClassIndex(double interval) {\r
- if (interval == lastEnteredValue) return lastClass;\r
- lastClass = (int) Math.floor( Math.log(interval) / log_base );\r
- lastEnteredValue = interval; \r
- return lastClass;\r
- }\r
- \r
- @Override\r
- public String toString() {\r
- StringBuilder sb = new StringBuilder();\r
- Formatter f = new Formatter(sb);\r
- sb.append("Index Range Count\n");\r
- for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {\r
- int ic = e.getKey();\r
- double start = getClassMin(ic);\r
- double end = getClassMax(ic);\r
- double avg = getClassAvg(ic);\r
- int count = e.getValue().value;\r
- String format;\r
- if (start<0.001) {\r
- start *= 1000.0;\r
- end *= 1000.0;\r
- avg *= 1000.0;\r
- format = " %+3d [ %(,8fm .. %(,8fm ) = %d, avg = %(,8fm\n";\r
- } else\r
- if (start<1) {\r
- start *= 1000.0;\r
- end *= 1000.0;\r
- avg *= 1000.0;\r
- format = " %+3d [ %(,8.2fm .. %(,8.2fm ) = %d, avg = %(,8.2fm\n";\r
- } else {\r
- format = " %+3d [ %(9.0f .. %(9.0f ) = %d, avg = %(8.1f\n";\r
- }\r
- f.format(format , ic, start, end, count, avg);\r
- }\r
- return sb.toString();\r
- }\r
- \r
-}\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007 VTT Technical Research Centre of Finland and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.history.util;
+
+import java.util.Formatter;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+
+import org.simantics.databoard.primitives.MutableInteger;
+
+/**
+ * This class gives a rough distribution classification for double values.
+ *
+ * It calculates the frequency of values in each class. All values are
+ * accounted. There is a value between two samples.
+ * n(sample intervals) = n(samples) - 1 <p>
+ *
+ * Classes are derieved using logarithmic scale.
+ * Each class accounts all values within a range [ base ^ class .. base ^ (class-1) ).
+ *
+ * Example for classes of base number 2.0
+ *
+ * Class Ranges
+ * -10 [ 0,98ms .. 1,95ms )
+ * -9 [ 1,95ms .. 3,91ms )
+ * -8 [ 3,91ms .. 7,81ms )
+ * -7 [ 7,81ms .. 15,63ms )
+ * -6 [ 15,63ms .. 31,25ms )
+ * -5 [ 31,25ms .. 62,50ms )
+ * -4 [ 62,50ms .. 125,00ms )
+ * -3 [ 125,00ms .. 250,00ms )
+ * -2 [ 250,00ms .. 500,00ms )
+ * -1 [ 500,00ms .. 1 000,00ms )
+ * 0 [ 1 000,00ms .. 2 000,00ms )
+ * +1 [ 2 000,00ms .. 4 000,00ms )
+ * +2 [ 4 000,00ms .. 8 000,00ms )
+ * +3 [ 8 000,00ms .. 16 000,00ms )
+ * +4 [ 16 000,00ms .. 32 000,00ms )
+ * +5 [ 32 000,00ms .. 64 000,00ms )
+ * +6 [ 64 000,00ms .. 128 000,00ms )
+ * +7 [ 128 000,00ms .. 256 000,00ms )
+ * +8 [ 256 000,00ms .. 512 000,00ms )
+ * +9 [ 512 000,00ms .. 1 024 000,00ms )
+ * +10 [ 1 024 000,00ms .. 2 048 000,00ms )
+ *
+ * @author Toni Kalajainen <toni.kalajainen@vtt.fi>
+ */
+public class ClassDistribution {
+
+ // Optimization that tries to cirumvent slow Math.log
+ // previously entered value and its class is remembered
+ private transient double lastEnteredValue;
+ private transient int lastClass;
+
+ double base;
+ private transient double log_base;
+
+ /** Distribution */
+ TreeMap<Integer, MutableInteger> distribution;
+
+ public ClassDistribution() {
+ this( 2.0 );
+ }
+
+ public ClassDistribution(double base) {
+ this.base = base;
+ log_base = Math.log( base );
+ lastEnteredValue = 0.001;
+ lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );
+ distribution = new TreeMap<Integer, MutableInteger>();
+ }
+
+ public ClassDistribution(double base, TreeMap<Integer, MutableInteger> initialBreakdown) {
+ this.base = base;
+ log_base = Math.log( base );
+ lastEnteredValue = 0.001;
+ lastClass = (int) Math.floor( Math.log( 0.001 ) / log_base );
+ distribution = new TreeMap<Integer, MutableInteger>( initialBreakdown );
+ }
+
+ public double getBase() {
+ return base;
+ }
+
+ public void setBase(double base) {
+ this.base = base;
+ log_base = Math.log( base );
+ }
+
+ public double getSmallest() {
+ if (distribution.isEmpty()) return 1.0;
+ int clazz = distribution.firstKey();
+ return getClassAvg(clazz);
+ }
+
+ /**
+ * Get median value
+ *
+ * @return
+ */
+ public double getMedian() {
+ // Count total
+ int n = 0;
+ for (MutableInteger v : distribution.values()) n += v.value;
+
+ double median = (double) n/2;
+ double sum = 0;
+ for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
+ sum += e.getValue().value;
+ if (sum==median) {
+ int c = e.getKey();
+ Integer nextC = distribution.higherKey( c );
+ if (nextC == null)
+ return getClassMax( c );
+
+ return ( getClassMax( c ) + getClassMin( nextC ) ) /2;
+ }
+ if (sum>median) {
+ int c = e.getKey();
+ return getClassAvg( c );
+ }
+ }
+ return 0;
+ }
+
+ /**
+ * Get an index to the class with highest frequency.
+ *
+ * @return interval class or 0 if there are no samples
+ */
+ public int getLargestClassIndex() {
+ int result = 0;
+ int nResult = -1;
+ for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
+ if (e.getValue().value > nResult) {
+ nResult = e.getValue().value;
+ result = e.getKey();
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Write distribution with user given map.
+ *
+ * @param result map where breakdown is written to
+ */
+ public void getDistribution(Map<Integer, Integer> result) {
+ result.clear();
+ for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
+ result.put( e.getKey(), Integer.valueOf(e.getValue().value));
+ }
+ }
+
+ public void setDistribution(Map<Integer, Integer> map) {
+ this.distribution.clear();
+ for (Entry<Integer, Integer> e : map.entrySet()) {
+ distribution.put( e.getKey(), new MutableInteger(e.getValue()) );
+ }
+ }
+
+ /**
+ * Create a snapshot copy of the distribution.
+ *
+ * @return a histogram
+ */
+ public TreeMap<Integer, Integer> getDistribution() {
+ TreeMap<Integer, Integer> result = new TreeMap<Integer, Integer>();
+ getDistribution(result);
+ return result;
+ }
+
+
+ /**
+ * Add new value to the distribution.
+ *
+ * @param value
+ */
+ public void addValue(double value) {
+ Integer k = Integer.valueOf( getClassIndex(value) );
+ MutableInteger r = distribution.get(k);
+ if ( r == null ) {
+ r = new MutableInteger();
+ distribution.put(k, r);
+ }
+ r.value ++;
+ }
+
+ /**
+ * Get lowest value of a class
+ *
+ * @param intervalClass
+ * @return min value
+ */
+ public double getClassMin(int intervalClass) {
+ return Math.pow(base, intervalClass);
+ }
+
+ /**
+ * Get highest value of a class
+ *
+ * @param intervalClass
+ * @return max value
+ */
+ public double getClassMax(int intervalClass) {
+ return Math.pow(base, intervalClass+1);
+ }
+
+ /**
+ * Get average value of a class
+ *
+ * @param intervalClass
+ * @return average interval
+ */
+ public double getClassAvg(int intervalClass) {
+ double min = getClassMin(intervalClass);
+ double max = getClassMax(intervalClass);
+ return (max-min)/2+min;
+ }
+
+ /**
+ * Get class index for a value
+ * @param interval
+ * @return class index
+ */
+ public int getClassIndex(double interval) {
+ if (interval == lastEnteredValue) return lastClass;
+ lastClass = (int) Math.floor( Math.log(interval) / log_base );
+ lastEnteredValue = interval;
+ return lastClass;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ Formatter f = new Formatter(sb);
+ sb.append("Index Range Count\n");
+ for (Entry<Integer, MutableInteger> e : distribution.entrySet()) {
+ int ic = e.getKey();
+ double start = getClassMin(ic);
+ double end = getClassMax(ic);
+ double avg = getClassAvg(ic);
+ int count = e.getValue().value;
+ String format;
+ if (start<0.001) {
+ start *= 1000.0;
+ end *= 1000.0;
+ avg *= 1000.0;
+ format = " %+3d [ %(,8fm .. %(,8fm ) = %d, avg = %(,8fm\n";
+ } else
+ if (start<1) {
+ start *= 1000.0;
+ end *= 1000.0;
+ avg *= 1000.0;
+ format = " %+3d [ %(,8.2fm .. %(,8.2fm ) = %d, avg = %(,8.2fm\n";
+ } else {
+ format = " %+3d [ %(9.0f .. %(9.0f ) = %d, avg = %(8.1f\n";
+ }
+ f.format(format , ic, start, end, count, avg);
+ }
+ return sb.toString();
+ }
+
+}
+