//
//  File:
//		TestConvolution.java
//
//  Authors:
//		jshore
//
//  Copyright:
//		2010 HSBC SECURITIES (USA) INC.  ALL RIGHTS RESERVED.
//
//		This software is only to be used for the purpose for which
//		it has been provided.  No part of it is to be reproduced,
//		disassembled, transmitted, stored in a retrieval system nor
//		translated in any human or computer language in any way or
//		for any other purposes whatsoever without the prior written
//		consent of HSBC SECURITIES (USA) INC.
//


package test.performance;



public class TestConvolution
{
	private static class Signal
	{
		/**
		 * This is a dumb substitute for the real class for the purposes of benchmarking
		 */
		public Signal (int numRow, int numCol)
		{
			this.numRows = numRow;
			this.numCols = numCol;
			this.data = new double[numRow*numCol];
			
			for (int i = 0 ; i < data.length ; i++)
				data[i] = Math.random();
		}
		
		public double[] 	data;
		public int			numRows;
		public int			numCols;
	}
	
	
	/**
	 * Simple FIR convolution of signals A and B in the time domain
	 *
	 * @param Sa		signal A
	 * @param Sb		signal B
	 * @param out		output matrix for convolution
	 * @return			reference to output vector
	 */
	public static void convolve (Signal Sa, Signal Sb, Signal out)
	{		
		final int La = Sa.numRows;
		final int Lb = Sb.numRows;
		final int nvar = Sa.numCols;

		final double[] Va = Sa.data;
		final double[] Vb = Sb.data;
		final double[] Vo = out.data;
		
		// loop over variables
		for (int iv = 0 ; iv < nvar ; iv++)
		{
			// main convolution
			for (int i = 0 ; i < (La-Lb) ; i++)
			{
				double sig = 0;
				for (int j = 0 ; j < Lb ; j++)
					sig += Va[(i+j) * nvar + iv] * Vb[(Lb-j-1) * nvar + iv];
				
				Vo [i*nvar + iv] = sig;
			}
			
			final double pad = 0;
			
			// boundary condition
			for (int i = Math.max ((La-Lb), 0) ; i < La ; i++)
			{
				double sig = 0;
				for (int j = 0 ; j < Lb ; j++)
				{
					final double v = ((i+j) < La) ? Va[(i+j) * nvar + iv] : pad; 
					sig += v * Vb[(Lb-j-1) * nvar + iv];
				}
				
				Vo [i * nvar + iv] = sig;
			}
		}
	}

	
	public static void main (String[] argv)
	{
		final int signallen = 100000;
		final int nvar = 1;
		final int iterations = 2;
		
		Signal Sa = new Signal (signallen, nvar);
		Signal Sb = new Signal (signallen, nvar);
		Signal out = new Signal (signallen, nvar);
		
		System.out.println ("starting evaluation"); 
		final long Tstart = System.nanoTime (); 
		
		for (int i = 0 ; i < iterations ; i++)
		{
			convolve (Sa, Sb, out);
		}
		
		final long Tend = System.nanoTime();
		final long Tdelta = (Tend-Tstart) / 1000000;
		System.out.println (" timing: " + Tdelta + " ms"); 
		
		double sum = 0.0;
		for (int i = 0 ; i < out.data.length ; i++)
			sum += out.data[i];
		
		System.err.println ("force evaluation: " + sum);
	}
}
