GNU Octave  8.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-2023 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 {
203  octave_value retval;
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 
324 
325 DEFMETHOD (bsxfun, interp, args, ,
326  doc: /* -*- texinfo -*-
327 @deftypefn {} {@var{C} =} bsxfun (@var{f}, @var{A}, @var{B})
328 Apply a binary function @var{f} element-by-element to two array arguments
329 @var{A} and @var{B}, expanding singleton dimensions in either input argument as
330 necessary.
331 
332 @var{f} is a function handle, inline function, or string containing the name
333 of the function to evaluate. The function @var{f} must be capable of accepting
334 two column-vector arguments of equal length, or one column vector argument and
335 a scalar.
336 
337 The dimensions of @var{A} and @var{B} must be equal or singleton. The
338 singleton dimensions of the arrays will be expanded to the same dimensionality
339 as the other array.
340 @seealso{arrayfun, cellfun}
341 @end deftypefn */)
342 {
343  if (args.length () != 3)
344  print_usage ();
345 
346  octave_value fcn = args(0);
347  if (fcn.is_string ())
348  {
349  std::string name = fcn.string_value ();
350 
351  symbol_table& symtab = interp.get_symbol_table ();
352 
353  fcn = symtab.find_function (name);
354 
355  if (fcn.is_undefined ())
356  error ("bsxfun: invalid function name: %s", name.c_str ());
357  }
358  else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
359  error ("bsxfun: F must be a string or function handle");
360 
361  octave_value_list retval;
362 
363  const octave_value A = args(1);
364  const octave_value B = args(2);
365 
366  if (fcn.is_builtin_function ()
367  || (fcn.is_function_handle () && ! A.isobject () && ! B.isobject ()))
368  {
369  // This may break if the default behavior is overridden. But if you
370  // override arithmetic operators for builtin classes, you should expect
371  // mayhem anyway (constant folding etc). Querying is_overloaded() may
372  // not be exactly what we need here.
373  octave_function *fcn_val = fcn.function_value ();
374  if (fcn_val)
375  {
376  octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
377  if (tmp.is_defined ())
378  retval(0) = tmp;
379  }
380  }
381 
382  if (retval.empty ())
383  {
384  dim_vector dva = A.dims ();
385  octave_idx_type nda = dva.ndims ();
386  dim_vector dvb = B.dims ();
387  octave_idx_type ndb = dvb.ndims ();
388  octave_idx_type nd = nda;
389 
390  if (nda > ndb)
391  dvb.resize (nda, 1);
392  else if (nda < ndb)
393  {
394  dva.resize (ndb, 1);
395  nd = ndb;
396  }
397 
398  for (octave_idx_type i = 0; i < nd; i++)
399  if (dva(i) != dvb(i) && dva(i) != 1 && dvb(i) != 1)
400  error ("bsxfun: dimensions of A and B must match");
401 
402  // Find the size of the output
403  dim_vector dvc;
404  dvc.resize (nd);
405 
406  for (octave_idx_type i = 0; i < nd; i++)
407  dvc(i) = (dva(i) < 1 ? dva(i)
408  : (dvb(i) < 1 ? dvb(i)
409  : (dva(i) > dvb(i) ? dva(i)
410  : dvb(i))));
411 
412  if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
413  {
414  octave_value_list inputs (2);
415  inputs(0) = A;
416  inputs(1) = B;
417  retval = feval (fcn, inputs, 1);
418  }
419  else if (dvc.numel () < 1)
420  {
421  octave_value_list inputs (2);
422  inputs(0) = A.resize (dvc);
423  inputs(1) = B.resize (dvc);
424  retval = feval (fcn, inputs, 1);
425  }
426  else
427  {
428  octave_idx_type ncount = 1;
429  for (octave_idx_type i = 1; i < nd; i++)
430  ncount *= dvc(i);
431 
432 #define BSXDEF(T) \
433  T result_ ## T; \
434  bool have_ ## T = false;
435 
436  BSXDEF(NDArray);
449 
450  octave_value Ac;
451  octave_value_list idxA;
452  octave_value Bc;
453  octave_value_list idxB;
454  octave_value C;
455  octave_value_list inputs (2);
456  Array<int> ra_idx (dim_vector (dvc.ndims (), 1), 0);
457 
458  for (octave_idx_type i = 0; i < ncount; i++)
459  {
460  if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
461  inputs(0) = Ac;
462 
463  if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
464  inputs(1) = Bc;
465 
466  octave_value_list tmp = feval (fcn, inputs, 1);
467 
468 #define BSXINIT(T, CLS, EXTRACTOR) \
469  (result_type == CLS) \
470  { \
471  have_ ## T = true; \
472  result_ ## T = tmp(0). EXTRACTOR ## _array_value (); \
473  result_ ## T .resize (dvc); \
474  }
475 
476  if (i == 0)
477  {
478  if (! tmp(0).issparse ())
479  {
480  std::string result_type = tmp(0).class_name ();
481  if (result_type == "double")
482  {
483  if (tmp(0).isreal ())
484  {
485  have_NDArray = true;
486  result_NDArray = tmp(0).array_value ();
487  result_NDArray.resize (dvc);
488  }
489  else
490  {
491  have_ComplexNDArray = true;
492  result_ComplexNDArray
493  = tmp(0).complex_array_value ();
494  result_ComplexNDArray.resize (dvc);
495  }
496  }
497  else if (result_type == "single")
498  {
499  if (tmp(0).isreal ())
500  {
501  have_FloatNDArray = true;
502  result_FloatNDArray
503  = tmp(0).float_array_value ();
504  result_FloatNDArray.resize (dvc);
505  }
506  else
507  {
508  have_FloatComplexNDArray = true;
509  result_FloatComplexNDArray
510  = tmp(0).float_complex_array_value ();
511  result_FloatComplexNDArray.resize (dvc);
512  }
513  }
514  else if BSXINIT(boolNDArray, "logical", bool)
515  else if BSXINIT(int8NDArray, "int8", int8)
516  else if BSXINIT(int16NDArray, "int16", int16)
517  else if BSXINIT(int32NDArray, "int32", int32)
518  else if BSXINIT(int64NDArray, "int64", int64)
519  else if BSXINIT(uint8NDArray, "uint8", uint8)
520  else if BSXINIT(uint16NDArray, "uint16", uint16)
521  else if BSXINIT(uint32NDArray, "uint32", uint32)
522  else if BSXINIT(uint64NDArray, "uint64", uint64)
523  else
524  {
525  C = tmp(0);
526  C = C.resize (dvc);
527  }
528  }
529  else // Skip semi-fast path for sparse matrices
530  {
531  C = tmp (0);
532  C = C.resize (dvc);
533  }
534  }
535  else
536  {
537  update_index (ra_idx, dvc, i);
538 
539  if (have_NDArray)
540  {
541  if (! tmp(0).isfloat ())
542  {
543  have_NDArray = false;
544  C = result_NDArray;
545  C = cat_op (C, tmp(0), ra_idx);
546  }
547  else if (tmp(0).isreal ())
548  result_NDArray.insert (tmp(0).array_value (), ra_idx);
549  else
550  {
551  result_ComplexNDArray
552  = ComplexNDArray (result_NDArray);
553  result_ComplexNDArray.insert
554  (tmp(0).complex_array_value (), ra_idx);
555  have_NDArray = false;
556  have_ComplexNDArray = true;
557  }
558  }
559  else if (have_FloatNDArray)
560  {
561  if (! tmp(0).isfloat ())
562  {
563  have_FloatNDArray = false;
564  C = result_FloatNDArray;
565  C = cat_op (C, tmp(0), ra_idx);
566  }
567  else if (tmp(0).isreal ())
568  result_FloatNDArray.insert
569  (tmp(0).float_array_value (), ra_idx);
570  else
571  {
572  result_FloatComplexNDArray
573  = FloatComplexNDArray (result_FloatNDArray);
574  result_FloatComplexNDArray.insert
575  (tmp(0).float_complex_array_value (), ra_idx);
576  have_FloatNDArray = false;
577  have_FloatComplexNDArray = true;
578  }
579  }
580 
581 #define BSXLOOP(T, CLS, EXTRACTOR) \
582  (have_ ## T) \
583  { \
584  if (tmp(0).class_name () != CLS) \
585  { \
586  have_ ## T = false; \
587  C = result_ ## T; \
588  C = cat_op (C, tmp(0), ra_idx); \
589  } \
590  else \
591  result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
592  }
593 
594  else if BSXLOOP(ComplexNDArray, "double", complex)
595  else if BSXLOOP(FloatComplexNDArray, "single", float_complex)
596  else if BSXLOOP(boolNDArray, "logical", bool)
597  else if BSXLOOP(int8NDArray, "int8", int8)
598  else if BSXLOOP(int16NDArray, "int16", int16)
599  else if BSXLOOP(int32NDArray, "int32", int32)
600  else if BSXLOOP(int64NDArray, "int64", int64)
601  else if BSXLOOP(uint8NDArray, "uint8", uint8)
602  else if BSXLOOP(uint16NDArray, "uint16", uint16)
603  else if BSXLOOP(uint32NDArray, "uint32", uint32)
604  else if BSXLOOP(uint64NDArray, "uint64", uint64)
605  else
606  C = cat_op (C, tmp(0), ra_idx);
607  }
608  }
609 
610 #define BSXEND(T) \
611  (have_ ## T) \
612  retval(0) = result_ ## T;
613 
614  if BSXEND(NDArray)
615  else if BSXEND(ComplexNDArray)
616  else if BSXEND(FloatNDArray)
617  else if BSXEND(FloatComplexNDArray)
618  else if BSXEND(boolNDArray)
619  else if BSXEND(int8NDArray)
620  else if BSXEND(int16NDArray)
621  else if BSXEND(int32NDArray)
622  else if BSXEND(int64NDArray)
623  else if BSXEND(uint8NDArray)
624  else if BSXEND(uint16NDArray)
625  else if BSXEND(uint32NDArray)
626  else if BSXEND(uint64NDArray)
627  else
628  retval(0) = C;
629  }
630  }
631 
632  return retval;
633 }
634 
635 /*
636 
637 %!shared a, b, c, f
638 %! a = randn (4, 4);
639 %! b = mean (a, 1);
640 %! c = mean (a, 2);
641 %! f = @minus;
642 %!error bsxfun (f)
643 %!error bsxfun (f, a)
644 %!error bsxfun (a, b)
645 %!error bsxfun (a, b, c)
646 %!error bsxfun (f, a, b, c)
647 %!error bsxfun (f, ones (4, 0), ones (4, 4))
648 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
649 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
650 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
651 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
652 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
653 
654 %!shared a, b, c, f
655 %! a = randn (4, 4);
656 %! a(1) *= 1i;
657 %! b = mean (a, 1);
658 %! c = mean (a, 2);
659 %! f = @minus;
660 %!error bsxfun (f)
661 %!error bsxfun (f, a)
662 %!error bsxfun (a, b)
663 %!error bsxfun (a, b, c)
664 %!error bsxfun (f, a, b, c)
665 %!error bsxfun (f, ones (4, 0), ones (4, 4))
666 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
667 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
668 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
669 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
670 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
671 
672 %!shared a, b, c, f
673 %! a = randn (4, 4);
674 %! a(end) *= 1i;
675 %! b = mean (a, 1);
676 %! c = mean (a, 2);
677 %! f = @minus;
678 %!error bsxfun (f)
679 %!error bsxfun (f, a)
680 %!error bsxfun (a, b)
681 %!error bsxfun (a, b, c)
682 %!error bsxfun (f, a, b, c)
683 %!error bsxfun (f, ones (4, 0), ones (4, 4))
684 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
685 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
686 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
687 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
688 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
689 
690 %!shared a, b, c, f
691 %! a = randn (4, 4);
692 %! b = a (1, :);
693 %! c = a (:, 1);
694 %! f = @(x, y) x == y;
695 %!error bsxfun (f)
696 %!error bsxfun (f, a)
697 %!error bsxfun (a, b)
698 %!error bsxfun (a, b, c)
699 %!error bsxfun (f, a, b, c)
700 %!error bsxfun (f, ones (4, 0), ones (4, 4))
701 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
702 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
703 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
704 %!assert (bsxfun (f, a, c), a == repmat (c, 1, 4))
705 
706 %!shared a, b, c, d, f
707 %! a = randn (4, 4, 4);
708 %! b = mean (a, 1);
709 %! c = mean (a, 2);
710 %! d = mean (a, 3);
711 %! f = @minus;
712 %!error bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4]))
713 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
714 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
715 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
716 %!assert (bsxfun (f, ones ([4, 4, 1]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
717 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 4])), zeros ([4, 4, 4]))
718 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 1])), zeros ([4, 4, 4]))
719 %!assert (bsxfun (f, a, b), a - repmat (b, [4, 1, 1]))
720 %!assert (bsxfun (f, a, c), a - repmat (c, [1, 4, 1]))
721 %!assert (bsxfun (f, a, d), a - repmat (d, [1, 1, 4]))
722 %!assert (bsxfun ("minus", ones ([4, 0, 4]), ones ([4, 1, 4])),
723 %! zeros ([4, 0, 4]))
724 
725 ## The test below is a very hard case to treat
726 %!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])),
727 %! zeros ([4, 4, 4, 4]))
728 
729 %!shared a, b, aa, bb
730 %! ## FIXME: Set a known "good" random seed. See bug #51779.
731 %! old_nstate = randn ("state");
732 %! restore_nstate = onCleanup (@() randn ("state", old_nstate));
733 %! randn ("state", 42); # initialize generator to make behavior reproducible
734 %! a = randn (3, 1, 3);
735 %! aa = a(:, ones (1, 3), :, ones (1, 3));
736 %! b = randn (1, 3, 3, 3);
737 %! bb = b(ones (1, 3), :, :, :);
738 %!assert (bsxfun (@plus, a, b), aa + bb)
739 %!assert (bsxfun (@minus, a, b), aa - bb)
740 %!assert (bsxfun (@times, a, b), aa .* bb)
741 %!assert (bsxfun (@rdivide, a, b), aa ./ bb)
742 %!assert (bsxfun (@ldivide, a, b), aa .\ bb)
743 %!assert (bsxfun (@power, a, b), aa .^ bb)
744 %!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
745 %!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
746 %!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
747 %!assert (bsxfun (@lt, a, b), aa < bb)
748 %!assert (bsxfun (@le, a, b), aa <= bb)
749 %!assert (bsxfun (@gt, a, b), aa > bb)
750 %!assert (bsxfun (@ge, a, b), aa >= bb)
751 %!assert (bsxfun (@min, a, b), min (aa, bb))
752 %!assert (bsxfun (@max, a, b), max (aa, bb))
753 %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
754 %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
755 
756 ## Test automatic bsxfun
757 %
758 %!test
759 %! fcns = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
760 %! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
761 %! @and, @or, @xor };
762 %!
763 %! float_types = {@single, @double};
764 %! int_types = {@int8, @int16, @int32, @int64, ...
765 %! @uint8, @uint16, @uint32, @uint64};
766 %!
767 %! ## FIXME: Set a known "good" random seed. See bug #51779.
768 %! old_state = rand ("state");
769 %! restore_state = onCleanup (@() rand ("state", old_state));
770 %! rand ("state", 42); # initialize generator to make behavior reproducible
771 %!
772 %! x = rand (3) * 10-5;
773 %! y = rand (3,1) * 10-5;
774 %!
775 %! for i=1:length (fcns)
776 %! for j = 1:length (float_types)
777 %! for k = 1:length (int_types)
778 %!
779 %! fcn = fcns{i};
780 %! f_type = float_types{j};
781 %! i_type = int_types{k};
782 %!
783 %! assert (bsxfun (fcn, f_type (x), i_type (y)), ...
784 %! fcn (f_type(x), i_type (y)));
785 %! assert (bsxfun (fcn, f_type (y), i_type (x)), ...
786 %! fcn (f_type(y), i_type (x)));
787 %!
788 %! assert (bsxfun (fcn, i_type (x), i_type (y)), ...
789 %! fcn (i_type (x), i_type (y)));
790 %! assert (bsxfun (fcn, i_type (y), i_type (x)), ...
791 %! fcn (i_type (y), i_type (x)));
792 %!
793 %! assert (bsxfun (fcn, f_type (x), f_type (y)), ...
794 %! fcn (f_type (x), f_type (y)));
795 %! assert (bsxfun (fcn, f_type(y), f_type(x)), ...
796 %! fcn (f_type (y), f_type (x)));
797 %! endfor
798 %! endfor
799 %! endfor
800 
801 ## Automatic broadcasting with zero length dimensions
802 %!assert <*47085> ([1 2 3] + zeros (0, 3), zeros (0, 3))
803 %!assert <*47085> (rand (3, 3, 1) + rand (3, 3, 0), zeros (3, 3, 0))
804 
805 ## In-place broadcasting with zero length dimensions
806 %!test <*47085>
807 %! a = zeros (0, 3);
808 %! a += [1 2 3];
809 %! assert (a, zeros (0, 3));
810 
811 %!test <*53179>
812 %! im = ones (4,4,2) + single (i);
813 %! mask = true (4,4);
814 %! mask(:,1:2) = false;
815 %! r = bsxfun (@times, im, mask);
816 %! assert (r(:,:,1), repmat (single ([0, 0, 1+i, 1+i]), [4, 1]));
817 
818 ## automatic broadcasting with inplace times operator
819 %!test <*38466>
820 %! a = ones (2, 2, 2);
821 %! b = 2 * ones (2, 1);
822 %! a .*= b;
823 %! assert (a, 2 * ones (2, 2, 2));
824 
825 %!test <*38466>
826 %! a = ones (2, 2, 2);
827 %! b = 2 * ones (1, 2);
828 %! a .*= b;
829 %! assert (a, 2 * ones (2, 2, 2));
830 
831 %!test <*38466>
832 %! a = ones (2, 2, 2);
833 %! b = 2 * ones (2, 2);
834 %! a .*= b;
835 %! assert (a, 2 * ones (2, 2, 2));
836 
837 %!test <*38466>
838 %! a = ones (2, 2, 2);
839 %! b = 2 * ones (1, 1, 2);
840 %! a .*= b;
841 %! assert (a, 2 * ones (2, 2, 2));
842 
843 %!assert (ones (2,2,2) .* ones (1,2), ones (2,2,2));
844 
845 */
846 
OCTAVE_END_NAMESPACE(octave)
ComplexNDArray bsxfun_pow(const ComplexNDArray &x, const ComplexNDArray &y)
Definition: CNDArray.cc:664
#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
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
OCTARRAY_API void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Definition: Array-base.cc:1032
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(void) const
Number of dimensions.
Definition: dim-vector.h:257
std::string name(void) const
Definition: ov-fcn.h:208
bool empty(void) const
Definition: ovl.h:115
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
OCTINTERP_API octave_function * function_value(bool silent=false) const
builtin_type_t builtin_type(void) const
Definition: ov.h:735
bool is_builtin_function(void) const
Definition: ov.h:834
bool is_string(void) const
Definition: ov.h:682
bool is_defined(void) const
Definition: ov.h:637
bool is_function_handle(void) const
Definition: ov.h:813
std::string string_value(bool force=false) const
Definition: ov.h:1019
bool is_undefined(void) const
Definition: ov.h:640
OCTINTERP_API octave_value single_subsref(const std::string &type, const octave_value_list &idx)
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope())
Definition: symtab.cc:249
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
OCTINTERP_API 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:979
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
class OCTAVE_API ComplexNDArray
Definition: mx-fwd.h:39
class OCTAVE_API FloatComplexNDArray
Definition: mx-fwd.h:41
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:10370
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
OCTINTERP_API octave_value cat_op(type_info &ti, const octave_value &a, const octave_value &b, const Array< octave_idx_type > &ra_idx)