GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
conv2.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1999-2024 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 #include "oct-convn.h"
31 
32 #include "defun.h"
33 #include "error.h"
34 #include "ovl.h"
35 #include "utils.h"
36 
38 
40 
41 DEFUN (conv2, args, ,
42  doc: /* -*- texinfo -*-
43 @deftypefn {} {@var{C} =} conv2 (@var{A}, @var{B})
44 @deftypefnx {} {@var{C} =} conv2 (@var{v1}, @var{v2}, @var{m})
45 @deftypefnx {} {@var{C} =} conv2 (@dots{}, @var{shape})
46 Return the 2-D convolution of @var{A} and @var{B}.
47 
48 The size of the result is determined by the optional @var{shape} argument
49 which takes the following values
50 
51 @table @asis
52 @item @var{shape} = @qcode{"full"}
53 Return the full convolution. (default)
54 
55 @item @var{shape} = @qcode{"same"}
56 Return the central part of the convolution with the same size as @var{A}.
57 The central part of the convolution begins at the indices
58 @code{floor ([size(@var{B})/2] + 1)}.
59 
60 @item @var{shape} = @qcode{"valid"}
61 Return only the parts which do not include zero-padded edges.
62 The size of the result is @code{max (size (A) - size (B) + 1, 0)}.
63 @end table
64 
65 When the third argument is a matrix, return the convolution of the matrix
66 @var{m} by the vector @var{v1} in the column direction and by the vector
67 @var{v2} in the row direction.
68 @seealso{conv, convn}
69 @end deftypefn */)
70 {
71  int nargin = args.length ();
72 
73  if (nargin < 2 || nargin > 4)
74  print_usage ();
75 
76  std::string shape = "full"; // default
77  bool separable = false;
79 
80  if (nargin == 3)
81  {
82  if (args(2).is_string ())
83  shape = args(2).string_value ();
84  else
85  separable = true;
86  }
87  else if (nargin == 4)
88  {
89  separable = true;
90  shape = args(3).string_value ();
91  }
92 
93  if (args(0).ndims () > 2 || args(1).ndims () > 2)
94  error ("conv2: A and B must be 1-D vectors or 2-D matrices");
95 
96  if (shape == "full")
97  ct = convn_full;
98  else if (shape == "same")
99  ct = convn_same;
100  else if (shape == "valid")
101  ct = convn_valid;
102  else
103  error ("conv2: SHAPE type not valid");
104 
105  octave_value retval;
106 
107  if (separable)
108  {
109  // If user requests separable, check first two params are vectors
110  if (! (1 == args(0).rows () || 1 == args(0).columns ())
111  || ! (1 == args(1).rows () || 1 == args(1).columns ()))
112  error ("conv2: arguments must be vectors for separable option");
113 
114  if (args(0).is_single_type () || args(1).is_single_type ()
115  || args(2).is_single_type ())
116  {
117  if (args(0).iscomplex () || args(1).iscomplex ()
118  || args(2).iscomplex ())
119  {
120  FloatComplexMatrix a (args(2).float_complex_matrix_value ());
121  if (args(1).isreal () && args(2).isreal ())
122  {
123  FloatColumnVector v1 (args(0).float_vector_value ());
124  FloatRowVector v2 (args(1).float_vector_value ());
125  retval = convn (a, v1, v2, ct);
126  }
127  else
128  {
129  FloatComplexColumnVector v1 (args(0).float_complex_vector_value ());
130  FloatComplexRowVector v2 (args(1).float_complex_vector_value ());
131  retval = convn (a, v1, v2, ct);
132  }
133  }
134  else
135  {
136  FloatColumnVector v1 (args(0).float_vector_value ());
137  FloatRowVector v2 (args(1).float_vector_value ());
138  FloatMatrix a (args(2).float_matrix_value ());
139  retval = convn (a, v1, v2, ct);
140  }
141  }
142  else
143  {
144  if (args(0).iscomplex () || args(1).iscomplex ()
145  || args(2).iscomplex ())
146  {
147  ComplexMatrix a (args(2).complex_matrix_value ());
148  if (args(1).isreal () && args(2).isreal ())
149  {
150  ColumnVector v1 (args(0).vector_value ());
151  RowVector v2 (args(1).vector_value ());
152  retval = convn (a, v1, v2, ct);
153  }
154  else
155  {
156  ComplexColumnVector v1 (args(0).complex_vector_value ());
157  ComplexRowVector v2 (args(1).complex_vector_value ());
158  retval = convn (a, v1, v2, ct);
159  }
160  }
161  else
162  {
163  ColumnVector v1 (args(0).vector_value ());
164  RowVector v2 (args(1).vector_value ());
165  Matrix a (args(2).matrix_value ());
166  retval = convn (a, v1, v2, ct);
167  }
168  }
169  } // if (separable)
170  else
171  {
172  if (args(0).is_single_type () || args(1).is_single_type ())
173  {
174  if (args(0).iscomplex () || args(1).iscomplex ())
175  {
176  FloatComplexMatrix a (args(0).float_complex_matrix_value ());
177  if (args(1).isreal ())
178  {
179  FloatMatrix b (args(1).float_matrix_value ());
180  retval = convn (a, b, ct);
181  }
182  else
183  {
184  FloatComplexMatrix b (args(1).float_complex_matrix_value ());
185  retval = convn (a, b, ct);
186  }
187  }
188  else
189  {
190  FloatMatrix a (args(0).float_matrix_value ());
191  FloatMatrix b (args(1).float_matrix_value ());
192  retval = convn (a, b, ct);
193  }
194  }
195  else
196  {
197  if (args(0).iscomplex () || args(1).iscomplex ())
198  {
199  ComplexMatrix a (args(0).complex_matrix_value ());
200  if (args(1).isreal ())
201  {
202  Matrix b (args(1).matrix_value ());
203  retval = convn (a, b, ct);
204  }
205  else
206  {
207  ComplexMatrix b (args(1).complex_matrix_value ());
208  retval = convn (a, b, ct);
209  }
210  }
211  else
212  {
213  Matrix a (args(0).matrix_value ());
214  Matrix b (args(1).matrix_value ());
215  retval = convn (a, b, ct);
216  }
217  }
218 
219  } // if (separable)
220 
221  return retval;
222 }
223 
224 /*
225 %!test
226 %! c = [0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18];
227 %! assert (conv2 ([0,1;1,2], [1,2,3;4,5,6;7,8,9]), c);
228 
229 %!test
230 %! c = single ([0,1,2,3;1,8,12,12;4,20,24,21;7,22,25,18]);
231 %! assert (conv2 (single ([0,1;1,2]), single ([1,2,3;4,5,6;7,8,9])), c);
232 
233 %!test
234 %! c = [1,4,4;5,18,16;14,48,40;19,62,48;15,48,36];
235 %! assert (conv2 (1:3, 1:2, [1,2;3,4;5,6]), c);
236 
237 %!assert (conv2 (1:3, 1:2, [1,2;3,4;5,6], "full"),
238 %! conv2 (1:3, 1:2, [1,2;3,4;5,6]));
239 
240 ## Test shapes
241 %!shared A, B, C
242 %! old_state = rand ("state");
243 %! restore_state = onCleanup (@() rand ("state", old_state));
244 %! rand ("state", 12345); # initialize generator to make behavior reproducible
245 %! A = rand (3, 4);
246 %! B = rand (4);
247 %! C = conv2 (A, B);
248 %!assert (conv2 (A,B, "full"), C)
249 %!assert (conv2 (A,B, "same"), C(3:5,3:6))
250 %!assert (conv2 (A,B, "valid"), zeros (0, 1))
251 %!assert (size (conv2 (B,A, "valid")), [2 1])
252 
253 %!test
254 %!shared A, B, C
255 %! old_state = rand ("state");
256 %! restore_state = onCleanup (@() rand ("state", old_state));
257 %! rand ("state", 12345); # initialize generator to make behavior reproducible
258 %! A = rand (3, 4);
259 %! B = rand (5);
260 %! C = conv2 (A, B);
261 %!assert (conv2 (A,B, "full"), C)
262 %!assert (conv2 (A,B, "same"), C(3:5,3:6))
263 %!assert (conv2 (A,B, "valid"), zeros (0, 0))
264 %!assert (size (conv2 (B,A, "valid")), [3 2])
265 
266 ## Clear shared variables so they are not reported for tests below
267 %!shared
268 
269 ## Test cases from Bug #34893
270 %!assert <*34893> (conv2 ([1:5;1:5], [1:2], "same"),
271 %! [4 7 10 13 10; 4 7 10 13 10])
272 %!assert <*34893> (conv2 ([1:5;1:5]', [1:2]', "same"),
273 %! [4 7 10 13 10; 4 7 10 13 10]')
274 %!assert <*34893> (conv2 ([1:5;1:5], [1:2], "valid"),
275 %! [4 7 10 13; 4 7 10 13])
276 %!assert <*34893> (conv2 ([1:5;1:5]', [1:2]', "valid"),
277 %! [4 7 10 13; 4 7 10 13]')
278 
279 %% Restore the rand "seed" and "state" values in order, so that the
280 %% new "state" algorithm remains active after these tests complete.
281 %!function restore_rand_state (seed, state)
282 %! rand ("seed", seed);
283 %! rand ("state", state);
284 %!endfunction
285 
286 %% FIXME: This test only passes when using the "old" random number
287 %% generator by setting the "seed" parameter to any value. If
288 %% the "state" parameter is used, the test fails. This probably
289 %% indicates that this test is particularly fragile. This might
290 %% need further investigation or a rewrite, for example using
291 %% random integer values to avoid precision overflow.
292 %!test
293 %! old_seed = rand ("seed");
294 %! old_state = rand ("state");
295 %! restore_state = onCleanup (@() restore_rand_state (old_seed, old_state));
296 %! rand ("seed", 42);
297 %! x = rand (100);
298 %! y = ones (5);
299 %! A = conv2 (x, y)(5:end-4,5:end-4);
300 %! B = conv2 (x, y, "valid");
301 %! assert (B, A); # Yes, this test is for *exact* equivalence.
302 
303 ## Test input validation
304 %!error conv2 ()
305 %!error conv2 (1)
306 %!error <must be 1-D vectors or 2-D matrices> conv2 (ones (2), ones (2,2,2))
307 %!error <SHAPE type not valid> conv2 (1,2, "NOT_A_SHAPE")
308 ## Test alternate calling form which should be 2 vectors and a matrix
309 %!error conv2 (ones (2), 1, 1)
310 %!error conv2 (1, ones (2), 1)
311 */
312 
313 DEFUN (convn, args, ,
314  doc: /* -*- texinfo -*-
315 @deftypefn {} {@var{C} =} convn (@var{A}, @var{B})
316 @deftypefnx {} {@var{C} =} convn (@var{A}, @var{B}, @var{shape})
317 Return the n-D convolution of @var{A} and @var{B}.
318 
319 The size of the result is determined by the optional @var{shape} argument
320 which takes the following values
321 
322 @table @asis
323 @item @var{shape} = @qcode{"full"}
324 Return the full convolution. (default)
325 
326 @item @var{shape} = @qcode{"same"}
327 Return central part of the convolution with the same size as @var{A}.
328 The central part of the convolution begins at the indices
329 @code{floor ([size(@var{B})/2] + 1)}.
330 
331 @item @var{shape} = @qcode{"valid"}
332 Return only the parts which do not include zero-padded edges.
333 The size of the result is @code{max (size (A) - size (B) + 1, 0)}.
334 @end table
335 
336 @seealso{conv2, conv}
337 @end deftypefn */)
338 {
339  int nargin = args.length ();
340 
341  if (nargin < 2 || nargin > 3)
342  print_usage ();
343 
344  std::string shape = "full"; // default
345  convn_type ct = convn_full;
346 
347  if (nargin == 3)
348  shape = args(2).xstring_value ("convn: SHAPE must be a string");
349 
350  if (shape == "full")
351  ct = convn_full;
352  else if (shape == "same")
353  ct = convn_same;
354  else if (shape == "valid")
355  ct = convn_valid;
356  else
357  error ("convn: SHAPE type not valid");
358 
359  octave_value retval;
360 
361  if (args(0).is_single_type () || args(1).is_single_type ())
362  {
363  if (args(0).iscomplex () || args(1).iscomplex ())
364  {
365  FloatComplexNDArray a (args(0).float_complex_array_value ());
366  if (args(1).isreal ())
367  {
368  FloatNDArray b (args(1).float_array_value ());
369  retval = convn (a, b, ct);
370  }
371  else
372  {
373  FloatComplexNDArray b (args(1).float_complex_array_value ());
374  retval = convn (a, b, ct);
375  }
376  }
377  else
378  {
379  FloatNDArray a (args(0).float_array_value ());
380  FloatNDArray b (args(1).float_array_value ());
381  retval = convn (a, b, ct);
382  }
383  }
384  else
385  {
386  if (args(0).iscomplex () || args(1).iscomplex ())
387  {
388  ComplexNDArray a (args(0).complex_array_value ());
389  if (args(1).isreal ())
390  {
391  NDArray b (args(1).array_value ());
392  retval = convn (a, b, ct);
393  }
394  else
395  {
396  ComplexNDArray b (args(1).complex_array_value ());
397  retval = convn (a, b, ct);
398  }
399  }
400  else
401  {
402  NDArray a (args(0).array_value ());
403  NDArray b (args(1).array_value ());
404  retval = convn (a, b, ct);
405  }
406  }
407 
408  return retval;
409 }
410 
411 /*
412 %!test <39314>
413 %! v = reshape ([1 2], [1 1 2]);
414 %! assert (convn (v, v), reshape ([1 4 4], [1 1 3]));
415 %! assert (convn (v, v, "same"), reshape ([4 4], [1 1 2]));
416 %! assert (convn (v, v, "valid"), 4);
417 
418 ## The following test may look weird since we are using the output
419 ## of convn to test itself. However, because calculations are done
420 ## differently based on the shape option, it will help to catch some
421 ## bugs. See also bug #39314.
422 ## FIXME: The "valid" option uses an entirely different code path
423 ## through C++ and Fortran to calculate inner convolution.
424 ## The terms in the convolution added in reverse order compared
425 ## to the "full" option. This produces differences on the order
426 ## of tens of eps. This should be fixed, but in the meantime
427 ## the tests will be marked as known failures.
428 %!shared a, b, c
429 %! ## test 3D by 3D
430 %! old_state = rand ("state");
431 %! restore_state = onCleanup (@() rand ("state", old_state));
432 %! rand ("state", 12345); # initialize generator to make behavior reproducible
433 %! a = rand (10, 10, 10);
434 %! b = rand (3, 3, 3);
435 %! c = convn (a, b, "full");
436 %!assert (convn (a, b, "same"), c(2:11,2:11,2:11))
437 %!test <39314>
438 %! assert (convn (a, b, "valid"), c(3:10,3:10,3:10));
439 %!
440 %!test
441 %! old_state = rand ("state");
442 %! restore_state = onCleanup (@() rand ("state", old_state));
443 %! rand ("state", 12345); # initialize generator to make behavior reproducible
444 %! ## test 3D by 2D
445 %! a = rand (10, 10, 10);
446 %! b = rand (3, 3);
447 %! c = convn (a, b, "full");
448 %!assert (convn (a, b, "same"), c(2:11,2:11,:))
449 %!test <39314>
450 %! assert (convn (a, b, "valid"), c(3:10,3:10,:));
451 %!
452 %!test
453 %! old_state = rand ("state");
454 %! restore_state = onCleanup (@() rand ("state", old_state));
455 %! rand ("state", 12345); # initialize generator to make behavior reproducible
456 %! ## test 2D by 3D
457 %! a = rand (10, 10);
458 %! b = rand (3, 3, 3);
459 %! c = convn (a, b, "full");
460 %!assert (convn (a, b, "same"), c(2:11,2:11,2))
461 %!assert (convn (a, b, "valid"), c(3:10,3:10,3:2)) # a 7x7x0 matrix
462 %!
463 %!test
464 %! old_state = rand ("state");
465 %! restore_state = onCleanup (@() rand ("state", old_state));
466 %! rand ("state", 12345); # initialize generator to make behavior reproducible
467 %! ## test multiple different number of dimensions, with odd and even numbers
468 %! a = rand (10, 15, 7, 8, 10);
469 %! b = rand (4, 3, 2, 3);
470 %! c = convn (a, b, "full");
471 %!assert (convn (a, b, "same"), c(3:12,2:16,2:8,2:9,:))
472 %!test <39314>
473 %! assert (convn (a, b, "valid"), c(4:10,3:15,2:7,3:8,:));
474 
475 %!test
476 %! a = reshape (floor (magic (16) /10), [4 8 4 2]);
477 %! b = reshape (magic (6), [4 3 3]);
478 %! c = zeros (7, 10, 6, 2);
479 %! c(:,:,1,1) = [
480 %! 875 1415 1215 741 288 264 635 1109 687 171
481 %! 110 467 1551 1790 1891 1651 1165 900 659 568
482 %! 883 1047 1475 1964 2181 2302 2117 1674 579 234
483 %! 940 2330 3099 2573 2306 2207 2442 2918 2272 1004
484 %! 161 500 1564 2066 2355 2270 2099 1621 1144 831
485 %! 644 622 886 1121 1652 1967 1907 1668 529 228
486 %! 160 752 1232 768 360 284 668 1132 1380 864];
487 %! c(:,:,2,1) = [
488 %! 150 1174 1903 1971 2030 1719 1467 1420 1220 472
489 %! 986 2243 2603 2385 2308 2530 2971 3181 2266 768
490 %! 914 2443 3750 3782 3976 3821 3723 3709 2599 1178
491 %! 1922 3374 5198 5472 5563 5853 5794 5543 3578 1820
492 %! 1060 2471 3846 3724 3682 3803 3812 3927 2876 1390
493 %! 470 2078 3283 3225 2701 2265 2165 2261 2324 1124
494 %! 700 1130 1486 1515 1830 2097 2081 2028 1009 348];
495 %! c(:,:,3,1) = [
496 %! 1350 2127 2461 2082 1694 1909 2230 2621 1681 683
497 %! 877 2473 4362 4556 4543 4314 3879 3703 2863 1497
498 %! 1934 4219 5874 6117 5966 6051 5984 5714 3891 1562
499 %! 1927 5997 8573 8456 8517 8025 7957 8101 6121 2500
500 %! 1558 3533 5595 6064 6453 6491 6275 5743 3794 1832
501 %! 1950 2762 3455 3423 4019 4578 4807 4857 2304 907
502 %! 525 1860 2731 2392 1872 1724 1961 2312 2315 1141];
503 %! c(:,:,4,1) = [
504 %! 150 1317 2230 2621 2996 2767 2472 2049 1514 583
505 %! 1429 3056 3879 3703 3756 3964 4394 4570 3111 1250
506 %! 1833 4037 5984 5714 5846 5788 5883 6129 4157 2011
507 %! 3143 5469 7957 8101 8063 8475 8564 8439 5306 2538
508 %! 2001 4514 6275 5743 5391 5389 5578 6110 4473 1953
509 %! 817 3196 4807 4857 4229 3659 3477 3375 3208 1400
510 %! 750 1365 1961 2312 2840 2993 2722 2344 1092 323];
511 %! c(:,:,5,1) = [
512 %! 475 734 1296 1352 1400 1595 1557 1517 960 490
513 %! 751 1977 2831 2746 2607 2665 2733 2833 2186 912
514 %! 1065 3142 4344 4150 3768 3734 3876 4086 3366 1327
515 %! 976 3712 5530 5921 6158 5802 5481 5071 3821 1491
516 %! 1397 2996 3971 4003 4088 4180 4199 4146 2649 985
517 %! 1273 2121 2555 2247 2378 2624 2908 3229 1788 705
518 %! 365 1108 1530 1652 1550 1407 1274 1127 889 264];
519 %! c(:,:,6,1) = [
520 %! 0 133 345 683 982 1058 960 623 310 100
521 %! 437 806 1313 1332 1383 1391 1397 1370 864 495
522 %! 928 1573 2201 1928 1864 1932 2183 2445 1557 855
523 %! 1199 2083 2739 2573 2507 2656 2786 2928 1795 736
524 %! 912 1997 2404 2028 1692 1591 1803 2159 1603 599
525 %! 345 1092 1526 1666 1593 1437 1275 1116 863 253
526 %! 50 235 510 811 998 894 615 318 77 0];
527 %! c(:,:,1,2) = [
528 %! 840 1350 1176 697 293 320 674 1153 717 180
529 %! 142 490 1563 1824 1929 1604 1132 857 624 587
530 %! 890 1084 1539 1979 2238 2333 2072 1610 509 202
531 %! 966 2263 3034 2518 2250 2235 2512 2992 2305 1016
532 %! 200 561 1607 2107 2361 2277 2030 1548 1102 818
533 %! 652 631 922 1128 1670 1997 1895 1665 467 197
534 %! 160 744 1192 692 292 256 708 1208 1448 900];
535 %! c(:,:,2,2) = [
536 %! 179 1199 1886 1987 1997 1716 1479 1383 1215 485
537 %! 988 2213 2552 2358 2304 2615 3011 3210 2246 744
538 %! 921 2483 3747 3768 3960 3835 3712 3698 2588 1183
539 %! 1903 3416 5254 5490 5572 5826 5761 5505 3502 1814
540 %! 1064 2507 3825 3666 3680 3748 3821 3958 2892 1395
541 %! 495 2129 3277 3228 2566 2216 2154 2250 2390 1154
542 %! 700 1105 1472 1524 1856 2113 2059 2019 975 325];
543 %! c(:,:,3,2) = [
544 %! 1302 2104 2439 2006 1723 1931 2280 2685 1678 690
545 %! 877 2507 4408 4580 4523 4233 3852 3647 2850 1516
546 %! 1949 4238 5895 6143 6018 6063 5930 5656 3847 1538
547 %! 1953 5975 8547 8433 8407 8060 7955 8069 6170 2506
548 %! 1621 3536 5624 6117 6459 6456 6180 5666 3735 1815
549 %! 1904 2751 3429 3366 4122 4622 4840 4864 2242 882
550 %! 517 1843 2674 2337 1777 1686 2005 2367 2385 1175];
551 %! c(:,:,4,2) = [
552 %! 198 1346 2280 2685 2980 2759 2396 1982 1497 576
553 %! 1413 2994 3852 3647 3756 4035 4418 4595 3109 1231
554 %! 1873 4025 5930 5656 5792 5772 5909 6152 4185 2035
555 %! 3110 5510 7955 8069 8139 8456 8541 8439 5276 2541
556 %! 1964 4462 6180 5666 5315 5409 5631 6178 4536 1998
557 %! 869 3215 4840 4864 4121 3579 3420 3386 3271 1430
558 %! 725 1361 2005 2367 2925 3006 2667 2297 1054 325];
559 %! c(:,:,5,2) = [
560 %! 462 754 1285 1359 1441 1605 1556 1488 938 488
561 %! 729 1967 2788 2732 2608 2683 2744 2830 2195 912
562 %! 1052 3139 4302 4101 3742 3730 3895 4103 3403 1335
563 %! 1007 3725 5577 5964 6165 5754 5407 5006 3846 1507
564 %! 1375 2969 3951 3990 4144 4183 4200 4150 2661 998
565 %! 1258 2090 2495 2188 2403 2664 2954 3279 1814 723
566 %! 388 1127 1551 1673 1525 1390 1253 1139 912 275];
567 %! c(:,:,6,2) = [
568 %! 19 147 384 716 1016 1059 927 570 276 80
569 %! 441 791 1298 1320 1401 1396 1409 1367 865 500
570 %! 932 1537 2155 1870 1860 1946 2221 2487 1584 874
571 %! 1201 2067 2705 2538 2512 2687 2806 2971 1812 756
572 %! 925 1976 2363 1971 1636 1600 1844 2239 1664 626
573 %! 372 1133 1558 1687 1570 1401 1243 1122 883 264
574 %! 60 270 556 857 1024 870 569 282 66 0];
575 %!assert (convn (a, b, "full"), c)
576 %!assert (convn (a, b, "same"), c(3:6,2:9,2:5,:))
577 %!assert (convn (a, b, "valid"), c(4,3:8,3:4,:))
578 
579 ## test correct class
580 %!shared a, b, c, d
581 %! old_state = rand ("state");
582 %! restore_state = onCleanup (@() rand ("state", old_state));
583 %! rand ("state", 12345); # initialize generator to make behavior reproducible
584 %! a = rand (5);
585 %! b = rand (3);
586 %! c = rand (5, "single");
587 %! d = rand (3, "single");
588 %!assert (class (convn (a, b)), "double")
589 %!assert (class (convn (c, b)), "single")
590 %!assert (class (convn (a, d)), "single")
591 %!assert (class (convn (true (5), b)), "double")
592 %!assert (class (convn (true (5), d)), "single")
593 %!assert (class (convn (ones (5, "uint8"), b)), "double")
594 %!assert (class (convn (d, ones (5, "uint8"))), "single")
595 
596 %!error convn ()
597 %!error convn (1)
598 %!error <SHAPE type not valid> convn (1,2, "NOT_A_SHAPE")
599 %!error convn (b, 1, 1)
600 */
601 
602 OCTAVE_END_NAMESPACE(octave)
Definition: dMatrix.h:42
Shape
Definition: conv2.cc:39
@ SHAPE_VALID
Definition: conv2.cc:39
@ SHAPE_SAME
Definition: conv2.cc:39
@ SHAPE_FULL
Definition: conv2.cc:39
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFUN(name, args_name, nargout_name, doc)
Macro to define a builtin function.
Definition: defun.h:56
void() error(const char *fmt,...)
Definition: error.cc:988
NDArray convn(const NDArray &a, const NDArray &b, convn_type ct)
Definition: oct-convn.cc:217
convn_type
Definition: oct-convn.h:52
@ convn_same
Definition: oct-convn.h:54
@ convn_valid
Definition: oct-convn.h:55
@ convn_full
Definition: oct-convn.h:53
const octave_char_matrix & v2