3Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
6This file is part of Octave.
8Octave is free software; you can redistribute it and/or modify it
9under the terms of the GNU General Public License as published by the
10Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
13Octave is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18You should have received a copy of the GNU General Public License
19along with Octave; see the file COPYING. If not, see
20<http://www.gnu.org/licenses/>.
33#define MAX(a,b) ((a) > (b) ? (a) : (b))
35enum Shape { SHAPE_FULL, SHAPE_SAME, SHAPE_VALID };
37#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
39conv2 (MArray<double>&, MArray<double>&, MArray2<double>&, Shape);
41extern MArray2<Complex>
42conv2 (MArray<Complex>&, MArray<Complex>&, MArray2<Complex>&, Shape);
45conv2 (MArray<float>&, MArray<float>&, MArray2<float>&, Shape);
47extern MArray2<FloatComplex>
48conv2 (MArray<FloatComplex>&, MArray<FloatComplex>&, MArray2<FloatComplex>&, Shape);
53conv2 (MArray<T>& R, MArray<T>& C, MArray2<T>& A, Shape ishape)
55 octave_idx_type Rn = R.length ();
56 octave_idx_type Cm = C.length ();
57 octave_idx_type Am = A.rows ();
58 octave_idx_type An = A.columns ();
60 // Calculate the size of the output matrix:
61 // in order to stay Matlab compatible, it is based
62 // on the third parameter if it's separable, and the
65 octave_idx_type outM = 0;
66 octave_idx_type outN = 0;
67 octave_idx_type edgM = 0;
68 octave_idx_type edgN = 0;
82 // Follow the Matlab convention (ie + instead of -)
98 error ("conv2: invalid value of parameter ishape");
101 MArray2<T> O (outM, outN);
103 // X accumulates the 1-D conv for each row, before calculating
104 // the convolution in the other direction
105 // There is no efficiency advantage to doing it in either direction
110 for (octave_idx_type oi = 0; oi < outM; oi++)
112 for (octave_idx_type oj = 0; oj < An; oj++)
116 octave_idx_type ci = Cm - 1 - MAX(0, edgM-oi);
117 octave_idx_type ai = MAX(0, oi-edgM);
118 const T* Ad = A.data() + ai + Am*oj;
119 const T* Cd = C.data() + ci;
120 for ( ; ci >= 0 && ai < Am; ci--, Cd--, ai++, Ad++)
121 sum += (*Ad) * (*Cd);
126 for (octave_idx_type oj = 0; oj < outN; oj++)
130 octave_idx_type rj = Rn - 1 - MAX(0, edgN-oj);
131 octave_idx_type aj = MAX(0, oj-edgN) ;
132 const T* Xd = X.data() + aj;
133 const T* Rd = R.data() + rj;
135 for ( ; rj >= 0 && aj < An; rj--, Rd--, aj++, Xd++)
136 sum += (*Xd) * (*Rd);
145#if !defined (CXX_NEW_FRIEND_TEMPLATE_DECL)
146extern MArray2<double>
147conv2 (MArray2<double>&, MArray2<double>&, Shape);
149extern MArray2<Complex>
150conv2 (MArray2<Complex>&, MArray2<Complex>&, Shape);
153conv2 (MArray2<float>&, MArray2<float>&, Shape);
155extern MArray2<FloatComplex>
156conv2 (MArray2<FloatComplex>&, MArray2<FloatComplex>&, Shape);
161conv2 (MArray2<T>&A, MArray2<T>&B, Shape ishape)
163 // Convolution works fastest if we choose the A matrix to be
166 // Here we calculate the size of the output matrix,
167 // in order to stay Matlab compatible, it is based
168 // on the third parameter if it's separable, and the
171 // NOTE in order to be Matlab compatible, we give argueably
172 // wrong sizes for 'valid' if the smallest matrix is first
174 octave_idx_type Am = A.rows ();
175 octave_idx_type An = A.columns ();
176 octave_idx_type Bm = B.rows ();
177 octave_idx_type Bn = B.columns ();
179 octave_idx_type outM = 0;
180 octave_idx_type outN = 0;
181 octave_idx_type edgM = 0;
182 octave_idx_type edgN = 0;
211 MArray2<T> O (outM, outN);
213 for (octave_idx_type oi = 0; oi < outM; oi++)
215 for (octave_idx_type oj = 0; oj < outN; oj++)
219 for (octave_idx_type bj = Bn - 1 - MAX (0, edgN-oj), aj= MAX (0, oj-edgN);
220 bj >= 0 && aj < An; bj--, aj++)
222 octave_idx_type bi = Bm - 1 - MAX (0, edgM-oi);
223 octave_idx_type ai = MAX (0, oi-edgM);
224 const T* Ad = A.data () + ai + Am*aj;
225 const T* Bd = B.data () + bi + Bm*bj;
227 for ( ; bi >= 0 && ai < Am; bi--, Bd--, ai++, Ad++)
229 sum += (*Ad) * (*Bd);
230 // Comment: it seems to be 2.5 x faster than this:
231 // sum+= A(ai,aj) * B(bi,bj);
244%! b = [0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18];
245%! assert(conv2([0,1;1,2],[1,2,3;4,5,6;7,8,9]),b);
248%! b = single([0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18]);
249%! assert(conv2(single([0,1;1,2]),single([1,2,3;4,5,6;7,8,9])),b);
252DEFUN_DLD (conv2, args, ,
254@deftypefn {Loadable Function} {y =} conv2 (@var{a}, @var{b}, @var{shape})\n\
255@deftypefnx {Loadable Function} {y =} conv2 (@var{v1}, @var{v2}, @var{M}, @var{shape})\n\
257Returns 2D convolution of @var{a} and @var{b} where the size\n\
258of @var{c} is given by\n\
261@item @var{shape}= 'full'\n\
262returns full 2-D convolution\n\
263@item @var{shape}= 'same'\n\
264same size as a. 'central' part of convolution\n\
265@item @var{shape}= 'valid'\n\
266only parts which do not include zero-padded edges\n\
269By default @var{shape} is 'full'. When the third argument is a matrix\n\
270returns the convolution of the matrix @var{M} by the vector @var{v1}\n\
271in the column direction and by vector @var{v2} in the row direction\n\
276 int nargin = args.length ();
277 std::string shape= "full"; //default
278 bool separable= false;
286 else if (nargin == 3)
288 if (args(2).is_string ())
289 shape = args(2).string_value ();
293 else if (nargin >= 4)
296 shape = args(3).string_value ();
301 else if (shape == "same")
303 else if (shape == "valid")
304 ishape = SHAPE_VALID;
307 error ("conv2: shape type not valid");
314 // If user requests separable, check first two params are vectors
316 if (! (1 == args(0).rows () || 1 == args(0).columns ())
317 || ! (1 == args(1).rows () || 1 == args(1).columns ()))
323 if (args(0).is_single_type () ||
324 args(1).is_single_type () ||
325 args(2).is_single_type ())
327 if (args(0).is_complex_type ()
328 || args(1).is_complex_type ()
329 || args(2).is_complex_type ())
331 FloatComplexColumnVector v1 (args(0).float_complex_vector_value ());
332 FloatComplexColumnVector v2 (args(1).float_complex_vector_value ());
333 FloatComplexMatrix a (args(2).float_complex_matrix_value ());
334 FloatComplexMatrix c (conv2 (v1, v2, a, ishape));
340 FloatColumnVector v1 (args(0).float_vector_value ());
341 FloatColumnVector v2 (args(1).float_vector_value ());
342 FloatMatrix a (args(2).float_matrix_value ());
343 FloatMatrix c (conv2 (v1, v2, a, ishape));
350 if (args(0).is_complex_type ()
351 || args(1).is_complex_type ()
352 || args(2).is_complex_type ())
354 ComplexColumnVector v1 (args(0).complex_vector_value ());
355 ComplexColumnVector v2 (args(1).complex_vector_value ());
356 ComplexMatrix a (args(2).complex_matrix_value ());
357 ComplexMatrix c (conv2 (v1, v2, a, ishape));
363 ColumnVector v1 (args(0).vector_value ());
364 ColumnVector v2 (args(1).vector_value ());
365 Matrix a (args(2).matrix_value ());
366 Matrix c (conv2 (v1, v2, a, ishape));
374 if (args(0).is_single_type () ||
375 args(1).is_single_type ())
377 if (args(0).is_complex_type ()
378 || args(1).is_complex_type ())
380 FloatComplexMatrix a (args(0).float_complex_matrix_value ());
381 FloatComplexMatrix b (args(1).float_complex_matrix_value ());
382 FloatComplexMatrix c (conv2 (a, b, ishape));
388 FloatMatrix a (args(0).float_matrix_value ());
389 FloatMatrix b (args(1).float_matrix_value ());
390 FloatMatrix c (conv2 (a, b, ishape));
397 if (args(0).is_complex_type ()
398 || args(1).is_complex_type ())
400 ComplexMatrix a (args(0).complex_matrix_value ());
401 ComplexMatrix b (args(1).complex_matrix_value ());
402 ComplexMatrix c (conv2 (a, b, ishape));
408 Matrix a (args(0).matrix_value ());
409 Matrix b (args(1).matrix_value ());
410 Matrix c (conv2 (a, b, ishape));
421template MArray2<double>
422conv2 (MArray<double>&, MArray<double>&, MArray2<double>&, Shape);
424template MArray2<double>
425conv2 (MArray2<double>&, MArray2<double>&, Shape);
427template MArray2<Complex>
428conv2 (MArray<Complex>&, MArray<Complex>&, MArray2<Complex>&, Shape);
430template MArray2<Complex>
431conv2 (MArray2<Complex>&, MArray2<Complex>&, Shape);