GNU Octave 7.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-2022 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
67const 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
87bsxfun_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
102template <typename NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
103static 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
111template <typename NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
112static 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.
122template <typename NDA, typename CNDA>
123static 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
134static 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
199static octave_value
200maybe_optimized_builtin (const std::string& name,
201 const octave_value& a, const octave_value& b)
202{
203 octave_value retval;
204
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
234static 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?
288static 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
310static 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
323OCTAVE_NAMESPACE_BEGIN
324
325DEFMETHOD (bsxfun, interp, args, ,
326 doc: /* -*- texinfo -*-
327@deftypefn {} {} bsxfun (@var{f}, @var{A}, @var{B})
328Apply 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
330necessary.
331
332@var{f} is a function handle, inline function, or string containing the name
333of the function to evaluate. The function @var{f} must be capable of accepting
334two column-vector arguments of equal length, or one column vector argument and
335a scalar.
336
337The dimensions of @var{A} and @var{B} must be equal or singleton. The
338singleton dimensions of the arrays will be expanded to the same dimensionality
339as the other array.
340@seealso{arrayfun, cellfun}
341@end deftypefn */)
342{
343 if (args.length () != 3)
344 print_usage ();
345
346 octave_value func = args(0);
347 if (func.is_string ())
348 {
349 std::string name = func.string_value ();
350
351 symbol_table& symtab = interp.get_symbol_table ();
352
353 func = symtab.find_function (name);
354
355 if (func.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 (func.is_builtin_function ()
367 || (func.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 = func.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 (func, 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 (func, 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
449
450 octave_value Ac;
452 octave_value Bc;
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 (func, 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)
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])), zeros ([4, 0, 4]))
723
724## The test below is a very hard case to treat
725%!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])), zeros ([4, 4, 4, 4]))
726
727%!shared a, b, aa, bb
728%! ## FIXME: Set a known "good" random seed. See bug #51779.
729%! old_nstate = randn ("state");
730%! restore_nstate = onCleanup (@() randn ("state", old_nstate));
731%! randn ("state", 42); # initialize generator to make behavior reproducible
732%! a = randn (3, 1, 3);
733%! aa = a(:, ones (1, 3), :, ones (1, 3));
734%! b = randn (1, 3, 3, 3);
735%! bb = b(ones (1, 3), :, :, :);
736%!assert (bsxfun (@plus, a, b), aa + bb)
737%!assert (bsxfun (@minus, a, b), aa - bb)
738%!assert (bsxfun (@times, a, b), aa .* bb)
739%!assert (bsxfun (@rdivide, a, b), aa ./ bb)
740%!assert (bsxfun (@ldivide, a, b), aa .\ bb)
741%!assert (bsxfun (@power, a, b), aa .^ bb)
742%!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
743%!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
744%!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
745%!assert (bsxfun (@lt, a, b), aa < bb)
746%!assert (bsxfun (@le, a, b), aa <= bb)
747%!assert (bsxfun (@gt, a, b), aa > bb)
748%!assert (bsxfun (@ge, a, b), aa >= bb)
749%!assert (bsxfun (@min, a, b), min (aa, bb))
750%!assert (bsxfun (@max, a, b), max (aa, bb))
751%!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
752%!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
753
754## Test automatic bsxfun
755%
756%!test
757%! funs = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
758%! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
759%! @and, @or, @xor };
760%!
761%! float_types = {@single, @double};
762%! int_types = {@int8, @int16, @int32, @int64, ...
763%! @uint8, @uint16, @uint32, @uint64};
764%!
765%! ## FIXME: Set a known "good" random seed. See bug #51779.
766%! old_state = rand ("state");
767%! restore_state = onCleanup (@() rand ("state", old_state));
768%! rand ("state", 42); # initialize generator to make behavior reproducible
769%!
770%! x = rand (3) * 10-5;
771%! y = rand (3,1) * 10-5;
772%!
773%! for i=1:length (funs)
774%! for j = 1:length (float_types)
775%! for k = 1:length (int_types)
776%!
777%! fun = funs{i};
778%! f_type = float_types{j};
779%! i_type = int_types{k};
780%!
781%! assert (bsxfun (fun, f_type (x), i_type (y)), ...
782%! fun (f_type(x), i_type (y)));
783%! assert (bsxfun (fun, f_type (y), i_type (x)), ...
784%! fun (f_type(y), i_type (x)));
785%!
786%! assert (bsxfun (fun, i_type (x), i_type (y)), ...
787%! fun (i_type (x), i_type (y)));
788%! assert (bsxfun (fun, i_type (y), i_type (x)), ...
789%! fun (i_type (y), i_type (x)));
790%!
791%! assert (bsxfun (fun, f_type (x), f_type (y)), ...
792%! fun (f_type (x), f_type (y)));
793%! assert (bsxfun (fun, f_type(y), f_type(x)), ...
794%! fun (f_type (y), f_type (x)));
795%! endfor
796%! endfor
797%! endfor
798
799## Automatic broadcasting with zero length dimensions
800%!assert <*47085> ([1 2 3] + zeros (0, 3), zeros (0, 3))
801%!assert <*47085> (rand (3, 3, 1) + rand (3, 3, 0), zeros (3, 3, 0))
802
803## In-place broadcasting with zero length dimensions
804%!test <*47085>
805%! a = zeros (0, 3);
806%! a += [1 2 3];
807%! assert (a, zeros (0, 3));
808
809%!test <*53179>
810%! im = ones (4,4,2) + single (i);
811%! mask = true (4,4);
812%! mask(:,1:2) = false;
813%! r = bsxfun (@times, im, mask);
814%! assert (r(:,:,1), repmat (single ([0, 0, 1+i, 1+i]), [4, 1]));
815
816*/
817
818OCTAVE_NAMESPACE_END
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.cc:1010
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:207
Array< octave_value > array_value(void) const
Definition: ovl.h:90
bool empty(void) const
Definition: ovl.h:115
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition: ovl.h:117
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
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:980
QString name
F77_RET_T const F77_INT F77_CMPLX const F77_INT F77_CMPLX * B
F77_RET_T const F77_INT F77_CMPLX * A
F77_RET_T const F77_DBLE * x
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:10300
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:75
@ btyp_float_complex
Definition: ov-base.h:79
@ btyp_double
Definition: ov-base.h:76
@ btyp_int32
Definition: ov-base.h:82
@ btyp_float
Definition: ov-base.h:77
@ btyp_uint16
Definition: ov-base.h:85
@ btyp_int64
Definition: ov-base.h:83
@ btyp_bool
Definition: ov-base.h:88
@ btyp_unknown
Definition: ov-base.h:93
@ btyp_uint64
Definition: ov-base.h:87
@ btyp_int16
Definition: ov-base.h:81
@ btyp_uint32
Definition: ov-base.h:86
@ btyp_num_types
Definition: ov-base.h:94
@ btyp_char
Definition: ov-base.h:89
@ btyp_uint8
Definition: ov-base.h:84
@ btyp_int8
Definition: ov-base.h:80
@ btyp_complex
Definition: ov-base.h:78
OCTINTERP_API octave_value cat_op(type_info &ti, const octave_value &a, const octave_value &b, const Array< octave_idx_type > &ra_idx)