/*******************************************************************************
* GenPlay, Einstein Genome Analyzer
* Copyright (C) 2009, 2014 Albert Einstein College of Medicine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu>
* Nicolas Fourel <nicolas.fourel@einstein.yu.edu>
* Eric Bouhassira <eric.bouhassira@einstein.yu.edu>
*
* Website: <http://genplay.einstein.yu.edu>
******************************************************************************/
package edu.yu.einstein.genplay.core.operation.SCWList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import edu.yu.einstein.genplay.core.manager.project.ProjectChromosomes;
import edu.yu.einstein.genplay.core.manager.project.ProjectManager;
import edu.yu.einstein.genplay.core.operation.Operation;
import edu.yu.einstein.genplay.core.operationPool.OperationPool;
import edu.yu.einstein.genplay.dataStructure.list.genomeWideList.SCWList.SCWList;
import edu.yu.einstein.genplay.dataStructure.list.listView.ListView;
import edu.yu.einstein.genplay.dataStructure.scoredChromosomeWindow.ScoredChromosomeWindow;
/**
* Computes statistics (eg: min, max, avg, stdev) on a specified {@link SCWList}
* @author Julien Lajugie
*/
public class SCWLOComputeStats implements Operation<Void> {
/** Smallest value of the list */
private float minimum = Float.POSITIVE_INFINITY;
/** Smallest values of each chromo */
private final float[] minimums;
/** Greatest value of the list */
private float maximum = Float.NEGATIVE_INFINITY;
/** Greatest value of each chromo */
private final float[] maximums;
/** Average of the list */
private double average = 0d;
/** Averages of each chromo */
private final double[] averages;
/** Standard deviation of the list */
private double standardDeviation = 0d;
/** Standard deviation of each chromo */
private final double[] standardDeviations;
/** Number of windows with a score different from 0 */
private long windowCount = 0l;
/** Number of windows with a score different from 0 for each chromo*/
private final long[] windowCounts;
/** Sum of the length of the windows with a score different from 0 */
private long windowLength = 0l;
/** Sum of the length of the windows with a score different from 0 for each chromosome */
private final long[] windowLengths;
/** Sum of Float scores of all windows */
private double scoreSum = 0d;
/** Sum of Float scores of all windows for each chromosome */
private final double[] scoreSums;
/** input list */
private final SCWList inputList;
/** True if the operation must be stopped */
private boolean stopped = false;
/**
* Creates an instance of {@link SCWLOComputeStats}
* @param inputList input list to analyze
*/
public SCWLOComputeStats(SCWList inputList) {
// retrieve the project manager
ProjectChromosomes projectChromosomes = ProjectManager.getInstance().getProjectChromosomes();
this.inputList = inputList;
minimums = new float[projectChromosomes.size()];
maximums = new float[projectChromosomes.size()];
averages = new double[projectChromosomes.size()];
standardDeviations = new double[projectChromosomes.size()];
windowCounts = new long[projectChromosomes.size()];
windowLengths = new long[projectChromosomes.size()];
scoreSums = new double[projectChromosomes.size()];
}
@Override
public Void compute() throws InterruptedException, ExecutionException {
// retrieve the project manager
ProjectChromosomes projectChromosomes = ProjectManager.getInstance().getProjectChromosomes();
// retrieve the instance of the OperationPool singleton
final OperationPool op = OperationPool.getInstance();
// list for the threads
final Collection<Callable<Void>> threadList = new ArrayList<Callable<Void>>();
// computes min / max / total score / non null bin count for each chromosome
for(short i = 0; i < inputList.size(); i++) {
final ListView<ScoredChromosomeWindow> currentList = inputList.get(i);
final short currentIndex = i;
Callable<Void> currentThread = new Callable<Void>() {
@Override
public Void call() throws Exception {
minimums[currentIndex] = Float.POSITIVE_INFINITY;
maximums[currentIndex] = Float.NEGATIVE_INFINITY;
if (currentList != null) {
for (int j = 0; (j < currentList.size()) && !stopped; j++) {
ScoredChromosomeWindow currentWindow = currentList.get(j);
if (currentWindow.getScore() != 0) {
minimums[currentIndex] = Math.min(minimums[currentIndex], currentWindow.getScore());
maximums[currentIndex] = Math.max(maximums[currentIndex], currentWindow.getScore());
scoreSums[currentIndex] += currentWindow.getScore() * currentWindow.getSize();
windowCounts[currentIndex]++;
windowLengths[currentIndex] += currentWindow.getSize();
}
}
}
// notify that the current chromosome is done
op.notifyDone();
return null;
}
};
threadList.add(currentThread);
}
// start the pool of thread
op.startPool(threadList);
// compute the genome wide result from the chromosomes results
for (int i = 0; i < projectChromosomes.size(); i++) {
minimum = Math.min(minimum, minimums[i]);
if (Float.isInfinite(minimums[i])) {
minimums[i] = 0;
}
maximum = Math.max(maximum, maximums[i]);
if (Float.isInfinite(maximums[i])) {
maximums[i] = 0;
}
if (windowLengths[i] != 0) {
averages[i] = scoreSums[i] / windowLengths[i];
}
scoreSum += scoreSums[i];
windowCount += windowCounts[i];
windowLength += windowLengths[i];
}
if (Float.isInfinite(minimum)) {
minimum = 0;
}
if (Float.isInfinite(maximum)) {
maximum = 0;
}
if (windowLength != 0) {
// compute the average
average = scoreSum / windowLength;
threadList.clear();
// standard deviation genome wide need to be computed separetly because it uses the average GW
final double[] gwStandardDeviations = new double[projectChromosomes.size()];
// compute the standard deviation for each chromosome
for(short i = 0; i < inputList.size(); i++) {
final ListView<ScoredChromosomeWindow> currentList = inputList.get(i);
final short currentIndex = i;
Callable<Void> currentThread = new Callable<Void>() {
@Override
public Void call() throws Exception {
if (currentList != null) {
for (int j = 0; (j < currentList.size()) && !stopped; j++) {
ScoredChromosomeWindow currentWindow = currentList.get(j);
if (currentWindow.getScore() != 0) {
gwStandardDeviations[currentIndex] += Math.pow(currentWindow.getScore() - average, 2) * currentWindow.getSize();
standardDeviations[currentIndex] += Math.pow(currentWindow.getScore() - averages[currentIndex], 2) * currentWindow.getSize();
}
}
if (windowLengths[currentIndex] != 0) {
standardDeviations[currentIndex] = Math.sqrt(standardDeviations[currentIndex] / windowLengths[currentIndex]);
}
}
// notify that the current chromosome is done
op.notifyDone();
return null;
}
};
threadList.add(currentThread);
}
// start the pool of thread
op.startPool(threadList);
// compute the genome wide standard deviation
for (int i = 0; i < projectChromosomes.size(); i++) {
standardDeviation += gwStandardDeviations[i];
}
standardDeviation = Math.sqrt(standardDeviation / windowLength);
}
return null;
}
/**
* @return the average
*/
public double getAverage() {
return average;
}
/**
* @return the averages
*/
public double[] getAverages() {
return averages;
}
@Override
public String getDescription() {
return "Operation: Compute Statistics";
}
/**
* @return the inputList
*/
public SCWList getInputList() {
return inputList;
}
/**
* @return the maximum
*/
public float getMaximum() {
return maximum;
}
/**
* @return the maximums
*/
public float[] getMaximums() {
return maximums;
}
/**
* @return the minimum
*/
public float getMinimum() {
return minimum;
}
/**
* @return the minimums
*/
public float[] getMinimums() {
return minimums;
}
@Override
public String getProcessingDescription() {
return "Computing Statistics";
}
/**
* @return the nonNullLength
*/
public double getScoreSum() {
return scoreSum;
}
/**
* @return the scoreSums
*/
public double[] getScoreSums() {
return scoreSums;
}
/**
* @return the standardDeviation
*/
public double getStandardDeviation() {
return standardDeviation;
}
/**
* @return the standardDeviations
*/
public double[] getStandardDeviations() {
return standardDeviations;
}
@Override
public int getStepCount() {
return 2;
}
/**
* @return the window count
*/
public long getWindowCount() {
return windowCount;
}
/**
* @return the window counts
*/
public long[] getWindowCounts() {
return windowCounts;
}
/**
* @return the window length
*/
public long getWindowLength() {
return windowLength;
}
/**
* @return the window lengths
*/
public long[] getWindowLengths() {
return windowLengths;
}
@Override
public void stop() {
stopped = true;
}
}