diff src/corefcn/conv2.cc @ 15039:e753177cde93

maint: Move non-dynamically linked functions from DLD-FUNCTIONS/ to corefcn/ directory * __contourc__.cc, __dispatch__.cc, __lin_interpn__.cc, __pchip_deriv__.cc, __qp__.cc, balance.cc, besselj.cc, betainc.cc, bsxfun.cc, cellfun.cc, colloc.cc, conv2.cc, daspk.cc, dasrt.cc, dassl.cc, det.cc, dlmread.cc, dot.cc, eig.cc, fft.cc, fft2.cc, fftn.cc, filter.cc, find.cc, gammainc.cc, gcd.cc, getgrent.cc, getpwent.cc, getrusage.cc, givens.cc, hess.cc, hex2num.cc, inv.cc, kron.cc, lookup.cc, lsode.cc, lu.cc, luinc.cc, matrix_type.cc, max.cc, md5sum.cc, mgorth.cc, nproc.cc, pinv.cc, quad.cc, quadcc.cc, qz.cc, rand.cc, rcond.cc, regexp.cc, schur.cc, spparms.cc, sqrtm.cc, str2double.cc, strfind.cc, sub2ind.cc, svd.cc, syl.cc, time.cc, tril.cc, typecast.cc: Move functions from DLD-FUNCTIONS/ to corefcn/ directory. Include "defun.h", not "defun-dld.h". Change docstring to refer to these as "Built-in Functions". * build-aux/mk-opts.pl: Generate options code with '#include "defun.h"'. Change option docstrings to refer to these as "Built-in Functions". * corefcn/module.mk: List of functions to build in corefcn/ dir. * DLD-FUNCTIONS/config-module.awk: Update to new build system. * DLD-FUNCTIONS/module-files: Remove functions which are now in corefcn/ directory. * src/Makefile.am: Update to build "convenience library" in corefcn/. Octave program now links against all other libraries + corefcn libary. * src/find-defun-files.sh: Strip $srcdir from filename. * src/link-deps.mk: Add REGEX and FFTW link dependencies for liboctinterp. * type.m, which.m: Change failing tests to use 'amd', still a dynamic function, rather than 'dot', which isn't.
author Rik <rik@octave.org>
date Fri, 27 Jul 2012 15:35:00 -0700
parents src/DLD-FUNCTIONS/conv2.cc@34f067bcac12
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/corefcn/conv2.cc	Fri Jul 27 15:35:00 2012 -0700
@@ -0,0 +1,393 @@
+/*
+
+Copyright (C) 1999-2012 Andy Adler
+Copyright (C) 2010 VZLU Prague
+
+This file is part of Octave.
+
+Octave 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 3 of the License, or (at your
+option) any later version.
+
+Octave 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 Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "oct-convn.h"
+
+#include "defun.h"
+#include "error.h"
+#include "oct-obj.h"
+#include "utils.h"
+
+enum Shape { SHAPE_FULL, SHAPE_SAME, SHAPE_VALID };
+
+DEFUN (conv2, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Built-in Function} {} conv2 (@var{A}, @var{B})\n\
+@deftypefnx {Built-in Function} {} conv2 (@var{v1}, @var{v2}, @var{m})\n\
+@deftypefnx {Built-in Function} {} conv2 (@dots{}, @var{shape})\n\
+Return the 2-D convolution of @var{A} and @var{B}.  The size of the result\n\
+is determined by the optional @var{shape} argument which takes the following\n\
+values\n\
+\n\
+@table @asis\n\
+@item @var{shape} = \"full\"\n\
+Return the full convolution.  (default)\n\
+\n\
+@item @var{shape} = \"same\"\n\
+Return the central part of the convolution with the same size as @var{A}.\n\
+The central part of the convolution begins at the indices\n\
+@code{floor ([size(@var{B})/2] + 1)}.\n\
+\n\
+@item @var{shape} = \"valid\"\n\
+Return only the parts which do not include zero-padded edges.\n\
+The size of the result is @code{max (size (A) - size (B) + 1, 0)}.\n\
+@end table\n\
+\n\
+When the third argument is a matrix, return the convolution of the matrix\n\
+@var{m} by the vector @var{v1} in the column direction and by the vector\n\
+@var{v2} in the row direction.\n\
+@seealso{conv, convn}\n\
+@end deftypefn")
+{
+  octave_value retval;
+  octave_value tmp;
+  int nargin = args.length ();
+  std::string shape = "full";   // default
+  bool separable = false;
+  convn_type ct;
+
+  if (nargin < 2)
+    {
+     print_usage ();
+     return retval;
+    }
+  else if (nargin == 3)
+    {
+      if (args(2).is_string ())
+        shape = args(2).string_value ();
+      else
+        separable = true;
+    }
+  else if (nargin >= 4)
+    {
+      separable = true;
+      shape = args(3).string_value ();
+    }
+
+  if (shape == "full")
+    ct = convn_full;
+  else if (shape == "same")
+    ct = convn_same;
+  else if (shape == "valid")
+    ct = convn_valid;
+  else
+    {
+      error ("conv2: SHAPE type not valid");
+      print_usage ();
+      return retval;
+    }
+
+   if (separable)
+     {
+      // If user requests separable, check first two params are vectors
+
+       if (! (1 == args(0).rows () || 1 == args(0).columns ())
+           || ! (1 == args(1).rows () || 1 == args(1).columns ()))
+         {
+           print_usage ();
+           return retval;
+         }
+
+       if (args(0).is_single_type () || args(1).is_single_type ()
+           || args(2).is_single_type ())
+         {
+           if (args(0).is_complex_type () || args(1).is_complex_type ()
+               || args(2).is_complex_type ())
+             {
+               FloatComplexMatrix a (args(2).float_complex_matrix_value ());
+               if (args(1).is_real_type () && args(2).is_real_type ())
+                 {
+                   FloatColumnVector v1 (args(0).float_vector_value ());
+                   FloatRowVector v2 (args(1).float_vector_value ());
+                   retval = convn (a, v1, v2, ct);
+                 }
+               else
+                 {
+                   FloatComplexColumnVector v1 (args(0).float_complex_vector_value ());
+                   FloatComplexRowVector v2 (args(1).float_complex_vector_value ());
+                   retval = convn (a, v1, v2, ct);
+                 }
+             }
+           else
+             {
+               FloatColumnVector v1 (args(0).float_vector_value ());
+               FloatRowVector v2 (args(1).float_vector_value ());
+               FloatMatrix a (args(2).float_matrix_value ());
+               retval = convn (a, v1, v2, ct);
+             }
+         }
+       else
+         {
+           if (args(0).is_complex_type () || args(1).is_complex_type ()
+               || args(2).is_complex_type ())
+             {
+               ComplexMatrix a (args(2).complex_matrix_value ());
+               if (args(1).is_real_type () && args(2).is_real_type ())
+                 {
+                   ColumnVector v1 (args(0).vector_value ());
+                   RowVector v2 (args(1).vector_value ());
+                   retval = convn (a, v1, v2, ct);
+                 }
+               else
+                 {
+                   ComplexColumnVector v1 (args(0).complex_vector_value ());
+                   ComplexRowVector v2 (args(1).complex_vector_value ());
+                   retval = convn (a, v1, v2, ct);
+                 }
+             }
+           else
+             {
+               ColumnVector v1 (args(0).vector_value ());
+               RowVector v2 (args(1).vector_value ());
+               Matrix a (args(2).matrix_value ());
+               retval = convn (a, v1, v2, ct);
+             }
+         }
+     } // if (separable)
+   else
+     {
+       if (args(0).is_single_type () || args(1).is_single_type ())
+         {
+           if (args(0).is_complex_type () || args(1).is_complex_type ())
+             {
+               FloatComplexMatrix a (args(0).float_complex_matrix_value ());
+               if (args(1).is_real_type ())
+                 {
+                   FloatMatrix b (args(1).float_matrix_value ());
+                   retval = convn (a, b, ct);
+                 }
+               else
+                 {
+                   FloatComplexMatrix b (args(1).float_complex_matrix_value ());
+                   retval = convn (a, b, ct);
+                 }
+             }
+           else
+             {
+               FloatMatrix a (args(0).float_matrix_value ());
+               FloatMatrix b (args(1).float_matrix_value ());
+               retval = convn (a, b, ct);
+             }
+         }
+       else
+         {
+           if (args(0).is_complex_type () || args(1).is_complex_type ())
+             {
+               ComplexMatrix a (args(0).complex_matrix_value ());
+               if (args(1).is_real_type ())
+                 {
+                   Matrix b (args(1).matrix_value ());
+                   retval = convn (a, b, ct);
+                 }
+               else
+                 {
+                   ComplexMatrix b (args(1).complex_matrix_value ());
+                   retval = convn (a, b, ct);
+                 }
+             }
+           else
+             {
+               Matrix a (args(0).matrix_value ());
+               Matrix b (args(1).matrix_value ());
+               retval = convn (a, b, ct);
+             }
+         }
+
+     } // if (separable)
+
+   return retval;
+}
+
+/*
+%!test
+%! c = [0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18];
+%! assert (conv2 ([0,1;1,2], [1,2,3;4,5,6;7,8,9]), c);
+
+%!test
+%! c = single ([0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18]);
+%! assert (conv2 (single ([0,1;1,2]), single ([1,2,3;4,5,6;7,8,9])), c);
+
+%!test
+%! c = [1,4,4;5,18,16;14,48,40;19,62,48;15,48,36];
+%! assert (conv2 (1:3, 1:2, [1,2;3,4;5,6]), c);
+
+%!assert (conv2 (1:3, 1:2, [1,2;3,4;5,6], "full"),
+%!        conv2 (1:3, 1:2, [1,2;3,4;5,6]));
+
+%% Test shapes
+%!shared A, B, C
+%! A = rand (3, 4);
+%! B = rand (4);
+%! C = conv2 (A, B);
+%!assert (conv2 (A,B, "full"), C)
+%!assert (conv2 (A,B, "same"), C(3:5,3:6))
+%!assert (conv2 (A,B, "valid"), zeros (0, 1))
+%!assert (size (conv2 (B,A, "valid")), [2 1])
+
+%!test
+%! B = rand (5);
+%! C = conv2 (A, B);
+%!assert (conv2 (A,B, "full"), C)
+%!assert (conv2 (A,B, "same"), C(3:5,3:6))
+%!assert (conv2 (A,B, "valid"), zeros (0, 0))
+%!assert (size (conv2 (B,A, "valid")), [3 2])
+
+%% Clear shared variables so they are not reported for tests below
+%!shared
+
+%% Test cases from Bug #34893
+%!assert (conv2 ([1:5;1:5], [1:2], "same"), [4 7 10 13 10; 4 7 10 13 10])
+%!assert (conv2 ([1:5;1:5]', [1:2]', "same"), [4 7 10 13 10; 4 7 10 13 10]')
+%!assert (conv2 ([1:5;1:5], [1:2], "valid"), [4 7 10 13; 4 7 10 13])
+%!assert (conv2 ([1:5;1:5]', [1:2]', "valid"), [4 7 10 13; 4 7 10 13]')
+
+%!test
+%! rand ("seed", 42);
+%! x = rand (100);
+%! y = ones (5);
+%! A = conv2 (x, y)(5:end-4,5:end-4);
+%! B = conv2 (x, y, "valid");
+%! assert (B, A); ## Yes, this test is for *exact* equivalence.
+
+
+%% Test input validation
+%!error conv2 ()
+%!error conv2 (1)
+%!error <SHAPE type not valid> conv2 (1,2, "NOT_A_SHAPE")
+%% Test alternate calling form which should be 2 vectors and a matrix
+%!error conv2 (ones (2), 1, 1)
+%!error conv2 (1, ones (2), 1)
+*/
+
+DEFUN (convn, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn  {Built-in Function} {@var{C} =} convn (@var{A}, @var{B})\n\
+@deftypefnx {Built-in Function} {@var{C} =} convn (@var{A}, @var{B}, @var{shape})\n\
+Return the n-D convolution of @var{A} and @var{B}.  The size of the result\n\
+is determined by the optional @var{shape} argument which takes the following\n\
+values\n\
+\n\
+@table @asis\n\
+@item @var{shape} = \"full\"\n\
+Return the full convolution.  (default)\n\
+\n\
+@item @var{shape} = \"same\"\n\
+Return central part of the convolution with the same size as @var{A}.\n\
+The central part of the convolution begins at the indices\n\
+@code{floor ([size(@var{B})/2] + 1)}.\n\
+\n\
+@item @var{shape} = \"valid\"\n\
+Return only the parts which do not include zero-padded edges.\n\
+The size of the result is @code{max (size (A) - size (B) + 1, 0)}.\n\
+@end table\n\
+\n\
+@seealso{conv2, conv}\n\
+@end deftypefn")
+{
+  octave_value retval;
+  octave_value tmp;
+  int nargin = args.length ();
+  std::string shape = "full";   // default
+  convn_type ct;
+
+  if (nargin < 2 || nargin > 3)
+    {
+     print_usage ();
+     return retval;
+    }
+  else if (nargin == 3)
+    {
+      if (args(2).is_string ())
+        shape = args(2).string_value ();
+    }
+
+  if (shape == "full")
+    ct = convn_full;
+  else if (shape == "same")
+    ct = convn_same;
+  else if (shape == "valid")
+    ct = convn_valid;
+  else
+    {
+      error ("convn: SHAPE type not valid");
+      print_usage ();
+      return retval;
+    }
+
+  if (args(0).is_single_type () || args(1).is_single_type ())
+    {
+      if (args(0).is_complex_type () || args(1).is_complex_type ())
+        {
+          FloatComplexNDArray a (args(0).float_complex_array_value ());
+          if (args(1).is_real_type ())
+            {
+              FloatNDArray b (args(1).float_array_value ());
+              retval = convn (a, b, ct);
+            }
+          else
+            {
+              FloatComplexNDArray b (args(1).float_complex_array_value ());
+              retval = convn (a, b, ct);
+            }
+        }
+      else
+        {
+          FloatNDArray a (args(0).float_array_value ());
+          FloatNDArray b (args(1).float_array_value ());
+          retval = convn (a, b, ct);
+        }
+    }
+  else
+    {
+      if (args(0).is_complex_type () || args(1).is_complex_type ())
+        {
+          ComplexNDArray a (args(0).complex_array_value ());
+          if (args(1).is_real_type ())
+            {
+              NDArray b (args(1).array_value ());
+              retval = convn (a, b, ct);
+            }
+          else
+            {
+              ComplexNDArray b (args(1).complex_array_value ());
+              retval = convn (a, b, ct);
+            }
+        }
+      else
+        {
+          NDArray a (args(0).array_value ());
+          NDArray b (args(1).array_value ());
+          retval = convn (a, b, ct);
+        }
+    }
+
+   return retval;
+}
+
+/*
+ FIXME: Need tests for convn in addition to conv2.
+*/