package oneLinersForAlgoTests;

import java.io.BufferedReader;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.nio.channels.FileChannel;
import java.util.ArrayList;


/** Java routines to do various simple tasks.
 * To be called in a single short line only.
 * 
 * The principal are:
 * 1) Someone else should be able to replace/rewrite the routine exactly without any information other than the routine's name (no JavaDoc or anything)
 *  	and it shouldn't take them more than a few minutes at the very most.
 * 2) Write them as you need them, don't try to make it general or make the float[] version and the double[] version etc just for the point of it.
 * 3) Don't worry about them existing elsewhere or trying to find if already exist in here, just write it and carry on.
 * 		(However if you see the same thing in here under different names, feel free to make one call the other and make it with [at]deprecate) 
 *  
 * @author oliford <codes(at)oliford.co.uk>
 * @author everyone-else
 *
 */
public class algoOneLiners {
	/** Finds the index into xs[] nearest x where xs[] < x (integers)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestLowerIndex(int xs[], int x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		return klo;
	}
	
	/** Finds the index into xs[] nearest x where xs[] < x (doubles)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestLowerIndex(double xs[], double x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		return klo;
	}
	
	/** Finds the index into xs[] nearest x (doubles)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestIndex(double xs[], double x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		if( (x - xs[klo]) < (xs[khi] - xs[klo])/2)
			return klo;		
		else
			return khi;
	}
	
	/** Finds the index into xs[] nearest x (floats)
	 * @params xs Array of values
	 * @param x Single value 
	 */	
	public final static int getNearestIndex(float xs[], float x){	
		int k,klo,khi;
		klo = 0;		
		khi = xs.length - 1;
		if(x <= xs[0])return 0;
		if(x >= xs[khi])return khi;
		while( khi - klo > 1){
			k = (khi + klo) / 2;
			if( x < xs[k])
				khi = k;
			else
				klo = k;			
		}		
		if( (x - xs[klo]) < (xs[khi] - xs[klo])/2)
			return klo;		
		else
			return khi;
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[][], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);		
			dumpArray(a, out);		
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public final static void dumpArray(int a[][], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);		
			dumpArray(a, out);		
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	public final static void dumpArray(int a[], String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}
	
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[][]){
		dumpArray(a, new PrintWriter(System.out, true));	
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[][]){
		dumpArray(a, new PrintWriter(System.out, true));	
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(Double a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	

	/** does what is says on the tin */
	public final static void dumpArray(float a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(boolean a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}

	
	
	/** does what is says on the tin */
	public final static void dumpArray(String a[]){
		dumpArray(a, new PrintWriter(System.out, true));
	}
	

	/** does what is says on the tin */
	public final static void dumpArray(double a[][], PrintWriter out){
		for(int i=0;i<a.length;i++)
			dumpArray(a[i], out);
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(int a[][], PrintWriter out){
		for(int i=0;i<a.length;i++)
			dumpArray(a[i], out);
	}
	
	
	/** does what is says on the tin */
	public final static void dumpArray(double a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(Double a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(float a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(int a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	/** does what is says on the tin */
	public final static void dumpArray(boolean a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}
	
	/** does what is says on the tin */
	public final static void dumpArray(String a[], PrintWriter out){
		out.print(a[0]);
		for(int i=1;i<a.length;i++)
			out.print("\t"+a[i]);				
		
		out.println("");		
	}

	
	/** 
	 * Dumps an array in what way? 
	 **/
	public final static void dumpArray(double a[], int n, int m, PrintWriter out){
		for (int i=0; i<m; i++)
			out.print("\t");
		out.print(a[0]);
		for(int i=1;i<a.length;i++) {
			if ((i)%n!=0)
				out.print("\t");
			else
				for (int j=0; j<m; j++)
					out.print("\t");
			out.print(a[i]);
			if ((i+1)%n==0)
				out.print("\n");
		}
		out.println("");		
	}

	/** 
	 * Dumps an array in what way? 
	 **/
	public final static void dumpArray(double a[], int n, int m, String fileName){
		makePath(fileName);
		try {
			PrintWriter out = new PrintWriter(fileName);
			dumpArray(a, n, m, out);	
			out.close();
		} catch (FileNotFoundException e) {
			throw new RuntimeException(e);
		}
	}

	
	public final static double[][] transpose(double dIn[][]){
		int i,j,ni,nj;
		ni = dIn.length;
		if(ni <= 0)return new double[0][0];
		nj = dIn[0].length;
		double dOut[][] = new double[nj][ni];
		for(i=0;i<ni;i++)
			for(j=0;j<nj;j++)
				dOut[j][i]=dIn[i][j];
		
		return dOut;
		
	}
	
	public final static double[] getColumn(double mat[][], int idx){
		int n = mat.length;
		double ret[] = new double[n];
		for(int i=0; i < n; i++)
			ret[i] = mat[i][idx];
		return ret;
	}
		
	
	public final static float[][] transpose(float dIn[][]){
		int i,j,ni,nj;
		ni = dIn.length;
		if(ni <= 0)return new float[0][0];
		nj = dIn[0].length;
		float dOut[][] = new float[nj][ni];
		for(i=0;i<ni;i++)
			for(j=0;j<nj;j++)
				dOut[j][i]=dIn[i][j];
		
		return dOut;		
	}
	
	/**
	 * Returns the diagonal elements of the given square matrix.
	 * @param dIn 
	 * @return
	 */
	public final static double[] diag(double dIn[][]) {
		if (dIn.length != dIn[0].length) {
			throw new RuntimeException("Matrix must be square: "+dIn.length+" != "+dIn[0].length);
		}
		double[] ret = new double[dIn.length];
		for(int i=0;i<ret.length;++i) {
			ret[i] = dIn[i][i];
		}
		
		return ret;
	}
	
	/** Makes the dirs in the path ready for the given file */
	public static void makePath(String fileName){
		//build dir up to and not including file name
		String bits[] = fileName.split("\\/");
		if(bits.length <= 1)return; //file into current dir, ignore
		
		StringBuffer dir = new StringBuffer("");
		for(int i=0;i<bits.length-1;i++){
			dir.append("/");
			dir.append(bits[i]);
		}
		
		File dirDesc = new File(dir.toString());
		if(dirDesc.exists()){
			if(!dirDesc.isDirectory())
				throw new RuntimeException("Cannot create directory '" + dir + "' because it already exists but is not a directory.");
				
			return; //already OK
		}
		
		//try to make it
		if(!dirDesc.mkdirs())
			throw new RuntimeException("Directory '" + dir + "' does not exist and we cannot create it.");
	}
	
	public final static boolean recursiveDelete(String path){
	    // Deletes all files and subdirectories under dir.
	    // Returns true if all deletions were successful.
	    // If a deletion fails, the method stops attempting to delete and returns false.
	    File dir = new File(path);
	    if (dir.isDirectory()) {
	        String[] children = dir.list();
	        for (int i=0; i<children.length; i++) {
	            boolean success = recursiveDelete(path+"/"+children[i]);
	            if (!success) {
	                return false;
	            }
	        }
	    }

	    // The directory is now empty so delete it
	    return dir.delete();
	    
	}
	
	public final static double[][] intToDouble(int a[][]){
		int n=a.length;
		int m=a[0].length;
		double b[][] = new double[n][m];
		
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				b[i][j] = a[i][j];
		
		return b;
	}
	
	public final static int[][] doubleToInt(double a[][]){
		int n=a.length;
		int m=a[0].length;
		int b[][] = new int[n][m];
		
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)
				b[i][j] = (int)a[i][j];
		
		return b;
	}
	
	public final static double[] intToDouble(int a[]){
		int n=a.length;
		double b[] = new double[n];
		
		for(int i=0;i<n;i++)
				b[i] = a[i];
		
		return b;
	}
	
	public final static int[] doubleToInt(double a[]){
		int n=a.length;
		int b[] = new int[n];
		
		for(int i=0;i<n;i++)
				b[i] = (int)a[i];
		
		return b;
	}
	
	public final static void TextToFile(String fileName, String text){
		algoOneLiners.makePath(fileName);
		
		try{
			FileOutputStream fOut = new FileOutputStream(fileName);
			fOut.write(text.getBytes());
			fOut.close();
		}catch(IOException err){
			throw new RuntimeException(err);
		}
	}
	
	/**
	 * From http://www.javapractices.com/topic/TopicAction.do?Id=42
	 */
	public final static String fileToText(String fileName) {
	    //...checks on aFile are elided
		File aFile = new File(fileName);
	    StringBuilder contents = new StringBuilder();
	    
	    try {
	      //use buffering, reading one line at a time
	      //FileReader always assumes default encoding is OK!
	      BufferedReader input =  new BufferedReader(new FileReader(aFile));
	      try {
	        String line = null; //not declared within while loop
	        /*
	        * readLine is a bit quirky :
	        * it returns the content of a line MINUS the newline.
	        * it returns null only for the END of the stream.
	        * it returns an empty String if two newlines appear in a row.
	        */
	        while (( line = input.readLine()) != null){
	          contents.append(line);
	          contents.append(System.getProperty("line.separator"));
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (IOException ex){ 
	      ex.printStackTrace();  
	      return null; //This needs to tell the caller something went wrong
	    }
	    
	    return contents.toString();
	}
	
	public final static String[] linesFromFile(String fileName) {
	    //...checks on aFile are elided
		File aFile = new File(fileName);
	    ArrayList <String>lines = new ArrayList <String>();
	    
	    try {
	      //use buffering, reading one line at a time
	      //FileReader always assumes default encoding is OK!
	      BufferedReader input =  new BufferedReader(new FileReader(aFile));
	      try {
	        String line = null; //not declared within while loop
	        /*
	        * readLine is a bit quirky :
	        * it returns the content of a line MINUS the newline.
	        * it returns null only for the END of the stream.
	        * it returns an empty String if two newlines appear in a row.
	        */
	        while (( line = input.readLine()) != null){
	        	lines.add(line);	          
	        }
	      }
	      finally {
	        input.close();
	      }
	    }
	    catch (IOException ex){
	      ex.printStackTrace();
	      return null;
	    }
	    
	    //return (String[])lines.toArray();
	    String lineArr[] = new String[lines.size()];
	    for(int i=0; i < lines.size(); i++)
	    	lineArr[i] = lines.get(i);
	    
	    return lineArr;
	}
	
	public final static double[] getRange(double f[][]){	
		double minF = Double.POSITIVE_INFINITY;
		double maxF = Double.NEGATIVE_INFINITY;
		for(int i=0; i < f.length; i++)
	        for(int j=0; j < f[i].length; j++){
	        	if( f[i][j] > maxF )
	        		maxF = f[i][j];
	        	if( f[i][j] < minF )
	        		minF = f[i][j];
	        }        	
        return new double[]{ minF, maxF };
	}
	
	public final static double[] getRange(double f[]){		
		double minF = Double.POSITIVE_INFINITY;
		double maxF = Double.NEGATIVE_INFINITY;
        for(int i=0; i < f.length; i++){
        	if( f[i] > maxF )
        		maxF = f[i];
        	if( f[i] < minF )
        		minF = f[i];
        }        	
        return new double[]{ minF, maxF };
	}
	
	public final static int min(int f[]){		
		int minF = Integer.MAX_VALUE;
		  for(int i=0; i < f.length; i++){
        	if( f[i] < minF )
        		minF = f[i];
        }        	
        return minF;
	}
	
	public final static int max(int f[]){		
		int maxF = Integer.MIN_VALUE;
        for(int i=0; i < f.length; i++){
        	if( f[i] > maxF )
        		maxF = f[i];
        }        	
        return maxF;
	}
	
	public final static double[] linSpace(double x0, double x1, int n){
        double f[] = new double[n];
        double dx = (x1 - x0)/(double)(n - 1.0);
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}
	
	public final static double[] linSpace(double x0, double x1, double dx){
		int n = (int)((x1 - x0)/dx + 1.0);		
        double f[] = new double[n];
        
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}

	public final static float[] linSpaceFloat(float x0, float x1, int n){
		float f[] = new float[n];
		float dx = (x1 - x0)/(float)(n - 1.0);
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}
	
	public final static float[] linSpaceFloat(float x0, float x1, float dx){
		int n = (int)((x1 - x0)/dx + 1.0);		
		float f[] = new float[n];
        
        for(int i=0; i<n; i++)
            f[i] = x0 + i*dx;
        return f;
	}

	/** Copies 2D arrays with rectangular shapes. For 1D arrays use the java Arrays class instead. */
	public final static double[][] copyArray(double[][] a) {
		int nr = a.length, nc = a[0].length;
		double[][] ret = new double[nr][nc];
		for(int i=0;i<nr;++i) {
			for(int j=0;j<nc;++j) {
				ret[i][j] = a[i][j];
			}
		}
		
		return ret;
	}
	
	/**
	 * Applies the given operator from the Math class to all elements
	 * in the given array. Slow but sometimes convenient.
	 * 
	 * Special operators: "+", "-", "*", "/" for the corresponding operations
	 * between two arrays.
	 * 
	 * @param op A Math method name, for example "sqrt"
	 * @param x An array with doubles.
	 * @param args Extra arguments for the operation.
	 * 
	 * @return An array with the given operation performed on each element in the original array.
	 */
	public final static double[] arrayOp(String op, double[] x, Object...args) {
		double[] ret = new double[x.length];
		
		if (op.equals("+")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]+y[i];
			}
			return ret;
		} else if (op.equals("-")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]-y[i];
			}
			return ret;			
		} else if (op.equals("*")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]*y[i];
			}
			return ret;			
		} else if (op.equals("/")) {
			double[] y = (double[]) args[0];
			for(int i=0;i<ret.length;++i) {
				ret[i] = x[i]/y[i];
			}
			return ret;
		}
		
		Method method = null;
		try {
			Class<?>[] argTypes = new Class<?>[1+args.length];
			argTypes[0] = double.class;
			for(int i=1;i<argTypes.length;++i) {
				argTypes[i] = args[i-1].getClass();
			}
			method = Math.class.getDeclaredMethod(op, argTypes);
			for(int i=0;i<ret.length;++i) {
				ret[i] = (Double) method.invoke(null, x[i]);
			}	
		} catch (Exception ex) { 			
			throw new RuntimeException("Field "+op+" with double argument does not exist in Math class.");
		}
					
		return ret;
	}
	
	/** Multiplies all the elements of the given array by the given scalar */
	public final static double[] arrayMultiply(double x[], double c){
		double ret[] = new double[x.length];
		for(int i=0; i<x.length; i++)
			ret[i] = x[i] * c;
		return ret;
	}
	
	/**
	 * Allocates and fills a double array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static double[] fillArray(double value, int n) {
		double[] ret = new double[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/**
	 * Takes the specified subsection of the given array an puts it in a new array of length n
	 * @param value The array to take n elements from 
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static double[] subArray(double in[], int i0, int n) {
		double[] ret = new double[n];
		for(int i=0;i<n;++i) {
			ret[i] = in[i0 + i];			
		}
		return ret;
	}


	/**
	 * Allocates and fills a float array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static float[] fillFloatArray(float value, int n) {
		float[] ret = new float[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/**
	 * Allocates and fills an int array with a specified value.
	 * @param value The value for each element in the array.
	 * @param n The array size.
	 * @return The allocated array.
	 */
	public final static int[] fillIntArray(int value, int n) {
		int[] ret = new int[n];
		for(int i=0;i<n;++i) {
			ret[i] = value;
		}
		return ret;
	}
	
	/** Flatten a 2D double array to 1D. Data returned is stored row by row data from 'mat'. */
	public final static double[] flatten(double mat[][]){
			int n = mat.length;
			int m = mat[0].length;
			double flatMat[] = new double[n*m];
			for(int i=0; i < n; i++)
				System.arraycopy(mat[i], 0, flatMat, i*m, m);
			return flatMat;
	}
	
	/** Unflattens a 1D double array to 2D. 
	 * @param flatMat	The matrix data, stored row by row
	 * @param n	Number of rows (shallowest dimension)
	 * @param m Number of columns (deepest dimension)
	 * @return mat[n][m]
	 */
	public final static double[][] unflatten(double flatMat[], int n, int m){
		double mat[][] = new double[n][m];
		for(int i=0; i < n; i++)
			System.arraycopy(flatMat, i*m, mat[i], 0, m);
		return mat;
	}
	
	/** Unflattens a 1D int array to 2D. 
	 * @param flatMat	The matrix data, stored row by row
	 * @param n	Number of rows (shallowest dimension)
	 * @param m Number of columns (deepest dimension)
	 * @return mat[n][m]
	 */
	public final static int[][] unflatten(int flatMat[], int n, int m){
		int mat[][] = new int[n][m];
		for(int i=0; i < n; i++)
			System.arraycopy(flatMat, i*m, mat[i], 0, m);
		return mat;
	}
	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static int[] appendArray(int[] arrayOne, int[] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new int[0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		int[] ans = new int[m+n];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}
	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static double[][] appendArray(double[][] arrayOne, double[][] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new double[0][0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		double[][] ans = new double[m+n][];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}

	
	/** Appends arrayTwo onto the end of arrayOne
	 * @param arrayOne - array to be extended by adding arrayTwo to its end
	 * @param arrayTwo - the array concatenated onto the end of arrayOne
	 * @return the concatenated array
	 */
	public final static double[] appendArray(double[] arrayOne, double[] arrayTwo) {
		if (arrayOne == null)
			arrayOne = new double[0];
		
		int n = arrayOne.length;
		int m = arrayTwo.length;
		double[] ans = new double[m+n];
		System.arraycopy(arrayOne, 0, ans, 0, n);
		System.arraycopy(arrayTwo, 0, ans, n, m);
		
		return ans;
	}
	
	/** Flatten a 2D double array that hasn't necessarily been square allocated to a 1D array. */
	public final static double[] flattenNonUniform(double mat[][]){
			int n = mat.length;
			int m = 0;
			int currentIdx = 0;
			
			for(int i=0; i < n; i++)
				m += mat[i].length;
			
			double flatMat[] = new double[m];
			
			for(int i=0; i < n; i++) {
				m = mat[i].length;
				System.arraycopy(mat[i], 0, flatMat, currentIdx, m);
				currentIdx += m;
			}
			return flatMat;
	}


	
	/** Mumble, mumble ... no way to call sensible OS routines ... mumble mumble */ 
	public final static void copyFile(String sourceName, String destName) throws IOException { copyFile(new File(sourceName), new File(destName)); }
	
	/** Mumble, mumble ... no way to call sensible OS routines ... mumble mumble */ 
	public final static void copyFile(File sourceFile, File destFile) throws IOException {

		
		if(!destFile.exists()) 
			destFile.createNewFile();		

		FileChannel source = null, destination = null;
		try {
			source = new FileInputStream(sourceFile).getChannel();
			destination = new FileOutputStream(destFile).getChannel();
			destination.transferFrom(source, 0, source.size());
		} finally {
			if(source != null) 
				source.close();			
			if(destination != null)
				destination.close();
		}
	}
	
    /** Java doesn't have the error function, which is annoying.
     * This was copied from somewhere. I can't remember where, but it works.
     * 
     * Fractional error in math formula less than 1.2 * 10 ^ -7.
     * although subject to catastrophic cancellation when z in very close to 0 */
	 public final static double erf(double z) {
	     double t = 1.0 / (1.0 + 0.5 * Math.abs(z));
	
	     // use Horner's method
	     double ans = 1 - t * Math.exp( -z*z   -   1.26551223 +
	                                         t * ( 1.00002368 +
	                                         t * ( 0.37409196 + 
	                                         t * ( 0.09678418 + 
	                                         t * (-0.18628806 + 
	                                         t * ( 0.27886807 + 
	                                         t * (-1.13520398 + 
	                                         t * ( 1.48851587 + 
	                                         t * (-0.82215223 + 
	                                         t * ( 0.17087277))))))))));
	     if (z >= 0) return  ans;
	     else        return -ans;
	 }

	public static int indexOfStringInList(String[] list, String string) {
		for(int i=0; i < list.length; i++){
			if(string.equals(list[i]))
				return i;
		}
		return -1;
	}	
	
	public static double[][] addColumRowHeaders(double[][] in, double rowHead[], double colHead[]) {
		int nRows = in.length, nCols=in[0].length;
		
		double out[][] = new double[nRows+1][nCols+1];
		for(int j=0; j < nCols; j++)
			out[0][j+1] = colHead[j];
		
		for(int i=0; i< nRows; i++){
			out[i+1][0] = rowHead[i];
			for(int j=0; j < nCols; j++){
				out[i+1][j+1] = in[i][j];
			}
		}
		
		return out;
	}

	/** (equ from wikipedia/rotation matrix) */
	public static final double[] rotateVectorAroundAxis(double angle, double rotVec[], double sourceVec[]){
		double cosAng = Math.cos(angle);
		double sinAng = Math.sin(angle);
		
		return new double[]{
				sourceVec[0] * (cosAng + rotVec[0]*rotVec[0]*(1.0 - cosAng) ) +
				sourceVec[1] * (rotVec[0]*rotVec[1]*(1.0 - cosAng) - rotVec[2]*sinAng) +
				sourceVec[2] * (rotVec[0]*rotVec[2]*(1.0 - cosAng) + rotVec[1]*sinAng),
		
				sourceVec[0] * (rotVec[1]*rotVec[0]*(1.0 - cosAng) + rotVec[2]*sinAng) +
				sourceVec[1] * (cosAng + rotVec[1]*rotVec[1]*(1.0 - cosAng) ) +
				sourceVec[2] * (rotVec[1]*rotVec[2]*(1.0 - cosAng) - rotVec[0]*sinAng),
				
				sourceVec[0] * (rotVec[2]*rotVec[0]*(1.0 - cosAng) - rotVec[1]*sinAng) +
				sourceVec[1] * (rotVec[2]*rotVec[1]*(1.0 - cosAng) + rotVec[0]*sinAng) +
				sourceVec[2] * (cosAng + rotVec[2]*rotVec[2]*(1.0 - cosAng) ),		
		};	
	}

}
