GNU Octave  3.8.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-2013 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);
180  FloatComplexNDArray, 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 (), btyp_b = b.builtin_type ();
205 
206  // Simplify single/double combinations.
207  if (btyp_a == btyp_float && btyp_b == btyp_double)
208  btyp_b = btyp_float;
209  else if (btyp_a == btyp_double && btyp_b == btyp_float)
210  btyp_a = btyp_float;
211  else if (btyp_a == btyp_float_complex && btyp_b == btyp_complex)
212  btyp_b = btyp_float_complex;
213  else if (btyp_a == btyp_complex && btyp_b == btyp_float_complex)
214  btyp_a = btyp_float_complex;
215 
216  if (btyp_a == btyp_b && btyp_a != btyp_unknown)
217  {
218  bsxfun_handler handler = bsxfun_handler_table[op][btyp_a];
219  if (handler)
220  retval = handler (a, b);
221  }
222  }
223 
224  return retval;
225 }
226 
227 static bool
229  const dim_vector& dva, const dim_vector& dvc,
231 {
232  octave_idx_type nd = dva.length ();
233 
234  if (i == 0)
235  {
236  idx(0) = octave_value (':');
237  for (octave_idx_type j = 1; j < nd; j++)
238  {
239  if (dva (j) == 1)
240  idx(j) = octave_value (1);
241  else
242  idx(j) = octave_value ((i % dvc(j)) + 1);
243 
244  i = i / dvc (j);
245  }
246 
247  Ac = A;
248  Ac = Ac.single_subsref ("(", idx);
249  return true;
250  }
251  else
252  {
253  bool is_changed = false;
254  octave_idx_type k = i;
255  octave_idx_type k1 = i - 1;
256  for (octave_idx_type j = 1; j < nd; j++)
257  {
258  if (dva(j) != 1 && k % dvc (j) != k1 % dvc (j))
259  {
260  idx (j) = octave_value ((k % dvc(j)) + 1);
261  is_changed = true;
262  }
263 
264  k = k / dvc (j);
265  k1 = k1 / dvc (j);
266  }
267 
268  if (is_changed)
269  {
270  Ac = A;
271  Ac = Ac.single_subsref ("(", idx);
272  return true;
273  }
274  else
275  return false;
276  }
277 }
278 
279 #if 0
280 // FIXME: this function is not used; is it OK to delete it?
281 static void
283 {
284  octave_idx_type nd = dv.length ();
285 
286  if (i == 0)
287  {
288  for (octave_idx_type j = nd - 1; j > 0; j--)
289  idx(j) = octave_value (static_cast<double>(1));
290  idx(0) = octave_value (':');
291  }
292  else
293  {
294  for (octave_idx_type j = 1; j < nd; j++)
295  {
296  idx (j) = octave_value (i % dv (j) + 1);
297  i = i / dv (j);
298  }
299  }
300 }
301 #endif
302 
303 static void
305 {
306  octave_idx_type nd = dv.length ();
307 
308  idx(0) = 0;
309  for (octave_idx_type j = 1; j < nd; j++)
310  {
311  idx (j) = i % dv (j);
312  i = i / dv (j);
313  }
314 }
315 
316 DEFUN (bsxfun, args, ,
317  "-*- texinfo -*-\n\
318 @deftypefn {Built-in Function} {} bsxfun (@var{f}, @var{A}, @var{B})\n\
319 The binary singleton expansion function applier performs broadcasting,\n\
320 that is, applies a binary function @var{f} element-by-element to two\n\
321 array arguments @var{A} and @var{B}, and expands as necessary\n\
322 singleton dimensions in either input argument. @var{f} is a function\n\
323 handle, inline function, or string containing the name of the function\n\
324 to evaluate. The function @var{f} must be capable of accepting two\n\
325 column-vector arguments of equal length, or one column vector argument\n\
326 and a scalar.\n\
327 \n\
328 The dimensions of @var{A} and @var{B} must be equal or singleton. The\n\
329 singleton dimensions of the arrays will be expanded to the same\n\
330 dimensionality as the other array.\n\
331 @seealso{arrayfun, cellfun}\n\
332 @end deftypefn")
333 {
334  int nargin = args.length ();
335  octave_value_list retval;
336 
337  if (nargin != 3)
338  print_usage ();
339  else
340  {
341  octave_value func = args(0);
342 
343  if (func.is_string ())
344  {
345  std::string name = func.string_value ();
346  func = symbol_table::find_function (name);
347  if (func.is_undefined ())
348  error ("bsxfun: invalid function name: %s", name.c_str ());
349  }
350  else if (! (args(0).is_function_handle ()
351  || args(0).is_inline_function ()))
352  error ("bsxfun: F must be a string or function handle");
353 
354  const octave_value A = args (1);
355  const octave_value B = args (2);
356 
357  if (func.is_builtin_function ()
358  || (func.is_function_handle ()
359  && ! A.is_object () && ! B.is_object ()))
360  {
361  // This may break if the default behavior is overriden. But if you
362  // override arithmetic operators for builtin classes, you should
363  // expect mayhem anyway (constant folding etc). Querying
364  // is_overloaded() may not be exactly what we need here.
365  octave_function *fcn_val = func.function_value ();
366  if (fcn_val)
367  {
368  octave_value tmp = maybe_optimized_builtin (fcn_val->name (),
369  A, B);
370  if (tmp.is_defined ())
371  retval(0) = tmp;
372  }
373  }
374 
375  if (! error_state && retval.empty ())
376  {
377  dim_vector dva = A.dims ();
378  octave_idx_type nda = dva.length ();
379  dim_vector dvb = B.dims ();
380  octave_idx_type ndb = dvb.length ();
381  octave_idx_type nd = nda;
382 
383  if (nda > ndb)
384  dvb.resize (nda, 1);
385  else if (nda < ndb)
386  {
387  dva.resize (ndb, 1);
388  nd = ndb;
389  }
390 
391  for (octave_idx_type i = 0; i < nd; i++)
392  if (dva (i) != dvb (i) && dva (i) != 1 && dvb (i) != 1)
393  {
394  error ("bsxfun: dimensions of A and B must match");
395  break;
396  }
397 
398  if (!error_state)
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)
408  ? dva (i) : dvb (i))));
409 
410  if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
411  {
412  octave_value_list inputs;
413  inputs (0) = A;
414  inputs (1) = B;
415  retval = func.do_multi_index_op (1, inputs);
416  }
417  else if (dvc.numel () < 1)
418  {
419  octave_value_list inputs;
420  inputs (0) = A.resize (dvc);
421  inputs (1) = B.resize (dvc);
422  retval = func.do_multi_index_op (1, inputs);
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;
454  Array<int> ra_idx (dim_vector (dvc.length (), 1), 0);
455 
456 
457  for (octave_idx_type i = 0; i < ncount; i++)
458  {
459  if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
460  inputs (0) = Ac;
461 
462  if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
463  inputs (1) = Bc;
464 
465  octave_value_list tmp = func.do_multi_index_op (1,
466  inputs);
467 
468  if (error_state)
469  break;
470 
471 #define BSXINIT(T, CLS, EXTRACTOR) \
472  (result_type == CLS) \
473  { \
474  have_ ## T = true; \
475  result_ ## T = \
476  tmp (0). EXTRACTOR ## _array_value (); \
477  result_ ## T .resize (dvc); \
478  }
479 
480  if (i == 0)
481  {
482  if (! tmp(0).is_sparse_type ())
483  {
484  std::string result_type = tmp(0).class_name ();
485  if (result_type == "double")
486  {
487  if (tmp(0).is_real_type ())
488  {
489  have_NDArray = true;
490  result_NDArray = tmp(0).array_value ();
491  result_NDArray.resize (dvc);
492  }
493  else
494  {
495  have_ComplexNDArray = true;
496  result_ComplexNDArray =
497  tmp(0).complex_array_value ();
498  result_ComplexNDArray.resize (dvc);
499  }
500  }
501  else if (result_type == "single")
502  {
503  if (tmp(0).is_real_type ())
504  {
505  have_FloatNDArray = true;
506  result_FloatNDArray
507  = tmp(0).float_array_value ();
508  result_FloatNDArray.resize (dvc);
509  }
510  else
511  {
512  have_ComplexNDArray = true;
513  result_ComplexNDArray =
514  tmp(0).complex_array_value ();
515  result_ComplexNDArray.resize (dvc);
516  }
517  }
518  else if BSXINIT(boolNDArray, "logical", bool)
519  else if BSXINIT(int8NDArray, "int8", int8)
520  else if BSXINIT(int16NDArray, "int16", int16)
521  else if BSXINIT(int32NDArray, "int32", int32)
522  else if BSXINIT(int64NDArray, "int64", int64)
523  else if BSXINIT(uint8NDArray, "uint8", uint8)
524  else if BSXINIT(uint16NDArray, "uint16", uint16)
525  else if BSXINIT(uint32NDArray, "uint32", uint32)
526  else if BSXINIT(uint64NDArray, "uint64", uint64)
527  else
528  {
529  C = tmp (0);
530  C = C.resize (dvc);
531  }
532  }
533  }
534  else
535  {
536  update_index (ra_idx, dvc, i);
537 
538  if (have_FloatNDArray ||
539  have_FloatComplexNDArray)
540  {
541  if (! tmp(0).is_float_type ())
542  {
543  if (have_FloatNDArray)
544  {
545  have_FloatNDArray = false;
546  C = result_FloatNDArray;
547  }
548  else
549  {
550  have_FloatComplexNDArray = false;
551  C = result_FloatComplexNDArray;
552  }
553  C = do_cat_op (C, tmp(0), ra_idx);
554  }
555  else if (tmp(0).is_double_type ())
556  {
557  if (tmp(0).is_complex_type () &&
558  have_FloatNDArray)
559  {
560  result_ComplexNDArray =
561  ComplexNDArray (result_FloatNDArray);
562  result_ComplexNDArray.insert
563  (tmp(0).complex_array_value (), ra_idx);
564  have_FloatComplexNDArray = false;
565  have_ComplexNDArray = true;
566  }
567  else
568  {
569  result_NDArray =
570  NDArray (result_FloatNDArray);
571  result_NDArray.insert
572  (tmp(0).array_value (), ra_idx);
573  have_FloatNDArray = false;
574  have_NDArray = true;
575  }
576  }
577  else if (tmp(0).is_real_type ())
578  result_FloatNDArray.insert
579  (tmp(0).float_array_value (), ra_idx);
580  else
581  {
582  result_FloatComplexNDArray =
583  FloatComplexNDArray (result_FloatNDArray);
584  result_FloatComplexNDArray.insert
585  (tmp(0).float_complex_array_value (),
586  ra_idx);
587  have_FloatNDArray = false;
588  have_FloatComplexNDArray = true;
589  }
590  }
591  else if (have_NDArray)
592  {
593  if (! tmp(0).is_float_type ())
594  {
595  have_NDArray = false;
596  C = result_NDArray;
597  C = do_cat_op (C, tmp(0), ra_idx);
598  }
599  else if (tmp(0).is_real_type ())
600  result_NDArray.insert (tmp(0).array_value (),
601  ra_idx);
602  else
603  {
604  result_ComplexNDArray =
605  ComplexNDArray (result_NDArray);
606  result_ComplexNDArray.insert
607  (tmp(0).complex_array_value (), ra_idx);
608  have_NDArray = false;
609  have_ComplexNDArray = true;
610  }
611  }
612 
613 #define BSXLOOP(T, CLS, EXTRACTOR) \
614  (have_ ## T) \
615  { \
616  if (tmp (0).class_name () != CLS) \
617  { \
618  have_ ## T = false; \
619  C = result_ ## T; \
620  C = do_cat_op (C, tmp (0), ra_idx); \
621  } \
622  else \
623  result_ ## T .insert \
624  (tmp(0). EXTRACTOR ## _array_value (), \
625  ra_idx); \
626  }
627 
628  else if BSXLOOP(ComplexNDArray, "double", complex)
629  else if BSXLOOP(boolNDArray, "logical", bool)
630  else if BSXLOOP(int8NDArray, "int8", int8)
631  else if BSXLOOP(int16NDArray, "int16", int16)
632  else if BSXLOOP(int32NDArray, "int32", int32)
633  else if BSXLOOP(int64NDArray, "int64", int64)
634  else if BSXLOOP(uint8NDArray, "uint8", uint8)
635  else if BSXLOOP(uint16NDArray, "uint16", uint16)
636  else if BSXLOOP(uint32NDArray, "uint32", uint32)
637  else if BSXLOOP(uint64NDArray, "uint64", uint64)
638  else
639  C = do_cat_op (C, tmp(0), ra_idx);
640  }
641  }
642 
643 #define BSXEND(T) \
644  (have_ ## T) \
645  retval(0) = result_ ## T;
646 
647  if BSXEND(NDArray)
648  else if BSXEND(ComplexNDArray)
649  else if BSXEND(FloatNDArray)
650  else if BSXEND(FloatComplexNDArray)
651  else if BSXEND(boolNDArray)
652  else if BSXEND(int8NDArray)
653  else if BSXEND(int16NDArray)
654  else if BSXEND(int32NDArray)
655  else if BSXEND(int64NDArray)
656  else if BSXEND(uint8NDArray)
657  else if BSXEND(uint16NDArray)
658  else if BSXEND(uint32NDArray)
659  else if BSXEND(uint64NDArray)
660  else
661  retval(0) = C;
662  }
663  }
664  }
665  }
666 
667  return retval;
668 }
669 
670 /*
671 
672 %!shared a, b, c, f
673 %! a = randn (4, 4);
674 %! b = mean (a, 1);
675 %! c = mean (a, 2);
676 %! f = @minus;
677 %!error (bsxfun (f))
678 %!error (bsxfun (f, a))
679 %!error (bsxfun (a, b))
680 %!error (bsxfun (a, b, c))
681 %!error (bsxfun (f, a, b, c))
682 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
683 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
684 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
685 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
686 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
687 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
688 
689 %!shared a, b, c, f
690 %! a = randn (4, 4);
691 %! a(1) *= 1i;
692 %! b = mean (a, 1);
693 %! c = mean (a, 2);
694 %! f = @minus;
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))
702 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
703 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
704 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
705 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
706 
707 %!shared a, b, c, f
708 %! a = randn (4, 4);
709 %! a(end) *= 1i;
710 %! b = mean (a, 1);
711 %! c = mean (a, 2);
712 %! f = @minus;
713 %!error (bsxfun (f))
714 %!error (bsxfun (f, a))
715 %!error (bsxfun (a, b))
716 %!error (bsxfun (a, b, c))
717 %!error (bsxfun (f, a, b, c))
718 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
719 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
720 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
721 %!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
722 %!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
723 %!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
724 
725 %!shared a, b, c, f
726 %! a = randn (4, 4);
727 %! b = a (1, :);
728 %! c = a (:, 1);
729 %! f = @(x, y) x == y;
730 %!error (bsxfun (f))
731 %!error (bsxfun (f, a))
732 %!error (bsxfun (a, b))
733 %!error (bsxfun (a, b, c))
734 %!error (bsxfun (f, a, b, c))
735 %!error (bsxfun (f, ones (4, 0), ones (4, 4)))
736 %!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
737 %!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
738 %!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
739 %!assert (bsxfun (f, a, c), a == repmat (c, 1, 4))
740 
741 %!shared a, b, c, d, f
742 %! a = randn (4, 4, 4);
743 %! b = mean (a, 1);
744 %! c = mean (a, 2);
745 %! d = mean (a, 3);
746 %! f = @minus;
747 %!error (bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4])))
748 %!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
749 %!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
750 %!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
751 %!assert (bsxfun (f, ones ([4, 4, 1]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
752 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 4])), zeros ([4, 4, 4]))
753 %!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 1])), zeros ([4, 4, 4]))
754 %!assert (bsxfun (f, a, b), a - repmat (b, [4, 1, 1]))
755 %!assert (bsxfun (f, a, c), a - repmat (c, [1, 4, 1]))
756 %!assert (bsxfun (f, a, d), a - repmat (d, [1, 1, 4]))
757 %!assert (bsxfun ("minus", ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
758 
759 %% The test below is a very hard case to treat
760 %!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])), zeros ([4, 4, 4, 4]));
761 
762 %!shared a, b, aa, bb
763 %! a = randn (3, 1, 3);
764 %! aa = a(:, ones (1, 3), :, ones (1, 3));
765 %! b = randn (1, 3, 3, 3);
766 %! bb = b(ones (1, 3), :, :, :);
767 %!assert (bsxfun (@plus, a, b), aa + bb)
768 %!assert (bsxfun (@minus, a, b), aa - bb)
769 %!assert (bsxfun (@times, a, b), aa .* bb)
770 %!assert (bsxfun (@rdivide, a, b), aa ./ bb)
771 %!assert (bsxfun (@ldivide, a, b), aa .\ bb)
772 %!assert (bsxfun (@power, a, b), aa .^ bb)
773 %!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
774 %!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
775 %!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
776 %!assert (bsxfun (@lt, a, b), aa < bb)
777 %!assert (bsxfun (@le, a, b), aa <= bb)
778 %!assert (bsxfun (@gt, a, b), aa > bb)
779 %!assert (bsxfun (@ge, a, b), aa >= bb)
780 %!assert (bsxfun (@min, a, b), min (aa, bb))
781 %!assert (bsxfun (@max, a, b), max (aa, bb))
782 %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
783 %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
784 
785 %% Test automatic bsxfun
786 %
787 %!test
788 %! funs = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
789 %! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
790 %! @and, @or, @xor };
791 %!
792 %! float_types = {@single, @double};
793 %! int_types = {@int8, @int16, @int32, @int64, ...
794 %! @uint8, @uint16, @uint32, @uint64};
795 %!
796 %! x = rand (3) * 10-5;
797 %! y = rand (3,1) * 10-5;
798 %!
799 %! for i=1:length (funs)
800 %! for j = 1:length (float_types)
801 %! for k = 1:length (int_types)
802 %!
803 %! fun = funs{i};
804 %! f_type = float_types{j};
805 %! i_type = int_types{k};
806 %!
807 %! assert (bsxfun (fun, f_type (x), i_type (y)), ...
808 %! fun (f_type(x), i_type (y)));
809 %! assert (bsxfun (fun, f_type (y), i_type (x)), ...
810 %! fun (f_type(y), i_type (x)));
811 %!
812 %! assert (bsxfun (fun, i_type (x), i_type (y)), ...
813 %! fun (i_type (x), i_type (y)));
814 %! assert (bsxfun (fun, i_type (y), i_type (x)), ...
815 %! fun (i_type (y), i_type (x)));
816 %!
817 %! assert (bsxfun (fun, f_type (x), f_type (y)), ...
818 %! fun (f_type (x), f_type (y)));
819 %! assert (bsxfun (fun, f_type(y), f_type(x)), ...
820 %! fun (f_type (y), f_type (x)));
821 %! endfor
822 %! endfor
823 %! endfor
824 %!
825 */