oct-binmap.h

Go to the documentation of this file.
00001 /*
00002 
00003 Copyright (C) 2010-2012 VZLU Prague
00004 
00005 This file is part of Octave.
00006 
00007 Octave is free software; you can redistribute it and/or modify it
00008 under the terms of the GNU General Public License as published by the
00009 Free Software Foundation; either version 3 of the License, or (at your
00010 option) any later version.
00011 
00012 Octave is distributed in the hope that it will be useful, but WITHOUT
00013 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00014 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00015 for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Octave; see the file COPYING.  If not, see
00019 <http://www.gnu.org/licenses/>.
00020 
00021 */
00022 
00023 #if !defined (octave_binmap_h)
00024 #define octave_binmap_h 1
00025 
00026 #include "Array.h"
00027 #include "Sparse.h"
00028 #include "Array-util.h"
00029 
00030 #include "bsxfun.h"
00031 
00032 // This source file implements a general binary maping function for
00033 // arrays. The syntax is binmap<type> (a, b, f, [name]). type denotes
00034 // the expected return type of the operation. a, b, should be one of
00035 // the 6 combinations:
00036 //
00037 // Array-Array
00038 // Array-scalar
00039 // scalar-Array
00040 // Sparse-Sparse
00041 // Sparse-scalar
00042 // scalar-Sparse
00043 //
00044 // If both operands are nonscalar, name must be supplied. It is used
00045 // as the base for error message when operands are nonconforming.
00046 //
00047 // The operation needs not be homogeneous, i.e. a, b and the result
00048 // may be of distinct types. f can have any of the four signatures:
00049 //
00050 // U f (T, R)
00051 // U f (const T&, R)
00052 // U f (T, const R&)
00053 // U f (const T&, const R&)
00054 //
00055 // Additionally, f can be an arbitrary functor object.
00056 //
00057 // octave_quit() is called at appropriate places, hence the operation
00058 // is breakable.
00059 
00060 // The following template wrappers are provided for automatic bsxfun
00061 // calls (see the function signature for do_bsxfun_op).
00062 
00063 template<typename R, typename X, typename Y, typename F>
00064 class bsxfun_wrapper
00065 {
00066 private:
00067   static F f;
00068 
00069 public:
00070   static void
00071   set_f (const F& f_in)
00072   {
00073     f = f_in;
00074   }
00075 
00076   static void
00077   op_mm (size_t n, R* r, const X* x , const Y* y)
00078   {
00079     for (size_t i = 0; i < n; i++)
00080       r[i] = f (x[i], y[i]);
00081   }
00082 
00083   static void
00084   op_sm (size_t n, R* r, X x, const Y* y)
00085   {
00086     for (size_t i = 0; i < n; i++)
00087       r[i] = f (x, y[i]);
00088   }
00089 
00090   static void
00091   op_ms (size_t n , R* r, const X* x, Y y)
00092   {
00093     for (size_t i = 0; i < n; i++)
00094       r[i] = f (x[i], y);
00095   }
00096 };
00097 
00098 // Static init
00099 template<typename R, typename X, typename Y, typename F>
00100 F bsxfun_wrapper<R, X, Y, F>::f;
00101 
00102 
00103 // scalar-Array
00104 template <class U, class T, class R, class F>
00105 Array<U>
00106 binmap (const T& x, const Array<R>& ya, F fcn)
00107 {
00108   octave_idx_type len = ya.numel ();
00109 
00110   const R *y = ya.data ();
00111 
00112   Array<U> result (ya.dims ());
00113   U *p = result.fortran_vec ();
00114 
00115   octave_idx_type i;
00116   for (i = 0; i < len - 3; i += 4)
00117     {
00118       octave_quit ();
00119 
00120       p[i] = fcn (x, y[i]);
00121       p[i+1] = fcn (x, y[i+1]);
00122       p[i+2] = fcn (x, y[i+2]);
00123       p[i+3] = fcn (x, y[i+3]);
00124     }
00125 
00126   octave_quit ();
00127 
00128   for (; i < len; i++)
00129     p[i] = fcn (x, y[i]);
00130 
00131   return result;
00132 }
00133 
00134 // Array-scalar
00135 template <class U, class T, class R, class F>
00136 Array<U>
00137 binmap (const Array<T>& xa, const R& y, F fcn)
00138 {
00139   octave_idx_type len = xa.numel ();
00140 
00141   const R *x = xa.data ();
00142 
00143   Array<U> result (xa.dims ());
00144   U *p = result.fortran_vec ();
00145 
00146   octave_idx_type i;
00147   for (i = 0; i < len - 3; i += 4)
00148     {
00149       octave_quit ();
00150 
00151       p[i] = fcn (x[i], y);
00152       p[i+1] = fcn (x[i+1], y);
00153       p[i+2] = fcn (x[i+2], y);
00154       p[i+3] = fcn (x[i+3], y);
00155     }
00156 
00157   octave_quit ();
00158 
00159   for (; i < len; i++)
00160     p[i] = fcn (x[i], y);
00161 
00162   return result;
00163 }
00164 
00165 // Array-Array (treats singletons as scalars)
00166 template <class U, class T, class R, class F>
00167 Array<U>
00168 binmap (const Array<T>& xa, const Array<R>& ya, F fcn, const char *name)
00169 {
00170   dim_vector xad = xa.dims (), yad = ya.dims ();
00171   if (xa.numel () == 1)
00172     return binmap<U, T, R, F> (xa(0), ya, fcn);
00173   else if (ya.numel () == 1)
00174     return binmap<U, T, R, F> (xa, ya(0), fcn);
00175   else if (xad != yad)
00176     {
00177       if (is_valid_bsxfun (name, xad, yad))
00178         {
00179           bsxfun_wrapper<U, T, R, F>::set_f(fcn);
00180           return do_bsxfun_op (xa, ya,
00181                                bsxfun_wrapper<U, T, R, F>::op_mm,
00182                                bsxfun_wrapper<U, T, R, F>::op_sm,
00183                                bsxfun_wrapper<U, T, R, F>::op_ms);
00184         }
00185       else
00186         gripe_nonconformant (name, xad, yad);
00187     }
00188 
00189   octave_idx_type len = xa.numel ();
00190 
00191   const T *x = xa.data ();
00192   const T *y = ya.data ();
00193 
00194   Array<U> result (xa.dims ());
00195   U *p = result.fortran_vec ();
00196 
00197   octave_idx_type i;
00198   for (i = 0; i < len - 3; i += 4)
00199     {
00200       octave_quit ();
00201 
00202       p[i] = fcn (x[i], y[i]);
00203       p[i+1] = fcn (x[i+1], y[i+1]);
00204       p[i+2] = fcn (x[i+2], y[i+2]);
00205       p[i+3] = fcn (x[i+3], y[i+3]);
00206     }
00207 
00208   octave_quit ();
00209 
00210   for (; i < len; i++)
00211     p[i] = fcn (x[i], y[i]);
00212 
00213   return result;
00214 }
00215 
00216 // scalar-Sparse
00217 template <class U, class T, class R, class F>
00218 Sparse<U>
00219 binmap (const T& x, const Sparse<R>& ys, F fcn)
00220 {
00221   octave_idx_type nz = ys.nnz ();
00222   Sparse<U> retval (ys.rows (), ys.cols (), nz);
00223   for (octave_idx_type i = 0; i < nz; i++)
00224     {
00225       octave_quit ();
00226       retval.xdata(i) = fcn (x, ys.data(i));
00227     }
00228 
00229   octave_quit ();
00230   retval.maybe_compress ();
00231   return retval;
00232 }
00233 
00234 // Sparse-scalar
00235 template <class U, class T, class R, class F>
00236 Sparse<U>
00237 binmap (const Sparse<T>& xs, const R& y, F fcn)
00238 {
00239   octave_idx_type nz = xs.nnz ();
00240   Sparse<U> retval (xs.rows (), xs.cols (), nz);
00241   for (octave_idx_type i = 0; i < nz; i++)
00242     {
00243       octave_quit ();
00244       retval.xdata(i) = fcn (xs.data(i), y);
00245     }
00246 
00247   octave_quit ();
00248   retval.maybe_compress ();
00249   return retval;
00250 }
00251 
00252 // Sparse-Sparse (treats singletons as scalars)
00253 template <class U, class T, class R, class F>
00254 Sparse<U>
00255 binmap (const Sparse<T>& xs, const Sparse<R>& ys, F fcn, const char *name)
00256 {
00257   if (xs.rows () == 1 && xs.cols () == 1)
00258     return binmap<U, T, R, F> (xs(0,0), ys, fcn);
00259   else if (ys.rows () == 1 && ys.cols () == 1)
00260     return binmap<U, T, R, F> (xs, ys(0,0), fcn);
00261   else if (xs.dims () != ys.dims ())
00262     gripe_nonconformant (name, xs.dims (), ys.dims ());
00263 
00264   T xzero = T ();
00265   R yzero = R ();
00266 
00267   U fz = fcn (xzero, yzero);
00268   if (fz == U())
00269     {
00270       // Sparsity-preserving function. Do it efficiently.
00271       octave_idx_type nr = xs.rows (), nc = xs.cols ();
00272       Sparse<T> retval (nr, nc);
00273 
00274       octave_idx_type nz = 0;
00275       // Count nonzeros.
00276       for (octave_idx_type j = 0; j < nc; j++)
00277         {
00278           octave_quit ();
00279           octave_idx_type ix = xs.cidx(j), iy = ys.cidx(j);
00280           octave_idx_type ux = xs.cidx(j+1), uy = ys.cidx(j+1);
00281           while (ix != ux || iy != uy)
00282             {
00283               octave_idx_type rx = xs.ridx(ix), ry = ys.ridx(ix);
00284               ix += rx <= ry;
00285               iy += ry <= rx;
00286               nz++;
00287             }
00288 
00289           retval.xcidx(j+1) = nz;
00290         }
00291 
00292       // Allocate space.
00293       retval.change_capacity (retval.xcidx(nc));
00294 
00295       // Fill.
00296       nz = 0;
00297       for (octave_idx_type j = 0; j < nc; j++)
00298         {
00299           octave_quit ();
00300           octave_idx_type ix = xs.cidx(j), iy = ys.cidx(j);
00301           octave_idx_type ux = xs.cidx(j+1), uy = ys.cidx(j+1);
00302           while (ix != ux || iy != uy)
00303             {
00304               octave_idx_type rx = xs.ridx(ix), ry = ys.ridx(ix);
00305               if (rx == ry)
00306                 {
00307                   retval.xridx(nz) = rx;
00308                   retval.xdata(nz) = fcn (xs.data(ix), ys.data(iy));
00309                   ix++;
00310                   iy++;
00311                 }
00312               else if (rx < ry)
00313                 {
00314                   retval.xridx(nz) = rx;
00315                   retval.xdata(nz) = fcn (xs.data(ix), yzero);
00316                   ix++;
00317                 }
00318               else if (ry < rx)
00319                 {
00320                   retval.xridx(nz) = ry;
00321                   retval.xdata(nz) = fcn (xzero, ys.data(iy));
00322                   iy++;
00323                 }
00324 
00325               nz++;
00326             }
00327         }
00328 
00329       retval.maybe_compress ();
00330       return retval;
00331     }
00332   else
00333     return Sparse<U> (binmap<U, T, R, F> (xs.array_value (), ys.array_value (),
00334                                           fcn, name));
00335 }
00336 
00337 // Overloads for function pointers.
00338 
00339 // Signature (T, R)
00340 
00341 template <class U, class T, class R>
00342 inline Array<U>
00343 binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, R), const char *name)
00344 { return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
00345 
00346 template <class U, class T, class R>
00347 inline Array<U>
00348 binmap (const T& x, const Array<R>& ya, U (*fcn) (T, R))
00349 { return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
00350 
00351 template <class U, class T, class R>
00352 inline Array<U>
00353 binmap (const Array<T>& xa, const R& y, U (*fcn) (T, R))
00354 { return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
00355 
00356 template <class U, class T, class R>
00357 inline Sparse<U>
00358 binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, R), const char *name)
00359 { return binmap<U, T, R, U (*) (T, R)> (xa, ya, fcn, name); }
00360 
00361 template <class U, class T, class R>
00362 inline Sparse<U>
00363 binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, R))
00364 { return binmap<U, T, R, U (*) (T, R)> (x, ya, fcn); }
00365 
00366 template <class U, class T, class R>
00367 inline Sparse<U>
00368 binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, R))
00369 { return binmap<U, T, R, U (*) (T, R)> (xa, y, fcn); }
00370 
00371 // Signature (const T&, const R&)
00372 
00373 template <class U, class T, class R>
00374 inline Array<U>
00375 binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, const R&), const char *name)
00376 { return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
00377 
00378 template <class U, class T, class R>
00379 inline Array<U>
00380 binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, const R&))
00381 { return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
00382 
00383 template <class U, class T, class R>
00384 inline Array<U>
00385 binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, const R&))
00386 { return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
00387 
00388 template <class U, class T, class R>
00389 inline Sparse<U>
00390 binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, const R&), const char *name)
00391 { return binmap<U, T, R, U (*) (const T&, const R&)> (xa, ya, fcn, name); }
00392 
00393 template <class U, class T, class R>
00394 inline Sparse<U>
00395 binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, const R&))
00396 { return binmap<U, T, R, U (*) (const T&, const R&)> (x, ya, fcn); }
00397 
00398 template <class U, class T, class R>
00399 inline Sparse<U>
00400 binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, const R&))
00401 { return binmap<U, T, R, U (*) (const T&, const R&)> (xa, y, fcn); }
00402 
00403 // Signature (const T&, R)
00404 
00405 template <class U, class T, class R>
00406 inline Array<U>
00407 binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (const T&, R), const char *name)
00408 { return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
00409 
00410 template <class U, class T, class R>
00411 inline Array<U>
00412 binmap (const T& x, const Array<R>& ya, U (*fcn) (const T&, R))
00413 { return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
00414 
00415 template <class U, class T, class R>
00416 inline Array<U>
00417 binmap (const Array<T>& xa, const R& y, U (*fcn) (const T&, R))
00418 { return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
00419 
00420 template <class U, class T, class R>
00421 inline Sparse<U>
00422 binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (const T&, R), const char *name)
00423 { return binmap<U, T, R, U (*) (const T&, R)> (xa, ya, fcn, name); }
00424 
00425 template <class U, class T, class R>
00426 inline Sparse<U>
00427 binmap (const T& x, const Sparse<R>& ya, U (*fcn) (const T&, R))
00428 { return binmap<U, T, R, U (*) (const T&, R)> (x, ya, fcn); }
00429 
00430 template <class U, class T, class R>
00431 inline Sparse<U>
00432 binmap (const Sparse<T>& xa, const R& y, U (*fcn) (const T&, R))
00433 { return binmap<U, T, R, U (*) (const T&, R)> (xa, y, fcn); }
00434 
00435 // Signature (T, const R&)
00436 
00437 template <class U, class T, class R>
00438 inline Array<U>
00439 binmap (const Array<T>& xa, const Array<R>& ya, U (*fcn) (T, const R&), const char *name)
00440 { return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
00441 
00442 template <class U, class T, class R>
00443 inline Array<U>
00444 binmap (const T& x, const Array<R>& ya, U (*fcn) (T, const R&))
00445 { return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
00446 
00447 template <class U, class T, class R>
00448 inline Array<U>
00449 binmap (const Array<T>& xa, const R& y, U (*fcn) (T, const R&))
00450 { return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
00451 
00452 template <class U, class T, class R>
00453 inline Sparse<U>
00454 binmap (const Sparse<T>& xa, const Sparse<R>& ya, U (*fcn) (T, const R&), const char *name)
00455 { return binmap<U, T, R, U (*) (T, const R&)> (xa, ya, fcn, name); }
00456 
00457 template <class U, class T, class R>
00458 inline Sparse<U>
00459 binmap (const T& x, const Sparse<R>& ya, U (*fcn) (T, const R&))
00460 { return binmap<U, T, R, U (*) (T, const R&)> (x, ya, fcn); }
00461 
00462 template <class U, class T, class R>
00463 inline Sparse<U>
00464 binmap (const Sparse<T>& xa, const R& y, U (*fcn) (T, const R&))
00465 { return binmap<U, T, R, U (*) (T, const R&)> (xa, y, fcn); }
00466 
00467 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines