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