SDSL: Succinct Data Structure Library
A C++ template library for succinct data structures
 All Classes Namespaces Files Functions Variables Typedefs Friends
sdsl/include/sdsl/algorithms.hpp
Go to the documentation of this file.
00001 /* sdsl - succinct data structures library
00002     Copyright (C) 2008 Simon Gog
00003 
00004     This program is free software: you can redistribute it and/or modify
00005     it under the terms of the GNU General Public License as published by
00006     the Free Software Foundation, either version 3 of the License, or
00007     (at your option) any later version.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program.  If not, see http://www.gnu.org/licenses/ .
00016 */
00022 #ifndef INCLUDED_SDSL_ALGORITHMS
00023 #define INCLUDED_SDSL_ALGORITHMS
00024 
00025 #include "int_vector.hpp"
00026 
00027 #include <stdexcept> // for exceptions
00028 #include <iostream>
00029 #include <cassert>
00030 #include <stack>
00031 #include <utility>
00032 
00033 
00034 namespace sdsl
00035 {
00036 
00038 
00041 namespace algorithm
00042 {
00043 //      private:
00044 //              algorithm(); // This helper class can not be instantiated
00045 
00046 // Returns if the pair (a1,a2) is lex. less or equal than (b1,b2)
00047 template<typename I>
00048 static bool leq(I a1, I a2, I b1, I b2)
00049 {
00050     return a1 < b1 || (a1 == b1 && a2 <= b2);
00051 }
00052 
00053 // Returns if the triple (a1,a2,a3) is lex. less or equal than (b1,b2,b3)
00054 template<typename I>
00055 static bool leq(I a1, I a2, I a3, I b1, I b2, I b3)
00056 {
00057     return a1 < b1 || (a1 == b1 && leq(a2,a3,b2,b3));
00058 }
00059 
00060 
00061 //      public:
00063 
00067 double H_0(const unsigned char* c);
00068 
00069 // Claculate the star entropy of T, see Manzini 2001 for details
00070 double H_0s(const unsigned char* c);
00071 
00072 
00074 
00080 template<class RandomAccessContainer1, class RandomAccessContainer2>
00081 static void sa2isa(const RandomAccessContainer1& sa, RandomAccessContainer2& isa);
00082 
00083 template<class RandomAccessContainer>
00084 static void sa2isa(const RandomAccessContainer& sa, int_vector<>& isa);
00085 
00087 
00095 template<class RandomAccessContainer>
00096 static void inverse_permutation_inplace(RandomAccessContainer& sa);
00097 
00099 
00106 template<class RandomAccessContainer1, class RandomAccessContainer2>
00107 void calculate_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv);
00108 
00109 
00111 
00113 template<class RandomAccessContainer1, class RandomAccessContainer2>
00114 static bool verify_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv);
00115 
00116 template<class RandomAccessContainer1, class RandomAccessContainer2>
00117 static void calculate_psv2(const RandomAccessContainer1& a, RandomAccessContainer2& psv);
00118 
00120 
00127 template<class RandomAccessContainer1, class RandomAccessContainer2>
00128 static void calculate_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv);
00129 
00131 template<class RandomAccessContainer1, class RandomAccessContainer2>
00132 static bool verify_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv);
00133 
00135 template<class RandomAccessContainer, class Text>
00136 static void calculate_lcp(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp);
00137 
00139 
00149 template<class RandomAccessContainer>
00150 static bool verify_sa(const unsigned char* c, typename RandomAccessContainer::size_type len, const RandomAccessContainer& sa);
00151 
00153 template<class SelectSupport>
00154 inline static bool verify_select_support(const SelectSupport& ss, const int_vector<1>& b);
00155 
00157 template<class Container1, class Container2>
00158 static bool equal_container_values(const Container1& c1, Container2& c2);
00159 
00161 
00167 template<class RandomAccessContainer>
00168 static void sa2isa_inplace(RandomAccessContainer& sa);
00169 
00171 /* \param bwt Burrows and Wheeler Transformation.
00172 * \param len Length of the bwt.
00173 * \param psi Container of size len for the result.
00174 * \par Time complexity
00175         *       \f$\Order{2n}\f$ i.e. linear.
00176 * \par Space complexity
00177 *       Space of bwt (\f$\Order{n}\f$ bits) + space of uncompressed \f$\Psi\f$-function (\f$\Order{4n}\f$ bits).
00178 */
00179 template<class RandomAccessContainer>
00180 static void bwt2psi(const unsigned char* bwt, typename RandomAccessContainer::size_type len, RandomAccessContainer& psi);
00181 
00183 
00190 template<class RandomAccessContainer1, class RandomAccessContainer2>
00191 static void sa2psi(const RandomAccessContainer1& sa, RandomAccessContainer2& psi);
00192 
00193 template<class RandomAccessContainer>
00194 static void sa2psi(const RandomAccessContainer& sa, int_vector<>& psi);
00195 
00197 
00204 template<class RandomAccessContainer, class Text>
00205 static void     calculate_lcp12(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp);
00206 
00208 
00214 template<class RandomAccessContainer1, class RandomAccessContainer2>
00215 static void psi2sa(const RandomAccessContainer1& psi, const typename RandomAccessContainer1::size_type isa_0,  RandomAccessContainer2& sa);
00216 
00217 template<class RandomAccessContainer>
00218 static void psi2sa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0,  int_vector<>& sa);
00220 
00226 template<class RandomAccessContainer>
00227 static void psi2isa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, RandomAccessContainer& isa);
00228 
00229 
00230 template<class RandomAccessContainer1, class RandomAccessContainer2>
00231 void calculate_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv)
00232 {
00233     assert(psv.size() == a.size());
00234     if (a.empty())
00235         return;
00236     psv[0] = psv.size();
00237     assert(psv[0] == psv.size());
00238     std::stack<typename RandomAccessContainer1::size_type> psv_index;
00239     typename RandomAccessContainer1::value_type min_element = a[0];
00240     for (typename RandomAccessContainer1::size_type i=0; i < a.size(); ++i) {
00241         if (a[i] <= min_element) {
00242             while (!psv_index.empty())
00243                 psv_index.pop();
00244             min_element = a[i];
00245             psv[i] = a.size();
00246             psv_index.push(i);
00247         } else { // a[i] > min_element => stack will not be empty
00248             while (a[psv_index.top()] >= a[i])
00249                 psv_index.pop();
00250             psv[i] = psv_index.top();
00251             psv_index.push(i);
00252         }
00253     }
00254 }
00255 
00256 template<class RandomAccessContainer1, class RandomAccessContainer2>
00257 bool verify_psv(const RandomAccessContainer1& a, RandomAccessContainer2& psv)
00258 {
00259     if (a.size()!=psv.size())
00260         return false;
00261     typename RandomAccessContainer1::value_type min_element = a[0];
00262     for (typename RandomAccessContainer1::size_type i=0; i<a.size(); ++i) {
00263         if (a[i] <= min_element) {
00264             min_element = a[i];
00265             if (psv[i] != a.size()) // see definition of calculate_psv
00266                 return false;
00267         } else {
00268             if (psv[i]>=i)
00269                 return false;
00270             if (a[psv[i]] >= a[i])
00271                 return false;
00272             for (typename RandomAccessContainer1::size_type j=psv[i]+1; j<i; ++j)
00273                 if (a[j]<a[i])
00274                     return false;
00275         }
00276     }
00277     return true;
00278 }
00279 
00280 
00281 template<class RandomAccessContainer1, class RandomAccessContainer2>
00282 void calculate_psv2(const RandomAccessContainer1& a, RandomAccessContainer2& psv)
00283 {
00284     assert(psv.size() == a.size());
00285     if (a.empty())
00286         return;
00287     psv[0] = psv.size();
00288     assert(psv[0] == psv.size());
00289     // TODO implementing the algorithm with use of a stack
00290     psv[0] = psv.size();
00291     typedef std::pair<typename RandomAccessContainer1::value_type, typename RandomAccessContainer1::size_type> tPII;
00292     std::stack<tPII> psv_stack;
00293     typename RandomAccessContainer1::value_type min_element = a[0], ai;
00294     for (typename RandomAccessContainer1::size_type i=0; i < a.size(); ++i) {
00295         if ((ai=a[i]) <= min_element) {
00296             while (!psv_stack.empty())
00297                 psv_stack.pop();
00298             min_element = ai;
00299             psv[i] = a.size();
00300             psv_stack.push(tPII(ai, i));
00301         } else { // a[i] > min_element => stack will not be empty
00302             while (psv_stack.top().first >= ai)
00303                 psv_stack.pop();
00304             psv[i] = psv_stack.top().second;
00305             psv_stack.push(tPII(ai, i));
00306         }
00307     }
00308 }
00309 
00310 template<class RandomAccessContainer1, class RandomAccessContainer2>
00311 void calculate_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv)
00312 {
00313     assert(nsv.size() == a.size());
00314     if (a.empty())
00315         return;
00316     nsv[nsv.size()-1] = 0;
00317     std::stack<typename RandomAccessContainer1::size_type> nsv_index;
00318     typename RandomAccessContainer1::value_type min_element = a[nsv.size()-1];
00319     for (typename RandomAccessContainer1::size_type i=nsv.size(); i > 0; --i) {
00320         if (a[i-1] <= min_element) {
00321             while (!nsv_index.empty())
00322                 nsv_index.pop();
00323             min_element = a[i-1];
00324             nsv[i-1] = 0;
00325             nsv_index.push(i-1);
00326         } else { // a[i] > min_element => stack will not be empty
00327             while (a[nsv_index.top()] >= a[i-1])
00328                 nsv_index.pop();
00329             nsv[i-1] = nsv_index.top();
00330             nsv_index.push(i-1);
00331         }
00332     }
00333 }
00334 
00335 
00336 template<class RandomAccessContainer1, class RandomAccessContainer2>
00337 bool verify_nsv(const RandomAccessContainer1& a, RandomAccessContainer2& nsv)
00338 {
00339     if (a.size() != nsv.size())
00340         return false;
00341     typename RandomAccessContainer1::value_type min_element = a[a.size()-1];
00342     for (typename RandomAccessContainer1::size_type i=a.size(); i>0; --i) {
00343         if (a[i-1] <= min_element) {
00344             min_element = a[i-1];
00345             if (nsv[i-1] != 0) // see definition of calculate_nsv
00346                 return false;
00347         } else {
00348             if (nsv[i-1] <= i-1)
00349                 return false;
00350             if (a[nsv[i-1]] >= a[i-1])
00351                 return false;
00352             for (typename RandomAccessContainer1::size_type j=i; j<nsv[i-1]; ++j)
00353                 if (a[j]<a[i-1])
00354                     return false;
00355         }
00356     }
00357     return true;
00358 }
00359 
00360 
00361 
00362 
00363 
00364 template<class RandomAccessContainer>
00365 void bwt2psi(const unsigned char* bwt, typename RandomAccessContainer::size_type len, RandomAccessContainer& psi)
00366 {
00367     if (psi.size() != len)
00368         psi.resize(len);
00369     typename RandomAccessContainer::size_type C[256] = {0}, index_of_dollar = 0;
00370     for (typename RandomAccessContainer::size_type i=0; i<len; ++i) {
00371         ++C[bwt[i]];
00372         if (bwt[i]=='\0')
00373             index_of_dollar = i;
00374     }
00375     //  std::cerr<<"index of . = "<<index_of_dollar<<std::endl;
00376     for (uint16_t i=255; i!=0; --i)
00377         C[i] = C[i-1];
00378     C[0]=0;
00379     for (uint16_t i=1; i<256; ++i) {
00380         C[i] += C[i-1];
00381     }
00382     //  assert(C[bwt[0]]==0);
00383     //  psi[C[bwt[0]]] = index_of_dollar;
00384     //  ++C[bwt[0]];
00385     for (typename RandomAccessContainer::size_type i=0; i<len; ++i) {
00386         psi[C[bwt[i]]] = i;
00387         ++C[bwt[i]];
00388     }
00389     /*  for(typename RandomAccessContainer::size_type i=index_of_dollar+1; i<len; ++i){
00390                 psi[C[bwt[i]]] = i;
00391                 ++C[bwt[i]];
00392         }
00393     */
00394     /*
00395         typename RandomAccessContainer::size_type C[256] = {0}, index_of_dollar = 0;
00396         for(typename RandomAccessContainer::size_type i=0; i<len+1; ++i){
00397                 ++C[bwt[i]];
00398                 if(bwt[i]=='\0')
00399                         index_of_dollar = i;
00400         }
00401     //  std::cerr<<"index of $ = "<<index_of_dollar<<std::endl;
00402         for(uint16_t i=255;i!=0;--i)
00403                 C[i] = C[i-1];
00404         C[0]=0;
00405         for(uint16_t i=1;i<256;++i){
00406                 C[i] += C[i-1];
00407         }
00408         psi[C[bwt[0]]-1] = index_of_dollar-1;
00409         ++C[bwt[0]];
00410         for(typename RandomAccessContainer::size_type i=1; i<index_of_dollar; ++i){
00411                 psi[C[bwt[i]]-1] = i-1;
00412                 ++C[bwt[i]];
00413         }
00414         for(typename RandomAccessContainer::size_type i=index_of_dollar+1; i<len+1; ++i){
00415                 psi[C[bwt[i]]-1] = i-1;
00416                 ++C[bwt[i]];
00417         }
00418     */
00419 }
00420 
00421 template<class RandomAccessContainer1, class RandomAccessContainer2>
00422 void sa2isa(const RandomAccessContainer1& sa, RandomAccessContainer2& isa)
00423 {
00424     isa.resize(sa.size()); // init isa
00425     typename RandomAccessContainer1::size_type i = 0;
00426     for (typename RandomAccessContainer1::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++i) {
00427         isa[ *sa_it ] = i;
00428     }
00429 }
00430 
00431 template<class RandomAccessContainer>
00432 void sa2isa(const RandomAccessContainer& sa, int_vector<>& isa)
00433 {
00434     isa.set_int_width(bit_magic::l1BP(sa.size())+1);
00435     isa.resize(sa.size()); // init isa
00436     typename RandomAccessContainer::size_type i = 0;
00437     for (typename RandomAccessContainer::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++i) {
00438         isa[ *sa_it ] = i;
00439     }
00440 }
00441 
00442 template<class RandomAccessContainer>
00443 void inverse_permutation_inplace(RandomAccessContainer& perm)
00444 {
00445     if (perm.size() == 0)
00446         return;
00447     typedef bit_vector::size_type size_type;
00448 #ifdef SDSL_DEBUG
00449     {
00450         // check if input permutation perm is really a permutation from \f$0..perm.size()-1\f$
00451         bit_vector visited(perm.size(),0);
00452         for (size_type i=0; i<perm.size(); ++i) {
00453             if (!(perm[i]>=0 and perm[i]<perm.size() and 0==visited[perm[i]]))
00454                 throw std::invalid_argument("Input for inverse_permutation_inplace is not a permutation!");
00455             visited[perm[i]]=1;
00456         }
00457     }
00458 #endif
00459     uint8_t  w          = bit_magic::l1BP(perm.size()-1)+1;
00460     uint64_t b          = 1ULL << ((w+1)%64);
00461     uint64_t biggest = b | (perm.size()-1);
00462     uint64_t perm_0 = perm[0];
00463     perm[0] = biggest;
00464     if (w != 63 and perm[0] == biggest) { // space left for real inplace calculation
00465 #ifdef SDSL_DEBUG
00466         std::cout<<"using real in-place procedure for inverse_permutation_inplace"<<std::endl;
00467 #endif
00468         perm[0] = perm_0;
00469         for (size_type i=0, j,jj,t; i < perm.size(); ++i) {
00470             if ((perm[i] & b) == 0) {
00471                 j = perm[i]; jj = i;
00472                 while ((perm[j] & b) == 0) {
00473                     t = perm[j];
00474                     perm[j] = jj | b; // mark perm[j] as visited
00475                     jj=j; j=t;
00476                 }
00477             }
00478         }
00479         for (size_type i=0; i < perm.size(); ++i)
00480             perm[i] = perm[i] & (b-1);
00481     } else { // not enough space for real inplace calculation =>  use additional
00482         perm[0] = perm_0;
00483         bit_vector is_inverse(perm.size(), 0);                          // indicator bit_vector!
00484         for (size_type i=0, j,jj,t; i<perm.size(); ++i) {
00485             if (!is_inverse[i]) {
00486                 j = perm[i]; jj = i;
00487                 while (!is_inverse[j]) {
00488                     is_inverse[j] = 1;  // mark perm[j] as visited
00489                     t = perm[j]; perm[j] = jj; jj=j; j=t;
00490                 }
00491             }
00492         }
00493     }
00494 #ifdef SDSL_DEBUG
00495     {
00496         // check if the result is really a permutation form \f$0..perm.size()-1\f$
00497         bit_vector visited(perm.size(),0);
00498         for (size_type i=0; i<perm.size(); ++i) {
00499             assert(perm[i]>=0 and perm[i]<perm.size() and 0==visited[perm[i]]);
00500             visited[perm[i]]=1;
00501         }
00502     }
00503 #endif
00504 }
00505 
00506 template<class RandomAccessContainer1, class RandomAccessContainer2>
00507 void sa2psi(const RandomAccessContainer1& sa, RandomAccessContainer2& psi)
00508 {
00509     RandomAccessContainer2 isa; // temporary array for the inverse suffix array
00510     sa2isa(sa, isa);
00511     psi.resize(sa.size());
00512     typename RandomAccessContainer1::value_type tmp; //
00513     typename RandomAccessContainer2::iterator psi_it = psi.begin();
00514     for (typename RandomAccessContainer1::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++psi_it) {
00515         if ((tmp = *sa_it+1) != sa.size())
00516             *psi_it = isa[tmp];
00517         else
00518             *psi_it = isa[0];
00519     }
00520 }
00521 
00522 template<class RandomAccessContainer>
00523 void sa2psi(const RandomAccessContainer& sa, int_vector<>& psi)
00524 {
00525     int_vector<> isa; // temporary array for the inverse suffix array
00526     sa2isa(sa, isa);
00527     psi.set_int_width(bit_magic::l1BP(sa.size())+1);
00528     psi.resize(sa.size());
00529     typename RandomAccessContainer::value_type tmp; //
00530     int_vector<>::iterator psi_it = psi.begin();
00531     for (typename RandomAccessContainer::const_iterator sa_it = sa.begin(), end = sa.end(); sa_it != end; ++sa_it, ++psi_it) {
00532         if ((tmp = *sa_it+1) != sa.size())
00533             *psi_it = isa[tmp];
00534         else
00535             *psi_it = isa[0];
00536     }
00537 }
00538 
00539 template<class RandomAccessContainer, class Text>
00540 void calculate_lcp(const RandomAccessContainer& sa, const Text& text, RandomAccessContainer& lcp)
00541 {
00542     lcp = sa;
00543     RandomAccessContainer isa;
00544     sa2isa(sa, isa);
00545 
00546     lcp[0] = 0;
00547     typename RandomAccessContainer::size_type i=0,j,k,l=0;
00548     for (typename RandomAccessContainer::const_iterator isa_it = isa.begin(), end = isa.end(); isa_it != end; ++isa_it, ++i) {
00549         if ((j = *isa_it)) {
00550             k = sa[j-1];
00551             while (text[k+l]==text[i+l])
00552                 ++l;
00553             lcp[j] = l;
00554             l = (l==0)?0:l-1;
00555         }
00556     }
00557 }
00558 
00559 /*
00560 TODO: add implementation and definition
00561 template<class RandomAccessContainer>
00562 void algorithm::calculate_lps(){
00563 
00564 }
00565 */
00566 
00567 template<class RandomAccessContainer1, class RandomAccessContainer2>
00568 void psi2sa(const RandomAccessContainer1& psi, const typename RandomAccessContainer1::size_type isa_0, RandomAccessContainer2& sa)
00569 {
00570     sa.resize(psi.size());
00571     if (psi.empty())
00572         return;
00573     typename RandomAccessContainer1::value_type isa_k = isa_0;
00574     for (typename RandomAccessContainer1::size_type k = 0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) {
00575         sa[isa_k]       = k;
00576     }
00577 }
00578 
00579 template<class RandomAccessContainer>
00580 void psi2sa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, int_vector<>& sa)
00581 {
00582     sa.set_int_width(bit_magic::l1BP(psi.size())+1);
00583     sa.resize(psi.size());
00584     if (psi.empty())
00585         return;
00586     typename RandomAccessContainer::value_type isa_k = isa_0;
00587     for (typename RandomAccessContainer::size_type k = 0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) {
00588         sa[isa_k]       = k;
00589     }
00590 }
00591 
00592 template<class RandomAccessContainer>
00593 void psi2isa(const RandomAccessContainer& psi, const typename RandomAccessContainer::size_type isa_0, RandomAccessContainer& isa)
00594 {
00595     isa = psi;
00596     if (psi.empty())
00597         return;
00598     typename RandomAccessContainer::value_type isa_k = isa_0;
00599     for (typename RandomAccessContainer::size_type k=0, size=psi.size(); k < size; ++k, isa_k = psi[isa_k]) {
00600         isa[k]  = isa_k;
00601     }
00602 }
00603 
00604 template<class RandomAccessContainer>
00605 bool verify_sa(const unsigned char* c, typename RandomAccessContainer::size_type len, const RandomAccessContainer& sa)
00606 {
00607     typedef typename RandomAccessContainer::size_type size_type;
00608     if (sa.size() != len) { // check length
00609         std::cerr<<"sa.size()!=len"<<std::endl;
00610         std::cerr<<sa.size()<<"!="<<len<<std::endl;
00611         return false;
00612     }
00613     {
00614         // check if values are in the range [0..len) and all are different
00615         int_vector<> occ(len);
00616         util::set_zero_bits(occ);
00617         for (typename RandomAccessContainer::const_iterator it=sa.begin(), end=sa.end(); it!=end; ++it) {
00618             size_type value = *it;
00619             if (value < len and !occ[value])
00620                 occ[value] = 1;
00621             else {
00622                 std::cerr<<"sa is not a permutation"<<std::endl;
00623                 return false;
00624             }
00625         }
00626     }
00627     // check if the lexicographic order is correct
00628     if (sa.size()<2)
00629         return true;
00630     size_type v1,v2;
00631     v1 = v2 = sa[(size_t)0];
00632     for (typename RandomAccessContainer::const_iterator it=sa.begin()+1, end = sa.end(); it!=end; ++it) {
00633         v1 = v2;
00634         v2 = *it;
00635         size_type i=v1, j=v2;
00636         for (; i!=len and j!=len; ++i, ++j) {
00637             if (c[i] < c[j])
00638                 break;
00639             else if (c[i]>c[j]) { // lex order is wrong!
00640                 std::cerr<<"lex order is wrong"<<std::endl;
00641                 std::cerr<<"v1="<<v1<<" v2="<<v2<<std::endl;
00642                 //                              std::cerr<<c+v1<<std::endl;
00643                 //                              std::cerr<<c+v2<<std::endl;
00644                 return false;
00645             }
00646         }
00647     }
00648     return true;
00649 }
00650 
00651 template<class SelectSupport>
00652 bool verify_select_support(const SelectSupport& ss, const int_vector<1>& b)
00653 {
00654     uint64_t i=0,j=0;
00655     for (int_vector<1>::const_iterator it = b.begin(), end = b.end(); it != end; ++it, ++i) {
00656         if (*it) {
00657             ++j;// it's the j-th 1 detected
00658             if (ss.select(j)!=i) return false;
00659         }
00660     }
00661     return true;
00662 }
00663 
00664 template<class Container1, class Container2>
00665 bool equal_container_values(const Container1& c1, Container2& c2)
00666 {
00667     if (c1.size() != c2.size())
00668         return false;
00669     typename Container2::const_iterator c2_it = c2.begin();
00670     for (typename Container1::const_iterator c1_it = c1.begin(), c1_end = c1.end(); c1_it!=c1.end(); ++c1_it, ++c2_it)
00671         if (*c1_it != *c2_it)
00672             return false;
00673     return true;
00674 }
00675 
00676 
00677 //      template<uint8_t w>
00678 //      void inplace_radix_sort(int_vector<w> &v);
00679 //      template<class RandomAccessContainer, class Text>
00680 //      static void calulate_lcp9(const RandomAccessContainer &sa, const Text &text, RandomAccessContainer& lcp);
00681 
00682 
00683 } // end namespace algorithm
00684 
00685 } // end namespace sdsl
00686 
00687 #include "algorithms_for_suffix_array_construction.hpp"
00688 #include "algorithms_for_balanced_parentheses.hpp"
00689 #include "algorithms_for_compressed_suffix_arrays.hpp"
00690 #include "algorithms_for_compressed_suffix_trees.hpp"
00691 #include "algorithms_for_string_matching.hpp"
00692 
00693 
00694 
00695 #endif