X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;ds=sidebyside;f=bundles%2Forg.simantics.history%2Fsrc%2Forg%2Fsimantics%2Fhistory%2Futil%2FWeightedMedian.java;h=0cb64b14066bad7367e12a916fc0a522f8f00a24;hb=4a7923add5be874cc352faf9afd0f627794de32e;hp=aa0ad6f8193f085bf0b3dce6d883ff20d1bccd63;hpb=969bd23cab98a79ca9101af33334000879fb60c5;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.history/src/org/simantics/history/util/WeightedMedian.java b/bundles/org.simantics.history/src/org/simantics/history/util/WeightedMedian.java index aa0ad6f81..0cb64b140 100644 --- a/bundles/org.simantics.history/src/org/simantics/history/util/WeightedMedian.java +++ b/bundles/org.simantics.history/src/org/simantics/history/util/WeightedMedian.java @@ -1,228 +1,228 @@ -/******************************************************************************* - * Copyright (c) 2007, 2011 Association for Decentralized Information Management in - * Industry THTH ry. - * 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 org.simantics.databoard.annotations.Optional; -import org.simantics.databoard.annotations.Referable; - -/** - * - * @author toni.kalajainen - */ -public class WeightedMedian { - - public int maxItems; - public int itemCount; - @Optional public Item median; - - // Relative pos = pos - median.accumulated weight - public double rpos; - - public WeightedMedian() - { - maxItems = Integer.MAX_VALUE; - } - - public WeightedMedian(int maxItems) - { - this.maxItems = maxItems; - } - - public void clear() { - itemCount = 0; - median = null; - rpos = 0; - } - - public void add(double weight, double value) - { - if (weight<=0) return; - if (median == null) { - median = new Item( weight, value ); - itemCount++; - rpos = weight / 2; - return; - } - - Item i = median; - while (true) { - - if (i.value==value) { - i.weight += weight; - break; - } - - if (value < i.value) { - - // i = 1st, add new item as first - if (i.prev==null) { - i.prev = new Item( weight, value, null, i ); - itemCount++; - break; - } - - // value is between two items, add new item - if (i.prev.value < value) { - Item n = new Item( weight, value, i.prev, i ); - itemCount++; - i.prev.next = n; - i.prev = n; - break; - } - - i = i.prev; - continue; - } - - if (value > i.value) { - - // i = last, add new item as last - if (i.next==null) { - i.next = new Item( weight, value, i, null ); - itemCount++; - break; - } - - // value is between two items, add new item - if (i.next.value > value) { - Item n = new Item( weight, value, i, i.next ); - itemCount++; - i.next.prev = n; - i.next = n; - break; - } - - i = i.next; - continue; - } - } - - rpos += (value=median.weight) { - rpos -= median.weight; - median = median.next; - } - - if (itemCount>maxItems) coalesce(); - } - - /** - */ - public void coalesce() { - coalesceVerySimple(); - } - - /** - * Simple coalesce, combine two samples - */ - public void coalesceVerySimple() - { - Item i = median.next; - while (i!=null) { - Item n = i.next; - if (n==null) break; - i.next = n.next; - if (n.next!=null) n.next.prev = i; - - Item itemToMerge = n.weight>i.weight ? n : i; - Item mergeToItem = n.weight>i.weight ? i : n; - - double totWeight = mergeToItem.weight+itemToMerge.weight; - //mergeToItem.value = ( mergeToItem.value * mergeToItem.weight + itemToMerge.value * itemToMerge.weight ) / totWeight; - mergeToItem.weight = totWeight; - i = i.next; - } - - i = median.prev; - while (i!=null) { - Item p = i.prev; - if (p==null) break; - i.prev = p.prev; - if (p.prev!=null) p.prev.next = i; - - Item itemToMerge = p.weight>i.weight ? p : i; - Item mergeToItem = p.weight>i.weight ? p : i; - - double totWeight = mergeToItem.weight+itemToMerge.weight; - //mergeToItem.value = ( mergeToItem.value * mergeToItem.weight + itemToMerge.value * itemToMerge.weight ) / totWeight; - mergeToItem.weight = totWeight; - - i.weight = totWeight; - i = i.prev; - } - } - - public double getMedian() - { - if (median==null) return Double.NaN; - return median.value; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append( "Median="+getMedian()+" "); - - Item i = head(); - while (i!=null) { - if (i==median) { - sb.append("(value="+i.value+", w="+i.weight+", pos="+rpos+")"); - } else { - sb.append("(value="+i.value+", w="+i.weight+")"); - } - i = i.next; - } - - return sb.toString(); - } - - Item head() { - if (median==null) return null; - Item i = median; - while (i.prev!=null) i = i.prev; - return i; - } - - @Referable - static public class Item { - public double weight; - public double value; - - public Item(double weight, double value) { - this.weight = weight; - this.value = value; - } - - public Item(double weight, double value, Item prev, Item next) { - this.weight = weight; - this.value = value; - this.prev = prev; - this.next = next; - } - - @Optional - public Item prev; - - @Optional - public Item next; - - @Override - public String toString() { - return "(value="+value+", w="+weight+")"; - } - } - -} +/******************************************************************************* + * Copyright (c) 2007, 2011 Association for Decentralized Information Management in + * Industry THTH ry. + * 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 org.simantics.databoard.annotations.Optional; +import org.simantics.databoard.annotations.Referable; + +/** + * + * @author toni.kalajainen + */ +public class WeightedMedian { + + public int maxItems; + public int itemCount; + @Optional public Item median; + + // Relative pos = pos - median.accumulated weight + public double rpos; + + public WeightedMedian() + { + maxItems = Integer.MAX_VALUE; + } + + public WeightedMedian(int maxItems) + { + this.maxItems = maxItems; + } + + public void clear() { + itemCount = 0; + median = null; + rpos = 0; + } + + public void add(double weight, double value) + { + if (weight<=0) return; + if (median == null) { + median = new Item( weight, value ); + itemCount++; + rpos = weight / 2; + return; + } + + Item i = median; + while (true) { + + if (i.value==value) { + i.weight += weight; + break; + } + + if (value < i.value) { + + // i = 1st, add new item as first + if (i.prev==null) { + i.prev = new Item( weight, value, null, i ); + itemCount++; + break; + } + + // value is between two items, add new item + if (i.prev.value < value) { + Item n = new Item( weight, value, i.prev, i ); + itemCount++; + i.prev.next = n; + i.prev = n; + break; + } + + i = i.prev; + continue; + } + + if (value > i.value) { + + // i = last, add new item as last + if (i.next==null) { + i.next = new Item( weight, value, i, null ); + itemCount++; + break; + } + + // value is between two items, add new item + if (i.next.value > value) { + Item n = new Item( weight, value, i, i.next ); + itemCount++; + i.next.prev = n; + i.next = n; + break; + } + + i = i.next; + continue; + } + } + + rpos += (value=median.weight) { + rpos -= median.weight; + median = median.next; + } + + if (itemCount>maxItems) coalesce(); + } + + /** + */ + public void coalesce() { + coalesceVerySimple(); + } + + /** + * Simple coalesce, combine two samples + */ + public void coalesceVerySimple() + { + Item i = median.next; + while (i!=null) { + Item n = i.next; + if (n==null) break; + i.next = n.next; + if (n.next!=null) n.next.prev = i; + + Item itemToMerge = n.weight>i.weight ? n : i; + Item mergeToItem = n.weight>i.weight ? i : n; + + double totWeight = mergeToItem.weight+itemToMerge.weight; + //mergeToItem.value = ( mergeToItem.value * mergeToItem.weight + itemToMerge.value * itemToMerge.weight ) / totWeight; + mergeToItem.weight = totWeight; + i = i.next; + } + + i = median.prev; + while (i!=null) { + Item p = i.prev; + if (p==null) break; + i.prev = p.prev; + if (p.prev!=null) p.prev.next = i; + + Item itemToMerge = p.weight>i.weight ? p : i; + Item mergeToItem = p.weight>i.weight ? p : i; + + double totWeight = mergeToItem.weight+itemToMerge.weight; + //mergeToItem.value = ( mergeToItem.value * mergeToItem.weight + itemToMerge.value * itemToMerge.weight ) / totWeight; + mergeToItem.weight = totWeight; + + i.weight = totWeight; + i = i.prev; + } + } + + public double getMedian() + { + if (median==null) return Double.NaN; + return median.value; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append( "Median="+getMedian()+" "); + + Item i = head(); + while (i!=null) { + if (i==median) { + sb.append("(value="+i.value+", w="+i.weight+", pos="+rpos+")"); + } else { + sb.append("(value="+i.value+", w="+i.weight+")"); + } + i = i.next; + } + + return sb.toString(); + } + + Item head() { + if (median==null) return null; + Item i = median; + while (i.prev!=null) i = i.prev; + return i; + } + + @Referable + static public class Item { + public double weight; + public double value; + + public Item(double weight, double value) { + this.weight = weight; + this.value = value; + } + + public Item(double weight, double value, Item prev, Item next) { + this.weight = weight; + this.value = value; + this.prev = prev; + this.next = next; + } + + @Optional + public Item prev; + + @Optional + public Item next; + + @Override + public String toString() { + return "(value="+value+", w="+weight+")"; + } + } + +}