package org.streaminer.stream.frequency; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; import org.streaminer.stream.frequency.util.CountEntry; /** * Majority algorithm. * https://github.com/gdusbabek/signalbrook * * @author Gary Dusbabek */ public class Majority extends BaseFrequency<Boolean> { private long n = 0; private boolean current = true; private long counter = 0; @Override public boolean add(Boolean item, long incrementCount) throws FrequencyException { boolean newItem = true; if (n == Long.MAX_VALUE) { throw new FrequencyException("Overflowed " + Long.MAX_VALUE); } else { n += 1; } if (current == item) { counter += 1; newItem = false; } else if (counter == 0) { current = item; counter = 1; } else { counter -= 1; } return newItem; } @Override public long estimateCount(Boolean item) { // invariant: major + minor == n. // this is busted after overflow, btw. long major = n / 2; long minor = n / 2 + (n % 2); while (major - minor != counter) { major += 1; minor -= 1; } return current == item ? major : minor; } @Override public long size() { return n; } @Override public Set<Boolean> keySet() { return null; } public boolean isMajority(boolean b) { return current == b && counter > 0; } public List<CountEntry<Boolean>> getFrequentItems(double minSupport) { List<CountEntry<Boolean>> list = new ArrayList<CountEntry<Boolean>>(2); list.add(new CountEntry<Boolean>(Boolean.TRUE, estimateCount(Boolean.TRUE))); list.add(new CountEntry<Boolean>(Boolean.FALSE, estimateCount(Boolean.FALSE))); Collections.sort(list); return list; } public boolean contains(Boolean item) { return estimateCount(item) > 0; } }