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