/* RISO: an implementation of distributed belief networks.
* Copyright (C) 1999, Robert Dodier.
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA,
* or visit the GNU web site, www.gnu.org.
*/
package riso.numerical;
import java.io.*;
import riso.general.*;
/** This class contains a method to compute the discrete convolution of two
* sequences.
*/
public class Convolve
{
/** Compute the discrete convolution of two sequences of data.
* First <tt>-Nx</tt> data are read for the first sequence, then <tt>-Ny</tt> data
* are read for the second.
*/
public static void main( String[] args )
{
try
{
int Nx = 0, Ny = 0;
for ( int i = 0; i < args.length; i++ )
{
if ( args[i].charAt(0) != '-' ) continue;
switch (args[i].charAt(1))
{
case 'N':
switch (args[i].charAt(2))
{
case 'x':
Nx = Integer.parseInt( args[++i] );
break;
case 'y':
Ny = Integer.parseInt( args[++i] );
break;
}
break;
}
}
SmarterTokenizer st = new SmarterTokenizer( new InputStreamReader( System.in ) );
double[] x = new double[Nx], y = new double[Ny];
for ( int i = 0; i < Nx; i++ )
{
st.nextToken();
x[i] = Double.parseDouble( st.sval );
}
for ( int i = 0; i < Ny; i++ )
{
st.nextToken();
y[i] = Double.parseDouble( st.sval );
}
double[] cxy = convolve(x,y);
System.err.println( "length of convolution: "+cxy.length );
for ( int i = 0; i < cxy.length; i++ )
System.out.println( cxy[i] );
}
catch (Exception e) { e.printStackTrace(); }
}
/** Compute convolution of two sequences. The length of the two sequences need not be
* the same, and the lengths need not be powers of two. The length of the output array
* will be the length of <tt>x</tt> plus the length of <tt>y</tt>, less one.
*/
public static double[] convolve( double[] x, double[] y )
{
int Npadded = x.length+y.length, N = x.length+y.length-1;
if ( (1 << FFT.ilog2(Npadded)) != Npadded )
// Npadded is not a power of two; round up to next power of 2.
Npadded = 1 << (FFT.ilog2(Npadded)+1);
Complex[] xy = new Complex[ Npadded ];
for ( int i = 0; i < Npadded; i++ ) xy[i] = new Complex();
for ( int i = 0; i < x.length; i++ ) xy[i].real = x[i];
for ( int i = 0; i < y.length; i++ ) xy[i].imag = y[i];
FFT.fft(xy); // compute FFT on both columns at once.
// Compute product of FFT's of each column of data.
Complex[] xx = new Complex[ Npadded ];
for ( int i = 0; i < Npadded; i++ )
{
// The FFT coefficient of the first column is (R1,I1), and
// that of the second is (R2,-I2). This bit is taken from
// Brigham (1974), The Fast Fourier Transform, Figure 10-9.
int i_reflect = (i == 0? 0: Npadded-i);
double R1 = (xy[i].real + xy[i_reflect].real)/2;
double I1 = (xy[i].imag - xy[i_reflect].imag)/2;
double R2 = (xy[i].imag + xy[i_reflect].imag)/2;
double I2 = (xy[i].real - xy[i_reflect].real)/2;
// Multiply the coefficients to obtain the convolution.
xx[i] = new Complex();
xx[i].real = R1*R2 + I1*I2;
xx[i].imag = -R1*I2 + I1*R2;
}
FFT.invfft(xx); // inverse transform to obtain convolution.
double[] cxy = new double[N];
for ( int i = 0; i < cxy.length; i++ )
cxy[i] = xx[i].real; // imaginary part is always zero.
return cxy;
}
}