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