GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
bsxfun.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2007-2025 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 "unwind-prot.h"
42#include "variables.h"
43
44// Optimized bsxfun operations
65
66const char *bsxfun_builtin_names[] =
67{
68 "plus",
69 "minus",
70 "times",
71 "rdivide",
72 "max",
73 "min",
74 "eq",
75 "ne",
76 "lt",
77 "le",
78 "gt",
79 "ge",
80 "and",
81 "or",
82 "power"
83};
84
86bsxfun_builtin_lookup (const std::string& name)
87{
88 for (int i = 0; i < bsxfun_num_builtin_ops; i++)
89 if (name == bsxfun_builtin_names[i])
90 return static_cast<bsxfun_builtin_op> (i);
91
93}
94
96 const octave_value&);
97
98// Static table of handlers.
100
101template <typename NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
102static octave_value
103bsxfun_forward_op (const octave_value& x, const octave_value& y)
104{
105 NDA xa = octave_value_extract<NDA> (x);
106 NDA ya = octave_value_extract<NDA> (y);
107 return octave_value (bsxfun_op (xa, ya));
108}
109
110template <typename NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
111static octave_value
112bsxfun_forward_rel (const octave_value& x, const octave_value& y)
113{
114 NDA xa = octave_value_extract<NDA> (x);
115 NDA ya = octave_value_extract<NDA> (y);
116 return octave_value (bsxfun_rel (xa, ya));
117}
118
119// pow() needs a special handler for reals
120// because of the potentially complex result.
121template <typename NDA, typename CNDA>
122static octave_value
123do_bsxfun_real_pow (const octave_value& x, const octave_value& y)
124{
125 NDA xa = octave_value_extract<NDA> (x);
126 NDA ya = octave_value_extract<NDA> (y);
127 if (! ya.all_integers () && xa.any_element_is_negative ())
128 return octave_value (bsxfun_pow (CNDA (xa), ya));
129 else
130 return octave_value (bsxfun_pow (xa, ya));
131}
132
133static void
134maybe_fill_table ()
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
205 maybe_fill_table ();
206
207 bsxfun_builtin_op op = bsxfun_builtin_lookup (name);
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
235maybe_update_column (octave_value& Ac, const octave_value& A,
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
286static void
287update_index (Array<int>& idx, const dim_vector& dv, octave_idx_type i)
288{
289 octave_idx_type nd = dv.ndims ();
290
291 idx(0) = 0;
292 for (octave_idx_type j = 1; j < nd; j++)
293 {
294 idx(j) = i % dv(j);
295 i /= dv(j);
296 }
297}
298
300
301DEFMETHOD (bsxfun, interp, args, ,
302 doc: /* -*- texinfo -*-
303@deftypefn {} {@var{C} =} bsxfun (@var{f}, @var{A}, @var{B})
304Apply a binary function @var{f} element-by-element to two array arguments
305@var{A} and @var{B}, expanding singleton dimensions in either input argument as
306necessary.
307
308@var{f} is a function handle, inline function, or string containing the name
309of the function to evaluate. The function @var{f} must be capable of accepting
310two column-vector arguments of equal length, or one column vector argument and
311a scalar.
312
313The dimensions of @var{A} and @var{B} must be equal or singleton. The
314singleton dimensions of the arrays will be expanded to the same dimensionality
315as the other array.
316@seealso{arrayfun, cellfun}
317@end deftypefn */)
318{
319 if (args.length () != 3)
320 print_usage ();
321
322 octave_value fcn = args(0);
323 if (fcn.is_string ())
324 {
325 std::string name = fcn.string_value ();
326
327 symbol_table& symtab = interp.get_symbol_table ();
328
329 fcn = symtab.find_function (name);
330
331 if (fcn.is_undefined ())
332 error ("bsxfun: invalid function name: %s", name.c_str ());
333 }
334 else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
335 error ("bsxfun: F must be a string or function handle");
336
337 octave_value_list retval;
338
339 const octave_value A = args(1);
340 const octave_value B = args(2);
341
342 if (fcn.is_builtin_function ()
343 || (fcn.is_function_handle () && ! A.isobject () && ! B.isobject ()))
344 {
345 // This may break if the default behavior is overridden. But if you
346 // override arithmetic operators for builtin classes, you should expect
347 // mayhem anyway (constant folding etc). Querying is_overloaded() may
348 // not be exactly what we need here.
349 octave_function *fcn_val = fcn.function_value ();
350 if (fcn_val)
351 {
352 octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
353 if (tmp.is_defined ())
354 retval(0) = tmp;
355 }
356 }
357
358 if (retval.empty ())
359 {
360 dim_vector dva = A.dims ();
361 octave_idx_type nda = dva.ndims ();
362 dim_vector dvb = B.dims ();
363 octave_idx_type ndb = dvb.ndims ();
364 octave_idx_type nd = nda;
365
366 if (nda > ndb)
367 dvb.resize (nda, 1);
368 else if (nda < ndb)
369 {
370 dva.resize (ndb, 1);
371 nd = ndb;
372 }
373
374 for (octave_idx_type i = 0; i < nd; i++)
375 if (dva(i) != dvb(i) && dva(i) != 1 && dvb(i) != 1)
376 error ("bsxfun: dimensions of A and B must match");
377
378 // Find the size of the output
379 dim_vector dvc;
380 dvc.resize (nd);
381
382 for (octave_idx_type i = 0; i < nd; i++)
383 dvc(i) = (dva(i) < 1 ? dva(i)
384 : (dvb(i) < 1 ? dvb(i)
385 : (dva(i) > dvb(i) ? dva(i)
386 : dvb(i))));
387
388 if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
389 {
390 octave_value_list inputs (2);
391 inputs(0) = A;
392 inputs(1) = B;
393 retval = interp.feval (fcn, inputs, 1);
394 }
395 else if (dvc.numel () < 1)
396 {
397 octave_value_list inputs (2);
398 inputs(0) = A.resize (dvc);
399 inputs(1) = B.resize (dvc);
400 retval = interp.feval (fcn, inputs, 1);
401 }
402 else
403 {
404 octave_idx_type ncount = 1;
405 for (octave_idx_type i = 1; i < nd; i++)
406 ncount *= dvc(i);
407
408#define BSXDEF(T) \
409 T result_ ## T; \
410 bool have_ ## T = false;
411
425
426 octave_value Ac;
428 octave_value Bc;
431 octave_value_list inputs (2);
432 Array<int> ra_idx (dim_vector (dvc.ndims (), 1), 0);
433
434 for (octave_idx_type i = 0; i < ncount; i++)
435 {
436 if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
437 inputs(0) = Ac;
438
439 if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
440 inputs(1) = Bc;
441
442 octave_value_list tmp = interp.feval (fcn, inputs, 1);
443
444#define BSXINIT(T, CLS, EXTRACTOR) \
445 (result_type == CLS) \
446 { \
447 have_ ## T = true; \
448 result_ ## T = tmp(0). EXTRACTOR ## _array_value (); \
449 result_ ## T .resize (dvc); \
450 }
451
452 if (i == 0)
453 {
454 if (! tmp(0).issparse ())
455 {
456 std::string result_type = tmp(0).class_name ();
457 if (result_type == "double")
458 {
459 if (tmp(0).isreal ())
460 {
461 have_NDArray = true;
462 result_NDArray = tmp(0).array_value ();
463 result_NDArray.resize (dvc);
464 }
465 else
466 {
467 have_ComplexNDArray = true;
468 result_ComplexNDArray
469 = tmp(0).complex_array_value ();
470 result_ComplexNDArray.resize (dvc);
471 }
472 }
473 else if (result_type == "single")
474 {
475 if (tmp(0).isreal ())
476 {
477 have_FloatNDArray = true;
478 result_FloatNDArray
479 = tmp(0).float_array_value ();
480 result_FloatNDArray.resize (dvc);
481 }
482 else
483 {
484 have_FloatComplexNDArray = true;
485 result_FloatComplexNDArray
486 = tmp(0).float_complex_array_value ();
487 result_FloatComplexNDArray.resize (dvc);
488 }
489 }
490 else if BSXINIT(boolNDArray, "logical", bool)
491 else if BSXINIT(int8NDArray, "int8", int8)
492 else if BSXINIT(int16NDArray, "int16", int16)
493 else if BSXINIT(int32NDArray, "int32", int32)
494 else if BSXINIT(int64NDArray, "int64", int64)
495 else if BSXINIT(uint8NDArray, "uint8", uint8)
496 else if BSXINIT(uint16NDArray, "uint16", uint16)
497 else if BSXINIT(uint32NDArray, "uint32", uint32)
498 else if BSXINIT(uint64NDArray, "uint64", uint64)
499 else
500 {
501 C = tmp(0);
502 C = C.resize (dvc);
503 }
504 }
505 else // Skip semi-fast path for sparse matrices
506 {
507 C = tmp (0);
508 C = C.resize (dvc);
509 }
510 }
511 else
512 {
513 update_index (ra_idx, dvc, i);
514
515 if (have_NDArray)
516 {
517 if (! tmp(0).isfloat ())
518 {
519 have_NDArray = false;
520 C = result_NDArray;
521 C = cat_op (C, tmp(0), ra_idx);
522 }
523 else if (tmp(0).isreal ())
524 result_NDArray.insert (tmp(0).array_value (), ra_idx);
525 else
526 {
527 result_ComplexNDArray
528 = ComplexNDArray (result_NDArray);
529 result_ComplexNDArray.insert
530 (tmp(0).complex_array_value (), ra_idx);
531 have_NDArray = false;
532 have_ComplexNDArray = true;
533 }
534 }
535 else if (have_FloatNDArray)
536 {
537 if (! tmp(0).isfloat ())
538 {
539 have_FloatNDArray = false;
540 C = result_FloatNDArray;
541 C = cat_op (C, tmp(0), ra_idx);
542 }
543 else if (tmp(0).isreal ())
544 result_FloatNDArray.insert
545 (tmp(0).float_array_value (), ra_idx);
546 else
547 {
548 result_FloatComplexNDArray
549 = FloatComplexNDArray (result_FloatNDArray);
550 result_FloatComplexNDArray.insert
551 (tmp(0).float_complex_array_value (), ra_idx);
552 have_FloatNDArray = false;
553 have_FloatComplexNDArray = true;
554 }
555 }
556
557#define BSXLOOP(T, CLS, EXTRACTOR) \
558 (have_ ## T) \
559 { \
560 if (tmp(0).class_name () != CLS) \
561 { \
562 have_ ## T = false; \
563 C = result_ ## T; \
564 C = cat_op (C, tmp(0), ra_idx); \
565 } \
566 else \
567 result_ ## T .insert (tmp(0). EXTRACTOR ## _array_value (), ra_idx); \
568 }
569
570 else if BSXLOOP(ComplexNDArray, "double", complex)
571 else if BSXLOOP(FloatComplexNDArray, "single", float_complex)
572 else if BSXLOOP(boolNDArray, "logical", bool)
573 else if BSXLOOP(int8NDArray, "int8", int8)
574 else if BSXLOOP(int16NDArray, "int16", int16)
575 else if BSXLOOP(int32NDArray, "int32", int32)
576 else if BSXLOOP(int64NDArray, "int64", int64)
577 else if BSXLOOP(uint8NDArray, "uint8", uint8)
578 else if BSXLOOP(uint16NDArray, "uint16", uint16)
579 else if BSXLOOP(uint32NDArray, "uint32", uint32)
580 else if BSXLOOP(uint64NDArray, "uint64", uint64)
581 else
582 C = cat_op (C, tmp(0), ra_idx);
583 }
584 }
585
586#define BSXEND(T) \
587 (have_ ## T) \
588 retval(0) = result_ ## T;
589
590 if BSXEND(NDArray)
591 else if BSXEND(ComplexNDArray)
592 else if BSXEND(FloatNDArray)
594 else if BSXEND(boolNDArray)
595 else if BSXEND(int8NDArray)
596 else if BSXEND(int16NDArray)
597 else if BSXEND(int32NDArray)
598 else if BSXEND(int64NDArray)
599 else if BSXEND(uint8NDArray)
600 else if BSXEND(uint16NDArray)
601 else if BSXEND(uint32NDArray)
602 else if BSXEND(uint64NDArray)
603 else
604 retval(0) = C;
605 }
606 }
607
608 return retval;
609}
610
611/*
612
613%!shared a, b, c, f
614%! a = randn (4, 4);
615%! b = mean (a, 1);
616%! c = mean (a, 2);
617%! f = @minus;
618%!error bsxfun (f)
619%!error bsxfun (f, a)
620%!error bsxfun (a, b)
621%!error bsxfun (a, b, c)
622%!error bsxfun (f, a, b, c)
623%!error bsxfun (f, ones (4, 0), ones (4, 4))
624%!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
625%!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
626%!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
627%!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
628%!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
629
630%!shared a, b, c, f
631%! a = randn (4, 4);
632%! a(1) *= 1i;
633%! b = mean (a, 1);
634%! c = mean (a, 2);
635%! f = @minus;
636%!error bsxfun (f)
637%!error bsxfun (f, a)
638%!error bsxfun (a, b)
639%!error bsxfun (a, b, c)
640%!error bsxfun (f, a, b, c)
641%!error bsxfun (f, ones (4, 0), ones (4, 4))
642%!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
643%!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
644%!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
645%!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
646%!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
647
648%!shared a, b, c, f
649%! a = randn (4, 4);
650%! a(end) *= 1i;
651%! b = mean (a, 1);
652%! c = mean (a, 2);
653%! f = @minus;
654%!error bsxfun (f)
655%!error bsxfun (f, a)
656%!error bsxfun (a, b)
657%!error bsxfun (a, b, c)
658%!error bsxfun (f, a, b, c)
659%!error bsxfun (f, ones (4, 0), ones (4, 4))
660%!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0))
661%!assert (bsxfun (f, ones (1, 4), ones (4, 1)), zeros (4, 4))
662%!assert (bsxfun (f, a, b), a - repmat (b, 4, 1))
663%!assert (bsxfun (f, a, c), a - repmat (c, 1, 4))
664%!assert (bsxfun ("minus", ones (1, 4), ones (4, 1)), zeros (4, 4))
665
666%!shared a, b, c, f
667%! a = randn (4, 4);
668%! b = a (1, :);
669%! c = a (:, 1);
670%! f = @(x, y) x == y;
671%!error bsxfun (f)
672%!error bsxfun (f, a)
673%!error bsxfun (a, b)
674%!error bsxfun (a, b, c)
675%!error bsxfun (f, a, b, c)
676%!error bsxfun (f, ones (4, 0), ones (4, 4))
677%!assert (bsxfun (f, ones (4, 0), ones (4, 1)), zeros (4, 0, "logical"))
678%!assert (bsxfun (f, ones (1, 4), ones (4, 1)), ones (4, 4, "logical"))
679%!assert (bsxfun (f, a, b), a == repmat (b, 4, 1))
680%!assert (bsxfun (f, a, c), a == repmat (c, 1, 4))
681
682%!shared a, b, c, d, f
683%! a = randn (4, 4, 4);
684%! b = mean (a, 1);
685%! c = mean (a, 2);
686%! d = mean (a, 3);
687%! f = @minus;
688%!error bsxfun (f, ones ([4, 0, 4]), ones ([4, 4, 4]))
689%!assert (bsxfun (f, ones ([4, 0, 4]), ones ([4, 1, 4])), zeros ([4, 0, 4]))
690%!assert (bsxfun (f, ones ([4, 4, 0]), ones ([4, 1, 1])), zeros ([4, 4, 0]))
691%!assert (bsxfun (f, ones ([1, 4, 4]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
692%!assert (bsxfun (f, ones ([4, 4, 1]), ones ([4, 1, 4])), zeros ([4, 4, 4]))
693%!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 4])), zeros ([4, 4, 4]))
694%!assert (bsxfun (f, ones ([4, 1, 4]), ones ([1, 4, 1])), zeros ([4, 4, 4]))
695%!assert (bsxfun (f, a, b), a - repmat (b, [4, 1, 1]))
696%!assert (bsxfun (f, a, c), a - repmat (c, [1, 4, 1]))
697%!assert (bsxfun (f, a, d), a - repmat (d, [1, 1, 4]))
698%!assert (bsxfun ("minus", ones ([4, 0, 4]), ones ([4, 1, 4])),
699%! zeros ([4, 0, 4]))
700
701## The test below is a very hard case to treat
702%!assert (bsxfun (f, ones ([4, 1, 4, 1]), ones ([1, 4, 1, 4])),
703%! zeros ([4, 4, 4, 4]))
704
705%!shared a, b, aa, bb
706%! ## FIXME: Set a known "good" random seed. See bug #51779.
707%! old_nstate = randn ("state");
708%! restore_nstate = onCleanup (@() randn ("state", old_nstate));
709%! randn ("state", 42); # initialize generator to make behavior reproducible
710%! a = randn (3, 1, 3);
711%! aa = a(:, ones (1, 3), :, ones (1, 3));
712%! b = randn (1, 3, 3, 3);
713%! bb = b(ones (1, 3), :, :, :);
714%!assert (bsxfun (@plus, a, b), aa + bb)
715%!assert (bsxfun (@minus, a, b), aa - bb)
716%!assert (bsxfun (@times, a, b), aa .* bb)
717%!assert (bsxfun (@rdivide, a, b), aa ./ bb)
718%!assert (bsxfun (@ldivide, a, b), aa .\ bb)
719%!assert (bsxfun (@power, a, b), aa .^ bb)
720%!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb)
721%!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb))
722%!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb))
723%!assert (bsxfun (@lt, a, b), aa < bb)
724%!assert (bsxfun (@le, a, b), aa <= bb)
725%!assert (bsxfun (@gt, a, b), aa > bb)
726%!assert (bsxfun (@ge, a, b), aa >= bb)
727%!assert (bsxfun (@min, a, b), min (aa, bb))
728%!assert (bsxfun (@max, a, b), max (aa, bb))
729%!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0))
730%!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0))
731
732## Test automatic bsxfun
733%
734%!test
735%! fcns = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, ...
736%! @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, ...
737%! @and, @or, @xor };
738%!
739%! float_types = {@single, @double};
740%! int_types = {@int8, @int16, @int32, @int64, ...
741%! @uint8, @uint16, @uint32, @uint64};
742%!
743%! ## FIXME: Set a known "good" random seed. See bug #51779.
744%! old_state = rand ("state");
745%! restore_state = onCleanup (@() rand ("state", old_state));
746%! rand ("state", 42); # initialize generator to make behavior reproducible
747%!
748%! x = rand (3) * 10-5;
749%! y = rand (3,1) * 10-5;
750%!
751%! for i=1:length (fcns)
752%! for j = 1:length (float_types)
753%! for k = 1:length (int_types)
754%!
755%! fcn = fcns{i};
756%! f_type = float_types{j};
757%! i_type = int_types{k};
758%!
759%! assert (bsxfun (fcn, f_type (x), i_type (y)), ...
760%! fcn (f_type(x), i_type (y)));
761%! assert (bsxfun (fcn, f_type (y), i_type (x)), ...
762%! fcn (f_type(y), i_type (x)));
763%!
764%! assert (bsxfun (fcn, i_type (x), i_type (y)), ...
765%! fcn (i_type (x), i_type (y)));
766%! assert (bsxfun (fcn, i_type (y), i_type (x)), ...
767%! fcn (i_type (y), i_type (x)));
768%!
769%! assert (bsxfun (fcn, f_type (x), f_type (y)), ...
770%! fcn (f_type (x), f_type (y)));
771%! assert (bsxfun (fcn, f_type(y), f_type(x)), ...
772%! fcn (f_type (y), f_type (x)));
773%! endfor
774%! endfor
775%! endfor
776
777## Automatic broadcasting with zero length dimensions
778%!assert <*47085> ([1 2 3] + zeros (0, 3), zeros (0, 3))
779%!assert <*47085> (rand (3, 3, 1) + rand (3, 3, 0), zeros (3, 3, 0))
780
781## In-place broadcasting with zero length dimensions
782%!test <*47085>
783%! a = zeros (0, 3);
784%! a += [1 2 3];
785%! assert (a, zeros (0, 3));
786
787%!test <*53179>
788%! im = ones (4,4,2) + single (i);
789%! mask = true (4,4);
790%! mask(:,1:2) = false;
791%! r = bsxfun (@times, im, mask);
792%! assert (r(:,:,1), repmat (single ([0, 0, 1+i, 1+i]), [4, 1]));
793
794## automatic broadcasting with inplace times operator
795%!test <*38466>
796%! a = ones (2, 2, 2);
797%! b = 2 * ones (2, 1);
798%! a .*= b;
799%! assert (a, 2 * ones (2, 2, 2));
800
801%!test <*38466>
802%! a = ones (2, 2, 2);
803%! b = 2 * ones (1, 2);
804%! a .*= b;
805%! assert (a, 2 * ones (2, 2, 2));
806
807%!test <*38466>
808%! a = ones (2, 2, 2);
809%! b = 2 * ones (2, 2);
810%! a .*= b;
811%! assert (a, 2 * ones (2, 2, 2));
812
813%!test <*38466>
814%! a = ones (2, 2, 2);
815%! b = 2 * ones (1, 1, 2);
816%! a .*= b;
817%! assert (a, 2 * ones (2, 2, 2));
818
819%!assert (ones (2,2,2) .* ones (1,2), ones (2,2,2));
820
821*/
822
823OCTAVE_END_NAMESPACE(octave)
ComplexNDArray bsxfun_pow(const ComplexNDArray &x, const ComplexNDArray &y)
Definition CNDArray.cc:665
#define C(a, b)
Definition Faddeeva.cc:256
boolNDArray bsxfun_or(const boolNDArray &x, const boolNDArray &y)
boolNDArray bsxfun_and(const boolNDArray &x, const boolNDArray &y)
#define REGISTER_STD_HANDLERS(BTYP, NDA)
bsxfun_handler bsxfun_handler_table[bsxfun_num_builtin_ops][btyp_num_types]
Definition bsxfun.cc:99
bsxfun_builtin_op
Definition bsxfun.cc:46
@ bsxfun_builtin_le
Definition bsxfun.cc:56
@ bsxfun_builtin_min
Definition bsxfun.cc:52
@ bsxfun_builtin_divide
Definition bsxfun.cc:50
@ bsxfun_builtin_eq
Definition bsxfun.cc:53
@ bsxfun_builtin_or
Definition bsxfun.cc:60
@ bsxfun_builtin_unknown
Definition bsxfun.cc:62
@ bsxfun_builtin_ge
Definition bsxfun.cc:58
@ bsxfun_builtin_plus
Definition bsxfun.cc:47
@ bsxfun_builtin_times
Definition bsxfun.cc:49
@ bsxfun_builtin_and
Definition bsxfun.cc:59
@ bsxfun_builtin_gt
Definition bsxfun.cc:57
@ bsxfun_builtin_power
Definition bsxfun.cc:61
@ bsxfun_builtin_ne
Definition bsxfun.cc:54
@ bsxfun_builtin_minus
Definition bsxfun.cc:48
@ bsxfun_builtin_lt
Definition bsxfun.cc:55
@ bsxfun_builtin_max
Definition bsxfun.cc:51
@ bsxfun_num_builtin_ops
Definition bsxfun.cc:63
#define BSXDEF(T)
#define BSXINIT(T, CLS, EXTRACTOR)
const char * bsxfun_builtin_names[]
Definition bsxfun.cc:66
#define BSXEND(T)
#define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL)
#define BSXLOOP(T, CLS, EXTRACTOR)
octave_value(* bsxfun_handler)(const octave_value &, const octave_value &)
Definition bsxfun.cc:95
#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
N Dimensional Array with copy-on-write semantics.
Definition Array.h:130
void resize(const dim_vector &dv, const T &rfv)
Size of the specified dimension.
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:253
std::string name() const
Definition ov-fcn.h:208
void resize(octave_idx_type n, const octave_value &rfv=octave_value())
Definition ovl.h:115
Array< octave_value > array_value() const
Definition ovl.h:88
bool empty() const
Definition ovl.h:113
bool is_function_handle() const
Definition ov.h:768
bool is_undefined() const
Definition ov.h:595
octave_function * function_value(bool silent=false) const
bool is_string() const
Definition ov.h:637
bool is_defined() const
Definition ov.h:592
std::string string_value(bool force=false) const
Definition ov.h:983
octave_value single_subsref(const std::string &type, const octave_value_list &idx)
bool is_builtin_function() const
Definition ov.h:789
builtin_type_t builtin_type() const
Definition ov.h:690
octave_value find_function(const std::string &name, const symbol_scope &search_scope=symbol_scope::invalid())
Definition symtab.cc:254
OCTAVE_BEGIN_NAMESPACE(octave) static octave_value daspk_fcn
void print_usage()
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:1003
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
const octave_base_value const Array< octave_idx_type > & ra_idx
builtin_type_t
Definition ov-base.h:83
@ btyp_float_complex
Definition ov-base.h:87
@ btyp_double
Definition ov-base.h:84
@ btyp_int32
Definition ov-base.h:90
@ btyp_float
Definition ov-base.h:85
@ btyp_uint16
Definition ov-base.h:93
@ btyp_int64
Definition ov-base.h:91
@ btyp_bool
Definition ov-base.h:96
@ btyp_unknown
Definition ov-base.h:101
@ btyp_uint64
Definition ov-base.h:95
@ btyp_int16
Definition ov-base.h:89
@ btyp_uint32
Definition ov-base.h:94
@ btyp_num_types
Definition ov-base.h:102
@ btyp_char
Definition ov-base.h:97
@ btyp_uint8
Definition ov-base.h:92
@ btyp_int8
Definition ov-base.h:88
@ btyp_complex
Definition ov-base.h:86
octave_value cat_op(type_info &ti, const octave_value &a, const octave_value &b, const Array< octave_idx_type > &ra_idx)