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} {@var{blk_size} =} bestblk (@var{IMS})
18## @deftypefnx {Function File} {@var{blk_size} =} bestblk (@var{IMS}, @var{max})
19## @deftypefnx {Function File} {[@var{Mb}, @var{Nb}, @dots{}] =} bestblk (@dots{})
20## Calculate block best size for block processing.
21##
22## Given a matrix of size @var{IMS}, calculates the largest size for distinct
23## blocks @var{blk_size}, that minimize padding and is smaller than or equal to
24## @var{k} (defaults to 100)
25##
26## The output @var{blk_size} is a row vector for the block size.  If there are
27## multiple output arguments, the number of rows is assigned to the first
28## (@var{Mb}), and the number of columns to the second (@var{Nb}), etc.
29##
30## To determine @var{blk_size}, the following is performed for each
31## dimension:
32##
33## @enumerate
34## @item
35## If dimension @var{IMS} is less or equal than @var{k}, it returns the
36## dimension value.
37##
38## @item
39## If not, find the highest value between @code{min (dimension/10, k/2)}
40## which minimizes padding.
41##
42## @end enumerate
43##
44## @seealso{blockproc, col2im, im2col}
45## @end deftypefn
46
47function [varargout] = bestblk (ims, k = 100)
48
49  if (nargin < 1 || nargin > 2)
50    print_usage ();
51  elseif (! isnumeric (ims) || ! isvector (ims) || any (ims(:) < 1))
52    error("bestblk: IMS must be a numeric vector of positive integers.");
53  elseif (numel (ims) < 2)
54    error ("bestblk: IMS must have at least 2 elements");
55  elseif (! isnumeric (k) || ! isscalar (k) || k < 1)
56    error ("bestblk: K must be a positive scalar");
57  endif
58
59  ims = floor (ims(:).');
60  k   = floor (k);
61
62  out = zeros (size (ims));
63  for dim = 1:numel (ims)
64    if (ims(dim) <= k)
65      out(dim) = ims(dim);
66    else
67      possible = k:-1:min (ims(dim) /10, k /2);
68      [~, ind] = min (mod (-ims(dim), possible));
69      out(dim) = possible(ind);
70    endif
71  endfor
72
73  if (nargout <= 1)
74    varargout{1} = out;
75  else
76    varargout = mat2cell (out', ones (1, numel (out)));
77  endif
78
79endfunction
80
81%!demo
82%! siz = bestblk ([200; 10], 50);
83%! disp (siz)
84
85%!error <numeric vector> bestblk ("string")
86%!error <positive scalar> bestblk ([100 200], "string")
87%!error <2 elements> bestblk ([100], 5)
88
89%!assert (bestblk ([ 10  12],   2), [  2   2]);
90%!assert (bestblk ([ 10  12],   3), [  2   3]);
91%!assert (bestblk ([300 100], 150), [150 100]);
92%!assert (bestblk ([256 128],  17), [ 16  16]);
93
94## make sure we really pick the highest one
95%!assert (bestblk ([ 17  17],   3), [  3   3]);
96
97## Test default
98%!assert (bestblk ([230 470]), bestblk ([230 470], 100))
99
100## Test N-dimensional
101%!assert (bestblk ([10 12 10], 3), [2 3 2]);
102%!assert (bestblk ([ 9 12  9], 3), [3 3 3]);
103%!assert (bestblk ([10 12 10 11], 5), [5 4 5 4]);
104