GNU Octave  9.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
bsxfun.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2007-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 <list>
31 #include <string>
32 #include <vector>
33 
34 #include "lo-mappers.h"
35 
36 #include "defun.h"
37 #include "interpreter.h"
38 #include "oct-map.h"
39 #include "ov-colon.h"
40 #include "ov-fcn-handle.h"
41 #include "unwind-prot.h"
42 #include "variables.h"
43 
44 // Optimized bsxfun operations
46 {
64 };
65 
66 const char *bsxfun_builtin_names[] =
67 {
68  "plus",
69  "minus",
70  "times",
71  "rdivide",
72  "max",
73  "min",
74  "eq",
75  "ne",
76  "lt",
77  "le",
78  "gt",
79  "ge",
80  "and",
81  "or",
82  "power"
83 };
84 
85 static bsxfun_builtin_op
86 bsxfun_builtin_lookup (const std::string& name)
87 {
88  for (int i = 0; i < bsxfun_num_builtin_ops; i++)
89  if (name == bsxfun_builtin_names[i])
90  return static_cast<bsxfun_builtin_op> (i);
91 
93 }
94 
96  const octave_value&);
97 
98 // Static table of handlers.
100 
101 template <typename NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
102 static octave_value
103 bsxfun_forward_op (const octave_value& x, const octave_value& y)
104 {
105  NDA xa = octave_value_extract<NDA> (x);
106  NDA ya = octave_value_extract<NDA> (y);
107  return octave_value (bsxfun_op (xa, ya));
108 }
109 
110 template <typename NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
111 static octave_value
112 bsxfun_forward_rel (const octave_value& x, const octave_value& y)
113 {
114  NDA xa = octave_value_extract<NDA> (x);
115  NDA ya = octave_value_extract<NDA> (y);
116  return octave_value (bsxfun_rel (xa, ya));
117 }
118 
119 // pow() needs a special handler for reals
120 // because of the potentially complex result.
121 template <typename NDA, typename CNDA>
122 static octave_value
123 do_bsxfun_real_pow (const octave_value& x, const octave_value& y)
124 {
125  NDA xa = octave_value_extract<NDA> (x);
126  NDA ya = octave_value_extract<NDA> (y);
127  if (! ya.all_integers () && xa.any_element_is_negative ())
128  return octave_value (bsxfun_pow (CNDA (xa), ya));
129  else
130  return octave_value (bsxfun_pow (xa, ya));
131 }
132 
133 static void
134 maybe_fill_table ()
135 {
136  static bool filled = false;
137  if (filled)
138  return;
139 
140 #define REGISTER_OP_HANDLER(OP, BTYP, NDA, FUNOP) \
141  bsxfun_handler_table[OP][BTYP] = bsxfun_forward_op<NDA, FUNOP>
142 
143 #define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL) \
144  bsxfun_handler_table[REL][BTYP] = bsxfun_forward_rel<NDA, FUNREL>
145 
146 #define REGISTER_STD_HANDLERS(BTYP, NDA) \
147  REGISTER_OP_HANDLER (bsxfun_builtin_plus, BTYP, NDA, bsxfun_add); \
148  REGISTER_OP_HANDLER (bsxfun_builtin_minus, BTYP, NDA, bsxfun_sub); \
149  REGISTER_OP_HANDLER (bsxfun_builtin_times, BTYP, NDA, bsxfun_mul); \
150  REGISTER_OP_HANDLER (bsxfun_builtin_divide, BTYP, NDA, bsxfun_div); \
151  REGISTER_OP_HANDLER (bsxfun_builtin_max, BTYP, NDA, bsxfun_max); \
152  REGISTER_OP_HANDLER (bsxfun_builtin_min, BTYP, NDA, bsxfun_min); \
153  REGISTER_REL_HANDLER (bsxfun_builtin_eq, BTYP, NDA, bsxfun_eq); \
154  REGISTER_REL_HANDLER (bsxfun_builtin_ne, BTYP, NDA, bsxfun_ne); \
155  REGISTER_REL_HANDLER (bsxfun_builtin_lt, BTYP, NDA, bsxfun_lt); \
156  REGISTER_REL_HANDLER (bsxfun_builtin_le, BTYP, NDA, bsxfun_le); \
157  REGISTER_REL_HANDLER (bsxfun_builtin_gt, BTYP, NDA, bsxfun_gt); \
158  REGISTER_REL_HANDLER (bsxfun_builtin_ge, BTYP, NDA, bsxfun_ge)
159 
172 
173  // For bools, we register and/or.
176 
177  // Register power handlers.
179  = do_bsxfun_real_pow<NDArray, ComplexNDArray>;
181  = do_bsxfun_real_pow<FloatNDArray, FloatComplexNDArray>;
182 
184  bsxfun_pow);
187 
188  // For chars, we want just relational handlers.
195 
196  filled = true;
197 }
198 
199 static octave_value
200 maybe_optimized_builtin (const std::string& name,
201  const octave_value& a, const octave_value& b)
202 {
203  octave_value retval;
204 
205  maybe_fill_table ();
206 
207  bsxfun_builtin_op op = bsxfun_builtin_lookup (name);
208  if (op != bsxfun_builtin_unknown)
209  {
210  builtin_type_t btyp_a = a.builtin_type ();
211  builtin_type_t btyp_b = b.builtin_type ();
212 
213  // Simplify single/double combinations.
214  if (btyp_a == btyp_float && btyp_b == btyp_double)
215  btyp_b = btyp_float;
216  else if (btyp_a == btyp_double && btyp_b == btyp_float)
217  btyp_a = btyp_float;
218  else if (btyp_a == btyp_float_complex && btyp_b == btyp_complex)
219  btyp_b = btyp_float_complex;
220  else if (btyp_a == btyp_complex && btyp_b == btyp_float_complex)
221  btyp_a = btyp_float_complex;
222 
223  if (btyp_a == btyp_b && btyp_a != btyp_unknown)
224  {
225  bsxfun_handler handler = bsxfun_handler_table[op][btyp_a];
226  if (handler)
227  retval = handler (a, b);
228  }
229  }
230 
231  return retval;
232 }
233 
234 static bool
235 maybe_update_column (octave_value& Ac, const octave_value& A,
236  const dim_vector& dva, const dim_vector& dvc,
238 {
239  octave_idx_type nd = dva.ndims ();
240 
241  if (i == 0)
242  {
243  idx(0) = octave_value (':');
244  for (octave_idx_type j = 1; j < nd; j++)
245  {
246  if (dva(j) == 1)
247  idx(j) = octave_value (1);
248  else
249  idx(j) = octave_value ((i % dvc(j)) + 1);
250 
251  i /= dvc(j);
252  }
253 
254  Ac = A;
255  Ac = Ac.single_subsref ("(", idx);
256  return true;
257  }
258  else
259  {
260  bool is_changed = false;
261  octave_idx_type k = i;
262  octave_idx_type k1 = i - 1;
263  for (octave_idx_type j = 1; j < nd; j++)
264  {
265  if (dva(j) != 1 && k % dvc(j) != k1 % dvc(j))
266  {
267  idx (j) = octave_value ((k % dvc(j)) + 1);
268  is_changed = true;
269  }
270 
271  k /= dvc(j);
272  k1 /= dvc(j);
273  }
274 
275  if (is_changed)
276  {
277  Ac = A;
278  Ac = Ac.single_subsref ("(", idx);
279  return true;
280  }
281  else
282  return false;
283  }
284 }
285 
286 static void
287 update_index (Array<int>& idx, const dim_vector& dv, octave_idx_type i)
288 {
289  octave_idx_type nd = dv.ndims ();
290 
291  idx(0) = 0;
292  for (octave_idx_type j = 1; j < nd; j++)
293  {
294  idx(j) = i % dv(j);
295  i /= dv(j);
296  }
297 }
298 
300 
301 DEFMETHOD (bsxfun, interp, args, ,
302  doc: /* -*- texinfo -*-
303 @deftypefn {} {@var{C} =} bsxfun (@var{f}, @var{A}, @var{B})
304 Apply a binary function @var{f} element-by-element to two array arguments
305 @var{A} and @var{B}, expanding singleton dimensions in either input argument as
306 necessary.
307 
308 @var{f} is a function handle, inline function, or string containing the name
309 of the function to evaluate. The function @var{f} must be capable of accepting
310 two column-vector arguments of equal length, or one column vector argument and
311 a scalar.
312 
313 The dimensions of @var{A} and @var{B} must be equal or singleton. The
314 singleton dimensions of the arrays will be expanded to the same dimensionality
315 as the other array.
316 @seealso{arrayfun, cellfun}
317 @end deftypefn */)
318 {
319  if (args.length () != 3)
320  print_usage ();
321 
322  octave_value fcn = args(0);
323  if (fcn.is_string ())
324  {
325  std::string name = fcn.string_value ();
326 
327  symbol_table& symtab = interp.get_symbol_table ();
328 
329  fcn = symtab.find_function (name);
330 
331  if (fcn.is_undefined ())
332  error ("bsxfun: invalid function name: %s", name.c_str ());
333  }
334  else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
335  error ("bsxfun: F must be a string or function handle");
336 
337  octave_value_list retval;
338 
339  const octave_value A = args(1);
340  const octave_value B = args(2);
341 
342  if (fcn.is_builtin_function ()
343  || (fcn.is_function_handle () && ! A.isobject () && ! B.isobject ()))
344  {
345  // This may break if the default behavior is overridden. But if you
346  // override arithmetic operators for builtin classes, you should expect
347  // mayhem anyway (constant folding etc). Querying is_overloaded() may
348  // not be exactly what we need here.
349  octave_function *fcn_val = fcn.function_value ();
350  if (fcn_val)
351  {
352  octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
353  if (tmp.is_defined ())
354  retval(0) = tmp;
355  }
356  }
357 
358  if (retval.empty ())
359  {
360  dim_vector dva = A.dims ();
361  octave_idx_type nda = dva.ndims ();
362  dim_vector dvb = B.dims ();
363  octave_idx_type ndb = dvb.ndims ();
364  octave_idx_type nd = nda;
365 
366  if (nda > ndb)
367  dvb.resize (nda, 1);
368  else if (nda < ndb)
369  {
370  dva.resize (ndb, 1);
371  nd = ndb;
372  }
373 
374  for (octave_idx_type i = 0; i < nd; i++)
375  if (dva(i) != dvb(i) && dva(i) != 1 && dvb(i) != 1)
376  error ("bsxfun: dimensions of A and B must match");
377 
378  // Find the size of the output
379  dim_vector dvc;
380  dvc.resize (nd);
381 
382  for (octave_idx_type i = 0; i < nd; i++)
383  dvc(i) = (dva(i) < 1 ? dva(i)
384  : (dvb(i) < 1 ? dvb(i)
385  : (dva(i) > dvb(i) ? dva(i)
386  : dvb(i))));
387 
388  if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
389  {
390  octave_value_list inputs (2);
391  inputs(0) = A;
392  inputs(1) = B;
393  retval = interp.feval (fcn, inputs, 1);
394  }
395  else if (dvc.numel () < 1)
396  {
397  octave_value_list inputs (2);
398  inputs(0) = A.resize (dvc);
399  inputs(1) = B.resize (dvc);
400  retval = interp.feval (fcn, inputs, 1);
401  }
402  else
403  {
404  octave_idx_type ncount = 1;
405  for (octave_idx_type i = 1; i < nd; i++)
406  ncount *= dvc(i);
407 
408 #define BSXDEF(T) \
409  T result_ ## T; \
410  bool have_ ## T = false;
411 
412  BSXDEF(NDArray);
425 
426  octave_value Ac;
427  octave_value_list idxA;
428  octave_value Bc;
429  octave_value_list idxB;
430  octave_value C;
431  octave_value_list inputs (2);
432  Array<int> ra_idx (dim_vector (dvc.ndims (), 1), 0);
433 
434  for (octave_idx_type i = 0; i < ncount; i++)
435  {
436  if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
437  inputs(0) = Ac;
438 
439  if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
440  inputs(1) = Bc;
441 
442  octave_value_list tmp = interp.feval (fcn, inputs, 1);
443 
444 #define BSXINIT(T, CLS, EXTRACTOR) \
445  (result_type == CLS) \
446  { \
447  have_ ## T = true; \
448  result_ ## T = tmp(0). EXTRACTOR ## _array_value (); \
449  result_ ## T .resize (dvc); \
450  }
451 
452  if (i == 0)
453  {
454  if (! tmp(0).issparse ())
455  {
456  std::string result_type = tmp(0).class_name ();
457  if (result_type == "double")
458  {
459  if (tmp(0).isreal ())
460  {
461  have_NDArray = true;
462  result_NDArray = tmp(0).array_value ();
463  result_NDArray.resize (dvc);
464  }
465  else
466  {
467  have_ComplexNDArray = true;
468  result_ComplexNDArray
469  = tmp(0).complex_array_value ();
470  result_ComplexNDArray.resize (dvc);
471  }
472  }
473  else if (result_type == "single")
474  {
475  if (tmp(0).isreal ())
476  {
477  have_FloatNDArray = true;
478  result_FloatNDArray
479  = tmp(0).float_array_value ();
480  result_FloatNDArray.resize (dvc);
481  }
482  else
483  {
484  have_FloatComplexNDArray = true;
485  result_FloatComplexNDArray
486  = tmp(0).float_complex_array_value ();
487  result_FloatComplexNDArray.resize (dvc);
488  }
489  }
490  else if BSXINIT(boolNDArray, "logical", bool)
491  else if BSXINIT(int8NDArray, "int8", int8)
492  else if BSXINIT(int16NDArray, "int16", int16)
493  else if BSXINIT(int32NDArray, "int32", int32)
494  else if BSXINIT(int64NDArray, "int64", int64)
495  else if BSXINIT(uint8NDArray, "uint8", uint8)
496  else if BSXINIT(uint16NDArray, "uint16", uint16)
497  else if BSXINIT(uint32NDArray, "uint32", uint32)
498  else if BSXINIT(uint64NDArray, "uint64", uint64)
499  else
500  {
501  C = tmp(0);
502  C = C.resize (dvc);
503  }
504  }
505  else // Skip semi-fast path for sparse matrices
506  {
507  C = tmp (0);
508  C = C.resize (dvc);
509  }
510  }
511  else
512  {
513  update_index (ra_idx, dvc, i);
514 
515  if (have_NDArray)
516  {
517  if (! tmp(0).isfloat ())
518  {
519  have_NDArray = false;
520  C = result_NDArray;
521  C = cat_op (C, tmp(0), ra_idx);
522  }
523  else if (tmp(0).isreal ())
524  result_NDArray.insert (tmp(0).array_value (), ra_idx);
525  else
526  {
527  result_ComplexNDArray
528  = ComplexNDArray (result_NDArray);
529  result_ComplexNDArray.insert
530  (tmp(0).complex_array_value (), ra_idx);
531  have_NDArray = false;
532  have_ComplexNDArray = true;
533  }
534  }
535  else if (have_FloatNDArray)
536  {
537  if (! tmp(0).isfloat ())
538  {
539  have_FloatNDArray = false;
540  C = result_FloatNDArray;
541  C = cat_op (C, tmp(0), ra_idx);
542  }
543  else if (tmp(0).isreal ())
544  result_FloatNDArray.insert
545  (tmp(0).float_array_value (), ra_idx);
546  else
547  {
548  result_FloatComplexNDArray
549  = FloatComplexNDArray (result_FloatNDArray);
550  result_FloatComplexNDArray.insert
551  (tmp(0).float_complex_array_value (), ra_idx);
552  have_FloatNDArray = false;
553  have_FloatComplexNDArray = true;
554  }
555  }
556 
557 #define BSXLOOP(T, CLS, EXTRACTOR) \
558  (have_ ## T) \
559  { \
560  if (tmp(0).class_name () != CLS) \
561  { \
562  have_ ## T = false; \
563  C = result_ ## T; \
564  C = cat_op (C, tmp(0), ra_idx); \
565  } \
566  else \
567  result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
568  }
569 
570  else if BSXLOOP(ComplexNDArray, "double", complex)
571  else if BSXLOOP(FloatComplexNDArray, "single", float_complex)
572  else if BSXLOOP(boolNDArray, "logical", bool)
573  else if BSXLOOP(int8NDArray, "int8", int8)
574  else if BSXLOOP(int16NDArray, "int16", int16)
575  else if BSXLOOP(int32NDArray, "int32", int32)
576  else if BSXLOOP(int64NDArray, "int64", int64)
577  else if BSXLOOP(uint8NDArray, "uint8", uint8)
578  else if BSXLOOP(uint16NDArray, "uint16", uint16)
579  else if BSXLOOP(uint32NDArray, "uint32", uint32)
580  else if BSXLOOP(uint64NDArray, "uint64", uint64)
581  else
582  C = cat_op (C, tmp(0), ra_idx);
583  }
584  }
585 
586 #define BSXEND(T) \
587  (have_ ## T) \
588  retval(0) = result_ ## T;
589 
590  if BSXEND(NDArray)
591  else if BSXEND(ComplexNDArray)
592  else if BSXEND(FloatNDArray)
593  else if BSXEND(FloatComplexNDArray)
594  else if BSXEND(boolNDArray)
595  else if BSXEND(int8NDArray)
596  else if BSXEND(int16NDArray)
597  else if BSXEND(int32NDArray)
598  else if BSXEND(int64NDArray)
599  else if BSXEND(uint8NDArray)
600  else if BSXEND(uint16NDArray)
601  else if BSXEND(uint32NDArray)
602  else if BSXEND(uint64NDArray)
603  else
604  retval(0) = C;
605  }
606  }
607 
608  return retval;
609 }
610 
611 /*
612 
613 %!shared a, b, c, f
614 %! a = randn (4, 4);
615 %! b = mean (a, 1);
616 %! c = mean (a, 2);
617 %! f = @minus;
618 %!error bsxfun (f)
619 %!error bsxfun (f, a)
620 %!error bsxfun (a, b)
621 %!error bsxfun (a, b, c)
622 %!error bsxfun (f, a, b, c)
623 %!error bsxfun (f, ones (4, 0), ones (4, 4))
624 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
625 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
626 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
627 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
628 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
629 
630 %!shared a, b, c, f
631 %! a = randn (4, 4);
632 %! a(1) *= 1i;
633 %! b = mean (a, 1);
634 %! c = mean (a, 2);
635 %! f = @minus;
636 %!error bsxfun (f)
637 %!error bsxfun (f, a)
638 %!error bsxfun (a, b)
639 %!error bsxfun (a, b, c)
640 %!error bsxfun (f, a, b, c)
641 %!error bsxfun (f, ones (4, 0), ones (4, 4))
642 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
643 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
644 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
645 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
646 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
647 
648 %!shared a, b, c, f
649 %! a = randn (4, 4);
650 %! a(end) *= 1i;
651 %! b = mean (a, 1);
652 %! c = mean (a, 2);
653 %! f = @minus;
654 %!error bsxfun (f)
655 %!error bsxfun (f, a)
656 %!error bsxfun (a, b)
657 %!error bsxfun (a, b, c)
658 %!error bsxfun (f, a, b, c)
659 %!error bsxfun (f, ones (4, 0), ones (4, 4))
660 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
661 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
662 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
663 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
664 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
665 
666 %!shared a, b, c, f
667 %! a = randn (4, 4);
668 %! b = a (1, :);
669 %! c = a (:, 1);
670 %! f = @(x, y) x == y;
671 %!error bsxfun (f)
672 %!error bsxfun (f, a)
673 %!error bsxfun (a, b)
674 %!error bsxfun (a, b, c)
675 %!error bsxfun (f, a, b, c)
676 %!error bsxfun (f, ones (4, 0), ones (4, 4))
677 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
678 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
679 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
680 %!assert (bsxfun (f, a, c), a == repmat (c, 1, 4))
681 
682 %!shared a, b, c, d, f
683 %! a = randn (4, 4, 4);
684 %! b = mean (a, 1);
685 %! c = mean (a, 2);
686 %! d = mean (a, 3);
687 %! f = @minus;
688 %!error bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4]))
689 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
690 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
691 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
692 %!assert (bsxfun (f, ones ([4, 4, 1]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
693 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 4])), zeros ([4, 4, 4]))
694 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 1])), zeros ([4, 4, 4]))
695 %!assert (bsxfun (f, a, b), a - repmat (b, [4, 1, 1]))
696 %!assert (bsxfun (f, a, c), a - repmat (c, [1, 4, 1]))
697 %!assert (bsxfun (f, a, d), a - repmat (d, [1, 1, 4]))
698 %!assert (bsxfun ("minus", ones ([4, 0, 4]), ones ([4, 1, 4])),
699 %! zeros ([4, 0, 4]))
700 
701 ## The test below is a very hard case to treat
702 %!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])),
703 %! zeros ([4, 4, 4, 4]))
704 
705 %!shared a, b, aa, bb
706 %! ## FIXME: Set a known "good" random seed. See bug #51779.
707 %! old_nstate = randn ("state");
708 %! restore_nstate = onCleanup (@() randn ("state", old_nstate));
709 %! randn ("state", 42); # initialize generator to make behavior reproducible
710 %! a = randn (3, 1, 3);
711 %! aa = a(:, ones (1, 3), :, ones (1, 3));
712 %! b = randn (1, 3, 3, 3);
713 %! bb = b(ones (1, 3), :, :, :);
714 %!assert (bsxfun (@plus, a, b), aa + bb)
715 %!assert (bsxfun (@minus, a, b), aa - bb)
716 %!assert (bsxfun (@times, a, b), aa .* bb)
717 %!assert (bsxfun (@rdivide, a, b), aa ./ bb)
718 %!assert (bsxfun (@ldivide, a, b), aa .\ bb)
719 %!assert (bsxfun (@power, a, b), aa .^ bb)
720 %!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
721 %!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
722 %!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
723 %!assert (bsxfun (@lt, a, b), aa < bb)
724 %!assert (bsxfun (@le, a, b), aa <= bb)
725 %!assert (bsxfun (@gt, a, b), aa > bb)
726 %!assert (bsxfun (@ge, a, b), aa >= bb)
727 %!assert (bsxfun (@min, a, b), min (aa, bb))
728 %!assert (bsxfun (@max, a, b), max (aa, bb))
729 %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
730 %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
731 
732 ## Test automatic bsxfun
733 %
734 %!test
735 %! fcns = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
736 %! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
737 %! @and, @or, @xor };
738 %!
739 %! float_types = {@single, @double};
740 %! int_types = {@int8, @int16, @int32, @int64, ...
741 %! @uint8, @uint16, @uint32, @uint64};
742 %!
743 %! ## FIXME: Set a known "good" random seed. See bug #51779.
744 %! old_state = rand ("state");
745 %! restore_state = onCleanup (@() rand ("state", old_state));
746 %! rand ("state", 42); # initialize generator to make behavior reproducible
747 %!
748 %! x = rand (3) * 10-5;
749 %! y = rand (3,1) * 10-5;
750 %!
751 %! for i=1:length (fcns)
752 %! for j = 1:length (float_types)
753 %! for k = 1:length (int_types)
754 %!
755 %! fcn = fcns{i};
756 %! f_type = float_types{j};
757 %! i_type = int_types{k};
758 %!
759 %! assert (bsxfun (fcn, f_type (x), i_type (y)), ...
760 %! fcn (f_type(x), i_type (y)));
761 %! assert (bsxfun (fcn, f_type (y), i_type (x)), ...
762 %! fcn (f_type(y), i_type (x)));
763 %!
764 %! assert (bsxfun (fcn, i_type (x), i_type (y)), ...
765 %! fcn (i_type (x), i_type (y)));
766 %! assert (bsxfun (fcn, i_type (y), i_type (x)), ...
767 %! fcn (i_type (y), i_type (x)));
768 %!
769 %! assert (bsxfun (fcn, f_type (x), f_type (y)), ...
770 %! fcn (f_type (x), f_type (y)));
771 %! assert (bsxfun (fcn, f_type(y), f_type(x)), ...
772 %! fcn (f_type (y), f_type (x)));
773 %! endfor
774 %! endfor
775 %! endfor
776 
777 ## Automatic broadcasting with zero length dimensions
778 %!assert <*47085> ([1 2 3] + zeros (0, 3), zeros (0, 3))
779 %!assert <*47085> (rand (3, 3, 1) + rand (3, 3, 0), zeros (3, 3, 0))
780 
781 ## In-place broadcasting with zero length dimensions
782 %!test <*47085>
783 %! a = zeros (0, 3);
784 %! a += [1 2 3];
785 %! assert (a, zeros (0, 3));
786 
787 %!test <*53179>
788 %! im = ones (4,4,2) + single (i);
789 %! mask = true (4,4);
790 %! mask(:,1:2) = false;
791 %! r = bsxfun (@times, im, mask);
792 %! assert (r(:,:,1), repmat (single ([0, 0, 1+i, 1+i]), [4, 1]));
793 
794 ## automatic broadcasting with inplace times operator
795 %!test <*38466>
796 %! a = ones (2, 2, 2);
797 %! b = 2 * ones (2, 1);
798 %! a .*= b;
799 %! assert (a, 2 * ones (2, 2, 2));
800 
801 %!test <*38466>
802 %! a = ones (2, 2, 2);
803 %! b = 2 * ones (1, 2);
804 %! a .*= b;
805 %! assert (a, 2 * ones (2, 2, 2));
806 
807 %!test <*38466>
808 %! a = ones (2, 2, 2);
809 %! b = 2 * ones (2, 2);
810 %! a .*= b;
811 %! assert (a, 2 * ones (2, 2, 2));
812 
813 %!test <*38466>
814 %! a = ones (2, 2, 2);
815 %! b = 2 * ones (1, 1, 2);
816 %! a .*= b;
817 %! assert (a, 2 * ones (2, 2, 2));
818 
819 %!assert (ones (2,2,2) .* ones (1,2), ones (2,2,2));
820 
821 */
822 
823 OCTAVE_END_NAMESPACE(octave)
ComplexNDArray bsxfun_pow(const ComplexNDArray &x, const ComplexNDArray &y)
Definition: CNDArray.cc:665
#define C(a, b)
Definition: Faddeeva.cc:259
boolNDArray bsxfun_or(const boolNDArray &x, const boolNDArray &y)
Definition: boolNDArray.cc:156
boolNDArray bsxfun_and(const boolNDArray &x, const boolNDArray &y)
Definition: boolNDArray.cc:155
#define REGISTER_STD_HANDLERS(BTYP, NDA)
bsxfun_handler bsxfun_handler_table[bsxfun_num_builtin_ops][btyp_num_types]
Definition: bsxfun.cc:99
bsxfun_builtin_op
Definition: bsxfun.cc:46
@ bsxfun_builtin_le
Definition: bsxfun.cc:56
@ bsxfun_builtin_min
Definition: bsxfun.cc:52
@ bsxfun_builtin_divide
Definition: bsxfun.cc:50
@ bsxfun_builtin_eq
Definition: bsxfun.cc:53
@ bsxfun_builtin_or
Definition: bsxfun.cc:60
@ bsxfun_builtin_unknown
Definition: bsxfun.cc:62
@ bsxfun_builtin_ge
Definition: bsxfun.cc:58
@ bsxfun_builtin_plus
Definition: bsxfun.cc:47
@ bsxfun_builtin_times
Definition: bsxfun.cc:49
@ bsxfun_builtin_and
Definition: bsxfun.cc:59
@ bsxfun_builtin_gt
Definition: bsxfun.cc:57
@ bsxfun_builtin_power
Definition: bsxfun.cc:61
@ bsxfun_builtin_ne
Definition: bsxfun.cc:54
@ bsxfun_builtin_minus
Definition: bsxfun.cc:48
@ bsxfun_builtin_lt
Definition: bsxfun.cc:55
@ bsxfun_builtin_max
Definition: bsxfun.cc:51
@ bsxfun_num_builtin_ops
Definition: bsxfun.cc:63
#define BSXDEF(T)
#define BSXINIT(T, CLS, EXTRACTOR)
const char * bsxfun_builtin_names[]
Definition: bsxfun.cc:66
#define BSXEND(T)
#define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL)
#define BSXLOOP(T, CLS, EXTRACTOR)
octave_value(* bsxfun_handler)(const octave_value &, const octave_value &)
Definition: bsxfun.cc:95
#define REGISTER_OP_HANDLER(OP, BTYP, NDA, FUNOP)
boolNDArray bsxfun_ge(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
boolNDArray bsxfun_lt(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
boolNDArray bsxfun_gt(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
boolNDArray bsxfun_eq(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
boolNDArray bsxfun_le(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
boolNDArray bsxfun_ne(const charNDArray &x, const charNDArray &y)
Definition: chNDArray.cc:261
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1023
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:94
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:335
void resize(int n, int fill_value=0)
Definition: dim-vector.h:272
octave_idx_type ndims() const
Number of dimensions.
Definition: dim-vector.h:257
std::string name() const
Definition: ov-fcn.h:206
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
Array< octave_value > array_value() const
Definition: ovl.h:90
bool empty() const
Definition: ovl.h:115
bool is_function_handle() const
Definition: ov.h:768
bool is_undefined() const
Definition: ov.h:595
bool is_string() const
Definition: ov.h:637
bool is_defined() const
Definition: ov.h:592
octave_function * function_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:974
octave_value single_subsref(const std::string &type, const octave_value_list &idx)
bool is_builtin_function() const
Definition: ov.h:789
builtin_type_t builtin_type() const
Definition: ov.h:690
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition: symtab.cc:254
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage(void)
Definition: defun-int.h:72
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:111
void() error(const char *fmt,...)
Definition: error.cc:988
F77_RET_T const F77_INT F77_CMPLX const F77_INT F77_CMPLX * B
F77_RET_T const F77_INT F77_CMPLX * A
F77_RET_T const F77_DBLE * x
const octave_base_value const Array< octave_idx_type > & ra_idx
return octave_value(v1.char_array_value() . concat(v2.char_array_value(), ra_idx),((a1.is_sq_string()||a2.is_sq_string()) ? '\'' :'"'))
builtin_type_t
Definition: ov-base.h:83
@ btyp_float_complex
Definition: ov-base.h:87
@ btyp_double
Definition: ov-base.h:84
@ btyp_int32
Definition: ov-base.h:90
@ btyp_float
Definition: ov-base.h:85
@ btyp_uint16
Definition: ov-base.h:93
@ btyp_int64
Definition: ov-base.h:91
@ btyp_bool
Definition: ov-base.h:96
@ btyp_unknown
Definition: ov-base.h:101
@ btyp_uint64
Definition: ov-base.h:95
@ btyp_int16
Definition: ov-base.h:89
@ btyp_uint32
Definition: ov-base.h:94
@ btyp_num_types
Definition: ov-base.h:102
@ btyp_char
Definition: ov-base.h:97
@ btyp_uint8
Definition: ov-base.h:92
@ btyp_int8
Definition: ov-base.h:88
@ btyp_complex
Definition: ov-base.h:86
octave_value cat_op(type_info &ti, const octave_value &a, const octave_value &b, const Array< octave_idx_type > &ra_idx)