X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.history%2Fsrc%2Forg%2Fsimantics%2Fhistory%2Futil%2FClassDistribution.java;h=f20c6b6d7d18f4464a1f033f1c60a1a7d071f94a;hb=refs%2Fchanges%2F38%2F238%2F2;hp=d6a5df81269af297f9408172e0cb739d1c2cb600;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.history/src/org/simantics/history/util/ClassDistribution.java b/bundles/org.simantics.history/src/org/simantics/history/util/ClassDistribution.java index d6a5df812..f20c6b6d7 100644 --- a/bundles/org.simantics.history/src/org/simantics/history/util/ClassDistribution.java +++ b/bundles/org.simantics.history/src/org/simantics/history/util/ClassDistribution.java @@ -1,274 +1,274 @@ -/******************************************************************************* - * 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

- * - * 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 - */ -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 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(); - } - - public ClassDistribution(double base, TreeMap 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( 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 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 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 result) { - result.clear(); - for (Entry e : distribution.entrySet()) { - result.put( e.getKey(), Integer.valueOf(e.getValue().value)); - } - } - - public void setDistribution(Map map) { - this.distribution.clear(); - for (Entry e : map.entrySet()) { - distribution.put( e.getKey(), new MutableInteger(e.getValue()) ); - } - } - - /** - * Create a snapshot copy of the distribution. - * - * @return a histogram - */ - public TreeMap getDistribution() { - TreeMap result = new TreeMap(); - 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 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(); - } - -} - +/******************************************************************************* + * 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

+ * + * 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 + */ +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 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(); + } + + public ClassDistribution(double base, TreeMap 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( 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 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 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 result) { + result.clear(); + for (Entry e : distribution.entrySet()) { + result.put( e.getKey(), Integer.valueOf(e.getValue().value)); + } + } + + public void setDistribution(Map map) { + this.distribution.clear(); + for (Entry e : map.entrySet()) { + distribution.put( e.getKey(), new MutableInteger(e.getValue()) ); + } + } + + /** + * Create a snapshot copy of the distribution. + * + * @return a histogram + */ + public TreeMap getDistribution() { + TreeMap result = new TreeMap(); + 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 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(); + } + +} +