org.broad.igv.Accumulator.java Source code

Java tutorial

Introduction

Here is the source code for org.broad.igv.Accumulator.java

Source

/*
  * Copyright (c) 2007-2010 by The Broad Institute, Inc. and the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * This software is licensed under the terms of the GNU Lesser General Public License (LGPL), Version 2.1 which
 * is available at http://www.opensource.org/licenses/lgpl-2.1.php.
 *
 * THE SOFTWARE IS PROVIDED "AS IS." THE BROAD AND MIT MAKE NO REPRESENTATIONS OR WARRANTIES OF
 * ANY KIND CONCERNING THE SOFTWARE, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT
 * OR OTHER DEFECTS, WHETHER OR NOT DISCOVERABLE.  IN NO EVENT SHALL THE BROAD OR MIT, OR THEIR
 * RESPECTIVE TRUSTEES, DIRECTORS, OFFICERS, EMPLOYEES, AND AFFILIATES BE LIABLE FOR ANY DAMAGES OF
 * ANY KIND, INCLUDING, WITHOUT LIMITATION, INCIDENTAL OR CONSEQUENTIAL DAMAGES, ECONOMIC
 * DAMAGES OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF WHETHER THE BROAD OR MIT SHALL
 * BE ADVISED, SHALL HAVE OTHER REASON TO KNOW, OR IN FACT SHALL KNOW OF THE POSSIBILITY OF THE
 * FOREGOING.
 */

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.broad.igv;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.math.stat.Percentile;

/**
 * Estimating percentiles -- weighted average of multiple estimates
 *
 * @author jrobinso
 * @author Thomas Abeel
 */
public class Accumulator {

    static Set<WindowFunction> PERCENTILE_WINDOW_FUNCTIONS = new HashSet();
    public static int MAX_VALUE_COUNT = 100000;
    private static Logger log = Logger.getLogger(Accumulator.class.getCanonicalName());

    static {
        PERCENTILE_WINDOW_FUNCTIONS.add(WindowFunction.median);
        PERCENTILE_WINDOW_FUNCTIONS.add(WindowFunction.percentile2);
        PERCENTILE_WINDOW_FUNCTIONS.add(WindowFunction.percentile10);
        PERCENTILE_WINDOW_FUNCTIONS.add(WindowFunction.percentile90);
        PERCENTILE_WINDOW_FUNCTIONS.add(WindowFunction.percentile98);
    }

    boolean isFinished = false;

    List<WindowFunction> windowFunctions;
    List<WindowFunction> quantileFunctions;
    DoubleArrayList values = null;
    float sum = 0.0f;
    int nPts = 0;

    Map<WindowFunction, List<PercentileValue>> percentiles = new HashMap();

    float min = Float.NaN;
    float max = Float.NaN;
    float mean = Float.NaN;
    float median = Float.NaN;
    float percentile2 = Float.NaN;
    float percentile10 = Float.NaN;
    float percentile90 = Float.NaN;
    float percentile98 = Float.NaN;

    public Accumulator(Collection<WindowFunction> windowFunctions) {
        this.windowFunctions = new ArrayList(windowFunctions);
        quantileFunctions = new ArrayList();
        for (WindowFunction wf : windowFunctions) {
            if (PERCENTILE_WINDOW_FUNCTIONS.contains(wf)) {
                quantileFunctions.add(wf);
                if (values == null) {
                    values = new DoubleArrayList();
                }
            }
        }
    }

    public void add(float v) {
        if (!Float.isNaN(v)) {
            min = Float.isNaN(min) ? v : Math.min(min, v);
            max = Float.isNaN(max) ? v : Math.max(max, v);
            sum += v;
            nPts++;
            if (values != null) {
                values.add(v);
                if (values.size() > MAX_VALUE_COUNT) {
                    computePercentiles();
                    values.clear();
                }
            }
        }
    }

    public void finish() {

        if (isFinished) {
            return;
        }

        mean = Float.isNaN(sum) ? Float.NaN : sum / nPts;

        if (values != null) {
            if (nPts == 1) {
                for (WindowFunction wf : quantileFunctions) {
                    setValue(wf, mean);
                }
            } else {
                if (values.size() > 1) {
                    computePercentiles();
                }
                for (WindowFunction wf : quantileFunctions) {

                    List<PercentileValue> pList = percentiles.get(wf);
                    float v = Float.NaN; // <= Default,
                    if (pList != null && pList.size() > 0) {
                        double weightedSum = 0;
                        double sumOfWeights = 0;
                        for (PercentileValue pv : pList) {
                            double weight = (double) pv.nPoints / nPts;
                            sumOfWeights += weight;
                            weightedSum += weight * pv.value;
                        }
                        v = (float) (weightedSum / sumOfWeights);
                    }
                    setValue(wf, v);

                }

            }
        }
        values = null;
        isFinished = true;

    }

    private Percentile percentile = new Percentile();

    private void computePercentiles() {
        if (values != null) {
            double[] valueArray = values.toArray();
            for (WindowFunction wf : quantileFunctions) {
                double p = this.getPercentile(wf);
                if (p > 0) {
                    float v = (float) percentile.evaluate(valueArray, p);
                    //                    float v = (float) StatUtils.percentile(valueArray, p);
                    if (Float.isInfinite(v)) {
                        log.log(Level.SEVERE, "Infinite percentile (" + wf + ")");
                    } else {
                        List<PercentileValue> pList = percentiles.get(wf);
                        if (pList == null) {
                            pList = new ArrayList();
                            percentiles.put(wf, pList);
                        }
                        pList.add(new PercentileValue(valueArray.length, v));
                    }
                }
            }
        }

    }

    private void setValue(WindowFunction wf, float value) {
        switch (wf) {
        case mean:
            mean = value;
            break;
        case median:
            median = value;
            break;
        case min:
            min = value;
            break;
        case max:
            max = value;
            break;
        case percentile2:
            percentile2 = value;
            break;
        case percentile10:
            percentile10 = value;
            break;
        case percentile90:
            percentile90 = value;
            break;
        case percentile98:
            percentile98 = value;
            break;
        default:
            System.err.println("Unexpected window function: " + wf.toString());
        }

    }

    public float getValue(WindowFunction wf) {

        switch (wf) {
        case mean:
            return mean;
        case median:
            return median;
        case min:
            return min;
        case max:
            return max;
        case percentile2:
            return percentile2;
        case percentile10:
            return percentile10;
        case percentile90:
            return percentile90;
        case percentile98:
            return percentile98;
        case count:
            return nPts;
        default:
            System.err.println("Unexpected window function: " + wf.toString());

        }
        return Float.NaN;

    }

    public double getPercentile(WindowFunction wf) {
        switch (wf) {
        case percentile2:
            return 2;
        case percentile10:
            return 10;
        case percentile90:
            return 90;
        case percentile98:
            return 98;
        case median:
            return 50;
        default:
            return -1.0;
        }
    }

    class PercentileValue {
        int nPoints;
        double value;

        PercentileValue(int nPoints, double value) {
            this.nPoints = nPoints;
            this.value = value;
        }
    }

}