bsxfun.cc

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2007-2012 David Bateman
00004 Copyright (C) 2009 VZLU Prague
00005 
00006 This file is part of Octave.
00007 
00008 Octave is free software; you can redistribute it and/or modify it
00009 under the terms of the GNU General Public License as published by the
00010 Free Software Foundation; either version 3 of the License, or (at your
00011 option) any later version.
00012 
00013 Octave is distributed in the hope that it will be useful, but WITHOUT
00014 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00015 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00016 for more details.
00017 
00018 You should have received a copy of the GNU General Public License
00019 along with Octave; see the file COPYING.  If not, see
00020 <http://www.gnu.org/licenses/>.
00021 
00022 */
00023 
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #include <string>
00029 #include <vector>
00030 #include <list>
00031 
00032 #include "lo-mappers.h"
00033 
00034 #include "oct-map.h"
00035 #include "defun-dld.h"
00036 #include "parse.h"
00037 #include "variables.h"
00038 #include "ov-colon.h"
00039 #include "unwind-prot.h"
00040 #include "ov-fcn-handle.h"
00041 
00042 // Optimized bsxfun operations
00043 enum bsxfun_builtin_op
00044 {
00045   bsxfun_builtin_plus = 0,
00046   bsxfun_builtin_minus,
00047   bsxfun_builtin_times,
00048   bsxfun_builtin_divide,
00049   bsxfun_builtin_max,
00050   bsxfun_builtin_min,
00051   bsxfun_builtin_eq,
00052   bsxfun_builtin_ne,
00053   bsxfun_builtin_lt,
00054   bsxfun_builtin_le,
00055   bsxfun_builtin_gt,
00056   bsxfun_builtin_ge,
00057   bsxfun_builtin_and,
00058   bsxfun_builtin_or,
00059   bsxfun_builtin_power,
00060   bsxfun_builtin_unknown,
00061   bsxfun_num_builtin_ops = bsxfun_builtin_unknown
00062 };
00063 
00064 const char *bsxfun_builtin_names[] =
00065 {
00066   "plus",
00067   "minus",
00068   "times",
00069   "rdivide",
00070   "max",
00071   "min",
00072   "eq",
00073   "ne",
00074   "lt",
00075   "le",
00076   "gt",
00077   "ge",
00078   "and",
00079   "or",
00080   "power"
00081 };
00082 
00083 static bsxfun_builtin_op
00084 bsxfun_builtin_lookup (const std::string& name)
00085 {
00086   for (int i = 0; i < bsxfun_num_builtin_ops; i++)
00087     if (name == bsxfun_builtin_names[i])
00088       return static_cast<bsxfun_builtin_op> (i);
00089   return bsxfun_builtin_unknown;
00090 }
00091 
00092 typedef octave_value (*bsxfun_handler) (const octave_value&, const octave_value&);
00093 
00094 // Static table of handlers.
00095 bsxfun_handler bsxfun_handler_table[bsxfun_num_builtin_ops][btyp_num_types];
00096 
00097 template <class NDA, NDA (bsxfun_op) (const NDA&, const NDA&)>
00098 static octave_value
00099 bsxfun_forward_op (const octave_value& x, const octave_value& y)
00100 {
00101   NDA xa = octave_value_extract<NDA> (x);
00102   NDA ya = octave_value_extract<NDA> (y);
00103   return octave_value (bsxfun_op (xa, ya));
00104 }
00105 
00106 template <class NDA, boolNDArray (bsxfun_rel) (const NDA&, const NDA&)>
00107 static octave_value
00108 bsxfun_forward_rel (const octave_value& x, const octave_value& y)
00109 {
00110   NDA xa = octave_value_extract<NDA> (x);
00111   NDA ya = octave_value_extract<NDA> (y);
00112   return octave_value (bsxfun_rel (xa, ya));
00113 }
00114 
00115 // Pow needs a special handler for reals because of the potentially complex result.
00116 template <class NDA, class CNDA>
00117 static octave_value
00118 do_bsxfun_real_pow (const octave_value& x, const octave_value& y)
00119 {
00120   NDA xa = octave_value_extract<NDA> (x);
00121   NDA ya = octave_value_extract<NDA> (y);
00122   if (! ya.all_integers () && xa.any_element_is_negative ())
00123     return octave_value (bsxfun_pow (CNDA (xa), ya));
00124   else
00125     return octave_value (bsxfun_pow (xa, ya));
00126 }
00127 
00128 static void maybe_fill_table (void)
00129 {
00130   static bool filled = false;
00131   if (filled)
00132     return;
00133 
00134 #define REGISTER_OP_HANDLER(OP, BTYP, NDA, FUNOP) \
00135   bsxfun_handler_table[OP][BTYP] = bsxfun_forward_op<NDA, FUNOP>
00136 #define REGISTER_REL_HANDLER(REL, BTYP, NDA, FUNREL) \
00137   bsxfun_handler_table[REL][BTYP] = bsxfun_forward_rel<NDA, FUNREL>
00138 #define REGISTER_STD_HANDLERS(BTYP, NDA) \
00139   REGISTER_OP_HANDLER (bsxfun_builtin_plus, BTYP, NDA, bsxfun_add); \
00140   REGISTER_OP_HANDLER (bsxfun_builtin_minus, BTYP, NDA, bsxfun_sub); \
00141   REGISTER_OP_HANDLER (bsxfun_builtin_times, BTYP, NDA, bsxfun_mul); \
00142   REGISTER_OP_HANDLER (bsxfun_builtin_divide, BTYP, NDA, bsxfun_div); \
00143   REGISTER_OP_HANDLER (bsxfun_builtin_max, BTYP, NDA, bsxfun_max); \
00144   REGISTER_OP_HANDLER (bsxfun_builtin_min, BTYP, NDA, bsxfun_min); \
00145   REGISTER_REL_HANDLER (bsxfun_builtin_eq, BTYP, NDA, bsxfun_eq); \
00146   REGISTER_REL_HANDLER (bsxfun_builtin_ne, BTYP, NDA, bsxfun_ne); \
00147   REGISTER_REL_HANDLER (bsxfun_builtin_lt, BTYP, NDA, bsxfun_lt); \
00148   REGISTER_REL_HANDLER (bsxfun_builtin_le, BTYP, NDA, bsxfun_le); \
00149   REGISTER_REL_HANDLER (bsxfun_builtin_gt, BTYP, NDA, bsxfun_gt); \
00150   REGISTER_REL_HANDLER (bsxfun_builtin_ge, BTYP, NDA, bsxfun_ge)
00151 
00152   REGISTER_STD_HANDLERS (btyp_double, NDArray);
00153   REGISTER_STD_HANDLERS (btyp_float, FloatNDArray);
00154   REGISTER_STD_HANDLERS (btyp_complex, ComplexNDArray);
00155   REGISTER_STD_HANDLERS (btyp_float_complex, FloatComplexNDArray);
00156   REGISTER_STD_HANDLERS (btyp_int8,  int8NDArray);
00157   REGISTER_STD_HANDLERS (btyp_int16, int16NDArray);
00158   REGISTER_STD_HANDLERS (btyp_int32, int32NDArray);
00159   REGISTER_STD_HANDLERS (btyp_int64, int64NDArray);
00160   REGISTER_STD_HANDLERS (btyp_uint8,  uint8NDArray);
00161   REGISTER_STD_HANDLERS (btyp_uint16, uint16NDArray);
00162   REGISTER_STD_HANDLERS (btyp_uint32, uint32NDArray);
00163   REGISTER_STD_HANDLERS (btyp_uint64, uint64NDArray);
00164 
00165   // For bools, we register and/or.
00166   REGISTER_OP_HANDLER (bsxfun_builtin_and, btyp_bool, boolNDArray, bsxfun_and);
00167   REGISTER_OP_HANDLER (bsxfun_builtin_or, btyp_bool, boolNDArray, bsxfun_or);
00168 
00169   // Register power handlers.
00170   bsxfun_handler_table[bsxfun_builtin_power][btyp_double] =
00171     do_bsxfun_real_pow<NDArray, ComplexNDArray>;
00172   bsxfun_handler_table[bsxfun_builtin_power][btyp_float] =
00173     do_bsxfun_real_pow<FloatNDArray, FloatComplexNDArray>;
00174 
00175   REGISTER_OP_HANDLER (bsxfun_builtin_power, btyp_complex, ComplexNDArray, bsxfun_pow);
00176   REGISTER_OP_HANDLER (bsxfun_builtin_power, btyp_float_complex, FloatComplexNDArray, bsxfun_pow);
00177 
00178   // For chars, we want just relational handlers.
00179   REGISTER_REL_HANDLER (bsxfun_builtin_eq, btyp_char, charNDArray, bsxfun_eq);
00180   REGISTER_REL_HANDLER (bsxfun_builtin_ne, btyp_char, charNDArray, bsxfun_ne);
00181   REGISTER_REL_HANDLER (bsxfun_builtin_lt, btyp_char, charNDArray, bsxfun_lt);
00182   REGISTER_REL_HANDLER (bsxfun_builtin_le, btyp_char, charNDArray, bsxfun_le);
00183   REGISTER_REL_HANDLER (bsxfun_builtin_gt, btyp_char, charNDArray, bsxfun_gt);
00184   REGISTER_REL_HANDLER (bsxfun_builtin_ge, btyp_char, charNDArray, bsxfun_ge);
00185 
00186   filled = true;
00187 }
00188 
00189 static octave_value
00190 maybe_optimized_builtin (const std::string& name,
00191                          const octave_value& a, const octave_value& b)
00192 {
00193   octave_value retval;
00194 
00195   maybe_fill_table ();
00196 
00197   bsxfun_builtin_op op = bsxfun_builtin_lookup (name);
00198   if (op != bsxfun_builtin_unknown)
00199     {
00200       builtin_type_t btyp_a = a.builtin_type (), btyp_b = b.builtin_type ();
00201 
00202       // Simplify single/double combinations.
00203       if (btyp_a == btyp_float && btyp_b == btyp_double)
00204         btyp_b = btyp_float;
00205       else if (btyp_a == btyp_double && btyp_b == btyp_float)
00206         btyp_a = btyp_float;
00207       else if (btyp_a == btyp_float_complex && btyp_b == btyp_complex)
00208         btyp_b = btyp_float_complex;
00209       else if (btyp_a == btyp_complex && btyp_b == btyp_float_complex)
00210         btyp_a = btyp_float_complex;
00211 
00212       if (btyp_a == btyp_b && btyp_a != btyp_unknown)
00213         {
00214           bsxfun_handler handler = bsxfun_handler_table[op][btyp_a];
00215           if (handler)
00216             retval = handler (a, b);
00217         }
00218     }
00219 
00220   return retval;
00221 }
00222 
00223 static bool
00224 maybe_update_column (octave_value& Ac, const octave_value& A,
00225                      const dim_vector& dva, const dim_vector& dvc,
00226                      octave_idx_type i, octave_value_list &idx)
00227 {
00228   octave_idx_type nd = dva.length ();
00229 
00230   if (i == 0)
00231     {
00232       idx(0) = octave_value (':');
00233       for (octave_idx_type j = 1; j < nd; j++)
00234         {
00235           if (dva (j) == 1)
00236             idx (j) = octave_value (1);
00237           else
00238             idx (j) = octave_value ((i % dvc(j)) + 1);
00239 
00240           i = i / dvc (j);
00241         }
00242 
00243       Ac = A;
00244       Ac = Ac.single_subsref ("(", idx);
00245       return true;
00246     }
00247   else
00248     {
00249       bool is_changed = false;
00250       octave_idx_type k = i;
00251       octave_idx_type k1 = i - 1;
00252       for (octave_idx_type j = 1; j < nd; j++)
00253         {
00254           if (dva(j) != 1 && k % dvc (j) != k1 % dvc (j))
00255             {
00256               idx (j) = octave_value ((k % dvc(j)) + 1);
00257               is_changed = true;
00258             }
00259 
00260           k = k / dvc (j);
00261           k1 = k1 / dvc (j);
00262         }
00263 
00264       if (is_changed)
00265         {
00266           Ac = A;
00267           Ac = Ac.single_subsref ("(", idx);
00268           return true;
00269         }
00270       else
00271         return false;
00272     }
00273 }
00274 
00275 #if 0
00276 // FIXME -- this function is not used; is it OK to delete it?
00277 static void
00278 update_index (octave_value_list& idx, const dim_vector& dv, octave_idx_type i)
00279 {
00280   octave_idx_type nd = dv.length ();
00281 
00282   if (i == 0)
00283     {
00284       for (octave_idx_type j = nd - 1; j > 0; j--)
00285         idx(j) = octave_value (static_cast<double>(1));
00286       idx(0) = octave_value (':');
00287     }
00288   else
00289     {
00290       for (octave_idx_type j = 1; j < nd; j++)
00291         {
00292           idx (j) = octave_value (i % dv (j) + 1);
00293           i = i / dv (j);
00294         }
00295     }
00296 }
00297 #endif
00298 
00299 static void
00300 update_index (Array<int>& idx, const dim_vector& dv, octave_idx_type i)
00301 {
00302   octave_idx_type nd = dv.length ();
00303 
00304   idx(0) = 0;
00305   for (octave_idx_type j = 1; j < nd; j++)
00306     {
00307       idx (j) = i % dv (j);
00308       i = i / dv (j);
00309     }
00310 }
00311 
00312 DEFUN_DLD (bsxfun, args, ,
00313   "-*- texinfo -*-\n\
00314 @deftypefn {Loadable Function} {} bsxfun (@var{f}, @var{A}, @var{B})\n\
00315 The binary singleton expansion function applier performs broadcasting,\n\
00316 that is, applies a binary function @var{f} element-by-element to two\n\
00317 array arguments @var{A} and @var{B}, and expands as necessary\n\
00318 singleton dimensions in either input argument.  @var{f} is a function\n\
00319 handle, inline function, or string containing the name of the function\n\
00320 to evaluate.  The function @var{f} must be capable of accepting two\n\
00321 column-vector arguments of equal length, or one column vector argument\n\
00322 and a scalar.\n\
00323 \n\
00324 The dimensions of @var{A} and @var{B} must be equal or singleton.  The\n\
00325 singleton dimensions of the arrays will be expanded to the same\n\
00326 dimensionality as the other array.\n\
00327 @seealso{arrayfun, cellfun}\n\
00328 @end deftypefn")
00329 {
00330   int nargin = args.length ();
00331   octave_value_list retval;
00332 
00333   if (nargin != 3)
00334     print_usage ();
00335   else
00336     {
00337       octave_value func = args(0);
00338 
00339       if (func.is_string ())
00340         {
00341           std::string name = func.string_value ();
00342           func = symbol_table::find_function (name);
00343           if (func.is_undefined ())
00344             error ("bsxfun: invalid function name: %s", name.c_str ());
00345         }
00346       else if (! (args(0).is_function_handle () || args(0).is_inline_function ()))
00347         error ("bsxfun: F must be a string or function handle");
00348 
00349       const octave_value A = args (1);
00350       const octave_value B = args (2);
00351 
00352       if (func.is_builtin_function ()
00353           || (func.is_function_handle () && ! A.is_object () && ! B.is_object ()))
00354         {
00355           // This may break if the default behavior is overriden. But if you override
00356           // arithmetic operators for builtin classes, you should expect mayhem
00357           // anyway (constant folding etc). Querying is_overloaded may not be
00358           // exactly what we need here.
00359           octave_function *fcn_val = func.function_value ();
00360           if (fcn_val)
00361             {
00362               octave_value tmp = maybe_optimized_builtin (fcn_val->name (), A, B);
00363               if (tmp.is_defined ())
00364                 retval(0) = tmp;
00365             }
00366         }
00367 
00368       if (! error_state && retval.empty ())
00369         {
00370           dim_vector dva = A.dims ();
00371           octave_idx_type nda = dva.length ();
00372           dim_vector dvb = B.dims ();
00373           octave_idx_type ndb = dvb.length ();
00374           octave_idx_type nd = nda;
00375 
00376           if (nda > ndb)
00377               dvb.resize (nda, 1);
00378           else if (nda < ndb)
00379             {
00380               dva.resize (ndb, 1);
00381               nd = ndb;
00382             }
00383 
00384           for (octave_idx_type i = 0; i < nd; i++)
00385             if (dva (i) != dvb (i) && dva (i) != 1 && dvb (i) != 1)
00386               {
00387                 error ("bsxfun: dimensions of A and B must match");
00388                 break;
00389               }
00390 
00391           if (!error_state)
00392             {
00393               // Find the size of the output
00394               dim_vector dvc;
00395               dvc.resize (nd);
00396 
00397               for (octave_idx_type i = 0; i < nd; i++)
00398                 dvc (i) = (dva (i) < 1  ? dva (i) : (dvb (i) < 1 ? dvb (i) :
00399                       (dva (i) > dvb (i) ? dva (i) : dvb (i))));
00400 
00401               if (dva == dvb || dva.numel () == 1 || dvb.numel () == 1)
00402                 {
00403                   octave_value_list inputs;
00404                   inputs (0) = A;
00405                   inputs (1) = B;
00406                   retval = func.do_multi_index_op (1, inputs);
00407                 }
00408               else if (dvc.numel () < 1)
00409                 {
00410                   octave_value_list inputs;
00411                   inputs (0) = A.resize (dvc);
00412                   inputs (1) = B.resize (dvc);
00413                   retval = func.do_multi_index_op (1, inputs);
00414                 }
00415               else
00416                 {
00417                   octave_idx_type ncount = 1;
00418                   for (octave_idx_type i = 1; i < nd; i++)
00419                     ncount *= dvc (i);
00420 
00421 #define BSXDEF(T) \
00422                   T result_ ## T; \
00423                   bool have_ ## T = false;
00424 
00425                   BSXDEF(NDArray);
00426                   BSXDEF(ComplexNDArray);
00427                   BSXDEF(FloatNDArray);
00428                   BSXDEF(FloatComplexNDArray);
00429                   BSXDEF(boolNDArray);
00430                   BSXDEF(int8NDArray);
00431                   BSXDEF(int16NDArray);
00432                   BSXDEF(int32NDArray);
00433                   BSXDEF(int64NDArray);
00434                   BSXDEF(uint8NDArray);
00435                   BSXDEF(uint16NDArray);
00436                   BSXDEF(uint32NDArray);
00437                   BSXDEF(uint64NDArray);
00438 
00439                   octave_value Ac ;
00440                   octave_value_list idxA;
00441                   octave_value Bc;
00442                   octave_value_list idxB;
00443                   octave_value C;
00444                   octave_value_list inputs;
00445                   Array<int> ra_idx (dim_vector (dvc.length(), 1), 0);
00446 
00447 
00448                   for (octave_idx_type i = 0; i < ncount; i++)
00449                     {
00450                       if (maybe_update_column (Ac, A, dva, dvc, i, idxA))
00451                         inputs (0) = Ac;
00452 
00453                       if (maybe_update_column (Bc, B, dvb, dvc, i, idxB))
00454                         inputs (1) = Bc;
00455 
00456                       octave_value_list tmp = func.do_multi_index_op (1, inputs);
00457 
00458                       if (error_state)
00459                         break;
00460 
00461 #define BSXINIT(T, CLS, EXTRACTOR) \
00462                       (result_type == CLS) \
00463                         { \
00464                             have_ ## T = true; \
00465                             result_ ## T = \
00466                                 tmp (0). EXTRACTOR ## _array_value (); \
00467                             result_ ## T .resize (dvc); \
00468                         }
00469 
00470                       if (i == 0)
00471                         {
00472                           if (! tmp(0).is_sparse_type ())
00473                             {
00474                               std::string result_type = tmp(0).class_name ();
00475                               if (result_type == "double")
00476                                 {
00477                                   if (tmp(0).is_real_type ())
00478                                     {
00479                                       have_NDArray = true;
00480                                       result_NDArray = tmp(0).array_value ();
00481                                       result_NDArray.resize (dvc);
00482                                     }
00483                                   else
00484                                     {
00485                                       have_ComplexNDArray = true;
00486                                       result_ComplexNDArray =
00487                                         tmp(0).complex_array_value ();
00488                                       result_ComplexNDArray.resize (dvc);
00489                                     }
00490                                 }
00491                               else if (result_type == "single")
00492                                 {
00493                                   if (tmp(0).is_real_type ())
00494                                     {
00495                                       have_FloatNDArray = true;
00496                                       result_FloatNDArray = tmp(0).float_array_value ();
00497                                       result_FloatNDArray.resize (dvc);
00498                                     }
00499                                   else
00500                                     {
00501                                       have_ComplexNDArray = true;
00502                                       result_ComplexNDArray =
00503                                         tmp(0).complex_array_value ();
00504                                       result_ComplexNDArray.resize (dvc);
00505                                     }
00506                                 }
00507                               else if BSXINIT(boolNDArray, "logical", bool)
00508                               else if BSXINIT(int8NDArray, "int8", int8)
00509                               else if BSXINIT(int16NDArray, "int16", int16)
00510                               else if BSXINIT(int32NDArray, "int32", int32)
00511                               else if BSXINIT(int64NDArray, "int64", int64)
00512                               else if BSXINIT(uint8NDArray, "uint8", uint8)
00513                               else if BSXINIT(uint16NDArray, "uint16", uint16)
00514                               else if BSXINIT(uint32NDArray, "uint32", uint32)
00515                               else if BSXINIT(uint64NDArray, "uint64", uint64)
00516                               else
00517                                 {
00518                                   C = tmp (0);
00519                                   C = C.resize (dvc);
00520                                 }
00521                             }
00522                         }
00523                       else
00524                         {
00525                           update_index (ra_idx, dvc, i);
00526 
00527                           if (have_FloatNDArray ||
00528                               have_FloatComplexNDArray)
00529                             {
00530                               if (! tmp(0).is_float_type ())
00531                                 {
00532                                   if (have_FloatNDArray)
00533                                     {
00534                                       have_FloatNDArray = false;
00535                                       C = result_FloatNDArray;
00536                                     }
00537                                   else
00538                                     {
00539                                       have_FloatComplexNDArray = false;
00540                                       C = result_FloatComplexNDArray;
00541                                     }
00542                                   C = do_cat_op (C, tmp(0), ra_idx);
00543                                 }
00544                               else if (tmp(0).is_double_type ())
00545                                 {
00546                                   if (tmp(0).is_complex_type () &&
00547                                       have_FloatNDArray)
00548                                     {
00549                                       result_ComplexNDArray =
00550                                         ComplexNDArray (result_FloatNDArray);
00551                                       result_ComplexNDArray.insert
00552                                         (tmp(0).complex_array_value(), ra_idx);
00553                                       have_FloatComplexNDArray = false;
00554                                       have_ComplexNDArray = true;
00555                                     }
00556                                   else
00557                                     {
00558                                       result_NDArray =
00559                                         NDArray (result_FloatNDArray);
00560                                       result_NDArray.insert
00561                                         (tmp(0).array_value(), ra_idx);
00562                                       have_FloatNDArray = false;
00563                                       have_NDArray = true;
00564                                     }
00565                                 }
00566                               else if (tmp(0).is_real_type ())
00567                                 result_FloatNDArray.insert
00568                                   (tmp(0).float_array_value(), ra_idx);
00569                               else
00570                                 {
00571                                   result_FloatComplexNDArray =
00572                                     FloatComplexNDArray (result_FloatNDArray);
00573                                   result_FloatComplexNDArray.insert
00574                                     (tmp(0).float_complex_array_value(), ra_idx);
00575                                   have_FloatNDArray = false;
00576                                   have_FloatComplexNDArray = true;
00577                                 }
00578                             }
00579                           else if (have_NDArray)
00580                             {
00581                               if (! tmp(0).is_float_type ())
00582                                 {
00583                                   have_NDArray = false;
00584                                   C = result_NDArray;
00585                                   C = do_cat_op (C, tmp(0), ra_idx);
00586                                 }
00587                               else if (tmp(0).is_real_type ())
00588                                 result_NDArray.insert (tmp(0).array_value(),
00589                                                        ra_idx);
00590                               else
00591                                 {
00592                                   result_ComplexNDArray =
00593                                     ComplexNDArray (result_NDArray);
00594                                   result_ComplexNDArray.insert
00595                                     (tmp(0).complex_array_value(), ra_idx);
00596                                   have_NDArray = false;
00597                                   have_ComplexNDArray = true;
00598                                 }
00599                             }
00600 
00601 #define BSXLOOP(T, CLS, EXTRACTOR) \
00602                         (have_ ## T) \
00603                           { \
00604                             if (tmp (0).class_name () != CLS) \
00605                               { \
00606                                 have_ ## T = false; \
00607                                 C = result_ ## T; \
00608                                 C = do_cat_op (C, tmp (0), ra_idx); \
00609                               } \
00610                             else \
00611                               result_ ## T .insert \
00612                                 (tmp(0). EXTRACTOR ## _array_value (), \
00613                                 ra_idx); \
00614                           }
00615 
00616                           else if BSXLOOP(ComplexNDArray, "double", complex)
00617                           else if BSXLOOP(boolNDArray, "logical", bool)
00618                           else if BSXLOOP(int8NDArray, "int8", int8)
00619                           else if BSXLOOP(int16NDArray, "int16", int16)
00620                           else if BSXLOOP(int32NDArray, "int32", int32)
00621                           else if BSXLOOP(int64NDArray, "int64", int64)
00622                           else if BSXLOOP(uint8NDArray, "uint8", uint8)
00623                           else if BSXLOOP(uint16NDArray, "uint16", uint16)
00624                           else if BSXLOOP(uint32NDArray, "uint32", uint32)
00625                           else if BSXLOOP(uint64NDArray, "uint64", uint64)
00626                           else
00627                             C = do_cat_op (C, tmp(0), ra_idx);
00628                         }
00629                     }
00630 
00631 #define BSXEND(T) \
00632                   (have_ ## T) \
00633                     retval (0) = result_ ## T;
00634 
00635                   if BSXEND(NDArray)
00636                   else if BSXEND(ComplexNDArray)
00637                   else if BSXEND(FloatNDArray)
00638                   else if BSXEND(FloatComplexNDArray)
00639                   else if BSXEND(boolNDArray)
00640                   else if BSXEND(int8NDArray)
00641                   else if BSXEND(int16NDArray)
00642                   else if BSXEND(int32NDArray)
00643                   else if BSXEND(int64NDArray)
00644                   else if BSXEND(uint8NDArray)
00645                   else if BSXEND(uint16NDArray)
00646                   else if BSXEND(uint32NDArray)
00647                   else if BSXEND(uint64NDArray)
00648                   else
00649                     retval(0) = C;
00650                 }
00651             }
00652         }
00653     }
00654 
00655   return retval;
00656 }
00657 
00658 /*
00659 
00660 %!shared a, b, c, f
00661 %! a = randn (4, 4);
00662 %! b = mean (a, 1);
00663 %! c = mean (a, 2);
00664 %! f = @minus;
00665 %!error(bsxfun (f));
00666 %!error(bsxfun (f, a));
00667 %!error(bsxfun (a, b));
00668 %!error(bsxfun (a, b, c));
00669 %!error(bsxfun (f, a, b, c));
00670 %!error(bsxfun (f, ones(4, 0), ones(4, 4)))
00671 %!assert(bsxfun (f, ones(4, 0), ones(4, 1)), zeros(4, 0));
00672 %!assert(bsxfun (f, ones(1, 4), ones(4, 1)), zeros(4, 4));
00673 %!assert(bsxfun (f, a, b), a - repmat(b, 4, 1));
00674 %!assert(bsxfun (f, a, c), a - repmat(c, 1, 4));
00675 %!assert(bsxfun ("minus", ones(1, 4), ones(4, 1)), zeros(4, 4));
00676 
00677 %!shared a, b, c, f
00678 %! a = randn (4, 4);
00679 %! a(1) *= 1i;
00680 %! b = mean (a, 1);
00681 %! c = mean (a, 2);
00682 %! f = @minus;
00683 %!error(bsxfun (f));
00684 %!error(bsxfun (f, a));
00685 %!error(bsxfun (a, b));
00686 %!error(bsxfun (a, b, c));
00687 %!error(bsxfun (f, a, b, c));
00688 %!error(bsxfun (f, ones(4, 0), ones(4, 4)))
00689 %!assert(bsxfun (f, ones(4, 0), ones(4, 1)), zeros(4, 0));
00690 %!assert(bsxfun (f, ones(1, 4), ones(4, 1)), zeros(4, 4));
00691 %!assert(bsxfun (f, a, b), a - repmat(b, 4, 1));
00692 %!assert(bsxfun (f, a, c), a - repmat(c, 1, 4));
00693 %!assert(bsxfun ("minus", ones(1, 4), ones(4, 1)), zeros(4, 4));
00694 
00695 %!shared a, b, c, f
00696 %! a = randn (4, 4);
00697 %! a(end) *= 1i;
00698 %! b = mean (a, 1);
00699 %! c = mean (a, 2);
00700 %! f = @minus;
00701 %!error(bsxfun (f));
00702 %!error(bsxfun (f, a));
00703 %!error(bsxfun (a, b));
00704 %!error(bsxfun (a, b, c));
00705 %!error(bsxfun (f, a, b, c));
00706 %!error(bsxfun (f, ones(4, 0), ones(4, 4)))
00707 %!assert(bsxfun (f, ones(4, 0), ones(4, 1)), zeros(4, 0));
00708 %!assert(bsxfun (f, ones(1, 4), ones(4, 1)), zeros(4, 4));
00709 %!assert(bsxfun (f, a, b), a - repmat(b, 4, 1));
00710 %!assert(bsxfun (f, a, c), a - repmat(c, 1, 4));
00711 %!assert(bsxfun ("minus", ones(1, 4), ones(4, 1)), zeros(4, 4));
00712 
00713 %!shared a, b, c, f
00714 %! a = randn (4, 4);
00715 %! b = a (1, :);
00716 %! c = a (:, 1);
00717 %! f = @(x, y) x == y;
00718 %!error(bsxfun (f));
00719 %!error(bsxfun (f, a));
00720 %!error(bsxfun (a, b));
00721 %!error(bsxfun (a, b, c));
00722 %!error(bsxfun (f, a, b, c));
00723 %!error(bsxfun (f, ones(4, 0), ones(4, 4)))
00724 %!assert(bsxfun (f, ones(4, 0), ones(4, 1)), zeros(4, 0, "logical"));
00725 %!assert(bsxfun (f, ones(1, 4), ones(4, 1)), ones(4, 4, "logical"));
00726 %!assert(bsxfun (f, a, b), a == repmat(b, 4, 1));
00727 %!assert(bsxfun (f, a, c), a == repmat(c, 1, 4));
00728 
00729 %!shared a, b, c, d, f
00730 %! a = randn (4, 4, 4);
00731 %! b = mean (a, 1);
00732 %! c = mean (a, 2);
00733 %! d = mean (a, 3);
00734 %! f = @minus;
00735 %!error(bsxfun (f, ones([4, 0, 4]), ones([4, 4, 4])));
00736 %!assert(bsxfun (f, ones([4, 0, 4]), ones([4, 1, 4])), zeros([4, 0, 4]));
00737 %!assert(bsxfun (f, ones([4, 4, 0]), ones([4, 1, 1])), zeros([4, 4, 0]));
00738 %!assert(bsxfun (f, ones([1, 4, 4]), ones([4, 1, 4])), zeros([4, 4, 4]));
00739 %!assert(bsxfun (f, ones([4, 4, 1]), ones([4, 1, 4])), zeros([4, 4, 4]));
00740 %!assert(bsxfun (f, ones([4, 1, 4]), ones([1, 4, 4])), zeros([4, 4, 4]));
00741 %!assert(bsxfun (f, ones([4, 1, 4]), ones([1, 4, 1])), zeros([4, 4, 4]));
00742 %!assert(bsxfun (f, a, b), a - repmat(b, [4, 1, 1]));
00743 %!assert(bsxfun (f, a, c), a - repmat(c, [1, 4, 1]));
00744 %!assert(bsxfun (f, a, d), a - repmat(d, [1, 1, 4]));
00745 %!assert(bsxfun ("minus", ones([4, 0, 4]), ones([4, 1, 4])), zeros([4, 0, 4]));
00746 
00747 %% The below is a very hard case to treat
00748 %!assert(bsxfun (f, ones([4, 1, 4, 1]), ones([1, 4, 1, 4])), zeros([4, 4, 4, 4]));
00749 
00750 %!shared a, b, aa, bb
00751 %! a = randn (3, 1, 3);
00752 %! aa = a(:, ones (1, 3), :, ones (1, 3));
00753 %! b = randn (1, 3, 3, 3);
00754 %! bb = b(ones (1, 3), :, :, :);
00755 %!assert (bsxfun (@plus, a, b), aa + bb);
00756 %!assert (bsxfun (@minus, a, b), aa - bb);
00757 %!assert (bsxfun (@times, a, b), aa .* bb);
00758 %!assert (bsxfun (@rdivide, a, b), aa ./ bb);
00759 %!assert (bsxfun (@ldivide, a, b), aa .\ bb);
00760 %!assert (bsxfun (@power, a, b), aa .^ bb);
00761 %!assert (bsxfun (@power, abs (a), b), abs (aa) .^ bb);
00762 %!assert (bsxfun (@eq, round (a), round (b)), round (aa) == round (bb));
00763 %!assert (bsxfun (@ne, round (a), round (b)), round (aa) != round (bb));
00764 %!assert (bsxfun (@lt, a, b), aa < bb);
00765 %!assert (bsxfun (@le, a, b), aa <= bb);
00766 %!assert (bsxfun (@gt, a, b), aa > bb);
00767 %!assert (bsxfun (@ge, a, b), aa >= bb);
00768 %!assert (bsxfun (@min, a, b), min (aa, bb));
00769 %!assert (bsxfun (@max, a, b), max (aa, bb));
00770 %!assert (bsxfun (@and, a > 0, b > 0), (aa > 0) & (bb > 0));
00771 %!assert (bsxfun (@or, a > 0, b > 0), (aa > 0) | (bb > 0));
00772 
00773 %% Test automatic bsxfun
00774 %
00775 %!test
00776 %! funs = {@plus, @minus, @times, @rdivide, @ldivide, @power, @max, @min, \
00777 %!         @rem, @mod, @atan2, @hypot, @eq, @ne, @lt, @le, @gt, @ge, \
00778 %!         @and, @or, @xor };
00779 %!
00780 %! float_types = {@single, @double};
00781 %! int_types = {@int8, @int16, @int32, @int64, \
00782 %!             @uint8, @uint16, @uint32, @uint64};
00783 %!
00784 %! x = rand (3)*10-5;
00785 %! y = rand (3,1)*10-5;
00786 %!
00787 %! for i=1:length (funs)
00788 %!   for j = 1:length(float_types)
00789 %!     for k = 1:length(int_types)
00790 %!
00791 %!       fun = funs{i};
00792 %!       f_type = float_types{j};
00793 %!       i_type = int_types{k};
00794 %!
00795 %!         assert (bsxfun (fun, f_type (x), i_type (y)), \
00796 %!                 fun (f_type(x), i_type (y)));
00797 %!         assert (bsxfun (fun, f_type (y), i_type (x)), \
00798 %!                 fun (f_type(y), i_type (x)));
00799 %!
00800 %!         assert (bsxfun (fun, i_type (x), i_type (y)), \
00801 %!                 fun (i_type (x), i_type (y)));
00802 %!         assert (bsxfun (fun, i_type (y), i_type (x)), \
00803 %!                 fun (i_type (y), i_type (x)));
00804 %!
00805 %!         assert (bsxfun (fun, f_type (x), f_type (y)), \
00806 %!                 fun (f_type (x), f_type (y)));
00807 %!         assert (bsxfun (fun, f_type(y), f_type(x)), \
00808 %!                 fun (f_type (y), f_type (x)));
00809 %!     endfor
00810 %!   endfor
00811 %! endfor
00812 %!
00813 */
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines