ivl 679
|
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