/*****************************************************************************
* Limpet - the Lightweight InforMation ProcEssing Toolkit
* http://limpet.info
*
* (C) 2015-2016, Deep Blue C Technologies Ltd
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Eclipse Public License v1.0
* (http://www.eclipse.org/legal/epl-v10.html)
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*****************************************************************************/
package info.limpet.analysis;
import info.limpet.IBaseTemporalCollection;
import info.limpet.ICollection;
import info.limpet.IStoreItem;
import info.limpet.data.operations.CollectionComplianceTests;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.math3.random.EmpiricalDistribution;
import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics;
import org.apache.commons.math3.stat.descriptive.SummaryStatistics;
public abstract class TimeFrequencyBins extends CoreAnalysis
{
private static final int MAX_SIZE = 10000;
private static final double THRESHOLD_VALUE = 0.001;
private final CollectionComplianceTests aTests =
new CollectionComplianceTests();
public TimeFrequencyBins()
{
super("Time Frequency Bins");
}
public static class BinnedData extends ArrayList<Bin>
{
/**
*
*/
private static final long serialVersionUID = 1L;
public BinnedData()
{
}
}
public static class Bin
{
private final long lowerVal;
private final long upperVal;
private final long freqVal;
public Bin(final long lower, final long upper, long freq)
{
upperVal = upper;
lowerVal = lower;
freqVal = freq;
}
public long getLowerVal()
{
return lowerVal;
}
public long getUpperVal()
{
return upperVal;
}
public long getFreqVal()
{
return freqVal;
}
}
public static BinnedData doBins(ICollection c, IBaseTemporalCollection o)
{
// collate the values into an array
double[] data = new double[c.getValuesCount()];
// Add the data from the array
int ctr = 0;
Iterator<Long> iterV = o.getTimes().iterator();
while (iterV.hasNext())
{
long time = iterV.next();
data[ctr++] = time;
}
// Get a DescriptiveStatistics instance
DescriptiveStatistics stats = new DescriptiveStatistics(data);
// also do some frequency binning
double range = stats.getMax() - stats.getMin();
// aah, double-check we don't have zero range
final int binCount;
final int maxRange = 30;
if (range > maxRange)
{
binCount = maxRange;
}
else
{
binCount = (int) Math.max(2, range);
}
BinnedData res = new BinnedData();
if (range > THRESHOLD_VALUE)
{
long[] histogram = new long[binCount];
EmpiricalDistribution distribution = new EmpiricalDistribution(binCount);
distribution.load(data);
int k = 0;
for (SummaryStatistics sStats : distribution.getBinStats())
{
histogram[k++] = sStats.getN();
}
long rangeSoFar = (long) stats.getMin();
long rangeStep = (long) (range / binCount);
for (int i = 0; i < histogram.length; i++)
{
long l = histogram[i];
res.add(new Bin(rangeSoFar, rangeSoFar + rangeStep, l));
rangeSoFar += rangeStep;
}
}
return res;
}
@Override
public void analyse(List<IStoreItem> selection)
{
List<String> titles = new ArrayList<String>();
List<String> values = new ArrayList<String>();
// check compatibility
if (appliesTo(selection) && selection.size() == 1)
{
// ok, let's go for it.
for (Iterator<IStoreItem> iter = selection.iterator(); iter.hasNext();)
{
ICollection thisC = (ICollection) iter.next();
IBaseTemporalCollection o = (IBaseTemporalCollection) thisC;
if (thisC.getValuesCount() > 1 && thisC.getValuesCount() < MAX_SIZE)
{
BinnedData res = doBins(thisC, o);
// now output the bins
StringBuffer freqBins = new StringBuffer();
Iterator<Bin> bIter = res.iterator();
while (bIter.hasNext())
{
TimeFrequencyBins.Bin bin = (TimeFrequencyBins.Bin) bIter.next();
freqBins.append((int) bin.getLowerVal());
freqBins.append("-");
freqBins.append((int) bin.getUpperVal());
freqBins.append(": ");
freqBins.append(bin.getFreqVal());
freqBins.append(", ");
}
titles.add("Frequency bins");
values.add(freqBins.toString());
}
}
}
if (titles.size() > 0)
{
presentResults(titles, values);
}
}
private boolean appliesTo(List<IStoreItem> selection)
{
return aTests.allCollections(selection) && aTests.allTemporal(selection);
}
protected abstract void presentResults(List<String> titles,
List<String> values);
}