1## Copyright (C) 2013 Carnë Draug <carandraug@octave.org>
2##
3## This program is free software; you can redistribute it and/or modify it under
4## the terms of the GNU General Public License as published by the Free Software
5## Foundation; either version 3 of the License, or (at your option) any later
6## version.
7##
8## This program is distributed in the hope that it will be useful, but WITHOUT
9## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11## details.
12##
13## You should have received a copy of the GNU General Public License along with
14## this program; if not, see <http://www.gnu.org/licenses/>.
15
16## -*- texinfo -*-
17## @deftypefn  {Function File} {} padarray (@var{A}, @var{padsize})
18## @deftypefnx {Function File} {} padarray (@dots{}, @var{padval})
19## @deftypefnx {Function File} {} padarray (@dots{}, @var{pattern})
20## @deftypefnx {Function File} {} padarray (@dots{}, @var{direction})
21## Pad array or matrix.
22##
23## Adds padding of length @var{padsize}, to a numeric matrix @var{A}.
24## @var{padsize} must be a vector of non-negative values, each of them
25## defining the length of padding to its corresponding dimension.  For
26## example, if @var{padsize} is [4 5], it adds 4 rows (1st dimension)
27## and 5 columns (2nd dimension), to both the start and end of @var{A}.
28##
29## If there's less values in @var{padsize} than number of dimensions in @var{A},
30## they're assumed to be zero.  Singleton dimensions of @var{A} are also
31## padded accordingly (except when @var{pattern} is @qcode{"reflect"}).
32##
33## The values used in the padding can either be a scalar value @var{padval}, or
34## the name of a specific @var{pattern}.  Available patterns are:
35##
36## @table @asis
37## @item @qcode{"zeros"} (default)
38## Pads with the value 0 (same as passing a @var{padval} of 0).  This is the
39## default.
40##
41## @item @qcode{"circular"}
42## Pads with a circular repetition of elements in @var{A} (similar to
43## tiling @var{A}).
44##
45## @item @qcode{"replicate"}
46## Pads replicating the values at the border of @var{A}.
47##
48## @item @qcode{"symmetric"}
49## Pads with a mirror reflection of @var{A}.
50##
51## @item @qcode{"reflect"}
52## Same as "symmetric", but the borders are not used in the padding.  Because
53## of this, it is not possible to pad singleton dimensions.
54##
55## @end table
56##
57## By default, padding is done in both directions.  To change this,
58## @var{direction} can be one of the following values:
59##
60## @table @asis
61## @item @qcode{"both"} (default)
62## Pad each dimension before the first element of @var{A} the number
63## of elements defined by @var{padsize}, and the same number again after
64## the last element. This is the default.
65##
66## @item @qcode{"pre"}
67## Pad each dimension before the first element of @var{A} the number of
68## elements defined by @var{padsize}.
69##
70## @item @qcode{"post"}
71## Pad each dimension after the last element of @var{A} the number of
72## elements defined by @var{padsize}.
73##
74## @end table
75##
76## @seealso{cat, flip, resize, prepad, postpad}
77## @end deftypefn
78
79function B = padarray(A, padsize, varargin)
80
81  if (nargin < 2 || nargin > 4)
82    print_usage ();
83  elseif (! isvector (padsize) || ! isnumeric (padsize) || any (padsize < 0) ||
84          any (padsize != fix (padsize)))
85    error ("padarray: PADSIZE must be a vector of non-negative integers");
86  endif
87
88  ## Assure padsize is a row vector
89  padsize = padsize(:).';
90
91  if (! any (padsize))
92    ## Nothing to do here
93    B = A;
94    return
95  endif
96
97  ## Default values
98  padval    = 0;
99  pattern   = "";
100  direction = "both";
101
102  ## There won't be more than 2 elements in varargin
103  ## We have to support setting the padval (shape) and direction in any
104  ## order. Both examples must work:
105  ##  padarray (A, padsize, "circular", "pre")
106  ##  padarray (A, padsize, "pre", "circular")
107  for opt = 1:numel(varargin)
108    val = varargin{opt};
109    if (ischar (val))
110      if (any (strcmpi (val, {"pre", "post", "both"})))
111        direction = val;
112      elseif (any (strcmpi (val, {"circular", "replicate", "reflect", "symmetric"})))
113        pattern = val;
114      elseif (strcmpi (val, "zeros"))
115        padval = 0;
116      else
117        error ("padarray: unrecognized string option `%s'", val);
118      endif
119    elseif (isscalar (val))
120      padval = val;
121    else
122      error ("padarray: PADVAL and DIRECTION must be a string or a scalar");
123    endif
124  endfor
125
126  fancy_pad = false;
127  if (! isempty (pattern))
128    fancy_pad = true;
129  endif
130
131  ## Check direction
132  pre  = any (strcmpi (direction, {"pre", "both"}));
133  post = any (strcmpi (direction, {"post", "both"}));
134
135  ## Create output matrix
136  B_ndims = max ([numel(padsize) ndims(A)]);
137  A_size  = size (A);
138  P_size  = padsize;
139  A_size(end+1:B_ndims) = 1;  # add singleton dimensions
140  P_size(end+1:B_ndims) = 0;  # assume zero for missing dimensions
141
142  pre_pad_size = P_size * pre;
143  B_size = A_size + pre_pad_size + (P_size * post);
144
145  ## insert input matrix into output matrix
146  A_idx = cell (B_ndims, 1);
147  for dim = 1:B_ndims
148    A_idx{dim} = (pre_pad_size(dim) +1):(pre_pad_size(dim) + A_size(dim));
149  endfor
150  if (post && ! pre && (padval == 0 || fancy_pad))
151    ## optimization for post padding only with zeros
152    B = resize (A, B_size);
153  else
154    B = repmat (cast (padval, class (A)), B_size);
155    B(A_idx{:}) = A;
156  endif
157
158  if (fancy_pad)
159    ## Init a template "index all" cell array
160    template_idx = repmat ({":"}, [B_ndims 1]);
161
162    circular = replicate = symmetric = reflect = false;
163    switch (tolower (pattern))
164      case "circular",  circular  = true;
165      case "replicate", replicate = true;
166      case "symmetric", symmetric = true;
167      case "reflect",   reflect   = true;
168      otherwise
169        error ("padarray: unknown PADVAL `%s'.", pattern);
170    endswitch
171
172    ## For a dimension of the input matrix of size 1, since reflect does
173    ## not includes the borders, it is not possible to pad singleton dimensions.
174    if (reflect && any ((! (A_size -1)) & P_size))
175      error ("padarray: can't add %s padding to singleton dimensions", pattern);
176    endif
177
178    ## For symmetric and reflect:
179    ##
180    ## The idea is to split the padding into 3 different cases:
181    ##    bits
182    ##        Parts of the input matrix that are used for the padding.
183    ##        In most user cases, there will be only this padding,
184    ##        complete will be zero, and so bits will be equal to padsize.
185    ##    complete
186    ##        Number of full copies of the input matrix are used for
187    ##        the padding (for reflect, "full" size is actually minus 1).
188    ##        This is divided into pair and unpaired complete. In most
189    ##        cases, this will be zero.
190    ##    pair complete
191    ##        Number of pairs of complete copies.
192    ##    unpaired complete
193    ##        This is either 1 or 0. If 1, then the complete copy closer
194    ##        to the output borders has already been flipped so that if
195    ##        there's bits used to pad as well, they don't need to be flipped.
196    ##
197    ## Reasoning pair and unpaired complete: when the pad is much larger
198    ## than the input matrix, we must pay we must pay special attention to
199    ## symmetric and reflect. In a normal case (the padding is smaller than
200    ## the input), we just use the flipped matrix to pad and we're done.
201    ## In other cases, if the input matrix is used multiple times on the
202    ## pad, every other copy of it must NOT be flipped (the padding must be
203    ## symmetric itself) or the padding will be circular.
204
205    if (reflect)
206      A_cut_size          = A_size -1;
207      complete            = floor (P_size ./ A_cut_size);
208      bits                = rem (P_size, A_cut_size);
209      pair_size           = A_cut_size * 2;
210      pair_complete       = floor (complete / 2);
211      unpaired_complete   = mod (complete, 2);
212    else
213      complete            = floor (P_size ./ A_size);
214      bits                = rem (P_size, A_size);
215      if (circular)
216        complete_size     = complete .* A_size;
217      elseif (symmetric)
218        pair_complete     = floor (complete / 2);
219        pair_size         = A_size * 2;
220        unpaired_complete = mod (complete, 2);
221      endif
222    endif
223
224    dim = 0;
225    for s = padsize
226      dim++;
227      if (s == 0)
228        ## skip this dimension if no padding requested
229        continue
230      endif
231
232      if (circular)
233        dim_idx     = template_idx;
234        source_idx  = template_idx;
235        A_idx_end   = A_idx{dim}(end);
236        A_idx_ini   = A_idx{dim}(1);
237
238        if (complete(dim))
239          dim_pad_size(1:B_ndims) = 1;
240          dim_pad_size(dim)       = complete(dim)*pre + complete(dim)*post;
241          dim_idx{dim}            = [];
242          if (pre)
243            dim_idx{dim}  = [(bits(dim) +1):(complete_size(dim) + bits(dim))];
244          endif
245          if (post)
246            dim_idx{dim}  = [dim_idx{dim} (A_idx_end +1):(A_idx_end + complete_size(dim))];
247          endif
248          source_idx{dim} = A_idx{dim};
249          B(dim_idx{:})   = repmat (B(source_idx{:}), dim_pad_size);
250        endif
251
252        if (pre)
253          if (bits(dim))
254            dim_idx{dim}    = 1:bits(dim);
255            source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end;
256            B(dim_idx{:})   = B(source_idx{:});
257          endif
258        endif
259        if (post)
260          if (bits(dim))
261            dim_idx{dim}    = (B_size(dim) -bits(dim) +1):B_size(dim);
262            source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1);
263            B(dim_idx{:})   = B(source_idx{:});
264          endif
265        endif
266
267      elseif (replicate)
268        dim_pad_size(1:B_ndims) = 1;
269        dim_pad_size(dim)       = P_size(dim);
270        dim_idx                 = template_idx;
271        source_idx              = template_idx;
272        if (pre)
273          dim_idx{dim}          = 1:P_size(dim);
274          source_idx{dim}       = P_size(dim) +1;
275          B(dim_idx{:})         = repmat (B(source_idx{:}), dim_pad_size);
276        endif
277        if (post)
278          dim_idx{dim}          = (A_idx{dim}(end) +1):B_size(dim);
279          source_idx{dim}       = A_idx{dim}(end);
280          B(dim_idx{:})         = repmat (B(source_idx{:}), dim_pad_size);
281        endif
282
283      ## The idea behind symmetric and reflect passing is the same so the
284      ## following cases have similar looking code. However, there's small
285      ## adjustements everywhere that makes it really hard to merge as a
286      ## common case.
287      elseif (symmetric)
288        dim_idx     = template_idx;
289        source_idx  = template_idx;
290        A_idx_ini   = A_idx{dim}(1);
291        A_idx_end   = A_idx{dim}(end);
292
293        if (pre)
294          if (bits(dim))
295            dim_idx{dim}      = 1:bits(dim);
296            if (unpaired_complete(dim))
297              source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end;
298              B(dim_idx{:})   = B(source_idx{:});
299            else
300              source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1);
301              B(dim_idx{:})   = flip (B(source_idx{:}), dim);
302            endif
303          endif
304        endif
305        if (post)
306          if (bits(dim))
307            dim_idx{dim}      = (B_size(dim) - bits(dim) +1):B_size(dim);
308            if (unpaired_complete(dim))
309              source_idx{dim} = A_idx_ini:(A_idx_ini + bits(dim) -1);
310              B(dim_idx{:})   = B(source_idx{:});
311            else
312              source_idx{dim} = (A_idx_end - bits(dim) +1):A_idx_end;
313              B(dim_idx{:})   = flip (B(source_idx{:}), dim);
314            endif
315          endif
316        endif
317
318        if (complete(dim))
319          dim_pad_size(1:B_ndims) = 1;
320          source_idx{dim}         = A_idx{dim};
321          flipped_source          = flip (B(source_idx{:}), dim);
322        endif
323
324        if (pair_complete(dim))
325          dim_pad_size(dim) = pair_complete(dim);
326          dim_idx{dim}      = [];
327          if (pre)
328            dim_idx{dim}    = [(1 + bits(dim) + (A_size(dim)*unpaired_complete(dim))):(A_idx_ini -1)];
329            B(dim_idx{:})   = repmat (cat (dim, B(source_idx{:}), flipped_source), dim_pad_size);
330          endif
331          if (post)
332            dim_idx{dim}    = [(A_idx_end +1):(A_idx_end + (pair_size(dim) * pair_complete(dim)))];
333            B(dim_idx{:})   = repmat (cat (dim, flipped_source, B(source_idx{:})), dim_pad_size);
334          endif
335        endif
336
337        if (unpaired_complete(dim))
338          source_idx = template_idx;
339          if (pre)
340            dim_idx{dim}  = (1 + bits(dim)):(bits(dim) + A_size(dim));
341            B(dim_idx{:}) = flipped_source(source_idx{:});
342          endif
343          if (post)
344            dim_idx{dim}  = (B_size(dim) - bits(dim) - A_size(dim) +1):(B_size(dim) - bits(dim));
345            B(dim_idx{:}) = flipped_source(source_idx{:});
346          endif
347        endif
348
349      elseif (reflect)
350        dim_idx     = template_idx;
351        source_idx  = template_idx;
352        A_idx_ini   = A_idx{dim}(1);
353        A_idx_end   = A_idx{dim}(end);
354
355        if (pre)
356          if (bits(dim))
357            dim_idx{dim}      = 1:bits(dim);
358            if (unpaired_complete(dim))
359              source_idx{dim} = (A_idx_end - bits(dim)):(A_idx_end -1);
360              B(dim_idx{:})   = B(source_idx{:});
361            else
362              source_idx{dim} = (A_idx_ini +1):(A_idx_ini + bits(dim));
363              B(dim_idx{:})   = flip (B(source_idx{:}), dim);
364            endif
365          endif
366        endif
367        if (post)
368          if (bits(dim))
369            dim_idx{dim}      = (B_size(dim) - bits(dim) +1):B_size(dim);
370            if (unpaired_complete(dim))
371              source_idx{dim} = (A_idx_ini +1):(A_idx_ini + bits(dim));
372              B(dim_idx{:})   = B(source_idx{:});
373            else
374              source_idx{dim} = (A_idx_end - bits(dim)):(A_idx_end -1);
375              B(dim_idx{:})   = flip (B(source_idx{:}), dim);
376            endif
377          endif
378        endif
379
380        if (complete(dim))
381          dim_pad_size(1:B_ndims) = 1;
382          source_idx{dim}         = A_idx{dim};
383          flipped_source          = flip (B(source_idx{:}), dim);
384        endif
385
386        if (pair_complete(dim))
387          dim_pad_size(dim) = pair_complete(dim);
388          dim_idx{dim}      = [];
389          if (pre)
390            flipped_source_idx = source_idx;
391            flipped_source_idx{dim} = 1:A_cut_size(dim);
392            source_idx{dim} = A_idx_ini:(A_idx_end -1);
393            dim_idx{dim}    = [(1 + bits(dim) + (A_cut_size(dim)*unpaired_complete(dim))):(A_idx_ini -1)];
394            B(dim_idx{:})   = repmat (cat (dim, B(source_idx{:}), flipped_source(flipped_source_idx{:})), dim_pad_size);
395          endif
396          if (post)
397            flipped_source_idx = source_idx;
398            flipped_source_idx{dim} = 2:A_size(dim);
399            source_idx{dim} = (A_idx_ini +1):A_idx_end;
400            dim_idx{dim}    = [(A_idx_end +1):(A_idx_end + (pair_size(dim) * pair_complete(dim)))];
401            B(dim_idx{:})   = repmat (cat (dim, flipped_source(flipped_source_idx{:}), B(source_idx{:})), dim_pad_size);
402          endif
403        endif
404
405        if (unpaired_complete(dim))
406          source_idx = template_idx;
407          if (pre)
408            source_idx{dim} = 1:(A_size(dim)-1);
409            dim_idx{dim}    = (1 + bits(dim)):(bits(dim) + A_size(dim) -1);
410            B(dim_idx{:})   = flipped_source(source_idx{:});
411          endif
412          if (post)
413            source_idx{dim} = 2:A_size(dim);
414            dim_idx{dim}    = (B_size(dim) - bits(dim) - A_size(dim) +2):(B_size(dim) - bits(dim));
415            B(dim_idx{:})   = flipped_source(source_idx{:});
416          endif
417        endif
418
419      endif
420    endfor
421  endif
422endfunction
423
424%!demo
425%! padarray([1,2,3;4,5,6],[2,1])
426%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 0
427
428%!demo
429%! padarray([1,2,3;4,5,6],[2,1],5)
430%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns of 5
431
432%!demo
433%! padarray([1,2,3;4,5,6],[2,1],0,'pre')
434%! % pads [1,2,3;4,5,6] with a left and top border of 2 rows and 1 columns of 0
435
436%!demo
437%! padarray([1,2,3;4,5,6],[2,1],'circular')
438%! % pads [1,2,3;4,5,6] with a whole 'circular' border of 2 rows and 1 columns
439%! % border 'repeats' data as if we tiled blocks of data
440
441%!demo
442%! padarray([1,2,3;4,5,6],[2,1],'replicate')
443%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which
444%! % 'replicates' edge data
445
446%!demo
447%! padarray([1,2,3;4,5,6],[2,1],'symmetric')
448%! % pads [1,2,3;4,5,6] with a whole border of 2 rows and 1 columns which
449%! % is symmetric to the data on the edge
450
451## Test default padval and direction
452%!assert (padarray ([1;2], [1]), [0;1;2;0]);
453%!assert (padarray ([3 4], [0 2]), [0 0 3 4 0 0]);
454%!assert (padarray ([1 2 3; 4 5 6], [1 2]),
455%!      [zeros(1, 7); 0 0 1 2 3 0 0; 0 0 4 5 6 0 0; zeros(1, 7)]);
456
457## Test padding on 3D array
458%!test
459%! assert (padarray ([1 2 3; 4 5 6], [3 2 1]),
460%!         cat(3, zeros(8, 7),
461%!                [ [             zeros(3, 7)               ]
462%!                  [zeros(2, 2) [1 2 3; 4 5 6] zeros(2, 2) ]
463%!                  [             zeros(3,7)]               ],
464%!                zeros (8, 7)));
465
466## Test if default param are ok
467%!assert (padarray ([1 2], [4 5]), padarray ([1 2], [4 5], 0));
468%!assert (padarray ([1 2], [4 5]), padarray ([1 2], [4 5], "both"));
469
470## Test literal padval
471%!assert (padarray ([1;2], [1], i), [i; 1; 2; i]);
472
473## Test directions (horizontal)
474%!assert (padarray ([1;2], [1], i, "pre"),  [i; 1; 2]);
475%!assert (padarray ([1;2], [1], i, "post"), [1; 2; i]);
476%!assert (padarray ([1;2], [1], i, "both"), [i; 1; 2; i]);
477
478## Test directions (vertical)
479%!assert (padarray ([1 2], [0 1], i, "pre"),  [i 1 2]);
480%!assert (padarray ([1 2], [0 1], i, "post"), [1 2 i]);
481%!assert (padarray ([1 2], [0 1], i, "both"), [i 1 2 i]);
482
483## Test vertical padsize
484%!assert (padarray ([1 2], [0;1], i, "both"), [i 1 2 i]);
485
486## Test circular padding
487%!test
488%! A = [1 2 3; 4 5 6];
489%! B = repmat (A, 7, 9);
490%! assert (padarray (A, [1 2], "circular", "pre"),  B(2:4,2:6));
491%! assert (padarray (A, [1 2], "circular", "post"), B(3:5,4:8));
492%! assert (padarray (A, [1 2], "circular", "both"), B(2:5,2:8));
493%! ## This tests when padding is bigger than data
494%! assert (padarray (A, [5 10], "circular", "both"), B(2:13,3:25));
495
496% Test circular padding with int* uint* class types
497%!test
498%! A = int8 ([1 2 3; 4 5 6]);
499%! B = repmat (A, 7, 9);
500%! assert (padarray (A, [1 2], "circular", "pre"),  B(2:4,2:6));
501%! assert (padarray (A, [1 2], "circular", "post"), B(3:5,4:8));
502%! assert (padarray (A, [1 2], "circular", "both"), B(2:5,2:8));
503%! ## This tests when padding is bigger than data
504%! assert (padarray (A, [5 10], "circular", "both"), B(2:13,3:25));
505
506## Test replicate padding
507%!test
508%! A = [1 2; 3 4];
509%! B = kron (A, ones (10, 5));
510%! assert (padarray (A, [9 4], "replicate", "pre"),  B(1:11,1:6));
511%! assert (padarray (A, [9 4], "replicate", "post"), B(10:20,5:10));
512%! assert (padarray (A, [9 4], "replicate", "both"), B);
513%! ## same with uint class
514%! assert (padarray (uint8 (A), [9 4], "replicate", "pre"),  uint8 (B(1:11,1:6)));
515%! assert (padarray (uint8 (A), [9 4], "replicate", "post"), uint8 (B(10:20,5:10)));
516%! assert (padarray (uint8 (A), [9 4], "replicate", "both"), uint8 (B));
517
518## Test symmetric padding
519%!test
520%! A    = [1:3
521%!         4:6];
522%! HA   = [3:-1:1
523%!         6:-1:4];
524%! VA   = [4:6
525%!         1:3];
526%! VHA  = [6:-1:4
527%!         3:-1:1];
528%! B    = [VHA VA VHA
529%!         HA  A  HA
530%!         VHA VA VHA];
531%! assert (padarray (A, [1 2], "symmetric", "pre"),  B(2:4,2:6));
532%! assert (padarray (A, [1 2], "symmetric", "post"), B(3:5,4:8));
533%! assert (padarray (A, [1 2], "symmetric", "both"), B(2:5,2:8));
534%! ## same with int class
535%! assert (padarray (int16 (A), [1 2], "symmetric", "pre"),  int16 (B(2:4,2:6)));
536%! assert (padarray (int16 (A), [1 2], "symmetric", "post"), int16 (B(3:5,4:8)));
537%! assert (padarray (int16 (A), [1 2], "symmetric", "both"), int16 (B(2:5,2:8)));
538
539## Repeat some tests with int* uint* class types
540%!assert (padarray (int8   ([1; 2]), [1]),            int8   ([0; 1; 2; 0]));
541%!assert (padarray (uint8  ([3  4]), [0 2]),          uint8  ([0 0 3 4 0 0]));
542%!assert (padarray (int16  ([1; 2]), [1], 4),         int16  ([4; 1; 2; 4]));
543%!assert (padarray (uint16 ([1; 2]), [1], 0),         uint16 ([0; 1; 2; 0]));
544%!assert (padarray (uint32 ([1; 2]), [1], 6, "post"), uint32 ([1; 2; 6]));
545%!assert (padarray (int32  ([1; 2]), [1], int32 (4), "pre"), int32 ([4; 1; 2]));
546
547## Test symmetric and reflect for multiple lengths of padding (since the way
548## it's done changes based on this). By iterating from 10 on a matrix of size
549## 10, we catch the cases where there's only part of the matrix on the pad, a
550## single copy of the matrix, a single copy with bits of non-flipped matrix, two
551##copies of the matrix (flipped and non-flipped), the two copies with bits.
552%!test
553%! in = [ 7  5  1  3
554%!        5  3  3  4
555%!        7  5  2  3
556%!        6  1  3  8];
557%! padded = [
558%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
559%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
560%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
561%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
562%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2
563%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
564%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
565%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2
566%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
567%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
568%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
569%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
570%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2
571%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
572%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
573%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2
574%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
575%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
576%!  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1  5  7  7  5  1  3  3  1
577%!  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3  3  5  5  3  3  4  4  3
578%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2
579%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
580%!  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3  1  6  6  1  3  8  8  3
581%!  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2  5  7  7  5  2  3  3  2];
582%! for ite = 1:10
583%!  assert (padarray (in, [ite ite], "symmetric"), padded((11-ite):(14+ite),(11-ite):(14+ite)));
584%!  assert (padarray (in, [ite ite], "symmetric", "pre"),  padded((11-ite):14,(11-ite):14));
585%!  assert (padarray (in, [ite ite], "symmetric", "post"), padded(11:(14+ite),11:(14+ite)));
586%! endfor
587
588%!test
589%! in = [ 7  5  4  9
590%!        6  4  5  1
591%!        5  3  3  3
592%!        2  6  7  3];
593%! padded = [
594%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
595%!  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6
596%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
597%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
598%!  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5
599%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
600%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
601%!  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6
602%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
603%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
604%!  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5
605%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
606%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
607%!  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6
608%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
609%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
610%!  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5
611%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
612%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
613%!  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6  7  3  7  6  2  6
614%!  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3  3  3  3  3  5  3
615%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4
616%!  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5  4  9  4  5  7  5
617%!  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4  5  1  5  4  6  4];
618%! for ite = 1:10
619%!  assert (padarray (in, [ite ite], "reflect"), padded((11-ite):(14+ite),(11-ite):(14+ite)));
620%!  assert (padarray (in, [ite ite], "reflect", "pre"),  padded((11-ite):14,(11-ite):14));
621%!  assert (padarray (in, [ite ite], "reflect", "post"), padded(11:(14+ite),11:(14+ite)));
622%! endfor
623