/**
 * Probably MIT licenced, as the blog links to a Julia version (https://github.com/johnmyleswhite/StreamStats.jl) which has an MIT license on it, despite the code on the blog not having a license.
 */
package ciir.jfoley.chai.math;

import ciir.jfoley.chai.collections.ArrayListMap;
import ciir.jfoley.chai.fn.SinkFn;

import java.util.Map;

/**
 * Ideas taken from:
 * http://www.johndcook.com/blog/standard_deviation/
 * @author jfoley
 */
public class StreamingStats implements SinkFn<Double> {
  private long numberOfElements;
  private double oldMean;
  private double newMean;
  private double oldS;
  private double newS;
  private double max;
  private double min;

  public StreamingStats() {
    clear();
  }
  public void push(double x) {
    numberOfElements++;

    max = Math.max(max, x);
    min = Math.min(min, x);

    // See Knuth TAOCP vol 2, 3rd edition, page 232
    if (numberOfElements == 1) {
      oldMean = newMean = x;
      oldS = 0.0;
      return;
    }

    newMean = oldMean + (x - oldMean)/ ((double) numberOfElements);
    newS = oldS + (x - oldMean)*(x - newMean);

    // set up for next iteration
    oldMean = newMean;
    oldS = newS;
  }
  public void clear() {
    numberOfElements = 0;
    oldMean = newMean = oldS = newS = 0;
    max = Double.MIN_VALUE;
    min = Double.MAX_VALUE;
  }
  double getMean() {
    return numberOfElements > 0 ? newMean : 0.0;
  }
  double getVariance() {
    if(numberOfElements <= 1) return 0.0;
    return newS / (double) (numberOfElements - 1);
  }
  double getStandardDeviation() { return Math.sqrt(getVariance()); }
  double getMax() {
    return max;
  }
  double getMin() {
    return min;
  }

  public long count() {
    return numberOfElements;
  }

  public Map<String, Double> features() {
    Map<String,Double> results = new ArrayListMap<>();
    results.put("mean", getMean());
    results.put("variance", getVariance());
    results.put("stddev", getStandardDeviation());
    results.put("max", getMax());
    results.put("min", getMin());
    return results;
  }

  @Override
  public String toString() {
    return features().toString();
  }

  @Override
  public void process(Double input) {
    push(input);
  }
}

@@ -669,16 +669,40 @@
 ble min;
+%0A  private double total;
 %0A%0A  publ
@@ -851,16 +851,32 @@
 min, x);
+%0A    total += x;
 %0A%0A    //
@@ -1360,32 +1360,39 @@
 AX_VALUE;%0A  %7D%0A  
+public 
 double getMean()
@@ -1441,32 +1441,39 @@
 an : 0.0;%0A  %7D%0A  
+public 
 double getVarian
@@ -1570,32 +1570,39 @@
 nts - 1);%0A  %7D%0A  
+public 
 double getStanda
@@ -1650,24 +1650,31 @@
 nce()); %7D%0A  
+public 
 double getMa
@@ -1701,16 +1701,23 @@
 ;%0A  %7D%0A  
+public 
 double g
@@ -1741,24 +1741,131 @@
 urn min;%0A  %7D
+%0A  public double getTotal() %7B%0A    return total;%0A  %7D%0A  public double getCount() %7B return numberOfElements; %7D
 %0A%0A  public l
@@ -2204,24 +2204,100 @@
  getMin());%0A
+    results.put(%22total%22, getTotal());%0A    results.put(%22count%22, getCount());%0A
     return r

Add count and total to "features"