content: package edu.stanford.rsl.conrad.utils;
  
  import ij.ImagePlus;
  import ij.process.FloatProcessor;
  
  import java.text.NumberFormat;
  import java.util.HashMap;
  
  
  public abstract class FloatArrayUtil {
  
  	private static HashMap<Integer, float[]> arrayBuffer = new HashMap<Integer, float[]>();
  	private static int max = -1;
  
  	/**
  	 * Stores an array for later visualization at index imageNumber
  	 * @param imageNumber the number
  	 * @param array the array
  	 */
  	public static void saveForVisualization(int imageNumber, float [] array){
  		arrayBuffer.put(new Integer(imageNumber), array);
  		if (imageNumber > max) max = imageNumber;
  	}
  
  	/**
  	 * Performs a 1-D convolution of the input array with the kernel array.<BR>
  	 * New array will be only of size <br>
  	 * <pre>
  	 * output.lenght = input.length - (2 * (kernel.length/2));
  	 * </pre>
  	 * (Note that integer arithmetic is used here)<br>
  	 * @param input the array to be convolved
  	 * @param kernel the kernel
  	 * @return the output array.
  	 */
  	public static float [] convolve(float [] input, float [] kernel){
  		int offset = ((kernel.length) / 2);
  		float [] revan = new float [input.length - (2* offset)];
  		float weightSum = 0;
  		for (int j = 0; j < kernel.length; j++){
  			weightSum += kernel[j];
  		}
  		if (weightSum == 0) weightSum = 1; 
  		for (int i = offset; i < input.length-offset;i++){
  			float sum = 0;
  			for (int j = -offset; j <= offset; j++){
  				sum += kernel[offset+j] * input[i+j];
  			}
  			sum /= weightSum;
  			revan [i-offset] = sum;
  		}
  		return revan;
  	}
  
  	/**
  	 * Displays the arrays stored with "saveForVisualization" as ImagePlus.
  	 * @param title the title of the ImagePlus
  	 * @return the reference to the ImagePlus
  	 * 
  	 * @see #saveForVisualization(int imageNumber, float [] array)
  	 */
  	public static ImagePlus visualizeBufferedArrays(String title){
  		if (max >= 0) {
  			int height = max+1;
  			int width = arrayBuffer.get(new Integer(0)).length;
  			FloatProcessor flo = new FloatProcessor(width, height);
  			for (int j = 0; j <= max; j++){
  				float [] array = arrayBuffer.get(new Integer(j));
  				for (int i = 0; i < array.length; i++){
  					flo.putPixelValue(i, max - j, array[i]);
  				}
  			}
  			return VisualizationUtil.showImageProcessor(flo, title);
  		} else {
  			return null;
  		}
  	}
  
  	/**
  	 * Forces an complex float array to be symmetric. Left / first half of the array is mirrored to the right / second half
  	 * @param array the complex array
  	 */
  	public static void forceSymmetryComplexDoubleArray(float [] array){
  		// Force Symmetry
  		int width = array.length / 2;
  		for (int i = 0; i < (width/2); i++){
  			array[(width) + (2 * i)] = array[(width)-(2*i)];
  			array[(width) + (2 * i)+1] = array[(width)-(2*i)+1];
  		}
  	}
  
  	/**
  	 * tests if any of the values in the given array is NaN
  	 * @param array
  	 * @return true if the array contains at least one entry with NaN
  	 */
  	public static boolean isNaN(float [] array){
  		boolean revan = true;
  		for (int i = 0; i < array.length; i++){
  			if (revan && Double.isNaN(array[i])) revan = false;
  		}
  		return !revan;
  	}
  
  	/**
  	 * Forces a real float array to be symmetric. Left / first half of the array is mirrored to the right / second half
  	 * @param array the real array
  	 */
  	public static void forceSymmetryRealArray(float [] array){
  		// Force Symmetry
  		int width = array.length;
  		for (int i = 0; i < (width/2); i++){
  			array[(width/2) + (i)] = array[(width/2)-(i)];
  		}
  	}
  
  	/**
  	 * returns the closest index in the array to the given value
  	 * @param x the value
  	 * @param array the array
  	 * @return the desired index in the array
  	 */
  	public static int findClosestIndex(float x, float [] array){
  		float min = (float) Double.MAX_VALUE;
  		int pos = 0;
  		for (int i = 0; i < array.length; i++){
  			float dist = Math.abs(array[i]-x);
  			if (dist < min){
  				min = dist;
  				pos = i;
  				if (dist == 0) break;
  			}
  		}
  		return pos;
  	}
  	
  	
  	/**
  	 * computes the covariance between two arrays
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the correlation
  	 */
  	public static float covarianceOfArrays(float [] x, float [] y){
  		float meanX = computeMean(x);
  		float meanY = computeMean(y);
  		float covariance = 0;
  		for (int i=0; i< x.length; i++){
  			covariance += ((x[i] - meanX) * (y[i] - meanY)) / x.length;
  		}
  		return covariance / x.length;
  	}
  
  	/**
  	 * computes the correlation coefficient between two arrays after Pearson
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the correlation
  	 */
  	public static float correlateArrays(float [] x, float [] y){
  		float meanX = computeMean(x);
  		float meanY = computeMean(y);
  		float covariance = 0;
  		float varX = 0, varY = 0;
  		for (int i=0; i< x.length; i++){
  			varX += Math.pow(x[i] - meanX, 2) / x.length;
  			varY += Math.pow(y[i] - meanY, 2) / y.length;
  			covariance += ((x[i] - meanX) * (y[i] - meanY)) / x.length;
  		}
  		if (varX == 0) varX = (float) CONRAD.SMALL_VALUE;
  		if (varY == 0) varY = (float) CONRAD.SMALL_VALUE;
  		return (float) (covariance / (Math.sqrt(varX) * Math.sqrt(varY)));
  	}
  	
  	/**
  	 * computes the correlation coefficient between two arrays after Pearson
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the correlation
  	 */
  	public static float computeSSIMArrays(float [] x, float [] y){
  		float meanX = computeMean(x);
  		float meanY = computeMean(y);
  		float covariance = 0;
  		float varX = 0, varY = 0;
  		for (int i=0; i< x.length; i++){
  			varX += Math.pow(x[i] - meanX, 2) / x.length;
  			varY += Math.pow(y[i] - meanY, 2) / y.length;
  			covariance += ((x[i] - meanX) * (y[i] - meanY)) / x.length;
  		}
  		if (varX == 0) varX = (float) CONRAD.SMALL_VALUE;
  		if (varY == 0) varY = (float) CONRAD.SMALL_VALUE;
  		return (float) ((2*covariance *2*meanX*meanY) / ((varX+varY) * (Math.pow(meanY, 2) + Math.pow(meanX, 2))));
  	}
  
  	
  	/**
  	 * computes the concordance correlation coefficient between two arrays
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the correlation
  	 */
  	public static float concordanceCorrelateArrays(float [] x, float [] y){
  		float meanX = computeMean(x);
  		float meanY = computeMean(y);
  		float covariance = 0;
  		float varX = 0, varY = 0;
  		for (int i=0; i< x.length; i++){
  			varX += Math.pow(x[i] - meanX, 2) / x.length;
  			varY += Math.pow(y[i] - meanY, 2) / y.length;
  			covariance += ((x[i] - meanX) * (y[i] - meanY)) / x.length;
  		}
  		if (varX == 0) varX = (float) CONRAD.SMALL_VALUE;
  		if (varY == 0) varY = (float) CONRAD.SMALL_VALUE;
  		return (float) ((2* covariance) / (varX + varY + Math.pow(meanX - meanY, 2)));
  	}
  	
  	/**
  	 * computes the mean square error of array x to array y
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the mean square error
  	 */
  	public static float computeMeanSquareError(float [] x, float [] y){
  		float sum = 0;
  		for (int i=0; i< x.length; i++){
  			sum += Math.pow(x[i] - y[i], 2);
  		}
  		return sum / x.length;
  	}
  	
  	/**
  	 * computes the root mean square error of array x to array y
  	 *
  	 * @param x the one array
  	 * @param y the other array
  	 * @return the root mean square error.
  	 */
  	public static float computeRootMeanSquareError(float [] x, float [] y){
  		return (float) Math.sqrt(computeMeanSquareError(x, y));
  	}
  
  	public static void suppressCenter(float [] weights, int threshold){
  		for (int i = 1; i < weights.length; i++){
  			if (!((i < threshold) || ((weights.length - i) < threshold))) {
  				weights[i] = (weights[threshold] + weights[weights.length-threshold]) /2;
  			}
  		}
  	}
  
  	/**
  	 * Removes outliers from the array which differ more than threshold from the last value.
  	 * @param weights the weight
  	 * @param threshold the threshold
  	 */
  	public static void removeOutliers(float [] weights, float threshold){
  		for (int i = 1; i < weights.length; i++){
  			if (Math.abs(weights[i] - weights[i - 1]) > threshold) weights[i] = weights[i - 1] + threshold * Math.signum(- weights[i - 1] + weights[i]);
  		}
  	}
  
  	/**
  	 * computes the mean of the array "values" on the interval [start, end].
  	 * @param values the array
  	 * @param start the start index
  	 * @param end the end index
  	 * @return the mean value
  	 */
  	public static float computeMean (float [] values, int start, int end){
  		float revan = 0;
  		for(int i = start; i <= end; i++){
  			revan += values[i];
  		}
  		revan /= end - start + 1;
  		return revan;
  	}
  
  	/**
  	 * Computes the average increment of the array
  	 * @param array the array
  	 * @return the average increment
  	 */
  	public static float computeAverageIncrement(float [] array){
  		float increment = 0;
  		for (int i = 1; i < array.length; i++){
  			float value = Math.abs(array[i-1] - array[i]);
  			if (value > 180) { 
  				value -= 360;
  				value = Math.abs(value);
  			}
  			increment += value;
  		}
  		return increment / (array.length - 1);
  	}
  
  	/**
  	 * Performs mean filtering of the array.
  	 * @param weights the array
  	 * @param context the context to be used for smoothing (from -context/2 to context/2)
  	 * @return the smoothed array
  	 */
  	public static float[] meanFilter(float [] weights, int context){
  		float meanFiltered [] = new float [weights.length];
  		float mean = 0;
  		for (int i = 0; i < weights.length; i++) {
  			if (i > context / 2){
  				mean -= weights[i - (context/2)];
  			} if (i < (weights.length -1) - (context / 2)){
  				mean += weights[i + (context /2)];
  			}
  			if (i < context/2){
  				meanFiltered[i] = computeMean(weights, 0, i);
  			} else if ((i+ context/2) >= weights.length){
  				meanFiltered[i] = computeMean(weights, i, weights.length - 1);
  			} else {
  				meanFiltered[i] = computeMean(weights, i - context/2, i + context/2);
  			}
  		}
  		return meanFiltered;
  	}
  
  	/**
  	 * Gaussian smoothing of the elements of the array "weights"
  	 * @param weights the array
  	 * @param sigma the standard deviation
  	 * @return the smoothed array
  	 */
  	public static float[] gaussianFilter(float [] weights, float sigma){
  		float meanFiltered [] = new float [weights.length];
  		int center = (int) Math.floor(sigma * 1.5) + 1;
  		float kernel [] = new float [(int) Math.ceil(center*2 +1)];
  		float kernelSum = 0;
  		for (int j = 0; j < (center*2) + 1; j++){
  			kernel[j] = (float) (Math.exp(-0.5 * Math.pow((center-j) / sigma, 2))/sigma/Math.sqrt(2*Math.PI));
  			kernelSum += kernel[j];
  		}
  		for (int i =0; i< meanFiltered.length; i++){
  			float sum = 0;		
  			for (int j = -center; j <= center; j++){
  				// Out of bounds at left side
  				if (i+j < 0)
  					sum += kernel[j+center] * weights[0];
  				// Out of bounds at right side
  				else if (i+j > weights.length-1)
  					sum += kernel[j+center] * weights[weights.length-1];
  				// Convolution applied inside the valid part of the signal
  				else
  					sum += kernel[j+center] * weights[i+j];
  			}
  			meanFiltered[i] = sum / kernelSum;
  		}
  		return meanFiltered;
  	}
  
  	/**
  	 * Computes the standard deviation given an array and its mean value
  	 * @param array the array
  	 * @param mean the mean value of the array
  	 * @return the standard deviation
  	 */
  	public static float computeStddev(float[] array, float mean){
  		float stddev = 0;
  		for (int i = 0; i < array.length; i++){	
  			stddev += Math.pow(array[i] - mean, 2);
  		}
  		return (float) Math.sqrt(stddev / array.length);
  	}
  	
  	public static float computeStddev(float[] array, float mean, int start, int end){
  		float stddev = 0;
  		for (int i = start; i < end; i++){	
  			stddev += Math.pow(array[i] - mean, 2);
  		}
  		return (float) Math.sqrt(stddev / (end-start));
  	}
  
  	/**
  	 * Computes the mean value of a given array
  	 * @param array the array
  	 * @return the mean value as float
  	 */
  	public static float computeMean(float[] array){
  		float mean = 0;
  		for (int i = 0; i < array.length; i++){	
  			mean += array[i];
  		}
  		return mean / array.length;
  	}
  
  	/**
  	 * Returns the minimal and the maximal value in a given array
  	 * @param array the array
  	 * @return an array with minimal and maximal value
  	 */
  	public static float [] minAndMaxOfArray(float [] array){
  		float [] revan = new float [2];
  		revan[0] = Float.MAX_VALUE;
  		revan[1] = -Float.MAX_VALUE;
  		for (int i = 0; i < array.length; i++){
  			if (array[i] < revan[0]) {
  				revan[0] = array[i];
  			}
  			if (array[i] > revan[1]) {
  				revan[1] = array[i];
  			}
  		}
  		return revan;		
  	}
  
  	/**
  	 * Returns the minimal value in a given array
  	 * @param array the array
  	 * @return the minimal value
  	 */
  	public static float minOfArray(float [] array){
  		float min = Float.MAX_VALUE;
  		for (int i = 0; i < array.length; i++){
  			if (array[i] < min) {
  				min = array[i];
  			}
  
  		}
  		return min;		
  	}
  
  
  	/**
  	 * forces monotony onto the input array
  	 * @param array the array
  	 * @param rising force rising monotony?
  	 */
  	protected void forceMonotony(float [] array, boolean rising){
  		float lastValid = array[0];
  		for (int i=0;i< array.length; i++){
  			float value = array[i];
  			if (rising) {
  				if (value < lastValid) {
  					value = lastValid;
  				} else {
  					lastValid = value;
  				}
  			} else {
  				if (value > lastValid) {
  					value = lastValid;
  				} else {
  					lastValid = value;
  				}
  			}
  			array[i] = value;
  		}
  	}
  
  	/**
  	 * Adds one array to the first array
  	 * @param sum the first array
  	 * @param toAdd the array to add
  	 */
  	public static void add(float[] sum, float[] toAdd) {
  		for (int i =0; i < sum.length; i++){
  			sum[i] += toAdd[i];
  		}
  	}
  
  	/**
  	 * Adds a constant to the first array
  	 * @param sum the first array
  	 * @param toAdd the constant to add
  	 */
  	public static float [] add(float[] sum, float toAdd) {
  		for (int i =0; i < sum.length; i++){
  			sum[i] += toAdd;
  		}
  		return sum;
  	}
  
  	/**
  	 * Divides all entries of array by divident.
  	 * @param array the array
  	 * @param divident the number used for division.
  	 */
  	public static float [] divide(float[] array, float divident) {
  		for (int i =0; i < array.length; i++){
  			array[i] /= divident;
  		}
  		return array;
  	}
  
  	/**
  	 * Multiplies all entries of array by factor.
  	 * @param array the array
  	 * @param factor the number used for multiplication.
  	 */
  	public static float [] multiply(float[] array, float factor) {
  		for (int i =0; i < array.length; i++){
  			array[i] *= factor;
  		}
  		return array;
  	}
  
  	/**
  	 * Multiplies all entries of the two arrays element by element.<bR>
  	 * Works in place and overwrites array.
  	 * @param array the array
  	 * @param array2 the other array.
  	 */
  	public static void multiply(float[] array, float[] array2) {
  		for (int i =0; i < array.length; i++){
  			array[i] *= array2[i];
  		}
  	}
  
  	/**
  	 * Uses Math.exp() on all elements of the array
  	 * Works in place and overwrites array.
  	 * @param array the array
  	 */
  	public static void exp(float[] array) {
  		for (int i =0; i < array.length; i++){
  			array[i] = (float) Math.exp(array[i]);
  		}
  	}
  
  	/**
  	 * Divides all entries of the two arrays element by element.<bR>
  	 * Works in place and overwrites array.
  	 * @param array the array
  	 * @param divident the other array.
  	 */
  	public static float [] divide(float[] array, float[] divident) {
  		for (int i =0; i < array.length; i++){
  			array[i] /= divident[i];
  		}
  		return array;
  	}
  
  	/**
  	 * Uses Math.log() on all elements of the array
  	 * Works in place and overwrites array.
  	 * @param array the array
  	 */
  	public static void log(float[] array) {
  		for (int i =0; i < array.length; i++){
  			array[i] = (float) Math.log(array[i]);
  		}
  	}
  
  	/**
  	 * Prints the contents of the float array on standard out.
  	 * @param array
  	 * @param nf the NumberFormat
  	 */
  	public static void print(float[] array, NumberFormat nf) {
  		System.out.print("[");
  		for (int i =0; i < array.length; i++){
  			System.out.print(" " + nf.format(array[i]));
  		}
  		System.out.println(" ]");
  	}
  
  	/**
  	 * Prints the array on standard out and denotes the arrays name.
  	 * @param name the name
  	 * @param array the array
  	 * @param nf the number format
  	 */
  	public static void print(String name, float[] array, NumberFormat nf) {
  		System.out.print(name + " = ");
  		print(array, nf);
  	}
  
  	/**
  	 * Prints the array on standard out. Uses NumberFormat.getInstance() for number formatting
  	 * @param name the name 
  	 * @param array the array
  	 */
  	public static void print(String name, float [] array){
  		print(name, array, NumberFormat.getInstance());
  	}
  
  	/**
  	 * Prints the array on standard out. Uses NumberFormat.getInstance() for number formatting
  	 * @param array the array
  	 */
  	public static void print (float [] array){
  		print(array, NumberFormat.getInstance());
  	}
  
  	/**
  	 * calls Math.pow for each element of the array
  	 * @param array
  	 * @param exp the exponent.
  	 * @return reference to the input array
  	 */
  	public static float [] pow(float[] array, float exp) {
  		for (int i =0; i < array.length; i++){
  			array[i] = (float) Math.pow((double)array[i], exp);
  		}
  		return array;
  	}
  
  	public static float[] min(float [] array, float min) {
  		for (int i =0; i < array.length; i++){
  			array[i] = Math.min(array[i], min);
  		}
  		return array;
  	}
  	
  	/**
  	 * Converts the array to a String representation. Calls toString(array, " ").
  	 * @param array the array
  	 * @return the String representation
  	 * @see #toString(float[],String)
  	 */
  	public static String toString(float [] array){
  		return toString(array, " ");
  	}
  
  	/**
  	 * Converts the array to a String representation. delimiter is used to connect the elements of the array.
  	 * @param array the array
  	 * @param delimiter the delimiter
  	 * @return the String representation
  	 */
  	public static String toString(float[] array, String delimiter) {
  		String revan = array[0] + delimiter;
  		for(int i=1;i<array.length -1;i++){
  			revan += array[i] + delimiter;
  		}
  		revan += array[array.length-1];
  		return revan;
  	}
  
  }
  /*
   * Copyright (C) 2010-2014  Andreas Maier
   * CONRAD is developed as an Open Source project under the GNU General Public License (GPL).
  */