File: histc.m

package info (click to toggle)
octave 3.8.2-4
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 84,396 kB
  • ctags: 45,547
  • sloc: cpp: 293,356; ansic: 42,041; fortran: 23,669; sh: 13,629; objc: 7,890; yacc: 7,093; lex: 3,442; java: 2,125; makefile: 1,589; perl: 1,009; awk: 974; xml: 34
file content (177 lines) | stat: -rw-r--r-- 5,037 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
## Copyright (C) 2009-2013 Søren Hauberg
## Copyright (C) 2009 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/>.

## -*- texinfo -*-
## @deftypefn  {Function File} {@var{n} =} histc (@var{x}, @var{edges})
## @deftypefnx {Function File} {@var{n} =} histc (@var{x}, @var{edges}, @var{dim})
## @deftypefnx {Function File} {[@var{n}, @var{idx}] =} histc (@dots{})
## Produce histogram counts.
##
## When @var{x} is a vector, the function counts the number of elements of
## @var{x} that fall in the histogram bins defined by @var{edges}.  This must be
## a vector of monotonically increasing values that define the edges of the
## histogram bins.  @code{@var{n}(k)} contains the number of elements in
## @var{x} for which @code{@var{edges}(k) <= @var{x} < @var{edges}(k+1)}.
## The final element of @var{n} contains the number of elements of @var{x}
## exactly equal to the last element of @var{edges}.
##
## When @var{x} is an @math{N}-dimensional array, the computation is
## carried out along dimension @var{dim}.  If not specified @var{dim} defaults
## to the first non-singleton dimension.
##
## When a second output argument is requested an index matrix is also returned.
## The @var{idx} matrix has the same size as @var{x}.  Each element of @var{idx}
## contains the index of the histogram bin in which the corresponding element
## of @var{x} was counted.
## @seealso{hist}
## @end deftypefn

function [n, idx] = histc (x, edges, dim)

  if (nargin < 2 || nargin > 3)
    print_usage ();
  endif

  if (!isreal (x))
    error ("histc: X argument must be real-valued, not complex");
  endif

  num_edges = numel (edges);
  if (num_edges == 0)
    error ("histc: EDGES must not be empty");
  endif

  if (!isreal (edges))
    error ("histc: EDGES must be real-valued, not complex");
  else
    ## Make sure 'edges' is sorted
    edges = edges(:);
    if (!issorted (edges) || edges(1) > edges(end))
      warning ("histc: edge values not sorted on input");
      edges = sort (edges);
    endif
  endif

  nd = ndims (x);
  sz = size (x);
  if (nargin < 3)
    ## Find the first non-singleton dimension.
    (dim = find (sz > 1, 1)) || (dim = 1);
  else
    if (!(isscalar (dim) && dim == fix (dim))
        || !(1 <= dim && dim <= nd))
      error ("histc: DIM must be an integer and a valid dimension");
    endif
  endif

  nsz = sz;
  nsz(dim) = num_edges;

  ## the splitting point is 3 bins

  if (num_edges <= 3)

    ## This is the O(M*N) algorithm.

    ## Allocate the histogram
    n = zeros (nsz);

    ## Allocate 'idx'
    if (nargout > 1)
      idx = zeros (sz);
    endif

    ## Prepare indices
    idx1 = cell (1, dim-1);
    for k = 1:length (idx1)
      idx1{k} = 1:sz(k);
    endfor
    idx2 = cell (length (sz) - dim);
    for k = 1:length (idx2)
      idx2{k} = 1:sz(k+dim);
    endfor

    ## Compute the histograms
    for k = 1:num_edges-1
      b = (edges (k) <= x & x < edges (k+1));
      n(idx1{:}, k, idx2{:}) = sum (b, dim);
      if (nargout > 1)
        idx(b) = k;
      endif
    endfor
    b = (x == edges (end));
    n(idx1{:}, num_edges, idx2{:}) = sum (b, dim);
    if (nargout > 1)
      idx(b) = num_edges;
    endif

  else

    ## This is the O(M*log(N) + N) algorithm.

    ## Look-up indices.
    idx = lookup (edges, x);
    ## Zero invalid ones (including NaNs). x < edges(1) are already zero.
    idx(! (x <= edges(end))) = 0;

    iidx = idx;

    ## In case of matrix input, we adjust the indices.
    if (! isvector (x))
      nl = prod (sz(1:dim-1));
      nn = sz(dim);
      nu = prod (sz(dim+1:end));
      if (nl != 1)
        iidx = (iidx-1) * nl;
        iidx += reshape (kron (ones (1, nn*nu), 1:nl), sz);
      endif
      if (nu != 1)
        ne =length (edges);
        iidx += reshape (kron (nl*ne*(0:nu-1), ones (1, nl*nn)), sz);
      endif
    endif

    ## Select valid elements.
    iidx = iidx(idx != 0);

    ## Call accumarray to sum the indexed elements.
    n = accumarray (iidx(:), 1, nsz);

  endif

endfunction


%!test
%! x = linspace (0, 10, 1001);
%! n = histc (x, 0:10);
%! assert (n, [repmat(100, 1, 10), 1]);

%!test
%! x = repmat (linspace (0, 10, 1001), [2, 1, 3]);
%! n = histc (x, 0:10, 2);
%! assert (n, repmat ([repmat(100, 1, 10), 1], [2, 1, 3]));

%!error histc ()
%!error histc (1)
%!error histc (1, 2, 3, 4)
%!error histc ([1:10 1+i], 2)
%!error histc (1:10, [])
%!error histc (1, 1, 3)