ivl 679
ivl/details/array/functions/array_functions.hpp
00001 /* This file is part of the ivl C++ library <http://image.ntua.gr/ivl>.
00002    A C++ template library extending syntax towards mathematical notation.
00003 
00004    Copyright (C) 2012 Yannis Avrithis <iavr@image.ntua.gr>
00005    Copyright (C) 2012 Kimon Kontosis <kimonas@image.ntua.gr>
00006 
00007    ivl is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU Lesser General Public License 
00009    version 3 as published by the Free Software Foundation.
00010 
00011    Alternatively, you can redistribute it and/or modify it under the terms 
00012    of the GNU General Public License version 2 as published by the Free 
00013    Software Foundation.
00014 
00015    ivl is distributed in the hope that it will be useful,
00016    but WITHOUT ANY WARRANTY; without even the implied warranty of
00017    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
00018    See the GNU General Public License for more details.
00019 
00020    You should have received a copy of the GNU General Public License 
00021    and a copy of the GNU Lesser General Public License along 
00022    with ivl. If not, see <http://www.gnu.org/licenses/>. */
00023 
00024 #ifndef IVL_ARRAY_DETAILS_ARRAY_FUNCTIONS_HPP
00025 #define IVL_ARRAY_DETAILS_ARRAY_FUNCTIONS_HPP
00026 
00027 namespace ivl {
00028 
00029 //--------------------------------------------------------------
00030 // array NON-MEMBER FUNCTIONS
00031 
00037 //----- functions returning scalar
00038 
00040 /* // Note: random access implementation should never be faster than
00041         // iterators and should not be necessary.
00042         // however it is kept here for a perfect solution that does the following:
00043         // if optimal_access_tag is random_access this is used else the other.
00044 template<class T, class S>
00045 typename types::promote<T>::type sum(const array<T, S>& a)
00046 {
00047         typedef typename types::promote<T>::type return_type;
00048         return_type s = cast<return_type>(a[0]);
00049         size_t len = a.length();
00050         for (size_t i = 1; i < len; i++)
00051                 s += cast<return_type>(a[i]);
00052         return s;
00053 }
00054 */
00055 template<class T, class S>
00056 typename types::promote<T>::type sum(const array<T, S>& a)
00057 {
00058         typedef typename types::promote<T>::type return_type;
00059         typedef typename types::get_value<T>::type val_type;
00060         typedef typename array<T, S>::const_iterator cit_t;
00061         if(!a.length()) 
00062                 return return_type();
00063         cit_t it = a.begin();
00064         return_type s = *it;
00065         for(cit_t it_e = a.end(); it != it_e; it++)
00066                 s += cast<val_type>(*it);
00067         return s;
00068 }
00069 
00071 template<class T, class S>
00072 typename types::to_floating<T>::type mean(const array<T, S>& a)
00073 {
00074         using namespace types;
00075 
00076         return cast<typename to_floating<T>::type>(sum(a)) /
00077                 typename to_real_floating<T>::type(a.length());
00078 }
00079 
00080 namespace select_k_details {
00081 
00082 template<class T, class S>
00083 T quick_select(array<T, S>& arr, size_t k)
00084 {
00085         //  This Quickselect routine is based on the algorithm described in
00086         //  "Numerical recipes in C", Second Edition,
00087         //  Cambridge University Press, 1992, Section 8.5, ISBN 0-521-43108-5
00088         //  This code by Nicolas Devillard - 1998. Public domain.
00089         size_t n = arr.size();
00090 
00091         size_t low, high;
00092         size_t median;
00093         size_t middle, ll, hh;
00094 
00095         low = 0 ; high = n - 1 ; median = k;
00096         for (;;) {
00097                 if (high <= low) // One element only
00098                         return arr[median];
00099 
00100                 if (high == low + 1) {  // Two elements only
00101                         if (arr[low] > arr[high])
00102                                 std::swap(arr[low], arr[high]);
00103                         return arr[median];
00104                 }
00105 
00106                 // Find median of low, middle and high items; swap into position low
00107                 middle = (low + high) / 2;
00108                 if (arr[middle] > arr[high]) std::swap(arr[middle], arr[high]);
00109                 if (arr[low] > arr[high])    std::swap(arr[low], arr[high]);
00110                 if (arr[middle] > arr[low])  std::swap(arr[middle], arr[low]);
00111 
00112                 // Swap low item (now in position middle) into position (low+1)
00113                 std::swap(arr[middle], arr[low + 1]);
00114 
00115                 // Nibble from each end towards middle, swapping items when stuck
00116                 ll = low + 1;
00117                 hh = high;
00118                 for (;;) {
00119                         do ll++; while (arr[low] > arr[ll]);
00120                         do hh--; while (arr[hh]  > arr[low]);
00121 
00122                         if (hh < ll)
00123                         break;
00124 
00125                         std::swap(arr[ll], arr[hh]);
00126                 }
00127 
00128                 // Swap middle item (in position low) back into correct position
00129                 std::swap(arr[low], arr[hh]);
00130 
00131                 // Re-set active partition
00132                 if (hh <= median)
00133                         low = ll;
00134                 if (hh >= median)
00135                         high = hh - 1;
00136         }
00137 }
00138 
00139 } // namespace select_k_details
00140 
00142 template <class T, class S>
00143 T select_k(const array<T, S>& a, size_t k)
00144 {
00145         array<T> arr = a;
00146         return select_k_details::quick_select(arr, k);
00147 }
00148 
00153 template<class T, class S>
00154 typename types::to_floating<T>::type median(const array<T, S>& a)
00155 {
00156         using namespace select_k_details;
00157         typedef typename types::to_floating<T>::type return_type;
00158 
00159         CHECK(a.length() != 0, erange);
00160 
00161         array<T> arr = a;
00162         int k = (arr.length() - 1) / 2;
00163 
00164         if((arr.length() & 2) == 1)
00165                 return cast<return_type>(quick_select(arr, k));
00166         else
00167                 return (cast<return_type>(quick_select(arr, k))
00168                         + cast<return_type>(quick_select(arr, k + 1)))
00169                         / cast<return_type>(2.0);
00170 }
00171 
00176 template <class T, class S>
00177 T median_lower(const array<T, S>& a)
00178 {
00179         array<T> arr = a;
00180         return select_k_details::quick_select(arr, (arr.length() - 1) / 2);
00181 }
00182 
00187 template <class T, class S>
00188 T median_upper(const array<T, S>& a)
00189 {
00190         array<T> arr = a;
00191         return select_k_details::quick_select(arr, arr.length() / 2);
00192 }
00193 
00194 /* old method
00196 template<class T, class S>
00197 typename types::to_floating<T>::type median(const array<T, S>& in)
00198 {
00199         typedef typename types::to_floating<T>::type return_type;
00200 
00201         //TO not DO:!! think if it should be simply array. and what kind of array?
00202         // created type? why? not for image purpose. only remaining is sparse
00203         // is it needed? I think i need to make it: array<T> a = sort(in);
00204         typename array<T, S>::create_similar a = sort(in.derived());
00205 
00206         if(in.length() % 2 == 1) // if array contains an odd number of elements
00207                 return cast<return_type>(a[a.length() / 2]);
00208         else
00209                 return (
00210                         cast<return_type>(a[a.length() / 2 - 1]) +
00211                         cast<return_type>(a[a.length() / 2])
00212                         ) / cast<return_type>(2.0);
00213 }
00214 */
00215 
00216 #if 0
00217 //redeclared as a corefunc
00218 
00225 template<class T, class S>
00226 T min(const array<T, S>& a)
00227 {
00228         T s = a[0];
00229         for (size_t i = 1; i < a.length(); i++)
00230                 if (a[i] < s)
00231                         s = a[i];
00232         return (s);
00233 }
00234 #endif
00235 
00236 //TODO: wipe @ some time!
00237 
00238 #if 0 // ivl fun
00239 
00245 template<class T, class S>
00246 T max(const array<T, S>& a)
00247 {
00248         T s = a[0];
00249         for (size_t i = 1; i < a.length(); i++)
00250                 if (a[i] > s)
00251                         s = a[i];
00252         return (s);
00253 }
00254 #endif
00255 
00256 #if 0 // this find is now implemented as an ivl func
00257 
00262 template <class T, class S>
00263 size_array find(const array<T, S>& in, const T& what, size_t start = 0)
00264 {
00265         size_array a(in.length());
00266         size_t n = 0;
00267         for (size_t i = start; i < in.length(); i++)
00268                 if (in[i] == what)
00269                         a[n++] = i;
00270         return n > 0 ? size_array(a, n) : size_array(0);
00271 }
00272 #endif
00273 
00275 template <class T, class S>
00276 size_t count(const array<T, S>& in)
00277 {
00278         size_t count = 0;
00279         for (size_t i = 0; i < in.length(); i++)
00280                 if(in[i])
00281                         count++;
00282         return count;
00283 }
00284 
00286 template<class T, class S>
00287 typename types::to_real_floating<T>::type var(const array<T, S>& in)
00288 {
00289         typedef typename types::to_real_floating<T>::type return_type;
00290         // kimon: the following line makes a redundant copy
00291         // it is because i cannot cast<T> from an array
00292         // kimon: fix for now, until array is wiped
00293         array<T> temporary = array<T>(in);
00294         array<typename types::to_floating<T>::type> a =
00295                 cast<typename types::to_floating<T>::type>(temporary);
00296 
00297         array<typename types::to_floating<T>::type> b = power(a - mean(a), 2.);
00298 
00299         // kimon: moreover, there are lots of redundant copies, because
00300         // of elem-func design. also check if a = elem_func(a) is safe.
00301         // (it probably is)
00302         array<return_type> c = abs(b);
00303 
00304         return return_type(sum(c)) /
00305                 return_type((a.length() == 1 ? 1 : a.length() - 1));
00306 
00307         return 0;
00308 }
00309 
00311 template<class T, class S>
00312 inline
00313 typename types::to_real_floating<T>::type std(const array<T, S>& in)
00314 {
00315         return std::sqrt(var(in));
00316 }
00317 
00318 
00320 template <class T, class S>
00321 array<T> array_common_base<array<T, S> >::cat(const array<T>& a) const
00322 {
00323         size_t len = to_array().length();
00324 
00325         array<T> c(len + a.length());
00326 
00327         for (size_t i = 0; i < len; i++)
00328                 c[i] = to_array()[i];
00329 
00330         for (size_t i = 0; i < a.length(); i++)
00331                 c[i + len] = a[i];
00332 
00333         return c;
00334 }
00335 
00343 inline const bool isequal(const int& x, const int& y)
00344                                                 { return x == y; }
00345 inline const bool isequal(const short& x, const short& y)
00346                                                 { return x == y; }
00347 inline const bool isequal(const unsigned short& x, const unsigned short& y)
00348                                                 { return x == y; }
00349 inline const bool isequal(const uint8_t& x, const uint8_t& y)
00350                                                 { return x == y; }
00351 inline const bool isequal(const int8_t& x, const int8_t& y)
00352                                                 { return x == y; }
00353 inline const bool isequal(const long long& x, const long long & y)
00354                                                 { return x == y; }
00355 #ifdef aa_MSC_VER
00356 
00357 // Gcc
00358 
00359 inline const bool isequal(const unsigned long long& x,
00360         const unsigned long long & y) { return x == y; }
00361 
00362 inline const bool isequal(const unsigned int& x, const unsigned int& y)
00363                                                 { return x == y; }
00364 inline const bool isequal(const char& x, const char& y)
00365                                                 { return x == y; }
00366 #else
00367 
00368 #ifdef IVL64
00369 
00370 inline const bool isequal(const unsigned int& x, const unsigned int& y)
00371                                                 { return x == y; }
00372 #else
00373 inline const bool isequal(const unsigned long long& x,
00374         const unsigned long long & y) { return x == y; }
00375 
00376 #endif // IVL64
00377 
00378 inline const bool isequal(const size_t& x, const size_t& y)
00379                                                 { return x == y; }
00380 
00381 #endif // _MSC_VER
00382 
00383 inline const bool isequal(const float& x, const float& y)
00384                                                 { return x == y; }
00385 inline const bool isequal(const double& x, const double& y)
00386                                                 { return x == y; }
00387 
00388 template<class T>
00389 const bool isequal(const std::complex<T>& x, const std::complex<T>& y)
00390 {
00391         return x == y;
00392 }
00393 
00401 template <class T, class S, class D>
00402 const bool isequal(const array<T, S>& a, const array<T, D>& b)
00403 {
00404         size_t s = a.length();
00405 
00406         typedef typename array<T, S>::derived_type d_a;
00407         typedef typename array<T, D>::derived_type d_b;
00408 
00409         const typename types::highest_common<d_a, d_b>::type_a& _a(a.derived());
00410         const typename types::highest_common<d_a, d_b>::type_b& _b(b.derived());
00411 
00412         if(!isequal(_a.size(), _b.size()))
00413                 return false;
00414 
00415         for (size_t i = 0; i < s; i++)
00416                 if (a[i] != b[i])
00417                         return false;
00418 
00419         return true;
00420 }
00421 
00423 template <class T>
00424 inline int compare(const ivl::array<T> &a, const ivl::array<T> &b)
00425 {
00426         for(size_t i=0;i<a.size();i++)
00427                 if(a[i]>b[i])
00428                         return 1; //a higher than b
00429                 else if(a[i]<b[i])
00430                         return -1;//b higher than a
00431 
00432         return 0;//a and b are equal
00433 }
00434 
00436 template <class T>
00437 inline int compare(const T &a,const T &b)
00438 {
00439         if(a>b)
00440                 return 1; //a higher than b
00441         else if(a<b)
00442                 return -1;//b higher than a
00443 
00444         return 0;//a and b are equal
00445 }
00446 
00449 template <class T>
00450 array<T> cross(const array<T>& a, const array<T>& b)
00451 {
00452         CHECK (a.length() == 3 && b.length() == 3, eshape());
00453 
00454         return arr<T>(a[1]*b[2] - a[2]*b[1], a[2]*b[0] - a[0]*b[2],
00455                 a[0]*b[1] - a[1]*b[0]);
00456 }
00457 
00458 #if 0 //this find is now implemented as an ivl func
00459 
00460 
00461 template <class D>
00462 inline
00463 size_array find(const array<bool, D>& ba)
00464 {
00465         const size_t len = ba.length();
00466         size_array a(len);
00467         size_t n = 0;
00468 
00469         for (size_t i = 0; i < len; i++)
00470                 if (ba[i])
00471                         a[n++] = i;
00472         return (n > 0) ? size_array(a, n) : size_array(0);
00473 }
00474 #endif
00475 
00478 template <class T>
00479 T dot(const array<T>& a, const array<T>& b)
00480 {
00481         CHECK (a.length() == b.length(), eshape());
00482 
00483         T res = 0;
00484         for (size_t i = 0; i < a.length(); i++)
00485                 res += a[i] * b[i];
00486 
00487         return res;
00488 }
00489 
00491 template <class T>
00492 array<T> linspace(const T& a, const T& b, size_t n = 100)
00493 {
00494         CHECK (n >= 2, erange());
00495 
00496         return range<T>(a, (b - a) / (n - 1) , b);
00497 }
00498 
00500 template <class T>
00501 array<T> logspace(double a, double b, size_t n = 50)
00502 {
00503         CHECK (n >= 2, erange());
00504 
00505 std::pow(double(10.0), double(a)) ;
00506 
00507         array<double> c(n);
00508         for (size_t i = 0; i < n; i++)
00509                 c[i] = std::pow(10, a) * std::pow(10, i * (b - a) / (n - 1) );
00510 
00511         return c;
00512 }
00513 
00514 //--------------------------------------------------------------
00515 // EXTERNAL (TEMPLATE) FUNCTIONS
00516 
00518 /*
00519 template<class C>
00520 C apply(C c, class C::value_type func(class C::value_type))
00521 {
00522         for (size_t i = 0; i < c.length(); ++i)
00523                 c[i] = func(c[i]);
00524 
00525         return c;
00526 }
00527 */
00528 
00530 template<class T, class S>
00531 typename array<T, S>::create_similar cshift(
00532         const array<T, S>& in, int count)
00533 {
00534         typename array<T, S>::create_similar out(in.derived().size());
00535         size_t len = in.length();
00536 
00537         for (int i = 0; i < int(len); i++)
00538                 out[i] = in[mod((i - count), int(len))];
00539 
00540         return out;
00541 }
00542 
00544 template<class T, class S>
00545 typename array<T, S>::create_similar cumsum(const array<T, S>& in)
00546 {
00547         typename array<T, S>::create_similar out(in.derived().size());
00548         size_t len = in.length();
00549 
00550         out[0] = in[0];
00551         for(size_t i = 1; i < len; i++)
00552                 out[i] = in[i] + out[i-1];
00553 
00554         return out;
00555 }
00556 
00558 template<class T, class S>
00559 typename array<T, S>::create_similar diff(const array<T, S>& in)
00560 {
00561         typename array<T, S>::create_similar out(in.derived().size());
00562         size_t len = in.length();
00563 
00564         out[0] = T(0);
00565         for(size_t i = 1; i < len; i++)
00566                 out[i] = in[i] - in[i-1];
00567 
00568         return out;
00569 }
00570 
00575 array<int> diff(const index_array& a);
00576 
00578 template<class T, class S>
00579 typename array<T, S>::create_similar flip(const array<T, S>& in)
00580 {
00581         typename array<T, S>::create_similar out(in.derived().size());
00582         size_t len = in.length();
00583 
00584         for(size_t i = 0; i < len; i++)
00585                 out[len - i - 1] = in[i];
00586 
00587         return out;
00588 }
00589 
00591 // SN: Comb sort is a very efficient algorithm improving on bubble sort, using variable gaps.
00592 // SN: It performs better than quick sort, and does not use extra memory.
00593 template<class T, class S>
00594 typename array<T, S>::create_similar sort(const array<T, S>& in,
00595                                                                                         bool descending = false)
00596 {
00597         typename array<T, S>::create_similar out(in.derived());
00598 
00599         size_t len = in.length();
00600 
00601         long gap = long(len) + 1;
00602         bool more = false;
00603 
00604         while (gap > 1  || more) {
00605                 // divide gap by 1.3 - the author says it's an empirical value
00606                 if (gap > 1)
00607                         gap = static_cast<long>(gap / 1.3);
00608 
00609                 // another empirical value
00610                 if (gap == 9 || gap == 10)
00611                         gap = 11;
00612 
00613                 more = false;
00614                 for (size_t i = 0; i < len - gap; i++) {
00615                 // SN original: if ((a[i] > a[i + gap]) ^ descending)
00616                 // SN: but it poses a heavy penalty on efficiency when descending = true
00617                 // SN: so, in that case, sort normally and then flip the array.
00618                         if ((out[i] > out[i + gap])) {
00619                                 // if the items are not in order, swap them
00620                                 std::swap(out[i], out[i + gap]);
00621                                 more = true;
00622                         }
00623                 }
00624         }
00625 
00626         if (descending)
00627                 out = flip(out);
00628 
00629         return out;
00630 }
00631 #if 0
00632 template<class C>
00633 C sort_q(const C& a, size_t top, size_t bottom) // SN: DO NOT USE. For testing purposes only.
00634 {
00635       // top = subscript of beginning of vector being considered
00636       // bottom = subscript of end of vector being considered
00637       // this process uses recursion - the process of calling itself
00638         C c(a.size());
00639         size_t middle;
00640         if (top < bottom)
00641         {
00642                 int x = c[top];
00643                 size_t i = top - 1;
00644                 size_t j = bottom + 1;
00645                 do {
00646                         do {
00647                                 j--;
00648                         }while (x > c[j]);
00649 
00650                         do {
00651                                 i++;
00652                         } while (x < c[i]);
00653 
00654                         if (i < j)
00655                                 swap(c[i], c[j]);
00656 
00657                 } while (i < j);
00658                 middle = j;
00659                 sort_q(c, top, middle);   // sort top partition
00660                 sort_q(c, middle+1, bottom);    // sort bottom partition
00661         }
00662 
00663         return c;
00664 }
00665 #endif
00666 #if 0
00667 
00668 template<class T, class S>
00669 typename array<T, S>::create_similar rem(const array<T, S>& in,
00670                                                                                         const T& s)
00671 {
00672         typename array<T, S, K>::create_similar out(in.derived().size());
00673         size_t len = in.length();
00674 
00675         for (size_t i = 0; i < len; ++i)
00676                 out[i] = in[i] - int(in[i] / s) * s;
00677 
00678         return out;
00679 }
00680 
00682 //TODO: elem func!!!
00683 template<class T, class S>
00684 typename array<T, S>::create_similar mod(const array<T, S>& in,
00685                                                                                         const T& s)
00686 {
00687         typename array<T, S>::create_similar out(in.derived().size());
00688         size_t len = in.length();
00689         T rem_result;   // remainder after division
00690 
00691         for (size_t i = 0; i < len; ++i) {
00692                 rem_result = in[i] % s;
00693                 out[i] = (rem_result >= 0) ? rem_result : (rem_result + s);
00694         }
00695 
00696         return out;
00697 }
00698 
00699 // specialization for mod with real types. different implementation
00700 template<class S>
00701 typename array<double, S>::create_similar mod(const array<double, S>& in,
00702                                                                                         const double& s)
00703 {
00704         typename array<double, S>::create_similar out(in.derived().size());
00705         size_t len = in.length();
00706 
00707         for (size_t i = 0; i < len; ++i)
00708                 out[i] = in[i] - std::floor(in[i] / s) * s;
00709 
00710         return out;
00711 }
00712 
00713 template<class S>
00714 typename array<float, S>::create_similar mod(const array<float, S>& in,
00715                                                                                                 const float& s)
00716 {
00717         typename array<float, S>::create_similar out(in.derived().size());
00718         size_t len = in.length();
00719 
00720         for (size_t i = 0; i < len; ++i)
00721                 out[i] = in[i] - std::floor(in[i]/s) * s;
00722 
00723         return out;
00724 }
00725 #endif
00726 
00728 } /* namespace ivl */
00729 
00730 #endif // IVL_ARRAY_DETAILS_ARRAY_FUNCTIONS_HPP
 All Classes Namespaces Files Functions Variables Typedefs Enumerations