GNU Octave  6.2.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-2021 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 "parse.h"
42 #include "unwind-prot.h"
43 #include "variables.h"
44 
45 // Optimized bsxfun operations
47 {
65 };
66 
67 const char *bsxfun_builtin_names[] =
68 {
69  "plus",
70  "minus",
71  "times",
72  "rdivide",
73  "max",
74  "min",
75  "eq",
76  "ne",
77  "lt",
78  "le",
79  "gt",
80  "ge",
81  "and",
82  "or",
83  "power"
84 };
85 
86 static bsxfun_builtin_op
87 bsxfun_builtin_lookup (const std::string& name)
88 {
89  for (int i = 0; i < bsxfun_num_builtin_ops; i++)
90  if (name == bsxfun_builtin_names[i])
91  return static_cast<bsxfun_builtin_op> (i);
92 
94 }
95 
97  const octave_value&);
98 
99 // Static table of handlers.
101 
102 template <typename NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
103 static octave_value
105 {
106  NDA xa = octave_value_extract<NDA> (x);
107  NDA ya = octave_value_extract<NDA> (y);
108  return octave_value (bsxfun_op (xa, ya));
109 }
110 
111 template <typename NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
112 static octave_value
114 {
115  NDA xa = octave_value_extract<NDA> (x);
116  NDA ya = octave_value_extract<NDA> (y);
117  return octave_value (bsxfun_rel (xa, ya));
118 }
119 
120 // pow() needs a special handler for reals
121 // because of the potentially complex result.
122 template <typename NDA, typename CNDA>
123 static octave_value
125 {
126  NDA xa = octave_value_extract<NDA> (x);
127  NDA ya = octave_value_extract<NDA> (y);
128  if (! ya.all_integers () && xa.any_element_is_negative ())
129  return octave_value (bsxfun_pow (CNDA (xa), ya));
130  else
131  return octave_value (bsxfun_pow (xa, ya));
132 }
133 
134 static void maybe_fill_table (void)
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 {
204 
205  maybe_fill_table ();
206 
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
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 #if 0
287 // FIXME: this function is not used; is it OK to delete it?
288 static void
290 {
291  octave_idx_type nd = dv.ndims ();
292 
293  if (i == 0)
294  {
295  for (octave_idx_type j = nd - 1; j > 0; j--)
296  idx(j) = octave_value (1.0);
297  idx(0) = octave_value (':');
298  }
299  else
300  {
301  for (octave_idx_type j = 1; j < nd; j++)
302  {
303  idx (j) = octave_value (i % dv(j) + 1);
304  i /= dv(j);
305  }
306  }
307 }
308 #endif
309 
310 static void
312 {
313  octave_idx_type nd = dv.ndims ();
314 
315  idx(0) = 0;
316  for (octave_idx_type j = 1; j < nd; j++)
317  {
318  idx(j) = i % dv(j);
319  i /= dv(j);
320  }
321 }
322 
323 DEFMETHOD (bsxfun, interp,args, ,
324  doc: /* -*- texinfo -*-
325 @deftypefn {} {} bsxfun (@var{f}, @var{A}, @var{B})
326 Apply a binary function @var{f} element-by-element to two array arguments
327 @var{A} and @var{B}, expanding singleton dimensions in either input argument as
328 necessary.
329 
330 @var{f} is a function handle, inline function, or string containing the name
331 of the function to evaluate. The function @var{f} must be capable of accepting
332 two column-vector arguments of equal length, or one column vector argument and
333 a scalar.
334 
335 The dimensions of @var{A} and @var{B} must be equal or singleton. The
336 singleton dimensions of the arrays will be expanded to the same dimensionality
337 as the other array.
338 @seealso{arrayfun, cellfun}
339 @end deftypefn */)
340 {
341  if (args.length () != 3)
342  print_usage ();
343 
344  octave_value func = args(0);
345  if (func.is_string ())
346  {
347  std::string name = func.string_value ();
348 
349  octave::symbol_table& symtab = interp.get_symbol_table ();
350 
351  func = symtab.find_function (name);
352 
353  if (func.is_undefined ())
354  error ("bsxfun: invalid function name: %s", name.c_str ());
355  }
356  else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
357  error ("bsxfun: F must be a string or function handle");
358 
360 
361  const octave_value A = args(1);
362  const octave_value B = args(2);
363 
364  if (func.is_builtin_function ()
365  || (func.is_function_handle () && ! A.isobject () && ! B.isobject ()))
366  {
367  // This may break if the default behavior is overridden. But if you
368  // override arithmetic operators for builtin classes, you should expect
369  // mayhem anyway (constant folding etc). Querying is_overloaded() may
370  // not be exactly what we need here.
371  octave_function *fcn_val = func.function_value ();
372  if (fcn_val)
373  {
374  octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
375  if (tmp.is_defined ())
376  retval(0) = tmp;
377  }
378  }
379 
380  if (retval.empty ())
381  {
382  dim_vector dva = A.dims ();
383  octave_idx_type nda = dva.ndims ();
384  dim_vector dvb = B.dims ();
385  octave_idx_type ndb = dvb.ndims ();
386  octave_idx_type nd = nda;
387 
388  if (nda > ndb)
389  dvb.resize (nda, 1);
390  else if (nda < ndb)
391  {
392  dva.resize (ndb, 1);
393  nd = ndb;
394  }
395 
396  for (octave_idx_type i = 0; i < nd; i++)
397  if (dva(i) != dvb(i) && dva(i) != 1 && dvb(i) != 1)
398  error ("bsxfun: dimensions of A and B must match");
399 
400  // Find the size of the output
401  dim_vector dvc;
402  dvc.resize (nd);
403 
404  for (octave_idx_type i = 0; i < nd; i++)
405  dvc(i) = (dva(i) < 1 ? dva(i)
406  : (dvb(i) < 1 ? dvb(i)
407  : (dva(i) > dvb(i) ? dva(i)
408  : dvb(i))));
409 
410  if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
411  {
412  octave_value_list inputs (2);
413  inputs(0) = A;
414  inputs(1) = B;
415  retval = octave::feval (func, inputs, 1);
416  }
417  else if (dvc.numel () < 1)
418  {
419  octave_value_list inputs (2);
420  inputs(0) = A.resize (dvc);
421  inputs(1) = B.resize (dvc);
422  retval = octave::feval (func, inputs, 1);
423  }
424  else
425  {
426  octave_idx_type ncount = 1;
427  for (octave_idx_type i = 1; i < nd; i++)
428  ncount *= dvc(i);
429 
430 #define BSXDEF(T) \
431  T result_ ## T; \
432  bool have_ ## T = false;
433 
434  BSXDEF(NDArray);
447 
448  octave_value Ac;
449  octave_value_list idxA;
450  octave_value Bc;
451  octave_value_list idxB;
452  octave_value C;
453  octave_value_list inputs (2);
454  Array<int> ra_idx (dim_vector (dvc.ndims (), 1), 0);
455 
456  for (octave_idx_type i = 0; i < ncount; i++)
457  {
458  if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
459  inputs(0) = Ac;
460 
461  if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
462  inputs(1) = Bc;
463 
464  octave_value_list tmp = octave::feval (func, inputs, 1);
465 
466 #define BSXINIT(T, CLS, EXTRACTOR) \
467  (result_type == CLS) \
468  { \
469  have_ ## T = true; \
470  result_ ## T = tmp(0). EXTRACTOR ## _array_value (); \
471  result_ ## T .resize (dvc); \
472  }
473 
474  if (i == 0)
475  {
476  if (! tmp(0).issparse ())
477  {
478  std::string result_type = tmp(0).class_name ();
479  if (result_type == "double")
480  {
481  if (tmp(0).isreal ())
482  {
483  have_NDArray = true;
484  result_NDArray = tmp(0).array_value ();
485  result_NDArray.resize (dvc);
486  }
487  else
488  {
489  have_ComplexNDArray = true;
490  result_ComplexNDArray
491  = tmp(0).complex_array_value ();
492  result_ComplexNDArray.resize (dvc);
493  }
494  }
495  else if (result_type == "single")
496  {
497  if (tmp(0).isreal ())
498  {
499  have_FloatNDArray = true;
500  result_FloatNDArray
501  = tmp(0).float_array_value ();
502  result_FloatNDArray.resize (dvc);
503  }
504  else
505  {
506  have_FloatComplexNDArray = true;
507  result_FloatComplexNDArray
508  = tmp(0).float_complex_array_value ();
509  result_FloatComplexNDArray.resize (dvc);
510  }
511  }
512  else if BSXINIT(boolNDArray, "logical", bool)
513  else if BSXINIT(int8NDArray, "int8", int8)
514  else if BSXINIT(int16NDArray, "int16", int16)
515  else if BSXINIT(int32NDArray, "int32", int32)
516  else if BSXINIT(int64NDArray, "int64", int64)
517  else if BSXINIT(uint8NDArray, "uint8", uint8)
518  else if BSXINIT(uint16NDArray, "uint16", uint16)
519  else if BSXINIT(uint32NDArray, "uint32", uint32)
520  else if BSXINIT(uint64NDArray, "uint64", uint64)
521  else
522  {
523  C = tmp(0);
524  C = C.resize (dvc);
525  }
526  }
527  else // Skip semi-fast path for sparse matrices
528  {
529  C = tmp (0);
530  C = C.resize (dvc);
531  }
532  }
533  else
534  {
535  update_index (ra_idx, dvc, i);
536 
537  if (have_NDArray)
538  {
539  if (! tmp(0).isfloat ())
540  {
541  have_NDArray = false;
542  C = result_NDArray;
543  C = do_cat_op (C, tmp(0), ra_idx);
544  }
545  else if (tmp(0).isreal ())
546  result_NDArray.insert (tmp(0).array_value (), ra_idx);
547  else
548  {
549  result_ComplexNDArray
550  = ComplexNDArray (result_NDArray);
551  result_ComplexNDArray.insert
552  (tmp(0).complex_array_value (), ra_idx);
553  have_NDArray = false;
554  have_ComplexNDArray = true;
555  }
556  }
557  else if (have_FloatNDArray)
558  {
559  if (! tmp(0).isfloat ())
560  {
561  have_FloatNDArray = false;
562  C = result_FloatNDArray;
563  C = do_cat_op (C, tmp(0), ra_idx);
564  }
565  else if (tmp(0).isreal ())
566  result_FloatNDArray.insert
567  (tmp(0).float_array_value (), ra_idx);
568  else
569  {
570  result_FloatComplexNDArray
571  = FloatComplexNDArray (result_FloatNDArray);
572  result_FloatComplexNDArray.insert
573  (tmp(0).float_complex_array_value (), ra_idx);
574  have_FloatNDArray = false;
575  have_FloatComplexNDArray = true;
576  }
577  }
578 
579 #define BSXLOOP(T, CLS, EXTRACTOR) \
580  (have_ ## T) \
581  { \
582  if (tmp(0).class_name () != CLS) \
583  { \
584  have_ ## T = false; \
585  C = result_ ## T; \
586  C = do_cat_op (C, tmp(0), ra_idx); \
587  } \
588  else \
589  result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
590  }
591 
592  else if BSXLOOP(ComplexNDArray, "double", complex)
593  else if BSXLOOP(FloatComplexNDArray, "single", float_complex)
594  else if BSXLOOP(boolNDArray, "logical", bool)
595  else if BSXLOOP(int8NDArray, "int8", int8)
596  else if BSXLOOP(int16NDArray, "int16", int16)
597  else if BSXLOOP(int32NDArray, "int32", int32)
598  else if BSXLOOP(int64NDArray, "int64", int64)
599  else if BSXLOOP(uint8NDArray, "uint8", uint8)
600  else if BSXLOOP(uint16NDArray, "uint16", uint16)
601  else if BSXLOOP(uint32NDArray, "uint32", uint32)
602  else if BSXLOOP(uint64NDArray, "uint64", uint64)
603  else
604  C = do_cat_op (C, tmp(0), ra_idx);
605  }
606  }
607 
608 #define BSXEND(T) \
609  (have_ ## T) \
610  retval(0) = result_ ## T;
611 
612  if BSXEND(NDArray)
613  else if BSXEND(ComplexNDArray)
614  else if BSXEND(FloatNDArray)
615  else if BSXEND(FloatComplexNDArray)
616  else if BSXEND(boolNDArray)
617  else if BSXEND(int8NDArray)
618  else if BSXEND(int16NDArray)
619  else if BSXEND(int32NDArray)
620  else if BSXEND(int64NDArray)
621  else if BSXEND(uint8NDArray)
622  else if BSXEND(uint16NDArray)
623  else if BSXEND(uint32NDArray)
624  else if BSXEND(uint64NDArray)
625  else
626  retval(0) = C;
627  }
628  }
629 
630  return retval;
631 }
632 
633 /*
634 
635 %!shared a, b, c, f
636 %! a = randn (4, 4);
637 %! b = mean (a, 1);
638 %! c = mean (a, 2);
639 %! f = @minus;
640 %!error (bsxfun (f))
641 %!error (bsxfun (f, a))
642 %!error (bsxfun (a, b))
643 %!error (bsxfun (a, b, c))
644 %!error (bsxfun (f, a, b, c))
645 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
646 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
647 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
648 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
649 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
650 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
651 
652 %!shared a, b, c, f
653 %! a = randn (4, 4);
654 %! a(1) *= 1i;
655 %! b = mean (a, 1);
656 %! c = mean (a, 2);
657 %! f = @minus;
658 %!error (bsxfun (f))
659 %!error (bsxfun (f, a))
660 %!error (bsxfun (a, b))
661 %!error (bsxfun (a, b, c))
662 %!error (bsxfun (f, a, b, c))
663 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
664 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
665 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
666 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
667 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
668 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
669 
670 %!shared a, b, c, f
671 %! a = randn (4, 4);
672 %! a(end) *= 1i;
673 %! b = mean (a, 1);
674 %! c = mean (a, 2);
675 %! f = @minus;
676 %!error (bsxfun (f))
677 %!error (bsxfun (f, a))
678 %!error (bsxfun (a, b))
679 %!error (bsxfun (a, b, c))
680 %!error (bsxfun (f, a, b, c))
681 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
682 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
683 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
684 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
685 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
686 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
687 
688 %!shared a, b, c, f
689 %! a = randn (4, 4);
690 %! b = a (1, :);
691 %! c = a (:, 1);
692 %! f = @(x, y) x == y;
693 %!error (bsxfun (f))
694 %!error (bsxfun (f, a))
695 %!error (bsxfun (a, b))
696 %!error (bsxfun (a, b, c))
697 %!error (bsxfun (f, a, b, c))
698 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
699 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
700 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
701 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
702 %!assert (bsxfun (f, a, c), a == repmat (c, 1, 4))
703 
704 %!shared a, b, c, d, f
705 %! a = randn (4, 4, 4);
706 %! b = mean (a, 1);
707 %! c = mean (a, 2);
708 %! d = mean (a, 3);
709 %! f = @minus;
710 %!error (bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4])))
711 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
712 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
713 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
714 %!assert (bsxfun (f, ones ([4, 4, 1]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
715 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 4])), zeros ([4, 4, 4]))
716 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 1])), zeros ([4, 4, 4]))
717 %!assert (bsxfun (f, a, b), a - repmat (b, [4, 1, 1]))
718 %!assert (bsxfun (f, a, c), a - repmat (c, [1, 4, 1]))
719 %!assert (bsxfun (f, a, d), a - repmat (d, [1, 1, 4]))
720 %!assert (bsxfun ("minus", ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
721 
722 ## The test below is a very hard case to treat
723 %!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])), zeros ([4, 4, 4, 4]))
724 
725 %!shared a, b, aa, bb
726 %! ## FIXME: Set a known "good" random seed. See bug #51779.
727 %! old_nstate = randn ("state");
728 %! restore_nstate = onCleanup (@() randn ("state", old_nstate));
729 %! randn ("state", 42); # initialize generator to make behavior reproducible
730 %! a = randn (3, 1, 3);
731 %! aa = a(:, ones (1, 3), :, ones (1, 3));
732 %! b = randn (1, 3, 3, 3);
733 %! bb = b(ones (1, 3), :, :, :);
734 %!assert (bsxfun (@plus, a, b), aa + bb)
735 %!assert (bsxfun (@minus, a, b), aa - bb)
736 %!assert (bsxfun (@times, a, b), aa .* bb)
737 %!assert (bsxfun (@rdivide, a, b), aa ./ bb)
738 %!assert (bsxfun (@ldivide, a, b), aa .\ bb)
739 %!assert (bsxfun (@power, a, b), aa .^ bb)
740 %!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
741 %!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
742 %!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
743 %!assert (bsxfun (@lt, a, b), aa < bb)
744 %!assert (bsxfun (@le, a, b), aa <= bb)
745 %!assert (bsxfun (@gt, a, b), aa > bb)
746 %!assert (bsxfun (@ge, a, b), aa >= bb)
747 %!assert (bsxfun (@min, a, b), min (aa, bb))
748 %!assert (bsxfun (@max, a, b), max (aa, bb))
749 %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
750 %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
751 
752 ## Test automatic bsxfun
753 %
754 %!test
755 %! funs = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
756 %! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
757 %! @and, @or, @xor };
758 %!
759 %! float_types = {@single, @double};
760 %! int_types = {@int8, @int16, @int32, @int64, ...
761 %! @uint8, @uint16, @uint32, @uint64};
762 %!
763 %! ## FIXME: Set a known "good" random seed. See bug #51779.
764 %! old_state = rand ("state");
765 %! restore_state = onCleanup (@() rand ("state", old_state));
766 %! rand ("state", 42); # initialize generator to make behavior reproducible
767 %!
768 %! x = rand (3) * 10-5;
769 %! y = rand (3,1) * 10-5;
770 %!
771 %! for i=1:length (funs)
772 %! for j = 1:length (float_types)
773 %! for k = 1:length (int_types)
774 %!
775 %! fun = funs{i};
776 %! f_type = float_types{j};
777 %! i_type = int_types{k};
778 %!
779 %! assert (bsxfun (fun, f_type (x), i_type (y)), ...
780 %! fun (f_type(x), i_type (y)));
781 %! assert (bsxfun (fun, f_type (y), i_type (x)), ...
782 %! fun (f_type(y), i_type (x)));
783 %!
784 %! assert (bsxfun (fun, i_type (x), i_type (y)), ...
785 %! fun (i_type (x), i_type (y)));
786 %! assert (bsxfun (fun, i_type (y), i_type (x)), ...
787 %! fun (i_type (y), i_type (x)));
788 %!
789 %! assert (bsxfun (fun, f_type (x), f_type (y)), ...
790 %! fun (f_type (x), f_type (y)));
791 %! assert (bsxfun (fun, f_type(y), f_type(x)), ...
792 %! fun (f_type (y), f_type (x)));
793 %! endfor
794 %! endfor
795 %! endfor
796 
797 ## Automatic broadcasting with zero length dimensions
798 %!assert <*47085> ([1 2 3] .+ zeros (0, 3), zeros (0, 3))
799 %!assert <*47085> (rand (3, 3, 1) .+ rand (3, 3, 0), zeros (3, 3, 0))
800 
801 ## In-place broadcasting with zero length dimensions
802 %!test <*47085>
803 %! a = zeros (0, 3);
804 %! a .+= [1 2 3];
805 %! assert (a, zeros (0, 3));
806 
807 %!test <*53179>
808 %! im = ones (4,4,2) + single (i);
809 %! mask = true (4,4);
810 %! mask(:,1:2) = false;
811 %! r = bsxfun (@times, im, mask);
812 %! assert (r(:,:,1), repmat (single ([0, 0, 1+i, 1+i]), [4, 1]));
813 
814 */
ComplexNDArray bsxfun_pow(const ComplexNDArray &x, const ComplexNDArray &y)
Definition: CNDArray.cc:663
#define C(a, b)
Definition: Faddeeva.cc:246
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
static octave_value bsxfun_forward_rel(const octave_value &x, const octave_value &y)
Definition: bsxfun.cc:113
static bool maybe_update_column(octave_value &Ac, const octave_value &A, const dim_vector &dva, const dim_vector &dvc, octave_idx_type i, octave_value_list &idx)
Definition: bsxfun.cc:235
static octave_value bsxfun_forward_op(const octave_value &x, const octave_value &y)
Definition: bsxfun.cc:104
#define REGISTER_STD_HANDLERS(BTYP, NDA)
static octave_value do_bsxfun_real_pow(const octave_value &x, const octave_value &y)
Definition: bsxfun.cc:124
bsxfun_handler bsxfun_handler_table[bsxfun_num_builtin_ops][btyp_num_types]
Definition: bsxfun.cc:100
bsxfun_builtin_op
Definition: bsxfun.cc:47
@ bsxfun_builtin_le
Definition: bsxfun.cc:57
@ bsxfun_builtin_min
Definition: bsxfun.cc:53
@ bsxfun_builtin_divide
Definition: bsxfun.cc:51
@ bsxfun_builtin_eq
Definition: bsxfun.cc:54
@ bsxfun_builtin_or
Definition: bsxfun.cc:61
@ bsxfun_builtin_unknown
Definition: bsxfun.cc:63
@ bsxfun_builtin_ge
Definition: bsxfun.cc:59
@ bsxfun_builtin_plus
Definition: bsxfun.cc:48
@ bsxfun_builtin_times
Definition: bsxfun.cc:50
@ bsxfun_builtin_and
Definition: bsxfun.cc:60
@ bsxfun_builtin_gt
Definition: bsxfun.cc:58
@ bsxfun_builtin_power
Definition: bsxfun.cc:62
@ bsxfun_builtin_ne
Definition: bsxfun.cc:55
@ bsxfun_builtin_minus
Definition: bsxfun.cc:49
@ bsxfun_builtin_lt
Definition: bsxfun.cc:56
@ bsxfun_builtin_max
Definition: bsxfun.cc:52
@ bsxfun_num_builtin_ops
Definition: bsxfun.cc:64
static bsxfun_builtin_op bsxfun_builtin_lookup(const std::string &name)
Definition: bsxfun.cc:87
#define BSXDEF(T)
#define BSXINIT(T, CLS, EXTRACTOR)
static void update_index(Array< int > &idx, const dim_vector &dv, octave_idx_type i)
Definition: bsxfun.cc:311
const char * bsxfun_builtin_names[]
Definition: bsxfun.cc:67
#define BSXEND(T)
#define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL)
#define BSXLOOP(T, CLS, EXTRACTOR)
static octave_value maybe_optimized_builtin(const std::string &name, const octave_value &a, const octave_value &b)
Definition: bsxfun.cc:200
octave_value(* bsxfun_handler)(const octave_value &, const octave_value &)
Definition: bsxfun.cc:96
static void maybe_fill_table(void)
Definition: bsxfun.cc:134
#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.cc:1011
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition: dim-vector.h:401
void resize(int n, int fill_value=0)
Definition: dim-vector.h:349
octave_idx_type ndims(void) const
Number of dimensions.
Definition: dim-vector.h:334
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
std::string name(void) const
Definition: ov-fcn.h:214
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
Array< octave_value > array_value(void) const
Definition: ovl.h:90
builtin_type_t builtin_type(void) const
Definition: ov.h:643
bool is_builtin_function(void) const
Definition: ov.h:742
bool is_string(void) const
Definition: ov.h:593
bool is_defined(void) const
Definition: ov.h:551
bool is_function_handle(void) const
Definition: ov.h:721
octave_function * function_value(bool silent=false) const
std::string string_value(bool force=false) const
Definition: ov.h:927
octave_value single_subsref(const std::string &type, const octave_value_list &idx)
bool is_undefined(void) const
Definition: ov.h:554
OCTINTERP_API void print_usage(void)
Definition: defun.cc:53
#define DEFMETHOD(name, interp_name, args_name, nargout_name, doc)
Macro to define a builtin method.
Definition: defun.h:138
void error(const char *fmt,...)
Definition: error.cc:968
QString name
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
octave_value_list feval(const char *name, const octave_value_list &args, int nargout)
Evaluate an Octave function (built-in or interpreted) and return the list of result values.
Definition: oct-parse.cc:9580
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:72
@ btyp_float_complex
Definition: ov-base.h:76
@ btyp_double
Definition: ov-base.h:73
@ btyp_int32
Definition: ov-base.h:79
@ btyp_float
Definition: ov-base.h:74
@ btyp_uint16
Definition: ov-base.h:82
@ btyp_int64
Definition: ov-base.h:80
@ btyp_bool
Definition: ov-base.h:85
@ btyp_unknown
Definition: ov-base.h:90
@ btyp_uint64
Definition: ov-base.h:84
@ btyp_int16
Definition: ov-base.h:78
@ btyp_uint32
Definition: ov-base.h:83
@ btyp_num_types
Definition: ov-base.h:91
@ btyp_char
Definition: ov-base.h:86
@ btyp_uint8
Definition: ov-base.h:81
@ btyp_int8
Definition: ov-base.h:77
@ btyp_complex
Definition: ov-base.h:75
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
OCTINTERP_API octave_value do_cat_op(octave::type_info &ti, const octave_value &a, const octave_value &b, const Array< octave_idx_type > &ra_idx)