GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
perms.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2023-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 <algorithm>
31 
32 #include "defun.h"
33 #include "error.h"
34 #include "errwarn.h"
35 #include "ovl.h"
36 
38 
39 static inline double
40 Factorial (octave_idx_type n)
41 {
42  double ret = 1;
43  for (octave_idx_type i = 2; i <= n; i++)
44  ret *= i;
45  return ret;
46 }
47 
48 //
49 // Use C++ template to cater for the different octave array classes.
50 //
51 template <typename T>
52 static inline Array<T>
53 GetPerms (const Array<T>& ar_in, bool uniq_v, bool do_sort = false)
54 {
55  octave_idx_type m = ar_in.numel ();
56  double nr = Factorial (m);
57 
58  // Setup index vector filled from 0..m-1
59  OCTAVE_LOCAL_BUFFER (int, myvidx, m);
60  for (int i = 0; i < m; i++)
61  myvidx[i] = i;
62 
63  // Interim array to sort ar_in for octave sort order and to implement
64  // "unique".
65  Array<T> ar (ar_in);
66 
67  if (uniq_v)
68  {
69  ar = ar.sort (ar.dims () (1) > ar.dims () (0) ? 1 : 0, ASCENDING);
70  const T *Ar = ar.data ();
71  int ctr = 0;
72  int N_el = 1;
73 
74  // Number of same elements where we need to remove permutations
75  // Number of unique permutations is n! / (n_el1! * n_el2! * ...)
76  for (octave_idx_type i = 0; i < m - 1; i++)
77  {
78  myvidx[i] = ctr;
79  if (Ar[i + 1] != Ar[i])
80  {
81  nr /= Factorial (N_el);
82  ctr = i + 1; // index of next different element
83  N_el = 1;
84  }
85  else
86  N_el++;
87  }
88  myvidx[m - 1] = ctr;
89  nr /= Factorial (N_el);
90  }
91  else if (do_sort)
92  {
93  ar = ar.sort (ar.dims () (1) > ar.dims () (0) ? 1 : 0, ASCENDING);
94  }
95 
96  // Sort vector indices for inverse lexicographic order later.
97  std::sort (myvidx, myvidx + m, std::greater<int> ());
98 
99  const T *Ar = ar.data ();
100 
101  // Set up result array
102  octave_idx_type n = static_cast<octave_idx_type> (nr);
103  Array<T> res (dim_vector (n, m));
104  T *Res = res.fortran_vec ();
105 
106  // Do the actual job
107  octave_idx_type i = 0;
108  std::sort (myvidx, myvidx + m, std::greater<int> ());
109  do
110  {
111  for (octave_idx_type j = 0; j < m; j++)
112  Res[i + j * n] = Ar[myvidx[j]];
113  i++;
114  }
115  while (std::next_permutation (myvidx, myvidx + m, std::greater<int> ()));
116 
117  return res;
118 }
119 
120 // Template for non-numerical types (e.g. Cell) without sorting.
121 // The C++ compiler complains as the provided type octave_value does not
122 // support the test of equality via '==' in the above template.
123 
124 template <typename T>
125 static inline Array<T>
126 GetPermsNoSort (const Array<T>& ar_in, bool uniq_v = false)
127 {
128  octave_idx_type m = ar_in.numel ();
129  double nr = Factorial (m);
130 
131  // Setup index vector filled from 0..m-1
132  OCTAVE_LOCAL_BUFFER (int, myvidx, m);
133  for (int i = 0; i < m; i++)
134  myvidx[i] = i;
135 
136  const T *Ar = ar_in.data ();
137 
138  if (uniq_v)
139  {
140  // Mutual Comparison using is_equal to detect duplicated values
141  int N_el = 1;
142  // Number of unique permutations is n! / (n_el1! * n_el2! * ...)
143  for (octave_idx_type i = 0; i < m - 1; i++)
144  {
145  for (octave_idx_type j = i + 1; j < m; j++)
146  {
147  if (myvidx[j] > myvidx[i] && Ar[i].is_equal (Ar[j]))
148  {
149  myvidx[j] = myvidx[i]; // not yet processed...
150  N_el++;
151  }
152  else
153  {
154  nr /= Factorial (N_el);
155  N_el = 1;
156  }
157  }
158  }
159  nr /= Factorial (N_el);
160  }
161 
162  // Sort vector indices for inverse lexicographic order later.
163  std::sort (myvidx, myvidx + m, std::greater<int> ());
164 
165  // Set up result array
166  octave_idx_type n = static_cast<octave_idx_type> (nr);
167  Array<T> res (dim_vector (n, m));
168  T *Res = res.fortran_vec ();
169 
170  // Do the actual job
171  octave_idx_type i = 0;
172  do
173  {
174  for (octave_idx_type j = 0; j < m; j++)
175  Res[i + j * n] = Ar[myvidx[j]];
176  i++;
177  }
178  while (std::next_permutation (myvidx, myvidx + m, std::greater<int> ()));
179 
180  return res;
181 }
182 
183 DEFUN (perms, args, ,
184  doc: /* -*- texinfo -*-
185 @deftypefn {} {@var{P} =} perms (@var{v})
186 @deftypefnx {} {@var{P} =} perms (@var{v}, "unique")
187 Generate all permutations of vector @var{v} with one row per permutation.
188 
189 Results are returned in reverse lexicographic order if @var{v} is in ascending
190 order. If @var{v} is in a different permutation, then the result is permuted
191 that way too. Consequently, an input in descending order yields a result in
192 normal lexicographic order. The result has size
193 @code{factorial (@var{n}) * @var{n}}, where @var{n} is the length of @var{v}.
194 Any repeated elements are included in the output.
195 
196 If the optional argument @qcode{"unique"} is given then only unique
197 permutations are returned, using less memory and taking less time than calling
198 @code{unique (perms (@var{v}), "rows")}.
199 
200 Example 1
201 
202 @example
203 @group
204 perms ([1, 2, 3])
205 @result{}
206 3 2 1
207 3 1 2
208 2 3 1
209 2 1 3
210 1 3 2
211 1 2 3
212 @end group
213 @end example
214 
215 Example 2
216 
217 @example
218 @group
219 perms ([1, 1, 2, 2], "unique")
220 @result{}
221 2 2 1 1
222 2 1 2 1
223 2 1 1 2
224 1 2 2 1
225 1 2 1 2
226 1 1 2 2
227 @end group
228 @end example
229 
230 Programming Note: If the @qcode{"unique"} option is not used, the length of
231 @var{v} should be no more than 10-12 to limit memory consumption. Even with
232 @qcode{"unique"}, there should be no more than 10-12 unique elements in
233 @var{v}.
234 @seealso{permute, randperm, nchoosek}
235 
236 @end deftypefn */)
237 {
238  int nargin = args.length ();
239 
240  if (nargin < 1 || nargin > 2)
241  print_usage ();
242 
243  octave_value retval;
244 
245  // Parameter check "unique"
246  bool uniq_v = false;
247  if (nargin == 2)
248  {
249  const charMatrix opt = args (1).char_matrix_value ();
250  const char *str = opt.data ();
251  if (std::string (str, opt.cols ()) != "unique")
252  {
253  error ("perms: option must be the string \"unique\".");
254  }
255  uniq_v = true;
256  }
257 
258  if (! (args (0).is_matrix_type () || args (0).is_range ()
259  || args (0).iscell () || args (0).is_scalar_type ()
260  || args (0).isstruct ()))
261  {
262  error ("perms: INPUT must be a matrix, a range, a cell array, "
263  "a struct or a scalar.");
264  }
265 
266  std::string clname = args (0).class_name ();
267 
268  // Execute main permutation code for the different classes
269  if (clname == "double")
270  retval = GetPerms<double> (args (0).array_value (), uniq_v);
271  else if (clname == "single")
272  retval = GetPerms<float> (args (0).float_array_value (), uniq_v);
273  else if (clname == "logical")
274  retval = GetPerms<bool> (args (0).bool_array_value (), uniq_v);
275  else if (clname == "char")
276  retval = GetPerms<char> (args (0).char_array_value (), uniq_v);
277  else if (clname == "int8")
278  retval = GetPerms<octave_int8> (args (0).int8_array_value (), uniq_v);
279  else if (clname == "int16")
280  retval = GetPerms<octave_int16> (args (0).int16_array_value (), uniq_v);
281  else if (clname == "int32")
282  retval = GetPerms<octave_int32> (args (0).int32_array_value (), uniq_v);
283  else if (clname == "int64")
284  retval = GetPerms<octave_int64> (args (0).int64_array_value (), uniq_v);
285  else if (clname == "uint8")
286  retval = GetPerms<octave_uint8> (args (0).uint8_array_value (), uniq_v);
287  else if (clname == "uint16")
288  retval = GetPerms<octave_uint16> (args (0).uint16_array_value (), uniq_v);
289  else if (clname == "uint32")
290  retval = GetPerms<octave_uint32> (args (0).uint32_array_value (), uniq_v);
291  else if (clname == "uint64")
292  retval = GetPerms<octave_uint64> (args (0).uint64_array_value (), uniq_v);
293  else if (clname == "cell")
294  retval = GetPermsNoSort<octave_value> (args (0).cell_value (), uniq_v);
295  else if (clname == "struct")
296  {
297  const octave_map map_in (args (0).map_value ());
298  string_vector fn = map_in.fieldnames ();
299  if (fn.numel () == 0 && map_in.numel () != 0)
300  {
301  octave_scalar_map out;
302  retval = out;
303  }
304  else
305  {
306  octave_map out;
307  if (fn.numel () == 0)
308  {
309  out = octave_map (dim_vector (1, 0));
310  }
311  else
312  {
313  for (octave_idx_type i = 0; i < fn.numel (); i++)
314  {
315  out.assign (fn (i), GetPermsNoSort<octave_value>
316  (map_in.contents (fn (i)), uniq_v));
317  }
318  }
319  retval = out;
320  }
321  }
322  else // none of the above class criteria were met
323  {
324  warning ("perms: unable to permute for class %s", clname.c_str ());
325  // retval stays empty
326  }
327  return ovl (retval);
328 }
329 
330 /*
331 
332 %!assert (rows (perms (1:6)), factorial (6))
333 %!assert (perms (pi), pi)
334 %!assert (perms ([e, pi]), [pi, e; e, pi])
335 %!assert (perms ([pi, e]), [e, pi; pi, e])
336 %!assert (perms ([1 2 3]), [3 2 1; 3 1 2; 2 3 1; 2 1 3; 1 3 2; 1 2 3])
337 %!assert (sortrows (perms (1:5)), sortrows (perms ([2 5 4 1 3]')))
338 %!assert (perms ("abc"), char ("cba", "cab", "bca", "bac", "acb", "abc"))
339 %!assert (sortrows (perms ("fobar")), unique (perms ("fobar"), "rows"))
340 %!assert (unique (perms (1:5)(:))', 1:5)
341 %!assert (perms (int8 (1:4)), int8 (perms (1:4)))
342 
343 %!assert (sortrows (perms ("abb", "unique")), ["abb"; "bab"; "bba"])
344 %!assert (size (perms ([1 1 1 1 2 2 2 3 3], "unique")), [1260 9])
345 %!assert (size (perms (int8([1 1 1 1 1 2 2 2 2 3 3 3]), "unique")), [27720 12])
346 
347 ## Should work for any array type, such as cells and structs,
348 ## and not only for numeric data.
349 
350 %!assert <*52431> (perms ({1}), {1})
351 %!assert <*52431> (perms ({0.1, "foo"}), {"foo", 0.1; 0.1, "foo"})
352 %!assert <*52431> (perms ({"foo", 0.1}), {0.1, "foo"; "foo", 0.1})
353 %!assert <*52431> (perms ({"foo"; 0.1}), {0.1, "foo"; "foo", 0.1})
354 %!assert <*52431> (perms ({0.1; "foo"}), {"foo", 0.1; 0.1, "foo"})
355 %!assert <*52431> (perms ({"foo", "bar"}), {"bar", "foo"; "foo", "bar"})
356 %!assert <*52431> (perms ({"bar", "foo"}), {"foo", "bar"; "bar", "foo"})
357 %!
358 %!assert <*52431> (perms (struct ()), struct ())
359 %!assert <*52431> (perms (struct ("foo", {1, 2})),
360 %! struct ("foo", {2, 1; 1, 2}))
361 %!assert <*52431> (perms (struct ("foo", {1, 2}, "bar", {3, 4})),
362 %! struct ("foo", {2, 1; 1, 2}, "bar", {4, 3; 3, 4}))
363 
364 ## Also sort logical input with order dependent on the input order and
365 ## not their values.
366 
367 %!assert <*52431> (perms (logical ([1 0])), logical ([0 1;, 1 0]))
368 %!assert <*52431> (perms (logical ([0 1])), logical ([1 0; 0 1]))
369 %!assert <*52431> (perms (logical ([0 1 0])),
370 %! logical ([0 1 0; 0 0 1; 1 0 0; 1 0 0; 0 0 1; 0 1 0]))
371 %!assert <*52431> (perms (logical ([0 1 1])),
372 %! logical ([1 1 0; 1 0 1; 1 1 0; 1 0 1; 0 1 1; 0 1 1]))
373 
374 %!assert <*52432> (perms ([]), reshape ([], 1, 0))
375 %!assert <*52432> (perms (single ([])), reshape (single ([]), 1, 0))
376 %!assert <*52432> (perms (int8 ([])), reshape (int8 ([]), 1, 0))
377 %!assert <*52432> (perms ({}), cell (1, 0))
378 
379 %!test <*52432>
380 %! s = struct ();
381 %! s(1) = [];
382 %! assert (perms (reshape (s, 0, 0)), reshape (s, 1, 0));
383 %! assert (perms (reshape (s, 0, 1)), reshape (s, 1, 0));
384 
385 ## test if "unique" works also for cell arrays
386 %!assert <*63965> (perms ({"foo"; "foo"}, "unique"), {"foo", "foo"})
387 %!assert <*63965> (perms ({"foo", "foo", "bar"}, "unique"), ...
388 %! {"bar", "foo", "foo";
389 %! "foo", "bar", "foo";
390 %! "foo", "foo", "bar"})
391 
392 ## Test input validation
393 %!error <Invalid call> perms ()
394 %!error <option must be the string "unique"> perms (1:5, "foobar")
395 %!error <option must be the string "unique"> perms (1:5, {"foo"})
396 
397 */
398 
399 OCTAVE_END_NAMESPACE (octave)
const T * data() const
Size of the specified dimension.
Definition: Array.h:663
octave_idx_type cols() const
Definition: Array.h:469
octave_idx_type numel() const
Number of elements in the array.
Definition: Array.h:414
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
string_vector fieldnames() const
Definition: oct-map.h:332
octave_idx_type numel() const
Definition: oct-map.h:368
void assign(const std::string &k, const Cell &val)
Definition: oct-map.h:344
const Cell & contents(const_iterator p) const
Definition: oct-map.h:310
octave_idx_type numel() const
Definition: str-vec.h:100
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 warning(const char *fmt,...)
Definition: error.cc:1063
void() error(const char *fmt,...)
Definition: error.cc:988
T octave_idx_type m
Definition: mx-inlines.cc:781
octave_idx_type n
Definition: mx-inlines.cc:761
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
@ ASCENDING
Definition: oct-sort.h:97
octave_value_list ovl(const OV_Args &... args)
Construct an octave_value_list with less typing.
Definition: ovl.h:219