From c4420cdac4009b616628b232954187e26f5dfb38 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sun, 10 Aug 2014 21:34:36 +0200 Subject: [PATCH 1/8] [algorithm] [searching] Add longest increasing subsequence algorithm. --- .../longest_increasing_subsequence.hpp | 218 ++++++++++++++++++ test/subsequence_test1.cpp | 207 +++++++++++++++++ 2 files changed, 425 insertions(+) create mode 100644 include/boost/algorithm/searching/longest_increasing_subsequence.hpp create mode 100644 test/subsequence_test1.cpp diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp new file mode 100644 index 000000000..3d873d5d4 --- /dev/null +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -0,0 +1,218 @@ +/* + Copyright (c) Marek Kurdej 2014. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#ifndef BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP +#define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP + +#include +#include // for std::iterator_traits + +#include +#include + +#include +#include + +#include +#include + +#include + +// #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG_HPP + +#include + +namespace boost { namespace algorithm { + +/* + A templated version of the longest (increasing) subsequence algorithm. + + Requirements: + * Random access iterators + * The two iterator types (patIter and corpusIter) must + "point to" the same underlying type. + * Additional requirements may be imposed buy the skip table, such as: + ** Numeric type (array-based skip table) + ** Hashable type (map-based skip table) + +https://en.wikipedia.org/wiki/Longest_increasing_subsequence + +*/ + + template ::value_type> > + class longest_increasing_subsequence { + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::value_type value_type; + public: + longest_increasing_subsequence (Compare cmp = Compare()) + : compare(cmp) { + } + + ~longest_increasing_subsequence () {} + + /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param first The start of the data to search (Random Access Iterator) + /// \param last One past the end of the data to search + /// \param cmp A predicate used for the search comparisons. + /// + std::vector operator () ( Iter first, Iter last ) const { + return this->do_search ( first, last ); + } + + template + typename boost::range_iterator::type operator () ( Range &r ) const { + return (*this) (boost::begin(r), boost::end(r)); + } + + private: +/// \cond DOXYGEN_HIDE + Compare compare; + + /// \fn do_search ( corpusIter corpus_first, corpusIter corpus_last ) + /// \brief Searches the corpus for the pattern that was passed into the constructor + /// + /// \param corpus_first The start of the data to search (Random Access Iterator) + /// \param corpus_last One past the end of the data to search + /// + std::vector do_search ( Iter first, Iter last ) const { + // typedef typename node::iterator iterator; + // typedef typename node* iterator; + // typedef typename node::const_iterator const_iterator; + // typedef typename node const* const_iterator; + + typedef std::size_t size_type; + typedef std::vector Container; + typedef typename std::iterator_traits::difference_type difference_type; + difference_type const n = std::distance(first, last); + // if (n == 0) + + /// P[k] - stores the index of the predecessor of X[k] in the longest increasing subsequence ending at X[k] + Container P(n); + /// M[j] - stores the index k of the smallest value X[k] such that there is an increasing subsequence of length j ending at X[k] on the range k <= i + /// (note we have j <= k <= i here, because j represents the length of the increasing subsequence, and k represents the index of its termination. + /// Obviously, we can never have an increasing subsequence of length 13 ending at index 11. k <= i by definition). + // -> j-elements: X[.] X[.] ... X[k] is an increasing subsequence + Container M(n + 1); + M[0] = 0; + + /// Length of the longest (increasing) subsequence found so far + size_type L = 0; + + for (difference_type i = 0; i < n; ++i) { + // Binary search for the largest positive j <= L, such that X[M[j]] < X[i] + size_type lo = 1; + size_type hi = L; + while (lo <= hi) { + size_type mid = (lo + hi) / 2; + assert(mid <= i); + if (compare(*(first + M[mid]), *(first + i))) { // X[M[mid]] < X[i] + lo = mid + 1; + } else { + hi = mid - 1; + } + } + + // After searching, lo is 1 greater than the length of the longest prefix of X[i] + size_type newL = lo; + + // The predecessor of X[i] is the last index of the subsequence of length newL-1 + assert(newL > 0); + P[i] = M[newL - 1]; + + assert(newL <= n); + assert(M[newL] < n); + if (newL > L) { + // If we found a subsequence longer than any we've found yet, update M and L + M[newL] = i; + L = newL; + } else if (compare(*(first + i), *(first + M[newL]))) { // X[i] < X[M[newL]] + // If we found a smaller last value for the + // subsequence of length newL, only update M + M[newL] = i; + } // if + } // for + + // Reconstruct the longest increasing subsequence + std::vector S(L); + size_type k = M[L]; + for (size_type i = L - 1; i > 0; --i) { + S[i] = first + k; // X[k]; + k = P[k]; + } + S[0] = first + k; // X[k]; + return S; + } +// \endcond + }; + +/* Two ranges as inputs gives us four possibilities; with 1,2 parameters + Use a bit of TMP to disambiguate the 3-argument templates */ + +/// \fn longest_increasing_subsequence_search ( corpusIter corpus_first, corpusIter corpus_last, +/// patIter pat_first, patIter pat_last ) +/// \brief Searches the corpus for the pattern. +/// +/// \param corpus_first The start of the data to search (Random Access Iterator) +/// \param corpus_last One past the end of the data to search +/// \param pat_first The start of the pattern to search for (Random Access Iterator) +/// \param pat_last One past the end of the data to search for +/// + template + std::size_t longest_increasing_subsequence_length( + Iter first, Iter last ) + { + longest_increasing_subsequence lis; + return lis.compute_length(first, last); + } + + template + std::size_t longest_increasing_subsequence_length( + Iter first, Iter last, Compare cmp ) + { + longest_increasing_subsequence lis(cmp); + return lis.compute_length( first, last ); + } + + template + Iter longest_increasing_subsequence_search ( + Iter first, Iter last ) + { + longest_increasing_subsequence lis; + return lis ( first, last ); + } + + template + OutputIter longest_increasing_subsequence_search ( + const Range &sequence ) + { + typedef typename boost::range_iterator::type pattern_iterator; + longest_increasing_subsequence lis; + return lis ( boost::begin(sequence), boost::end(sequence) ); + } + + // Creator functions -- take a pattern range, return an object + template + boost::algorithm::longest_increasing_subsequence::type> + make_longest_increasing_subsequence ( const Range &r ) { + return boost::algorithm::longest_increasing_subsequence + ::type> (boost::begin(r), boost::end(r)); + } + + template + boost::algorithm::longest_increasing_subsequence::type> + make_longest_increasing_subsequence ( Range &r ) { + return boost::algorithm::longest_increasing_subsequence + ::type> (boost::begin(r), boost::end(r)); + } + +}} + +#endif // BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP diff --git a/test/subsequence_test1.cpp b/test/subsequence_test1.cpp new file mode 100644 index 000000000..6059ddfcd --- /dev/null +++ b/test/subsequence_test1.cpp @@ -0,0 +1,207 @@ +/* + Copyright (c) Marek Kurdej 2014. + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + For more information, see http://www.boost.org +*/ + +#include + +#define BOOST_TEST_MAIN +#include +#include + +#include +#include +#include +#include + +#include // for 'list_of()', tuple_list_of +using namespace boost::assign; // bring 'list_of()' into scope + +namespace ba = boost::algorithm; + +namespace { + template + void check_lis ( const Container &sequence, std::size_t expected_length, Compare cmp ) { + } + + template + void check_length ( const Container &sequence, std::size_t expected_length, Compare cmp ) { + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; + + ba::longest_increasing_subsequence ls(cmp); + ResultContainer res = ls(sequence.begin(), sequence.end()); + + BOOST_CHECK_EQUAL(res.size(), expected_length); + + // check_one_iter ( haystack, needle, expected ); + // check_one_pointer ( haystack, needle, expected ); + // check_one_object ( haystack, needle, expected ); + } + + // template + // void check_length ( const Container &sequence, std::size_t expected_length ) { + // typedef typename Container::value_type value_type; + // check_length ( sequence, expected_length, std::less() ); + // } + + template + void check_lis ( const Container &sequence, const Container &expected_lis, Compare cmp ) { + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; + + ba::longest_increasing_subsequence ls(cmp); + ResultContainer res = ls(sequence.begin(), sequence.end()); + Container lis; + lis.resize(res.size()); + for (std::size_t i = 0; i < res.size(); ++i) { + lis[i] = *res[i]; + } + + BOOST_CHECK_EQUAL_COLLECTIONS(lis.begin(), lis.end(), expected_lis.begin(), expected_lis.end()); + } + + template + void check_lis ( const Container &sequence, const ContainerContainer &expected_lises, Compare cmp ) { + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; + + ba::longest_increasing_subsequence ls(cmp); + ResultContainer res = ls(sequence.begin(), sequence.end()); + Container lis; + lis.resize(res.size()); + for (std::size_t i = 0; i < res.size(); ++i) { + lis[i] = *res[i]; + } + + bool any_equal = false; + for (std::size_t i = 0; i < expected_lises.size(); ++i) { + const Container &expected_lis = expected_lises[i]; + BOOST_REQUIRE_EQUAL(lis.size(), expected_lis.size()); + any_equal |= std::equal(lis.begin(), lis.end(), expected_lis.begin()/*, expected_lis.end()*/); + // try { + // BOOST_CHECK_EQUAL_COLLECTIONS(lis.begin(), lis.end(), expected_lis.begin(), expected_lis.end()); + // } catch (...) { + // any_equal = false; + // } + } + BOOST_CHECK(any_equal); + } + + template + void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const Container &expected_lis, Compare cmp ) { + BOOST_TEST_CHECKPOINT ( test_name ); + check_length ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL( expected_lis.size(), expected_length ); + check_lis ( sequence, expected_lis, cmp ); + } + + template + void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const ContainerContainer &expected_lises, Compare cmp ) { + BOOST_TEST_CHECKPOINT ( test_name ); + check_length ( sequence, expected_length, cmp ); + for (std::size_t i = 0; i < expected_lises.size(); ++i) { + BOOST_REQUIRE_EQUAL ( expected_lises[i].size(), expected_length ); + } + check_lis ( sequence, expected_lises, cmp ); + } + + template + void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const Container &expected_lis ) { + typedef typename Container::value_type value_type; + check_one ( test_name, sequence, expected_length, expected_lis, std::less() ); + } + + template + void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const ContainerContainer &expected_lises ) { + typedef typename Container::value_type value_type; + check_one ( test_name, sequence, expected_length, expected_lises, std::less() ); + } + +} + +template +void ReadFromFile ( const char *name, std::back_insert_iterator inserter ) { + std::ifstream in ( name, std::ios_base::binary | std::ios_base::in ); + std::istream_iterator begin(in); + std::istream_iterator end; + + std::copy ( begin, end, inserter ); +} + +template +std::string make_str ( Iter first, std::size_t len ) { + std::string retVal ( len + 2, '\'' ); + std::copy ( first, first + len, retVal.begin() + 1); + return retVal; +} + +BOOST_AUTO_TEST_CASE( test_main ) +{ + typedef std::vector vec; + typedef std::vector res; + typedef std::vector resvec; + using std::string; + using std::wstring; + + vec seq1 = list_of(5); + res exp1 = list_of(5); + vec seq2 = list_of(5) (6) (7); + res exp2 = list_of(5) (6) (7); + vec seq3 = list_of(5) (7) (6); + res exp3a = list_of(5) (6); + res exp3b = list_of(5) (7); + resvec exp3 = list_of(exp3a) (exp3b); + vec seq4 = list_of(7) (2) (8) (1) (3) (4) (10) (6) (9) (5); + res exp4 = list_of(1) (3) (4) (6) (9); + vec seq5 = list_of(3) (2) (6) (4) (5) (1); + res exp5a = list_of(2) (4) (5); + res exp5b = list_of(3) (4) (5); + resvec exp5 = list_of(exp5a) (exp5b); + vec seq6 = list_of(0) (8) (4) (12) (2) (10) (6) (14) (1) (9) (5) (13) (3) (11) (7) (15); + res exp6a = list_of(0) (2) (6) (9) (11) (15); + res exp6b = list_of(0) (4) (6) (9) (13) (15); + resvec exp6 = list_of(exp6a) (exp6b); + string str1 = "abcdef"; + string estr1 = str1; + string str2 = "All human beings are born free and equal in dignity and rights."; + string estr2 = " abdeginrs"; + wstring wstr1 = L"abcdef"; + wstring ewstr1 = wstr1; + check_one("seq1", seq1, 1, exp1); + check_one("seq2", seq2, 3, exp2); + check_one("seq3", seq3, 2, exp3); + check_one("seq5", seq4, 5, exp4); + check_one("seq5", seq5, 3, exp5); + check_one("seq6", seq6, 6, exp6); + + check_one("str1", str1, 6, estr1); + check_one("str2", str2, 10, estr2); + check_one("wstr1", wstr1, 6, ewstr1); + + + string c1; ReadFromFile ( "search_test_data/0001.corpus", std::back_inserter(c1) ); + string ec1 = "+/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + string p1b; ReadFromFile ( "search_test_data/0001b.pat", std::back_inserter(p1b) ); + string ep1b = "0AKPScdehlnpwxz"; + + string p1e; ReadFromFile ( "search_test_data/0001e.pat", std::back_inserter(p1e) ); + string ep1e = "BCGHIJVdg"; + + string p1f; ReadFromFile ( "search_test_data/0001f.pat", std::back_inserter(p1f) ); + string ep1f = "/3568BENOPQUgxz"; + + string p1n; ReadFromFile ( "search_test_data/0001n.pat", std::back_inserter(p1n) ); + string ep1n = "013DEIMNTUY"; + + check_one("c1", c1, 64, ec1); + check_one("p1b", p1b, 15, ep1b); + check_one("p1e", p1e, 9, ep1e); + check_one("p1f", p1f, 15, ep1f); + check_one("p1n", p1n, 11, ep1n); +} From 2407bc32351b0dddfa3d1fe59f1583f5760cbb11 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Wed, 13 Aug 2014 19:44:08 +0200 Subject: [PATCH 2/8] [algorithm] [searching] [longest_increasing_subsequence] Format. Doc. Add .clang-format configuration file (requires version >3.5.0). Conflicts: test/Jamfile.v2 --- .clang-format | 56 +++ .../longest_increasing_subsequence.hpp | 381 ++++++++++-------- test/Jamfile.v2 | 3 + test/subsequence_test1.cpp | 322 ++++++++------- 4 files changed, 456 insertions(+), 306 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..5f808d8d2 --- /dev/null +++ b/.clang-format @@ -0,0 +1,56 @@ +# Style: Boost.Algorithm +BasedOnStyle: LLVM +Language: Cpp +AccessModifierOffset: -4 +# ConstructorInitializerIndentWidth: 4 +# AlignEscapedNewlinesLeft: false +# AlignTrailingComments: true +# AllowAllParametersOfDeclarationOnNextLine: true +# AllowShortBlocksOnASingleLine: false +AllowShortIfStatementsOnASingleLine: true +AllowShortLoopsOnASingleLine: true +# AllowShortFunctionsOnASingleLine: All +AlwaysBreakAfterDefinitionReturnType: true # needs version 3.6.0 +# AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: true +# BreakBeforeBinaryOperators: false +# BreakBeforeTernaryOperators: true +# BreakConstructorInitializersBeforeComma: false +# BinPackParameters: true +ColumnLimit: 80 +# ConstructorInitializerAllOnOneLineOrOnePerLine: false +# DerivePointerAlignment: false +# ExperimentalAutoDetectBinPacking: false +# IndentCaseLabels: false +# IndentWrappedFunctionNames: false +# IndentFunctionDeclarationAfterType: false +# MaxEmptyLinesToKeep: 1 +# KeepEmptyLinesAtTheStartOfBlocks: true +# NamespaceIndentation: None +# ObjCSpaceAfterProperty: false +# ObjCSpaceBeforeProtocolList: true +# PenaltyBreakBeforeFirstCallParameter: 19 +# PenaltyBreakComment: 300 +# PenaltyBreakString: 1000 +# PenaltyBreakFirstLessLess: 120 +# PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 0 +PointerAlignment: Right +SpacesBeforeTrailingComments: 2 +# Cpp11BracedListStyle: true +Standard: Cpp03 +IndentWidth: 4 +# TabWidth: 4 +# UseTab: Never +BreakBeforeBraces: Stroustrup #GNU # Linux +SpacesInParentheses: true +# SpacesInAngles: false +# SpaceInEmptyParentheses: false +# SpacesInCStyleCastParentheses: false +# SpacesInContainerLiterals: true +# SpaceBeforeAssignmentOperators: true +# ContinuationIndentWidth: 4 +# CommentPragmas: '^ IWYU pragma:' +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +SpaceBeforeParens: Always # ControlStatements +# DisableFormat: false \ No newline at end of file diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index 3d873d5d4..b99a63cb0 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -1,4 +1,4 @@ -/* +/* Copyright (c) Marek Kurdej 2014. Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -10,8 +10,7 @@ #ifndef BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP -#include -#include // for std::iterator_traits +#include // for std::iterator_traits #include #include @@ -19,9 +18,6 @@ #include #include -#include -#include - #include // #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG_HPP @@ -32,187 +28,238 @@ namespace boost { namespace algorithm { /* A templated version of the longest (increasing) subsequence algorithm. - + Requirements: * Random access iterators - * The two iterator types (patIter and corpusIter) must - "point to" the same underlying type. - * Additional requirements may be imposed buy the skip table, such as: - ** Numeric type (array-based skip table) - ** Hashable type (map-based skip table) https://en.wikipedia.org/wiki/Longest_increasing_subsequence */ - template ::value_type> > - class longest_increasing_subsequence { - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::value_type value_type; - public: - longest_increasing_subsequence (Compare cmp = Compare()) - : compare(cmp) { - } - - ~longest_increasing_subsequence () {} - - /// \fn operator ( corpusIter corpus_first, corpusIter corpus_last, Pred p ) - /// \brief Searches the corpus for the pattern that was passed into the constructor - /// - /// \param first The start of the data to search (Random Access Iterator) - /// \param last One past the end of the data to search - /// \param cmp A predicate used for the search comparisons. - /// - std::vector operator () ( Iter first, Iter last ) const { - return this->do_search ( first, last ); - } - - template - typename boost::range_iterator::type operator () ( Range &r ) const { - return (*this) (boost::begin(r), boost::end(r)); - } +template ::value_type> > +class longest_increasing_subsequence { + typedef + typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::value_type value_type; - private: -/// \cond DOXYGEN_HIDE - Compare compare; - - /// \fn do_search ( corpusIter corpus_first, corpusIter corpus_last ) - /// \brief Searches the corpus for the pattern that was passed into the constructor - /// - /// \param corpus_first The start of the data to search (Random Access Iterator) - /// \param corpus_last One past the end of the data to search - /// - std::vector do_search ( Iter first, Iter last ) const { - // typedef typename node::iterator iterator; - // typedef typename node* iterator; - // typedef typename node::const_iterator const_iterator; - // typedef typename node const* const_iterator; - - typedef std::size_t size_type; - typedef std::vector Container; - typedef typename std::iterator_traits::difference_type difference_type; - difference_type const n = std::distance(first, last); - // if (n == 0) - - /// P[k] - stores the index of the predecessor of X[k] in the longest increasing subsequence ending at X[k] - Container P(n); - /// M[j] - stores the index k of the smallest value X[k] such that there is an increasing subsequence of length j ending at X[k] on the range k <= i - /// (note we have j <= k <= i here, because j represents the length of the increasing subsequence, and k represents the index of its termination. - /// Obviously, we can never have an increasing subsequence of length 13 ending at index 11. k <= i by definition). - // -> j-elements: X[.] X[.] ... X[k] is an increasing subsequence - Container M(n + 1); - M[0] = 0; - - /// Length of the longest (increasing) subsequence found so far - size_type L = 0; - - for (difference_type i = 0; i < n; ++i) { - // Binary search for the largest positive j <= L, such that X[M[j]] < X[i] - size_type lo = 1; - size_type hi = L; - while (lo <= hi) { - size_type mid = (lo + hi) / 2; - assert(mid <= i); - if (compare(*(first + M[mid]), *(first + i))) { // X[M[mid]] < X[i] - lo = mid + 1; - } else { - hi = mid - 1; - } - } - - // After searching, lo is 1 greater than the length of the longest prefix of X[i] - size_type newL = lo; - - // The predecessor of X[i] is the last index of the subsequence of length newL-1 - assert(newL > 0); - P[i] = M[newL - 1]; - - assert(newL <= n); - assert(M[newL] < n); - if (newL > L) { - // If we found a subsequence longer than any we've found yet, update M and L - M[newL] = i; - L = newL; - } else if (compare(*(first + i), *(first + M[newL]))) { // X[i] < X[M[newL]] - // If we found a smaller last value for the - // subsequence of length newL, only update M - M[newL] = i; - } // if - } // for - - // Reconstruct the longest increasing subsequence - std::vector S(L); - size_type k = M[L]; - for (size_type i = L - 1; i > 0; --i) { - S[i] = first + k; // X[k]; - k = P[k]; - } - S[0] = first + k; // X[k]; - return S; - } -// \endcond - }; - -/* Two ranges as inputs gives us four possibilities; with 1,2 parameters - Use a bit of TMP to disambiguate the 3-argument templates */ - -/// \fn longest_increasing_subsequence_search ( corpusIter corpus_first, corpusIter corpus_last, -/// patIter pat_first, patIter pat_last ) -/// \brief Searches the corpus for the pattern. -/// -/// \param corpus_first The start of the data to search (Random Access Iterator) -/// \param corpus_last One past the end of the data to search -/// \param pat_first The start of the pattern to search for (Random Access Iterator) -/// \param pat_last One past the end of the data to search for -/// - template - std::size_t longest_increasing_subsequence_length( - Iter first, Iter last ) +public: + longest_increasing_subsequence ( Compare cmp = Compare () ) + : compare ( cmp ) { - longest_increasing_subsequence lis; - return lis.compute_length(first, last); } - - template - std::size_t longest_increasing_subsequence_length( - Iter first, Iter last, Compare cmp ) + + ~longest_increasing_subsequence () {} + + /// \brief Searches the longest (increasing) subsequence in the data + /// + /// The result is a vector of iterators defining the longest increasing + /// subsequence (possibly non-continuous elements). By giving a different + /// comparison predicate to the constructor, one can find as well, e.g., the + /// longest decreasing substring (with std::greater() predicate) or the + /// non-decreasing one (with std::not1(std::greater())). + /// + /// \param first The start of the data to search (Forward Input + /// Iterator) + /// \param last One past the end of the data to search + /// + std::vector operator()( Iter first, Iter last ) const { - longest_increasing_subsequence lis(cmp); - return lis.compute_length( first, last ); + return this->do_search ( first, last ); } - template - Iter longest_increasing_subsequence_search ( - Iter first, Iter last ) + template + typename boost::range_iterator::type operator()( Range &r ) const { - longest_increasing_subsequence lis; - return lis ( first, last ); + return ( *this )( boost::begin ( r ), boost::end ( r ) ); } - template - OutputIter longest_increasing_subsequence_search ( - const Range &sequence ) +private: + /// \cond DOXYGEN_HIDE + Compare compare; + + std::vector + do_search ( Iter first, Iter last ) const { - typedef typename boost::range_iterator::type pattern_iterator; - longest_increasing_subsequence lis; - return lis ( boost::begin(sequence), boost::end(sequence) ); - } + typedef std::size_t size_type; + typedef std::vector Container; + typedef typename std::iterator_traits< + typename Container::iterator>::difference_type difference_type; + difference_type const n = std::distance ( first, last ); + // if (n == 0) - // Creator functions -- take a pattern range, return an object - template - boost::algorithm::longest_increasing_subsequence::type> - make_longest_increasing_subsequence ( const Range &r ) { - return boost::algorithm::longest_increasing_subsequence - ::type> (boost::begin(r), boost::end(r)); - } + /// P[k] - stores the index of the predecessor of X[k] in the longest + /// increasing subsequence ending at X[k] + Container P ( n ); + /// M[j] - stores the index k of the smallest value X[k] such that there + /// is an increasing subsequence of length j ending at X[k] on the range + /// k <= i + /// (note we have j <= k <= i here, because j represents the length of + /// the increasing subsequence, and k represents the index of its + /// termination. + /// Obviously, we can never have an increasing subsequence of length 13 + /// ending at index 11. k <= i by definition). + // -> j-elements: X[.] X[.] ... X[k] is an increasing subsequence + Container M ( n + 1 ); + M[0] = 0; - template - boost::algorithm::longest_increasing_subsequence::type> - make_longest_increasing_subsequence ( Range &r ) { - return boost::algorithm::longest_increasing_subsequence - ::type> (boost::begin(r), boost::end(r)); + /// Length of the longest (increasing) subsequence found so far + size_type L = 0; + + for ( difference_type i = 0; i < n; ++i ) { + // Binary search for the largest positive j <= L, such that X[M[j]] + // < X[i] + size_type lo = 1; + size_type hi = L; + while ( lo <= hi ) { + size_type mid = ( lo + hi ) / 2; + assert ( mid <= i ); + if ( compare ( *( first + M[mid] ), + *( first + i ) ) ) { // X[M[mid]] < X[i] + lo = mid + 1; + } + else { + hi = mid - 1; + } + } + + // After searching, lo is 1 greater than the length of the longest + // prefix of X[i] + size_type newL = lo; + + // The predecessor of X[i] is the last index of the subsequence of + // length newL-1 + assert ( newL > 0 ); + P[i] = M[newL - 1]; + + assert ( newL <= n ); + assert ( M[newL] < n ); + if ( newL > L ) { + // If we found a subsequence longer than any we've found yet, + // update M and L + M[newL] = i; + L = newL; + } + else if ( compare ( *( first + i ), + *( first + M[newL] ) ) ) { // X[i] < X[M[newL]] + // If we found a smaller last value for the + // subsequence of length newL, only update M + M[newL] = i; + } // if + } // for + + // Reconstruct the longest increasing subsequence + std::vector S ( L ); + size_type k = M[L]; + for ( size_type i = L - 1; i > 0; --i ) { + S[i] = first + k; // X[k]; + k = P[k]; } + S[0] = first + k; // X[k]; + return S; + } + // \endcond +}; + +/// \fn longest_increasing_subsequence_length ( Iter first, Iter last ) +/// \brief Searches the range [first, last) for the length of the longest +/// increasing substring. +/// +/// \param first The start of the pattern to search for (Forward Input +/// Iterator) +/// \param last One past the end of the data to search for +/// +template +std::size_t +longest_increasing_subsequence_length ( Iter first, Iter last ) +{ + longest_increasing_subsequence lis; + return lis.compute_length ( first, last ); +} + +/// \fn longest_increasing_subsequence_length ( Iter first, Iter last, Compare +/// cmp ) +/// \brief Searches the range [first, last) for the length of the longest +/// subsequence ordered by custom predicate cmp. +/// +/// \param first The start of the pattern to search for (Forward Input +/// Iterator) +/// \param last One past the end of the data to search for +/// \param cmp Comparison predicate defining the ordering +/// +template +std::size_t +longest_increasing_subsequence_length ( Iter first, Iter last, Compare cmp ) +{ + longest_increasing_subsequence lis ( cmp ); + return lis.compute_length ( first, last ); +} + +/// \fn longest_increasing_subsequence_search ( Iter first, Iter last ) +/// \brief Searches the range [first, last) for the longest increasing +/// substring. +/// +/// \param first The start of the pattern to search for (Forward Input +/// Iterator) +/// \param last One past the end of the data to search for +/// +template +Iter +longest_increasing_subsequence_search ( Iter first, Iter last ) +{ + longest_increasing_subsequence lis; + return lis ( first, last ); +} + +/// \fn longest_increasing_subsequence_search ( Iter first, Iter last, Compare +/// cmp ) +/// \brief Searches the range [first, last) for the longest subsequence ordered +/// by custom predicate cmp. +/// +/// \param first The start of the pattern to search for (Forward Input +/// Iterator) +/// \param last One past the end of the data to search for +/// \param cmp Comparison predicate defining the ordering +/// +template +Iter +longest_increasing_subsequence_search ( Iter first, Iter last, Compare cmp ) +{ + longest_increasing_subsequence lis ( cmp ); + return lis ( first, last ); +} + +template +OutputIter +longest_increasing_subsequence_search ( const Range &sequence ) +{ + typedef typename boost::range_iterator::type pattern_iterator; + longest_increasing_subsequence lis; + return lis ( boost::begin ( sequence ), boost::end ( sequence ) ); +} + +// Creator functions -- take a pattern range, return an object +template +boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> +make_longest_increasing_subsequence ( const Range &r ) +{ + return boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> ( boost::begin ( r ), + boost::end ( r ) ); +} + +template +boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> +make_longest_increasing_subsequence ( Range &r ) +{ + return boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> ( boost::begin ( r ), + boost::end ( r ) ); +} -}} +} // namespace algorithm +} // namespace boost #endif // BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index bb4dff653..f54953a6c 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -27,6 +27,9 @@ alias unit_test_framework [ compile-fail search_fail2.cpp : : : : ] [ compile-fail search_fail3.cpp : : : : ] +# Longest increasing/common subsequence/substring tests + [ run subsequence_test1.cpp unit_test_framework : : : : subsequence_test1 ] + # Clamp tests [ run clamp_test.cpp unit_test_framework : : : : clamp_test ] diff --git a/test/subsequence_test1.cpp b/test/subsequence_test1.cpp index 6059ddfcd..4b4aa8425 100644 --- a/test/subsequence_test1.cpp +++ b/test/subsequence_test1.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright (c) Marek Kurdej 2014. Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -18,129 +18,166 @@ #include #include -#include // for 'list_of()', tuple_list_of -using namespace boost::assign; // bring 'list_of()' into scope +#include // for 'list_of()', tuple_list_of +using namespace boost::assign; // bring 'list_of()' into scope namespace ba = boost::algorithm; namespace { - template - void check_lis ( const Container &sequence, std::size_t expected_length, Compare cmp ) { - } +template +void +check_lis ( const Container &sequence, std::size_t expected_length, + Compare cmp ) +{ +} - template - void check_length ( const Container &sequence, std::size_t expected_length, Compare cmp ) { - typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; - - ba::longest_increasing_subsequence ls(cmp); - ResultContainer res = ls(sequence.begin(), sequence.end()); - - BOOST_CHECK_EQUAL(res.size(), expected_length); - - // check_one_iter ( haystack, needle, expected ); - // check_one_pointer ( haystack, needle, expected ); - // check_one_object ( haystack, needle, expected ); - } - - // template - // void check_length ( const Container &sequence, std::size_t expected_length ) { - // typedef typename Container::value_type value_type; - // check_length ( sequence, expected_length, std::less() ); - // } - - template - void check_lis ( const Container &sequence, const Container &expected_lis, Compare cmp ) { - typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; - - ba::longest_increasing_subsequence ls(cmp); - ResultContainer res = ls(sequence.begin(), sequence.end()); - Container lis; - lis.resize(res.size()); - for (std::size_t i = 0; i < res.size(); ++i) { - lis[i] = *res[i]; - } - - BOOST_CHECK_EQUAL_COLLECTIONS(lis.begin(), lis.end(), expected_lis.begin(), expected_lis.end()); - } +template +void +check_length ( const Container &sequence, std::size_t expected_length, + Compare cmp ) +{ + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; - template - void check_lis ( const Container &sequence, const ContainerContainer &expected_lises, Compare cmp ) { - typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; - - ba::longest_increasing_subsequence ls(cmp); - ResultContainer res = ls(sequence.begin(), sequence.end()); - Container lis; - lis.resize(res.size()); - for (std::size_t i = 0; i < res.size(); ++i) { - lis[i] = *res[i]; - } - - bool any_equal = false; - for (std::size_t i = 0; i < expected_lises.size(); ++i) { - const Container &expected_lis = expected_lises[i]; - BOOST_REQUIRE_EQUAL(lis.size(), expected_lis.size()); - any_equal |= std::equal(lis.begin(), lis.end(), expected_lis.begin()/*, expected_lis.end()*/); - // try { - // BOOST_CHECK_EQUAL_COLLECTIONS(lis.begin(), lis.end(), expected_lis.begin(), expected_lis.end()); - // } catch (...) { - // any_equal = false; - // } - } - BOOST_CHECK(any_equal); - } + ba::longest_increasing_subsequence ls ( cmp ); + ResultContainer res = ls ( sequence.begin (), sequence.end () ); - template - void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const Container &expected_lis, Compare cmp ) { - BOOST_TEST_CHECKPOINT ( test_name ); - check_length ( sequence, expected_length, cmp ); - BOOST_REQUIRE_EQUAL( expected_lis.size(), expected_length ); - check_lis ( sequence, expected_lis, cmp ); + BOOST_CHECK_EQUAL ( res.size (), expected_length ); + + // check_one_iter ( haystack, needle, expected ); + // check_one_pointer ( haystack, needle, expected ); + // check_one_object ( haystack, needle, expected ); +} + +// template +// void check_length ( const Container &sequence, std::size_t expected_length ) +// { +// typedef typename Container::value_type value_type; +// check_length ( sequence, expected_length, std::less() ); +// } + +template +void +check_lis ( const Container &sequence, const Container &expected_lis, + Compare cmp ) +{ + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; + + ba::longest_increasing_subsequence ls ( cmp ); + ResultContainer res = ls ( sequence.begin (), sequence.end () ); + Container lis; + lis.resize ( res.size () ); + for ( std::size_t i = 0; i < res.size (); ++i ) { + lis[i] = *res[i]; } - template - void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const ContainerContainer &expected_lises, Compare cmp ) { - BOOST_TEST_CHECKPOINT ( test_name ); - check_length ( sequence, expected_length, cmp ); - for (std::size_t i = 0; i < expected_lises.size(); ++i) { - BOOST_REQUIRE_EQUAL ( expected_lises[i].size(), expected_length ); - } - check_lis ( sequence, expected_lises, cmp ); + BOOST_CHECK_EQUAL_COLLECTIONS ( + lis.begin (), lis.end (), expected_lis.begin (), expected_lis.end () ); +} + +template +void +check_lis ( const Container &sequence, const ContainerContainer &expected_lises, + Compare cmp ) +{ + typedef typename Container::const_iterator const_iterator; + typedef std::vector ResultContainer; + + ba::longest_increasing_subsequence ls ( cmp ); + ResultContainer res = ls ( sequence.begin (), sequence.end () ); + Container lis; + lis.resize ( res.size () ); + for ( std::size_t i = 0; i < res.size (); ++i ) { + lis[i] = *res[i]; } - template - void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const Container &expected_lis ) { - typedef typename Container::value_type value_type; - check_one ( test_name, sequence, expected_length, expected_lis, std::less() ); + bool any_equal = false; + for ( std::size_t i = 0; i < expected_lises.size (); ++i ) { + const Container &expected_lis = expected_lises[i]; + BOOST_REQUIRE_EQUAL ( lis.size (), expected_lis.size () ); + any_equal |= + std::equal ( lis.begin (), lis.end (), + expected_lis.begin () /*, expected_lis.end()*/ ); + // try { + // BOOST_CHECK_EQUAL_COLLECTIONS(lis.begin(), lis.end(), + // expected_lis.begin(), expected_lis.end()); + // } catch (...) { + // any_equal = false; + // } } + BOOST_CHECK ( any_equal ); +} - template - void check_one ( const std::string& test_name, const Container &sequence, std::size_t expected_length, const ContainerContainer &expected_lises ) { - typedef typename Container::value_type value_type; - check_one ( test_name, sequence, expected_length, expected_lises, std::less() ); +template +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Compare cmp ) +{ + BOOST_TEST_CHECKPOINT ( test_name ); + check_length ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); + check_lis ( sequence, expected_lis, cmp ); +} + +template +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, + const ContainerContainer &expected_lises, Compare cmp ) +{ + BOOST_TEST_CHECKPOINT ( test_name ); + check_length ( sequence, expected_length, cmp ); + for ( std::size_t i = 0; i < expected_lises.size (); ++i ) { + BOOST_REQUIRE_EQUAL ( expected_lises[i].size (), expected_length ); } + check_lis ( sequence, expected_lises, cmp ); +} + +template +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis ) +{ + typedef typename Container::value_type value_type; + check_one ( test_name, sequence, expected_length, expected_lis, + std::less () ); +} +template +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, + const ContainerContainer &expected_lises ) +{ + typedef typename Container::value_type value_type; + check_one ( test_name, sequence, expected_length, expected_lises, + std::less () ); +} } template -void ReadFromFile ( const char *name, std::back_insert_iterator inserter ) { +void +ReadFromFile ( const char *name, std::back_insert_iterator inserter ) +{ std::ifstream in ( name, std::ios_base::binary | std::ios_base::in ); - std::istream_iterator begin(in); + std::istream_iterator begin ( in ); std::istream_iterator end; - + std::copy ( begin, end, inserter ); } template -std::string make_str ( Iter first, std::size_t len ) { +std::string +make_str ( Iter first, std::size_t len ) +{ std::string retVal ( len + 2, '\'' ); - std::copy ( first, first + len, retVal.begin() + 1); + std::copy ( first, first + len, retVal.begin () + 1 ); return retVal; } -BOOST_AUTO_TEST_CASE( test_main ) +BOOST_AUTO_TEST_CASE ( test_main ) { typedef std::vector vec; typedef std::vector res; @@ -148,60 +185,67 @@ BOOST_AUTO_TEST_CASE( test_main ) using std::string; using std::wstring; - vec seq1 = list_of(5); - res exp1 = list_of(5); - vec seq2 = list_of(5) (6) (7); - res exp2 = list_of(5) (6) (7); - vec seq3 = list_of(5) (7) (6); - res exp3a = list_of(5) (6); - res exp3b = list_of(5) (7); - resvec exp3 = list_of(exp3a) (exp3b); - vec seq4 = list_of(7) (2) (8) (1) (3) (4) (10) (6) (9) (5); - res exp4 = list_of(1) (3) (4) (6) (9); - vec seq5 = list_of(3) (2) (6) (4) (5) (1); - res exp5a = list_of(2) (4) (5); - res exp5b = list_of(3) (4) (5); - resvec exp5 = list_of(exp5a) (exp5b); - vec seq6 = list_of(0) (8) (4) (12) (2) (10) (6) (14) (1) (9) (5) (13) (3) (11) (7) (15); - res exp6a = list_of(0) (2) (6) (9) (11) (15); - res exp6b = list_of(0) (4) (6) (9) (13) (15); - resvec exp6 = list_of(exp6a) (exp6b); + vec seq1 = list_of ( 5 ); + res exp1 = list_of ( 5 ); + vec seq2 = list_of ( 5 )( 6 )( 7 ); + res exp2 = list_of ( 5 )( 6 )( 7 ); + vec seq3 = list_of ( 5 )( 7 )( 6 ); + res exp3a = list_of ( 5 )( 6 ); + res exp3b = list_of ( 5 )( 7 ); + resvec exp3 = list_of ( exp3a )( exp3b ); + vec seq4 = list_of ( 7 )( 2 )( 8 )( 1 )( 3 )( 4 )( 10 )( 6 )( 9 )( 5 ); + res exp4 = list_of ( 1 )( 3 )( 4 )( 6 )( 9 ); + vec seq5 = list_of ( 3 )( 2 )( 6 )( 4 )( 5 )( 1 ); + res exp5a = list_of ( 2 )( 4 )( 5 ); + res exp5b = list_of ( 3 )( 4 )( 5 ); + resvec exp5 = list_of ( exp5a )( exp5b ); + vec seq6 = list_of ( 0 )( 8 )( 4 )( 12 )( 2 )( 10 )( 6 )( 14 )( 1 )( 9 )( + 5 )( 13 )( 3 )( 11 )( 7 )( 15 ); + res exp6a = list_of ( 0 )( 2 )( 6 )( 9 )( 11 )( 15 ); + res exp6b = list_of ( 0 )( 4 )( 6 )( 9 )( 13 )( 15 ); + resvec exp6 = list_of ( exp6a )( exp6b ); string str1 = "abcdef"; string estr1 = str1; - string str2 = "All human beings are born free and equal in dignity and rights."; + string str2 = + "All human beings are born free and equal in dignity and rights."; string estr2 = " abdeginrs"; wstring wstr1 = L"abcdef"; wstring ewstr1 = wstr1; - check_one("seq1", seq1, 1, exp1); - check_one("seq2", seq2, 3, exp2); - check_one("seq3", seq3, 2, exp3); - check_one("seq5", seq4, 5, exp4); - check_one("seq5", seq5, 3, exp5); - check_one("seq6", seq6, 6, exp6); - - check_one("str1", str1, 6, estr1); - check_one("str2", str2, 10, estr2); - check_one("wstr1", wstr1, 6, ewstr1); - - - string c1; ReadFromFile ( "search_test_data/0001.corpus", std::back_inserter(c1) ); - string ec1 = "+/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; - - string p1b; ReadFromFile ( "search_test_data/0001b.pat", std::back_inserter(p1b) ); + check_one ( "seq1", seq1, 1, exp1 ); + check_one ( "seq2", seq2, 3, exp2 ); + check_one ( "seq3", seq3, 2, exp3 ); + check_one ( "seq5", seq4, 5, exp4 ); + check_one ( "seq5", seq5, 3, exp5 ); + check_one ( "seq6", seq6, 6, exp6 ); + + check_one ( "str1", str1, 6, estr1 ); + check_one ( "str2", str2, 10, estr2 ); + check_one ( "wstr1", wstr1, 6, ewstr1 ); + + string c1; + ReadFromFile ( "search_test_data/0001.corpus", std::back_inserter ( c1 ) ); + string ec1 = + "+/0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + + string p1b; + ReadFromFile ( "search_test_data/0001b.pat", std::back_inserter ( p1b ) ); string ep1b = "0AKPScdehlnpwxz"; - string p1e; ReadFromFile ( "search_test_data/0001e.pat", std::back_inserter(p1e) ); + string p1e; + ReadFromFile ( "search_test_data/0001e.pat", std::back_inserter ( p1e ) ); string ep1e = "BCGHIJVdg"; - string p1f; ReadFromFile ( "search_test_data/0001f.pat", std::back_inserter(p1f) ); + string p1f; + ReadFromFile ( "search_test_data/0001f.pat", std::back_inserter ( p1f ) ); string ep1f = "/3568BENOPQUgxz"; - string p1n; ReadFromFile ( "search_test_data/0001n.pat", std::back_inserter(p1n) ); + string p1n; + ReadFromFile ( "search_test_data/0001n.pat", std::back_inserter ( p1n ) ); string ep1n = "013DEIMNTUY"; - check_one("c1", c1, 64, ec1); - check_one("p1b", p1b, 15, ep1b); - check_one("p1e", p1e, 9, ep1e); - check_one("p1f", p1f, 15, ep1f); - check_one("p1n", p1n, 11, ep1n); + check_one ( "c1", c1, 64, ec1 ); + check_one ( "p1b", p1b, 15, ep1b ); + check_one ( "p1e", p1e, 9, ep1e ); + check_one ( "p1f", p1f, 15, ep1f ); + check_one ( "p1n", p1n, 11, ep1n ); } From 5a82430f6955b3abecde2d7b95109eeab5016aba Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Thu, 14 Aug 2014 17:32:31 +0200 Subject: [PATCH 3/8] [algorithm] [searching] [longest_increasing_subsequence] Fix interface (WIP). --- .../longest_increasing_subsequence.hpp | 147 ++++++++++++++---- 1 file changed, 116 insertions(+), 31 deletions(-) diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index b99a63cb0..e453f35db 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -18,9 +18,12 @@ #include #include -#include +#include -// #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG_HPP +// #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG +#ifdef BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG +#include +#endif #include @@ -44,6 +47,9 @@ class longest_increasing_subsequence { typedef typename std::iterator_traits::value_type value_type; public: + typedef std::vector iterator_vector; + typedef std::vector value_vector; + longest_increasing_subsequence ( Compare cmp = Compare () ) : compare ( cmp ) { @@ -51,25 +57,63 @@ class longest_increasing_subsequence { ~longest_increasing_subsequence () {} - /// \brief Searches the longest (increasing) subsequence in the data + /// \brief Searches the longest (increasing) subsequence in the sequence /// /// The result is a vector of iterators defining the longest increasing /// subsequence (possibly non-continuous elements). By giving a different /// comparison predicate to the constructor, one can find as well, e.g., the - /// longest decreasing substring (with std::greater() predicate) or the + /// longest decreasing subsequence (with std::greater() predicate) or the /// non-decreasing one (with std::not1(std::greater())). + /// The time complexity of the algorithm is log-linear O(n logn) where n is the length + /// of the sequence (`std::distance(first, last)`). + /// The space complexity is linear O(n). /// - /// \param first The start of the data to search (Forward Input + /// \param first The start of the sequence to search (Random Access /// Iterator) - /// \param last One past the end of the data to search + /// \param last One past the end of the sequence to search /// - std::vector operator()( Iter first, Iter last ) const + iterator_vector operator()( Iter first, Iter last ) const { return this->do_search ( first, last ); } + template + OutputIter + operator()( Iter first, Iter last, OutputIter d_first ) const + { + BOOST_STATIC_ASSERT (( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); + return this->do_search ( first, last, d_first ); + } + template - typename boost::range_iterator::type operator()( Range &r ) const + iterator_vector operator()( const Range &r ) const + { + return ( *this )( boost::begin ( r ), boost::end ( r ) ); + } + + template + OutputIter + operator()( const Range &r, OutputIter d_first ) const + { + BOOST_STATIC_ASSERT (( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); + return this->do_search ( boost::begin ( r ), boost::end ( r ), d_first ); + } + + std::size_t + compute_length ( Iter first, Iter last ) const + { + // TODO: separate search from output creation, and use the first part here + iterator_vector result = ( *this )( first, last ); + return result.size (); + } + + template + std::size_t + compute_length ( const Range &r ) const { return ( *this )( boost::begin ( r ), boost::end ( r ) ); } @@ -78,7 +122,7 @@ class longest_increasing_subsequence { /// \cond DOXYGEN_HIDE Compare compare; - std::vector + iterator_vector do_search ( Iter first, Iter last ) const { typedef std::size_t size_type; @@ -149,7 +193,7 @@ class longest_increasing_subsequence { } // for // Reconstruct the longest increasing subsequence - std::vector S ( L ); + iterator_vector S ( L ); size_type k = M[L]; for ( size_type i = L - 1; i > 0; --i ) { S[i] = first + k; // X[k]; @@ -163,11 +207,11 @@ class longest_increasing_subsequence { /// \fn longest_increasing_subsequence_length ( Iter first, Iter last ) /// \brief Searches the range [first, last) for the length of the longest -/// increasing substring. +/// increasing subsequence. /// -/// \param first The start of the pattern to search for (Forward Input +/// \param first The start of the sequence to search for (Forward Input /// Iterator) -/// \param last One past the end of the data to search for +/// \param last One past the end of the sequence to search for /// template std::size_t @@ -177,76 +221,108 @@ longest_increasing_subsequence_length ( Iter first, Iter last ) return lis.compute_length ( first, last ); } +template +std::size_t +longest_increasing_subsequence_length ( const Range &r ) +{ + typedef typename boost::range_iterator::type range_iterator; + longest_increasing_subsequence lis; + return lis.compute_length ( boost::begin ( r ), boost::end ( r ) ); +} +// TODO: do we need a non-const range overload? + /// \fn longest_increasing_subsequence_length ( Iter first, Iter last, Compare /// cmp ) /// \brief Searches the range [first, last) for the length of the longest /// subsequence ordered by custom predicate cmp. /// -/// \param first The start of the pattern to search for (Forward Input +/// \param first The start of the sequence to search for (Forward Input /// Iterator) -/// \param last One past the end of the data to search for +/// \param last One past the end of the sequence to search for /// \param cmp Comparison predicate defining the ordering /// template std::size_t longest_increasing_subsequence_length ( Iter first, Iter last, Compare cmp ) { - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence lis ( cmp ); return lis.compute_length ( first, last ); } +template +std::size_t +longest_increasing_subsequence_length ( const Range &r, Compare cmp ) +{ + typedef typename boost::range_iterator::type range_iterator; + longest_increasing_subsequence lis ( cmp ); + return lis.compute_length ( boost::begin ( r ), boost::end ( r ) ); +} +// TODO: do we need a non-const range overload? + /// \fn longest_increasing_subsequence_search ( Iter first, Iter last ) /// \brief Searches the range [first, last) for the longest increasing -/// substring. +/// subsequence. /// -/// \param first The start of the pattern to search for (Forward Input +/// \param first The start of the sequence to search for (Forward Input /// Iterator) -/// \param last One past the end of the data to search for +/// \param last One past the end of the sequence to search for /// template -Iter +std::vector longest_increasing_subsequence_search ( Iter first, Iter last ) { longest_increasing_subsequence lis; return lis ( first, last ); } +// TODO: range /// \fn longest_increasing_subsequence_search ( Iter first, Iter last, Compare /// cmp ) /// \brief Searches the range [first, last) for the longest subsequence ordered /// by custom predicate cmp. /// -/// \param first The start of the pattern to search for (Forward Input +/// \param first The start of the sequence to search for (Forward Input /// Iterator) -/// \param last One past the end of the data to search for +/// \param last One past the end of the sequence to search for /// \param cmp Comparison predicate defining the ordering /// template -Iter +std::vector longest_increasing_subsequence_search ( Iter first, Iter last, Compare cmp ) { longest_increasing_subsequence lis ( cmp ); return lis ( first, last ); } +// TODO: range template -OutputIter -longest_increasing_subsequence_search ( const Range &sequence ) +void +longest_increasing_subsequence_search ( const Range &sequence, + OutputIter output_first ) { - typedef typename boost::range_iterator::type pattern_iterator; - longest_increasing_subsequence lis; - return lis ( boost::begin ( sequence ), boost::end ( sequence ) ); + typedef typename boost::range_iterator::type range_iterator; + longest_increasing_subsequence lis; + return lis ( boost::begin ( sequence ), boost::end ( sequence ), + output_first ); } -// Creator functions -- take a pattern range, return an object +// Creator functions -- take a range, return an object template boost::algorithm::longest_increasing_subsequence< typename boost::range_iterator::type> make_longest_increasing_subsequence ( const Range &r ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( boost::begin ( r ), - boost::end ( r ) ); + typename boost::range_iterator::type> (); +} + +template +boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type, Compare> +make_longest_increasing_subsequence ( const Range &r, Compare cmp ) +{ + return boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> ( cmp ); } template @@ -259,6 +335,15 @@ make_longest_increasing_subsequence ( Range &r ) boost::end ( r ) ); } +template +boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type, Compare> +make_longest_increasing_subsequence ( Range &r, Compare cmp ) +{ + return boost::algorithm::longest_increasing_subsequence< + typename boost::range_iterator::type> ( cmp ); +} + } // namespace algorithm } // namespace boost From 459938807fad2ce31c0e08365acf818dead56862 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sat, 16 Aug 2014 11:07:47 +0200 Subject: [PATCH 4/8] [longest_increasing_subsequence] Accepting Output Iterator as an optional argument. Rename variables. --- .../longest_increasing_subsequence.hpp | 203 +++++++++++------- test/subsequence_test1.cpp | 31 ++- 2 files changed, 134 insertions(+), 100 deletions(-) diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index e453f35db..675d6c199 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -47,7 +47,6 @@ class longest_increasing_subsequence { typedef typename std::iterator_traits::value_type value_type; public: - typedef std::vector iterator_vector; typedef std::vector value_vector; longest_increasing_subsequence ( Compare cmp = Compare () ) @@ -72,7 +71,7 @@ class longest_increasing_subsequence { /// Iterator) /// \param last One past the end of the sequence to search /// - iterator_vector operator()( Iter first, Iter last ) const + value_vector operator()( Iter first, Iter last ) const { return this->do_search ( first, last ); } @@ -81,14 +80,14 @@ class longest_increasing_subsequence { OutputIter operator()( Iter first, Iter last, OutputIter d_first ) const { - BOOST_STATIC_ASSERT (( boost::is_same< - typename std::iterator_traits::value_type, - typename std::iterator_traits::value_type>::value )); + // BOOST_STATIC_ASSERT (( boost::is_same< + // typename std::iterator_traits::value_type, + // typename std::iterator_traits::value_type>::value )); return this->do_search ( first, last, d_first ); } template - iterator_vector operator()( const Range &r ) const + value_vector operator()( const Range &r ) const { return ( *this )( boost::begin ( r ), boost::end ( r ) ); } @@ -107,7 +106,7 @@ class longest_increasing_subsequence { compute_length ( Iter first, Iter last ) const { // TODO: separate search from output creation, and use the first part here - iterator_vector result = ( *this )( first, last ); + value_vector result = ( *this )( first, last ); return result.size (); } @@ -122,20 +121,20 @@ class longest_increasing_subsequence { /// \cond DOXYGEN_HIDE Compare compare; - iterator_vector - do_search ( Iter first, Iter last ) const + template + OutputIter + do_search ( Iter first, Iter last, OutputIter d_first ) const { typedef std::size_t size_type; - typedef std::vector Container; + typedef std::vector index_vector; typedef typename std::iterator_traits< - typename Container::iterator>::difference_type difference_type; + typename index_vector::iterator>::difference_type difference_type; difference_type const n = std::distance ( first, last ); - // if (n == 0) - /// P[k] - stores the index of the predecessor of X[k] in the longest + /// predecessor[k] - stores the index of the predecessor of X[k] in the longest /// increasing subsequence ending at X[k] - Container P ( n ); - /// M[j] - stores the index k of the smallest value X[k] such that there + index_vector predecessor ( n ); + /// lis_tail[j] - stores the index k of the smallest value X[k] such that there /// is an increasing subsequence of length j ending at X[k] on the range /// k <= i /// (note we have j <= k <= i here, because j represents the length of @@ -144,63 +143,74 @@ class longest_increasing_subsequence { /// Obviously, we can never have an increasing subsequence of length 13 /// ending at index 11. k <= i by definition). // -> j-elements: X[.] X[.] ... X[k] is an increasing subsequence - Container M ( n + 1 ); - M[0] = 0; + index_vector lis_tail ( n + 1 ); /// Length of the longest (increasing) subsequence found so far - size_type L = 0; - + size_type lis_length = 0; for ( difference_type i = 0; i < n; ++i ) { - // Binary search for the largest positive j <= L, such that X[M[j]] - // < X[i] - size_type lo = 1; - size_type hi = L; - while ( lo <= hi ) { - size_type mid = ( lo + hi ) / 2; - assert ( mid <= i ); - if ( compare ( *( first + M[mid] ), - *( first + i ) ) ) { // X[M[mid]] < X[i] - lo = mid + 1; - } - else { - hi = mid - 1; + // Binary search for the largest positive j <= lis_length, such that + // X[lis_tail[j]] < X[i]. + // After searching, lo is 1 greater than the length of the longest + // prefix of X[i]. + size_type new_lis_length; + { + size_type lo = 1; + size_type hi = lis_length; + while ( lo <= hi ) { + size_type mid = ( lo + hi ) / 2; + assert ( mid <= i ); + if ( compare ( *( first + lis_tail[mid] ), + *( first + i ) ) ) { // X[lis_tail[mid]] < X[i] + lo = mid + 1; + } + else { + hi = mid - 1; + } } + new_lis_length = lo; } - // After searching, lo is 1 greater than the length of the longest - // prefix of X[i] - size_type newL = lo; - // The predecessor of X[i] is the last index of the subsequence of - // length newL-1 - assert ( newL > 0 ); - P[i] = M[newL - 1]; - - assert ( newL <= n ); - assert ( M[newL] < n ); - if ( newL > L ) { - // If we found a subsequence longer than any we've found yet, - // update M and L - M[newL] = i; - L = newL; + // length new_lis_length-1 + assert ( new_lis_length > 0 ); + predecessor[i] = lis_tail[new_lis_length - 1]; + + assert ( new_lis_length <= n ); + assert ( lis_tail[new_lis_length] < n ); + if ( new_lis_length > lis_length ) { + // If we found a subsequence longer than any we have found yet, + // update lis_tail and lis_length + lis_tail[new_lis_length] = i; + lis_length = new_lis_length; } else if ( compare ( *( first + i ), - *( first + M[newL] ) ) ) { // X[i] < X[M[newL]] + *( first + lis_tail[new_lis_length] ) ) ) { // X[i] < X[lis_tail[new_lis_length]] // If we found a smaller last value for the - // subsequence of length newL, only update M - M[newL] = i; - } // if - } // for + // subsequence of length new_lis_length, only update lis_tail + lis_tail[new_lis_length] = i; + } + } // Reconstruct the longest increasing subsequence - iterator_vector S ( L ); - size_type k = M[L]; - for ( size_type i = L - 1; i > 0; --i ) { - S[i] = first + k; // X[k]; - k = P[k]; + index_vector lis ( lis_length ); + size_type k = lis_tail[lis_length]; + for ( size_type i = lis_length; i--; ) { + lis[i] = k; // X[k]; + k = predecessor[k]; + } + // Output the found subsequence + for ( size_type i = 0; i < lis_length; ++i ) { + *d_first++ = *(first + lis[i]); } - S[0] = first + k; // X[k]; - return S; + return d_first; + } + + value_vector + do_search ( Iter first, Iter last ) const + { + value_vector lis; + this->do_search ( first, last, std::back_inserter(lis) ); + return lis; } // \endcond }; @@ -267,45 +277,74 @@ longest_increasing_subsequence_length ( const Range &r, Compare cmp ) /// Iterator) /// \param last One past the end of the sequence to search for /// -template -std::vector -longest_increasing_subsequence_search ( Iter first, Iter last ) +// template +// std::vector +// longest_increasing_subsequence_search ( Iter first, Iter last ) +// { + // longest_increasing_subsequence lis; + // return lis ( first, last ); +// } +// TODO: range + +template +OutputIter +longest_increasing_subsequence_search ( Iter first, Iter last, + OutputIter d_first ) { longest_increasing_subsequence lis; - return lis ( first, last ); + return lis ( first, last, d_first ); } -// TODO: range -/// \fn longest_increasing_subsequence_search ( Iter first, Iter last, Compare -/// cmp ) -/// \brief Searches the range [first, last) for the longest subsequence ordered -/// by custom predicate cmp. -/// -/// \param first The start of the sequence to search for (Forward Input -/// Iterator) -/// \param last One past the end of the sequence to search for -/// \param cmp Comparison predicate defining the ordering -/// -template -std::vector -longest_increasing_subsequence_search ( Iter first, Iter last, Compare cmp ) +template +OutputIter +longest_increasing_subsequence_search ( Iter first, Iter last, + OutputIter d_first, Compare cmp ) { longest_increasing_subsequence lis ( cmp ); - return lis ( first, last ); + return lis ( first, last, d_first ); } -// TODO: range template -void +OutputIter longest_increasing_subsequence_search ( const Range &sequence, - OutputIter output_first ) + OutputIter d_first ) { typedef typename boost::range_iterator::type range_iterator; longest_increasing_subsequence lis; return lis ( boost::begin ( sequence ), boost::end ( sequence ), - output_first ); + d_first ); +} + +template +OutputIter +longest_increasing_subsequence_search ( const Range &sequence, + OutputIter d_first, Compare cmp ) +{ + typedef typename boost::range_iterator::type range_iterator; + longest_increasing_subsequence lis ( cmp ); + return lis ( boost::begin ( sequence ), boost::end ( sequence ), + d_first ); } +/// \fn longest_increasing_subsequence_search ( Iter first, Iter last, Compare +/// cmp ) +/// \brief Searches the range [first, last) for the longest subsequence ordered +/// by custom predicate cmp. +/// +/// \param first The start of the sequence to search for (Forward Input +/// Iterator) +/// \param last One past the end of the sequence to search for +/// \param cmp Comparison predicate defining the ordering +/// +// template +// std::vector +// longest_increasing_subsequence_search ( Iter first, Iter last, Compare cmp ) +// { + // longest_increasing_subsequence lis ( cmp ); + // return lis ( first, last ); +// } +// TODO: range + // Creator functions -- take a range, return an object template boost::algorithm::longest_increasing_subsequence< diff --git a/test/subsequence_test1.cpp b/test/subsequence_test1.cpp index 4b4aa8425..7286cb793 100644 --- a/test/subsequence_test1.cpp +++ b/test/subsequence_test1.cpp @@ -37,12 +37,13 @@ check_length ( const Container &sequence, std::size_t expected_length, Compare cmp ) { typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; + typedef typename Container::value_type value_type; + typedef typename std::vector ResultContainer; ba::longest_increasing_subsequence ls ( cmp ); - ResultContainer res = ls ( sequence.begin (), sequence.end () ); + ResultContainer lis = ls ( sequence.begin (), sequence.end () ); - BOOST_CHECK_EQUAL ( res.size (), expected_length ); + BOOST_CHECK_EQUAL ( lis.size (), expected_length ); // check_one_iter ( haystack, needle, expected ); // check_one_pointer ( haystack, needle, expected ); @@ -62,18 +63,18 @@ check_lis ( const Container &sequence, const Container &expected_lis, Compare cmp ) { typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; + typedef typename Container::value_type value_type; + typedef typename std::vector ResultContainer; ba::longest_increasing_subsequence ls ( cmp ); - ResultContainer res = ls ( sequence.begin (), sequence.end () ); - Container lis; - lis.resize ( res.size () ); - for ( std::size_t i = 0; i < res.size (); ++i ) { - lis[i] = *res[i]; - } - + ResultContainer lis = ls ( sequence.begin (), sequence.end () ); BOOST_CHECK_EQUAL_COLLECTIONS ( lis.begin (), lis.end (), expected_lis.begin (), expected_lis.end () ); + + ResultContainer lis2; + ls ( sequence.begin (), sequence.end (), std::back_inserter(lis2) ); + BOOST_CHECK_EQUAL_COLLECTIONS ( + lis2.begin (), lis2.end (), expected_lis.begin (), expected_lis.end () ); } template @@ -82,15 +83,9 @@ check_lis ( const Container &sequence, const ContainerContainer &expected_lises, Compare cmp ) { typedef typename Container::const_iterator const_iterator; - typedef std::vector ResultContainer; ba::longest_increasing_subsequence ls ( cmp ); - ResultContainer res = ls ( sequence.begin (), sequence.end () ); - Container lis; - lis.resize ( res.size () ); - for ( std::size_t i = 0; i < res.size (); ++i ) { - lis[i] = *res[i]; - } + Container lis = ls ( sequence.begin (), sequence.end () ); bool any_equal = false; for ( std::size_t i = 0; i < expected_lises.size (); ++i ) { From 890fc1e27a6f849fd65b11fb81cbe58d2ae25fc1 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sat, 16 Aug 2014 11:44:24 +0200 Subject: [PATCH 5/8] [longest_increasing_subsequence] Change interface to accept a tag defining the return type (a collection of values or a collection of iterators). --- .../longest_increasing_subsequence.hpp | 172 ++++++++++-------- 1 file changed, 100 insertions(+), 72 deletions(-) diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index 675d6c199..e7856f8d2 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -39,17 +39,26 @@ namespace boost { namespace algorithm { */ -template ::value_type> > +/// Longest increasing subsequence algorithm. +/// +/// @time O(N logN) +/// @space O(N) +template ::value_type> > class longest_increasing_subsequence { - typedef - typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type difference_type; + typedef typename std::iterator_traits::value_type value_type; public: + typedef std::vector iterator_vector; typedef std::vector value_vector; + + struct iterator_output_tag_t {}; + struct value_output_tag_t {}; + + static iterator_output_tag_t iterator_output_tag; + static value_output_tag_t value_output_tag; - longest_increasing_subsequence ( Compare cmp = Compare () ) + longest_increasing_subsequence ( Comparator cmp = Comparator () ) : compare ( cmp ) { } @@ -71,39 +80,50 @@ class longest_increasing_subsequence { /// Iterator) /// \param last One past the end of the sequence to search /// - value_vector operator()( Iter first, Iter last ) const + value_vector operator()( RandomIterator first, RandomIterator last, value_output_tag_t tag = value_output_tag ) const + { + return this->do_search ( first, last, tag ); + } + + iterator_vector operator()( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const { - return this->do_search ( first, last ); + return this->do_search ( first, last, tag ); } - template - OutputIter - operator()( Iter first, Iter last, OutputIter d_first ) const + template + OutputIterator + operator()( RandomIterator first, RandomIterator last, OutputIterator d_first ) const { // BOOST_STATIC_ASSERT (( boost::is_same< - // typename std::iterator_traits::value_type, - // typename std::iterator_traits::value_type>::value )); + // typename std::iterator_traits::value_type, + // typename std::iterator_traits::value_type>::value )); return this->do_search ( first, last, d_first ); } template - value_vector operator()( const Range &r ) const + value_vector operator()( const Range &r, value_output_tag_t tag = value_output_tag ) const { - return ( *this )( boost::begin ( r ), boost::end ( r ) ); + return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } - template - OutputIter - operator()( const Range &r, OutputIter d_first ) const + template + iterator_vector operator()( const Range &r, iterator_output_tag_t tag ) const + { + return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); + } + + template + OutputIterator + operator()( const Range &r, OutputIterator d_first ) const { BOOST_STATIC_ASSERT (( boost::is_same< - typename std::iterator_traits::value_type, - typename std::iterator_traits::value_type>::value )); + typename std::iterator_traits::value_type, + typename std::iterator_traits::value_type>::value )); return this->do_search ( boost::begin ( r ), boost::end ( r ), d_first ); } std::size_t - compute_length ( Iter first, Iter last ) const + compute_length ( RandomIterator first, RandomIterator last ) const { // TODO: separate search from output creation, and use the first part here value_vector result = ( *this )( first, last ); @@ -119,11 +139,11 @@ class longest_increasing_subsequence { private: /// \cond DOXYGEN_HIDE - Compare compare; + Comparator compare; - template - OutputIter - do_search ( Iter first, Iter last, OutputIter d_first ) const + template + OutputIterator + do_search ( RandomIterator first, RandomIterator last, OutputIterator d_first ) const { typedef std::size_t size_type; typedef std::vector index_vector; @@ -206,16 +226,24 @@ class longest_increasing_subsequence { } value_vector - do_search ( Iter first, Iter last ) const + do_search ( RandomIterator first, RandomIterator last, value_output_tag_t tag ) const { value_vector lis; this->do_search ( first, last, std::back_inserter(lis) ); return lis; } + + iterator_vector + do_search ( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const + { + iterator_vector lis; + this->do_search ( first, last, std::back_inserter(lis) ); + return lis; + } // \endcond }; -/// \fn longest_increasing_subsequence_length ( Iter first, Iter last ) +/// \fn longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last ) /// \brief Searches the range [first, last) for the length of the longest /// increasing subsequence. /// @@ -223,11 +251,11 @@ class longest_increasing_subsequence { /// Iterator) /// \param last One past the end of the sequence to search for /// -template +template std::size_t -longest_increasing_subsequence_length ( Iter first, Iter last ) +longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last ) { - longest_increasing_subsequence lis; + longest_increasing_subsequence lis; return lis.compute_length ( first, last ); } @@ -241,7 +269,7 @@ longest_increasing_subsequence_length ( const Range &r ) } // TODO: do we need a non-const range overload? -/// \fn longest_increasing_subsequence_length ( Iter first, Iter last, Compare +/// \fn longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last, Comparator /// cmp ) /// \brief Searches the range [first, last) for the length of the longest /// subsequence ordered by custom predicate cmp. @@ -251,25 +279,25 @@ longest_increasing_subsequence_length ( const Range &r ) /// \param last One past the end of the sequence to search for /// \param cmp Comparison predicate defining the ordering /// -template +template std::size_t -longest_increasing_subsequence_length ( Iter first, Iter last, Compare cmp ) +longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last, Comparator cmp ) { - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence lis ( cmp ); return lis.compute_length ( first, last ); } -template +template std::size_t -longest_increasing_subsequence_length ( const Range &r, Compare cmp ) +longest_increasing_subsequence_length ( const Range &r, Comparator cmp ) { typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence lis ( cmp ); return lis.compute_length ( boost::begin ( r ), boost::end ( r ) ); } // TODO: do we need a non-const range overload? -/// \fn longest_increasing_subsequence_search ( Iter first, Iter last ) +/// \fn longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last ) /// \brief Searches the range [first, last) for the longest increasing /// subsequence. /// @@ -277,37 +305,37 @@ longest_increasing_subsequence_length ( const Range &r, Compare cmp ) /// Iterator) /// \param last One past the end of the sequence to search for /// -// template -// std::vector -// longest_increasing_subsequence_search ( Iter first, Iter last ) +// template +// std::vector +// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last ) // { - // longest_increasing_subsequence lis; + // longest_increasing_subsequence lis; // return lis ( first, last ); // } // TODO: range -template -OutputIter -longest_increasing_subsequence_search ( Iter first, Iter last, - OutputIter d_first ) +template +OutputIterator +longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, + OutputIterator d_first ) { - longest_increasing_subsequence lis; + longest_increasing_subsequence lis; return lis ( first, last, d_first ); } -template -OutputIter -longest_increasing_subsequence_search ( Iter first, Iter last, - OutputIter d_first, Compare cmp ) +template +OutputIterator +longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, + OutputIterator d_first, Comparator cmp ) { - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence lis ( cmp ); return lis ( first, last, d_first ); } -template -OutputIter +template +OutputIterator longest_increasing_subsequence_search ( const Range &sequence, - OutputIter d_first ) + OutputIterator d_first ) { typedef typename boost::range_iterator::type range_iterator; longest_increasing_subsequence lis; @@ -315,18 +343,18 @@ longest_increasing_subsequence_search ( const Range &sequence, d_first ); } -template -OutputIter +template +OutputIterator longest_increasing_subsequence_search ( const Range &sequence, - OutputIter d_first, Compare cmp ) + OutputIterator d_first, Comparator cmp ) { typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence lis ( cmp ); return lis ( boost::begin ( sequence ), boost::end ( sequence ), d_first ); } -/// \fn longest_increasing_subsequence_search ( Iter first, Iter last, Compare +/// \fn longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, Comparator /// cmp ) /// \brief Searches the range [first, last) for the longest subsequence ordered /// by custom predicate cmp. @@ -336,11 +364,11 @@ longest_increasing_subsequence_search ( const Range &sequence, /// \param last One past the end of the sequence to search for /// \param cmp Comparison predicate defining the ordering /// -// template -// std::vector -// longest_increasing_subsequence_search ( Iter first, Iter last, Compare cmp ) +// template +// std::vector +// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, Comparator cmp ) // { - // longest_increasing_subsequence lis ( cmp ); + // longest_increasing_subsequence lis ( cmp ); // return lis ( first, last ); // } // TODO: range @@ -355,13 +383,13 @@ make_longest_increasing_subsequence ( const Range &r ) typename boost::range_iterator::type> (); } -template +template boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type, Compare> -make_longest_increasing_subsequence ( const Range &r, Compare cmp ) + typename boost::range_iterator::type, Comparator> +make_longest_increasing_subsequence ( const Range &r, Comparator cmp ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( cmp ); + typename boost::range_iterator::type> ( cmp ); } template @@ -374,13 +402,13 @@ make_longest_increasing_subsequence ( Range &r ) boost::end ( r ) ); } -template +template boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type, Compare> -make_longest_increasing_subsequence ( Range &r, Compare cmp ) + typename boost::range_iterator::type, Comparator> +make_longest_increasing_subsequence ( Range &r, Comparator cmp ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( cmp ); + typename boost::range_iterator::type> ( cmp ); } } // namespace algorithm From f393da2c7b35c254ddb0f1af01582a392b3716e5 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sat, 16 Aug 2014 12:14:33 +0200 Subject: [PATCH 6/8] [longest_increasing_subsequence] Refactor. --- .../longest_increasing_subsequence.hpp | 96 +++++++++++++------ 1 file changed, 66 insertions(+), 30 deletions(-) diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index e7856f8d2..7022cb40f 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -80,14 +80,16 @@ class longest_increasing_subsequence { /// Iterator) /// \param last One past the end of the sequence to search /// - value_vector operator()( RandomIterator first, RandomIterator last, value_output_tag_t tag = value_output_tag ) const + value_vector + operator()( RandomIterator first, RandomIterator last, value_output_tag_t tag = value_output_tag ) const { - return this->do_search ( first, last, tag ); + return this->do_search_and_output ( first, last, tag ); } - iterator_vector operator()( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const + iterator_vector + operator()( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const { - return this->do_search ( first, last, tag ); + return this->do_search_and_output ( first, last, tag ); } template @@ -97,17 +99,19 @@ class longest_increasing_subsequence { // BOOST_STATIC_ASSERT (( boost::is_same< // typename std::iterator_traits::value_type, // typename std::iterator_traits::value_type>::value )); - return this->do_search ( first, last, d_first ); + return this->do_search_and_output ( first, last, d_first ); } template - value_vector operator()( const Range &r, value_output_tag_t tag = value_output_tag ) const + value_vector + operator()( const Range &r, value_output_tag_t tag = value_output_tag ) const { return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } template - iterator_vector operator()( const Range &r, iterator_output_tag_t tag ) const + iterator_vector + operator()( const Range &r, iterator_output_tag_t tag ) const { return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } @@ -119,15 +123,13 @@ class longest_increasing_subsequence { BOOST_STATIC_ASSERT (( boost::is_same< typename std::iterator_traits::value_type, typename std::iterator_traits::value_type>::value )); - return this->do_search ( boost::begin ( r ), boost::end ( r ), d_first ); + return this->do_search_and_output ( boost::begin ( r ), boost::end ( r ), d_first ); } std::size_t compute_length ( RandomIterator first, RandomIterator last ) const { - // TODO: separate search from output creation, and use the first part here - value_vector result = ( *this )( first, last ); - return result.size (); + return this->do_search ( first, last); } template @@ -141,20 +143,29 @@ class longest_increasing_subsequence { /// \cond DOXYGEN_HIDE Comparator compare; - template - OutputIterator - do_search ( RandomIterator first, RandomIterator last, OutputIterator d_first ) const + typedef std::size_t size_type; + typedef std::vector index_vector; + + size_type + do_search ( RandomIterator first, RandomIterator last ) const { - typedef std::size_t size_type; - typedef std::vector index_vector; - typedef typename std::iterator_traits< - typename index_vector::iterator>::difference_type difference_type; - difference_type const n = std::distance ( first, last ); + index_vector predecessor; + index_vector lis_tail; + return do_search ( first, last, predecessor, lis_tail ); + } - /// predecessor[k] - stores the index of the predecessor of X[k] in the longest + size_type + do_search ( RandomIterator first, RandomIterator last, + /*output*/ index_vector &predecessor, + /*output*/ index_vector &lis_tail) const + { + difference_type const n = std::distance ( first, last ); + /// Length of the longest (increasing) subsequence found so far + size_type lis_length = 0; + /// predecessor[k, 0 <= k < n] - stores the index of the predecessor of X[k] in the longest /// increasing subsequence ending at X[k] - index_vector predecessor ( n ); - /// lis_tail[j] - stores the index k of the smallest value X[k] such that there + predecessor.resize ( n ); + /// lis_tail[j, 0 <= k <= n] - stores the index k of the smallest value X[k] such that there /// is an increasing subsequence of length j ending at X[k] on the range /// k <= i /// (note we have j <= k <= i here, because j represents the length of @@ -162,11 +173,8 @@ class longest_increasing_subsequence { /// termination. /// Obviously, we can never have an increasing subsequence of length 13 /// ending at index 11. k <= i by definition). - // -> j-elements: X[.] X[.] ... X[k] is an increasing subsequence - index_vector lis_tail ( n + 1 ); + lis_tail.resize ( n + 1 ); - /// Length of the longest (increasing) subsequence found so far - size_type lis_length = 0; for ( difference_type i = 0; i < n; ++i ) { // Binary search for the largest positive j <= lis_length, such that // X[lis_tail[j]] < X[i]. @@ -210,7 +218,15 @@ class longest_increasing_subsequence { lis_tail[new_lis_length] = i; } } + return lis_length; + } + template + OutputIterator do_output ( RandomIterator first, RandomIterator /*last*/, + size_type lis_length, + index_vector const &predecessor, index_vector const &lis_tail, + OutputIterator d_first) const + { // Reconstruct the longest increasing subsequence index_vector lis ( lis_length ); size_type k = lis_tail[lis_length]; @@ -224,20 +240,40 @@ class longest_increasing_subsequence { } return d_first; } + + template + OutputIterator + do_search_and_output ( RandomIterator first, RandomIterator last, OutputIterator d_first ) const + { + index_vector predecessor; + index_vector lis_tail; + size_type lis_length = do_search(first, last, predecessor, lis_tail); + return do_output ( first, last, lis_length, predecessor, lis_tail, d_first ); + } value_vector - do_search ( RandomIterator first, RandomIterator last, value_output_tag_t tag ) const + do_search_and_output ( RandomIterator first, RandomIterator last, value_output_tag_t tag ) const { + index_vector predecessor; + index_vector lis_tail; + size_type lis_length = do_search(first, last, predecessor, lis_tail); + value_vector lis; - this->do_search ( first, last, std::back_inserter(lis) ); + lis.reserve ( lis_length ); + this->do_output ( first, last, lis_length, predecessor, lis_tail, std::back_inserter(lis) ); return lis; } iterator_vector - do_search ( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const + do_search_and_output ( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const { + index_vector predecessor; + index_vector lis_tail; + size_type lis_length = do_search(first, last, predecessor, lis_tail); + iterator_vector lis; - this->do_search ( first, last, std::back_inserter(lis) ); + lis.reserve ( lis_length ); + this->do_output ( first, last, lis_length, predecessor, lis_tail, std::back_inserter(lis), tag ); return lis; } // \endcond From e7a8f2304b449e311f770b87b180f73a12654b08 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sat, 16 Aug 2014 12:18:48 +0200 Subject: [PATCH 7/8] [longest_increasing_subsequence] Format. --- .../longest_increasing_subsequence.hpp | 171 ++++++++++-------- 1 file changed, 97 insertions(+), 74 deletions(-) diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index 7022cb40f..7aa0b3f30 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -27,7 +27,8 @@ #include -namespace boost { namespace algorithm { +namespace boost { +namespace algorithm { /* A templated version of the longest (increasing) subsequence algorithm. @@ -43,17 +44,23 @@ namespace boost { namespace algorithm { /// /// @time O(N logN) /// @space O(N) -template ::value_type> > +template ::value_type> > class longest_increasing_subsequence { - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::value_type value_type; + typedef typename std::iterator_traits::difference_type + difference_type; + typedef + typename std::iterator_traits::value_type value_type; public: typedef std::vector iterator_vector; typedef std::vector value_vector; - - struct iterator_output_tag_t {}; - struct value_output_tag_t {}; + + struct iterator_output_tag_t { + }; + struct value_output_tag_t { + }; static iterator_output_tag_t iterator_output_tag; static value_output_tag_t value_output_tag; @@ -72,39 +79,40 @@ class longest_increasing_subsequence { /// comparison predicate to the constructor, one can find as well, e.g., the /// longest decreasing subsequence (with std::greater() predicate) or the /// non-decreasing one (with std::not1(std::greater())). - /// The time complexity of the algorithm is log-linear O(n logn) where n is the length - /// of the sequence (`std::distance(first, last)`). + /// The time complexity of the algorithm is log-linear O(n logn) where n is + /// the length of the sequence (`std::distance(first, last)`). /// The space complexity is linear O(n). /// /// \param first The start of the sequence to search (Random Access /// Iterator) /// \param last One past the end of the sequence to search /// - value_vector - operator()( RandomIterator first, RandomIterator last, value_output_tag_t tag = value_output_tag ) const + value_vector operator()( RandomIterator first, RandomIterator last, + value_output_tag_t tag = value_output_tag ) const { return this->do_search_and_output ( first, last, tag ); } - iterator_vector - operator()( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const + iterator_vector operator()( RandomIterator first, RandomIterator last, + iterator_output_tag_t tag ) const { return this->do_search_and_output ( first, last, tag ); } template - OutputIterator - operator()( RandomIterator first, RandomIterator last, OutputIterator d_first ) const + OutputIterator operator()( RandomIterator first, RandomIterator last, + OutputIterator d_first ) const { // BOOST_STATIC_ASSERT (( boost::is_same< - // typename std::iterator_traits::value_type, - // typename std::iterator_traits::value_type>::value )); + // typename std::iterator_traits::value_type, + // typename std::iterator_traits::value_type>::value + // )); return this->do_search_and_output ( first, last, d_first ); } template - value_vector - operator()( const Range &r, value_output_tag_t tag = value_output_tag ) const + value_vector operator()( const Range &r, + value_output_tag_t tag = value_output_tag ) const { return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } @@ -117,19 +125,20 @@ class longest_increasing_subsequence { } template - OutputIterator - operator()( const Range &r, OutputIterator d_first ) const + OutputIterator operator()( const Range &r, OutputIterator d_first ) const { - BOOST_STATIC_ASSERT (( boost::is_same< - typename std::iterator_traits::value_type, - typename std::iterator_traits::value_type>::value )); - return this->do_search_and_output ( boost::begin ( r ), boost::end ( r ), d_first ); + BOOST_STATIC_ASSERT ( ( boost::is_same< + typename std::iterator_traits::value_type, + typename std::iterator_traits< + OutputIterator>::value_type>::value ) ); + return this->do_search_and_output ( boost::begin ( r ), + boost::end ( r ), d_first ); } std::size_t compute_length ( RandomIterator first, RandomIterator last ) const { - return this->do_search ( first, last); + return this->do_search ( first, last ); } template @@ -157,20 +166,19 @@ class longest_increasing_subsequence { size_type do_search ( RandomIterator first, RandomIterator last, /*output*/ index_vector &predecessor, - /*output*/ index_vector &lis_tail) const + /*output*/ index_vector &lis_tail ) const { difference_type const n = std::distance ( first, last ); /// Length of the longest (increasing) subsequence found so far size_type lis_length = 0; - /// predecessor[k, 0 <= k < n] - stores the index of the predecessor of X[k] in the longest - /// increasing subsequence ending at X[k] + /// predecessor[k, 0 <= k < n] - stores the index of the predecessor of + /// X[k] in the longest increasing subsequence ending at X[k] predecessor.resize ( n ); - /// lis_tail[j, 0 <= k <= n] - stores the index k of the smallest value X[k] such that there - /// is an increasing subsequence of length j ending at X[k] on the range - /// k <= i - /// (note we have j <= k <= i here, because j represents the length of - /// the increasing subsequence, and k represents the index of its - /// termination. + /// lis_tail[j, 0 <= k <= n] - stores the index k of the smallest value + /// X[k] such that there is an increasing subsequence of length j ending + /// at X[k] on the range k <= i (note we have j <= k <= i here, because + /// j represents the length of the increasing subsequence, and k + /// represents the index of its termination. /// Obviously, we can never have an increasing subsequence of length 13 /// ending at index 11. k <= i by definition). lis_tail.resize ( n + 1 ); @@ -187,8 +195,9 @@ class longest_increasing_subsequence { while ( lo <= hi ) { size_type mid = ( lo + hi ) / 2; assert ( mid <= i ); - if ( compare ( *( first + lis_tail[mid] ), - *( first + i ) ) ) { // X[lis_tail[mid]] < X[i] + if ( compare ( + *( first + lis_tail[mid] ), + *( first + i ) ) ) { // X[lis_tail[mid]] < X[i] lo = mid + 1; } else { @@ -212,9 +221,10 @@ class longest_increasing_subsequence { lis_length = new_lis_length; } else if ( compare ( *( first + i ), - *( first + lis_tail[new_lis_length] ) ) ) { // X[i] < X[lis_tail[new_lis_length]] - // If we found a smaller last value for the - // subsequence of length new_lis_length, only update lis_tail + *( first + lis_tail[new_lis_length] ) ) ) { + // X[i] < X[lis_tail[new_lis_length]] + // If we found a smaller last value for the subsequence of + // length new_lis_length, only update lis_tail lis_tail[new_lis_length] = i; } } @@ -222,10 +232,10 @@ class longest_increasing_subsequence { } template - OutputIterator do_output ( RandomIterator first, RandomIterator /*last*/, - size_type lis_length, - index_vector const &predecessor, index_vector const &lis_tail, - OutputIterator d_first) const + OutputIterator + do_output ( RandomIterator first, RandomIterator /*last*/, + size_type lis_length, index_vector const &predecessor, + index_vector const &lis_tail, OutputIterator d_first ) const { // Reconstruct the longest increasing subsequence index_vector lis ( lis_length ); @@ -236,50 +246,57 @@ class longest_increasing_subsequence { } // Output the found subsequence for ( size_type i = 0; i < lis_length; ++i ) { - *d_first++ = *(first + lis[i]); + *d_first++ = *( first + lis[i] ); } return d_first; } - + template OutputIterator - do_search_and_output ( RandomIterator first, RandomIterator last, OutputIterator d_first ) const + do_search_and_output ( RandomIterator first, RandomIterator last, + OutputIterator d_first ) const { index_vector predecessor; index_vector lis_tail; - size_type lis_length = do_search(first, last, predecessor, lis_tail); - return do_output ( first, last, lis_length, predecessor, lis_tail, d_first ); + size_type lis_length = do_search ( first, last, predecessor, lis_tail ); + return do_output ( first, last, lis_length, predecessor, lis_tail, + d_first ); } value_vector - do_search_and_output ( RandomIterator first, RandomIterator last, value_output_tag_t tag ) const + do_search_and_output ( RandomIterator first, RandomIterator last, + value_output_tag_t tag ) const { index_vector predecessor; index_vector lis_tail; - size_type lis_length = do_search(first, last, predecessor, lis_tail); + size_type lis_length = do_search ( first, last, predecessor, lis_tail ); value_vector lis; lis.reserve ( lis_length ); - this->do_output ( first, last, lis_length, predecessor, lis_tail, std::back_inserter(lis) ); + this->do_output ( first, last, lis_length, predecessor, lis_tail, + std::back_inserter ( lis ) ); return lis; } iterator_vector - do_search_and_output ( RandomIterator first, RandomIterator last, iterator_output_tag_t tag ) const + do_search_and_output ( RandomIterator first, RandomIterator last, + iterator_output_tag_t tag ) const { index_vector predecessor; index_vector lis_tail; - size_type lis_length = do_search(first, last, predecessor, lis_tail); + size_type lis_length = do_search ( first, last, predecessor, lis_tail ); iterator_vector lis; lis.reserve ( lis_length ); - this->do_output ( first, last, lis_length, predecessor, lis_tail, std::back_inserter(lis), tag ); + this->do_output ( first, last, lis_length, predecessor, lis_tail, + std::back_inserter ( lis ), tag ); return lis; } // \endcond }; -/// \fn longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last ) +/// \fn longest_increasing_subsequence_length ( RandomIterator first, +/// RandomIterator last ) /// \brief Searches the range [first, last) for the length of the longest /// increasing subsequence. /// @@ -289,7 +306,8 @@ class longest_increasing_subsequence { /// template std::size_t -longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last ) +longest_increasing_subsequence_length ( RandomIterator first, + RandomIterator last ) { longest_increasing_subsequence lis; return lis.compute_length ( first, last ); @@ -305,7 +323,8 @@ longest_increasing_subsequence_length ( const Range &r ) } // TODO: do we need a non-const range overload? -/// \fn longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last, Comparator +/// \fn longest_increasing_subsequence_length ( RandomIterator first, +/// RandomIterator last, Comparator /// cmp ) /// \brief Searches the range [first, last) for the length of the longest /// subsequence ordered by custom predicate cmp. @@ -317,7 +336,8 @@ longest_increasing_subsequence_length ( const Range &r ) /// template std::size_t -longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last, Comparator cmp ) +longest_increasing_subsequence_length ( RandomIterator first, + RandomIterator last, Comparator cmp ) { longest_increasing_subsequence lis ( cmp ); return lis.compute_length ( first, last ); @@ -333,7 +353,8 @@ longest_increasing_subsequence_length ( const Range &r, Comparator cmp ) } // TODO: do we need a non-const range overload? -/// \fn longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last ) +/// \fn longest_increasing_subsequence_search ( RandomIterator first, +/// RandomIterator last ) /// \brief Searches the range [first, last) for the longest increasing /// subsequence. /// @@ -343,16 +364,18 @@ longest_increasing_subsequence_length ( const Range &r, Comparator cmp ) /// // template // std::vector -// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last ) +// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator +// last ) // { - // longest_increasing_subsequence lis; - // return lis ( first, last ); +// longest_increasing_subsequence lis; +// return lis ( first, last ); // } // TODO: range template OutputIterator -longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, OutputIterator d_first ) { longest_increasing_subsequence lis; @@ -361,7 +384,8 @@ longest_increasing_subsequence_search ( RandomIterator first, RandomIterator las template OutputIterator -longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, OutputIterator d_first, Comparator cmp ) { longest_increasing_subsequence lis ( cmp ); @@ -375,8 +399,7 @@ longest_increasing_subsequence_search ( const Range &sequence, { typedef typename boost::range_iterator::type range_iterator; longest_increasing_subsequence lis; - return lis ( boost::begin ( sequence ), boost::end ( sequence ), - d_first ); + return lis ( boost::begin ( sequence ), boost::end ( sequence ), d_first ); } template @@ -386,12 +409,11 @@ longest_increasing_subsequence_search ( const Range &sequence, { typedef typename boost::range_iterator::type range_iterator; longest_increasing_subsequence lis ( cmp ); - return lis ( boost::begin ( sequence ), boost::end ( sequence ), - d_first ); + return lis ( boost::begin ( sequence ), boost::end ( sequence ), d_first ); } -/// \fn longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, Comparator -/// cmp ) +/// \fn longest_increasing_subsequence_search ( RandomIterator first, +/// RandomIterator last, Comparator cmp ) /// \brief Searches the range [first, last) for the longest subsequence ordered /// by custom predicate cmp. /// @@ -402,10 +424,11 @@ longest_increasing_subsequence_search ( const Range &sequence, /// // template // std::vector -// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, Comparator cmp ) +// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator +// last, Comparator cmp ) // { - // longest_increasing_subsequence lis ( cmp ); - // return lis ( first, last ); +// longest_increasing_subsequence lis ( cmp ); +// return lis ( first, last ); // } // TODO: range From d15d6b744b13deedf68c592ed8f231bc9f2abbd9 Mon Sep 17 00:00:00 2001 From: MarekKurdej Date: Sun, 17 Aug 2014 16:05:58 +0200 Subject: [PATCH 8/8] [longest_increasing_subsequence] Test all possible interfaces: A) with two iterators B) with a range C) with two pointers D) using object methods directly with case A. 1) output iterator 2) vector of values (with value_output_tag as argument) 3) vector of iterators (with iterator_output_tag as argument) --- .clang-format | 2 +- .../longest_increasing_subsequence.hpp | 332 ++++++++++------ test/subsequence_test1.cpp | 371 ++++++++++++++---- 3 files changed, 508 insertions(+), 197 deletions(-) diff --git a/.clang-format b/.clang-format index 5f808d8d2..a6b09a488 100644 --- a/.clang-format +++ b/.clang-format @@ -44,7 +44,7 @@ IndentWidth: 4 # UseTab: Never BreakBeforeBraces: Stroustrup #GNU # Linux SpacesInParentheses: true -# SpacesInAngles: false +SpacesInAngles: true # SpaceInEmptyParentheses: false # SpacesInCStyleCastParentheses: false # SpacesInContainerLiterals: true diff --git a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp index 7aa0b3f30..30c4287f6 100644 --- a/include/boost/algorithm/searching/longest_increasing_subsequence.hpp +++ b/include/boost/algorithm/searching/longest_increasing_subsequence.hpp @@ -11,6 +11,7 @@ #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_HPP #include // for std::iterator_traits +#include #include #include @@ -18,6 +19,7 @@ #include #include +#include #include // #define BOOST_ALGORITHM_LONGEST_INCREASING_SUBSEQUENCE_DEBUG @@ -25,8 +27,6 @@ #include #endif -#include - namespace boost { namespace algorithm { @@ -40,30 +40,29 @@ namespace algorithm { */ +// TODO: doc +struct iterator_output_tag { +}; +// TODO: doc +struct value_output_tag { +}; + /// Longest increasing subsequence algorithm. /// /// @time O(N logN) /// @space O(N) -template ::value_type> > +template < typename RandomIterator, + typename Comparator = std::less< + typename std::iterator_traits< RandomIterator >::value_type > > class longest_increasing_subsequence { - typedef typename std::iterator_traits::difference_type + typedef typename std::iterator_traits< RandomIterator >::difference_type difference_type; typedef - typename std::iterator_traits::value_type value_type; + typename std::iterator_traits< RandomIterator >::value_type value_type; public: - typedef std::vector iterator_vector; - typedef std::vector value_vector; - - struct iterator_output_tag_t { - }; - struct value_output_tag_t { - }; - - static iterator_output_tag_t iterator_output_tag; - static value_output_tag_t value_output_tag; + typedef std::vector< RandomIterator > iterator_vector; + typedef std::vector< value_type > value_vector; longest_increasing_subsequence ( Comparator cmp = Comparator () ) : compare ( cmp ) @@ -88,49 +87,39 @@ class longest_increasing_subsequence { /// \param last One past the end of the sequence to search /// value_vector operator()( RandomIterator first, RandomIterator last, - value_output_tag_t tag = value_output_tag ) const + value_output_tag tag ) const { return this->do_search_and_output ( first, last, tag ); } iterator_vector operator()( RandomIterator first, RandomIterator last, - iterator_output_tag_t tag ) const + iterator_output_tag tag ) const { return this->do_search_and_output ( first, last, tag ); } - template + template < typename OutputIterator > OutputIterator operator()( RandomIterator first, RandomIterator last, OutputIterator d_first ) const { - // BOOST_STATIC_ASSERT (( boost::is_same< - // typename std::iterator_traits::value_type, - // typename std::iterator_traits::value_type>::value - // )); return this->do_search_and_output ( first, last, d_first ); } - template - value_vector operator()( const Range &r, - value_output_tag_t tag = value_output_tag ) const + template < typename Range > + value_vector operator()( const Range &r, value_output_tag tag ) const { return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } - template - iterator_vector - operator()( const Range &r, iterator_output_tag_t tag ) const + template < typename Range > + iterator_vector operator()( const Range &r, iterator_output_tag tag ) const { return ( *this )( boost::begin ( r ), boost::end ( r ), tag ); } - template + template < typename Range, typename OutputIterator > OutputIterator operator()( const Range &r, OutputIterator d_first ) const { - BOOST_STATIC_ASSERT ( ( boost::is_same< - typename std::iterator_traits::value_type, - typename std::iterator_traits< - OutputIterator>::value_type>::value ) ); return this->do_search_and_output ( boost::begin ( r ), boost::end ( r ), d_first ); } @@ -141,10 +130,13 @@ class longest_increasing_subsequence { return this->do_search ( first, last ); } - template + template < typename Range > std::size_t compute_length ( const Range &r ) const { + // BOOST_STATIC_ASSERT ( ( boost::is_same< + // typename std::iterator_traits::value_type, + // typename std::iterator_traits::value_type>::value ) ); return ( *this )( boost::begin ( r ), boost::end ( r ) ); } @@ -153,7 +145,7 @@ class longest_increasing_subsequence { Comparator compare; typedef std::size_t size_type; - typedef std::vector index_vector; + typedef std::vector< size_type > index_vector; size_type do_search ( RandomIterator first, RandomIterator last ) const @@ -231,7 +223,7 @@ class longest_increasing_subsequence { return lis_length; } - template + template < typename OutputIterator > OutputIterator do_output ( RandomIterator first, RandomIterator /*last*/, size_type lis_length, index_vector const &predecessor, @@ -251,7 +243,38 @@ class longest_increasing_subsequence { return d_first; } - template + value_vector + do_output ( RandomIterator first, RandomIterator /*last*/, + size_type lis_length, index_vector const &predecessor, + index_vector const &lis_tail, value_output_tag /*tag*/ ) const + { + // Reconstruct the longest increasing subsequence values + value_vector lis ( lis_length ); + size_type k = lis_tail[lis_length]; + for ( size_type i = lis_length; i--; ) { + lis[i] = *( first + k ); // X[k]; + k = predecessor[k]; + } + return lis; + } + + iterator_vector + do_output ( RandomIterator first, RandomIterator /*last*/, + size_type lis_length, index_vector const &predecessor, + index_vector const &lis_tail, + iterator_output_tag /*tag*/ ) const + { + // Reconstruct the longest increasing subsequence iterators + iterator_vector lis ( lis_length ); + size_type k = lis_tail[lis_length]; + for ( size_type i = lis_length; i--; ) { + lis[i] = first + k; // &X[k]; + k = predecessor[k]; + } + return lis; + } + + template < typename OutputIterator > OutputIterator do_search_and_output ( RandomIterator first, RandomIterator last, OutputIterator d_first ) const @@ -265,32 +288,24 @@ class longest_increasing_subsequence { value_vector do_search_and_output ( RandomIterator first, RandomIterator last, - value_output_tag_t tag ) const + value_output_tag tag ) const { index_vector predecessor; index_vector lis_tail; size_type lis_length = do_search ( first, last, predecessor, lis_tail ); - - value_vector lis; - lis.reserve ( lis_length ); - this->do_output ( first, last, lis_length, predecessor, lis_tail, - std::back_inserter ( lis ) ); - return lis; + return this->do_output ( first, last, lis_length, predecessor, lis_tail, + tag ); } iterator_vector do_search_and_output ( RandomIterator first, RandomIterator last, - iterator_output_tag_t tag ) const + iterator_output_tag tag ) const { index_vector predecessor; index_vector lis_tail; size_type lis_length = do_search ( first, last, predecessor, lis_tail ); - - iterator_vector lis; - lis.reserve ( lis_length ); - this->do_output ( first, last, lis_length, predecessor, lis_tail, - std::back_inserter ( lis ), tag ); - return lis; + return this->do_output ( first, last, lis_length, predecessor, lis_tail, + tag ); } // \endcond }; @@ -304,21 +319,21 @@ class longest_increasing_subsequence { /// Iterator) /// \param last One past the end of the sequence to search for /// -template +template < typename RandomIterator > std::size_t longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last ) { - longest_increasing_subsequence lis; + longest_increasing_subsequence< RandomIterator > lis; return lis.compute_length ( first, last ); } -template +template < typename Range > std::size_t longest_increasing_subsequence_length ( const Range &r ) { - typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis; + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator > lis; return lis.compute_length ( boost::begin ( r ), boost::end ( r ) ); } // TODO: do we need a non-const range overload? @@ -334,21 +349,22 @@ longest_increasing_subsequence_length ( const Range &r ) /// \param last One past the end of the sequence to search for /// \param cmp Comparison predicate defining the ordering /// -template +template < typename RandomIterator, typename Comparator > std::size_t longest_increasing_subsequence_length ( RandomIterator first, RandomIterator last, Comparator cmp ) { - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence< RandomIterator, Comparator > lis ( cmp ); return lis.compute_length ( first, last ); } -template -std::size_t +template < typename Range, typename Comparator > +typename boost::disable_if< boost::is_same< Range, Comparator >, + std::size_t >::type longest_increasing_subsequence_length ( const Range &r, Comparator cmp ) { - typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis ( cmp ); + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator, Comparator > lis ( cmp ); return lis.compute_length ( boost::begin ( r ), boost::end ( r ) ); } // TODO: do we need a non-const range overload? @@ -361,113 +377,193 @@ longest_increasing_subsequence_length ( const Range &r, Comparator cmp ) /// \param first The start of the sequence to search for (Forward Input /// Iterator) /// \param last One past the end of the sequence to search for + +/// \fn longest_increasing_subsequence_search ( RandomIterator first, +/// RandomIterator last, Comparator cmp ) +/// \brief Searches the range [first, last) for the longest subsequence ordered +/// by custom predicate cmp. +/// \param first The start of the sequence to search for (Forward Input +/// Iterator) +/// \param last One past the end of the sequence to search for +/// \param cmp Comparison predicate defining the ordering /// -// template -// std::vector -// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator -// last ) -// { -// longest_increasing_subsequence lis; -// return lis ( first, last ); -// } -// TODO: range - -template + +// Vector of values +template < typename RandomIterator > +typename longest_increasing_subsequence< RandomIterator >::value_vector +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, + value_output_tag tag ) +{ + longest_increasing_subsequence< RandomIterator > lis; + return lis ( first, last, tag ); +} + +template < typename RandomIterator, typename Comparator > +typename longest_increasing_subsequence< RandomIterator, + Comparator >::value_vector +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, + value_output_tag tag, Comparator cmp ) +{ + longest_increasing_subsequence< RandomIterator, Comparator > lis ( cmp ); + return lis ( first, last, tag ); +} + +// Vector of iterators +template < typename RandomIterator > +typename longest_increasing_subsequence< RandomIterator >::iterator_vector +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, + iterator_output_tag tag ) +{ + longest_increasing_subsequence< RandomIterator > lis; + return lis ( first, last, tag ); +} + +template < typename RandomIterator, typename Comparator > +typename longest_increasing_subsequence< RandomIterator, + Comparator >::iterator_vector +longest_increasing_subsequence_search ( RandomIterator first, + RandomIterator last, + iterator_output_tag tag, + Comparator cmp ) +{ + longest_increasing_subsequence< RandomIterator, Comparator > lis ( cmp ); + return lis ( first, last, tag ); +} + +// Output iterator +template < typename RandomIterator, typename OutputIterator > OutputIterator longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, OutputIterator d_first ) { - longest_increasing_subsequence lis; + longest_increasing_subsequence< RandomIterator > lis; return lis ( first, last, d_first ); } -template +template < typename RandomIterator, typename OutputIterator, + typename Comparator > OutputIterator longest_increasing_subsequence_search ( RandomIterator first, RandomIterator last, OutputIterator d_first, Comparator cmp ) { - longest_increasing_subsequence lis ( cmp ); + longest_increasing_subsequence< RandomIterator, Comparator > lis ( cmp ); return lis ( first, last, d_first ); } -template +// Range - Vector of values +template < typename Range > +typename longest_increasing_subsequence< + typename boost::range_iterator< const Range >::type >::value_vector +longest_increasing_subsequence_search ( const Range &sequence, + value_output_tag tag ) +{ + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator > lis; + return lis ( boost::begin ( sequence ), boost::end ( sequence ), tag ); +} + +template < typename Range, typename Comparator > +typename longest_increasing_subsequence< + typename boost::range_iterator< const Range >::type, + Comparator >::value_vector +longest_increasing_subsequence_search ( const Range &sequence, + value_output_tag tag, Comparator cmp ) +{ + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator, Comparator > lis ( cmp ); + return lis ( boost::begin ( sequence ), boost::end ( sequence ), tag ); +} + +// Range - Vector of iterators +template < typename Range > +typename longest_increasing_subsequence< + typename boost::range_iterator< const Range >::type >::iterator_vector +longest_increasing_subsequence_search ( const Range &sequence, + iterator_output_tag tag ) +{ + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator > lis; + return lis ( boost::begin ( sequence ), boost::end ( sequence ), tag ); +} + +template < typename Range, typename Comparator > +typename longest_increasing_subsequence< + typename boost::range_iterator< const Range >::type, + Comparator >::iterator_vector +longest_increasing_subsequence_search ( const Range &sequence, + iterator_output_tag tag, + Comparator cmp ) +{ + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator, Comparator > lis ( cmp ); + return lis ( boost::begin ( sequence ), boost::end ( sequence ), tag ); +} + +// Range - Output Iterator +template < typename Range, typename OutputIterator > OutputIterator longest_increasing_subsequence_search ( const Range &sequence, OutputIterator d_first ) { - typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis; + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator > lis; return lis ( boost::begin ( sequence ), boost::end ( sequence ), d_first ); } -template -OutputIterator +// Use a bit of TMP to disambiguate the 3-argument templates +template < typename Range, typename OutputIterator, typename Comparator > +typename boost::disable_if< boost::is_same< Range, OutputIterator >, + OutputIterator >::type longest_increasing_subsequence_search ( const Range &sequence, OutputIterator d_first, Comparator cmp ) { - typedef typename boost::range_iterator::type range_iterator; - longest_increasing_subsequence lis ( cmp ); + typedef typename boost::range_iterator< const Range >::type range_iterator; + longest_increasing_subsequence< range_iterator, Comparator > lis ( cmp ); return lis ( boost::begin ( sequence ), boost::end ( sequence ), d_first ); } -/// \fn longest_increasing_subsequence_search ( RandomIterator first, -/// RandomIterator last, Comparator cmp ) -/// \brief Searches the range [first, last) for the longest subsequence ordered -/// by custom predicate cmp. -/// -/// \param first The start of the sequence to search for (Forward Input -/// Iterator) -/// \param last One past the end of the sequence to search for -/// \param cmp Comparison predicate defining the ordering -/// -// template -// std::vector -// longest_increasing_subsequence_search ( RandomIterator first, RandomIterator -// last, Comparator cmp ) -// { -// longest_increasing_subsequence lis ( cmp ); -// return lis ( first, last ); -// } -// TODO: range - // Creator functions -- take a range, return an object -template +template < typename Range > boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> + typename boost::range_iterator< const Range >::type > make_longest_increasing_subsequence ( const Range &r ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> (); + typename boost::range_iterator< const Range >::type > (); } -template +template < typename Range, typename Comparator > boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type, Comparator> + typename boost::range_iterator< const Range >::type, Comparator > make_longest_increasing_subsequence ( const Range &r, Comparator cmp ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( cmp ); + typename boost::range_iterator< const Range, Comparator >::type > ( + cmp ); } -template +template < typename Range > boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> + typename boost::range_iterator< Range >::type > make_longest_increasing_subsequence ( Range &r ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( boost::begin ( r ), - boost::end ( r ) ); + typename boost::range_iterator< Range >::type > ( boost::begin ( r ), + boost::end ( r ) ); } -template +template < typename Range, typename Comparator > boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type, Comparator> + typename boost::range_iterator< Range >::type, Comparator > make_longest_increasing_subsequence ( Range &r, Comparator cmp ) { return boost::algorithm::longest_increasing_subsequence< - typename boost::range_iterator::type> ( cmp ); + typename boost::range_iterator< Range, Comparator >::type > ( cmp ); } } // namespace algorithm diff --git a/test/subsequence_test1.cpp b/test/subsequence_test1.cpp index 7286cb793..ebfcf02bc 100644 --- a/test/subsequence_test1.cpp +++ b/test/subsequence_test1.cpp @@ -11,7 +11,8 @@ #define BOOST_TEST_MAIN #include -#include + +#include #include #include @@ -23,69 +24,312 @@ using namespace boost::assign; // bring 'list_of()' into scope namespace ba = boost::algorithm; +struct null_insert_iterator + : std::iterator< std::output_iterator_tag, null_insert_iterator > { + // Null-op assignment + template < typename T > + void operator=( T const & ) + { + } + + // Null-op operators + null_insert_iterator &operator++() { return *this; } + null_insert_iterator operator++( int ) { return *this; } + null_insert_iterator &operator*() { return *this; } +}; + namespace { -template + +// Length checking + +template < typename Container, typename Comparator > void -check_lis ( const Container &sequence, std::size_t expected_length, - Compare cmp ) +check_length_iter ( const Container &sequence, std::size_t expected_length, + Comparator cmp ) { + // TODO: move to separate test + (void)ba::longest_increasing_subsequence_length ( + sequence.begin (), sequence.end () ); // check interface, ignore result + std::size_t size = ba::longest_increasing_subsequence_length ( + sequence.begin (), sequence.end (), cmp ); + BOOST_CHECK_EQUAL ( size, expected_length ); } -template +template < typename Container, typename Comparator > void -check_length ( const Container &sequence, std::size_t expected_length, - Compare cmp ) +check_length_range ( const Container &sequence, std::size_t expected_length, + Comparator cmp ) { typedef typename Container::const_iterator const_iterator; - typedef typename Container::value_type value_type; - typedef typename std::vector ResultContainer; + boost::iterator_range< const_iterator > range ( sequence.begin (), + sequence.end () ); + // TODO: move to separate test + (void)ba::longest_increasing_subsequence_length ( + range ); // check interface, ignore result + std::size_t size = ba::longest_increasing_subsequence_length ( range, cmp ); + BOOST_CHECK_EQUAL ( size, expected_length ); + // TODO: range creator functions make_* +} - ba::longest_increasing_subsequence ls ( cmp ); - ResultContainer lis = ls ( sequence.begin (), sequence.end () ); +template < typename Container, typename Comparator > +void +check_length_pointer ( const Container &sequence, std::size_t expected_length, + Comparator cmp ) +{ + typedef const typename Container::value_type *ptr_type; + ptr_type sBeg = sequence.size () == 0 ? NULL : &*sequence.begin (); + ptr_type sEnd = sBeg + sequence.size (); + + // TODO: move to separate test + (void)ba::longest_increasing_subsequence_length ( + sBeg, sEnd ); // check interface, ignore result + std::size_t size = + ba::longest_increasing_subsequence_length ( sBeg, sEnd, cmp ); + BOOST_CHECK_EQUAL ( size, expected_length ); +} - BOOST_CHECK_EQUAL ( lis.size (), expected_length ); +template < typename Container, typename Comparator > +void +check_length_object ( const Container &sequence, std::size_t expected_length, + Comparator cmp ) +{ + typedef typename Container::const_iterator const_iterator; - // check_one_iter ( haystack, needle, expected ); - // check_one_pointer ( haystack, needle, expected ); - // check_one_object ( haystack, needle, expected ); + // TODO: move to separate test + ba::longest_increasing_subsequence< const_iterator > + ls_no_comparator; // check interface, ignore result + (void)ls_no_comparator; + ba::longest_increasing_subsequence< const_iterator, Comparator > ls ( cmp ); + std::size_t size = ls.compute_length ( sequence.begin (), sequence.end () ); + BOOST_CHECK_EQUAL ( size, expected_length ); + // TODO: range-based make_* } -// template -// void check_length ( const Container &sequence, std::size_t expected_length ) -// { -// typedef typename Container::value_type value_type; -// check_length ( sequence, expected_length, std::less() ); -// } +// Content checking -template +template < typename Container, typename Comparator > void -check_lis ( const Container &sequence, const Container &expected_lis, - Compare cmp ) +check_lis_iter ( const Container &sequence, const Container &expected_lis, + Comparator cmp ) { typedef typename Container::const_iterator const_iterator; - typedef typename Container::value_type value_type; - typedef typename std::vector ResultContainer; + typedef typename ba::longest_increasing_subsequence< + const_iterator >::value_vector value_vector; + typedef typename ba::longest_increasing_subsequence< + const_iterator >::iterator_vector iterator_vector; + + // value output + (void)ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), + ba::value_output_tag () ); // check interface + value_vector lis_value = ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), ba::value_output_tag (), cmp ); + BOOST_CHECK_EQUAL_COLLECTIONS ( lis_value.begin (), lis_value.end (), + expected_lis.begin (), + expected_lis.end () ); + + // iterator output + (void)ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), + ba::iterator_output_tag () ); // check interface + iterator_vector iter = ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), ba::iterator_output_tag (), cmp ); + value_vector lis_iter ( iter.size () ); + for ( std::size_t i = 0; i < iter.size (); ++i ) { + lis_iter[i] = *iter[i]; + } + BOOST_CHECK_EQUAL_COLLECTIONS ( lis_iter.begin (), lis_iter.end (), + expected_lis.begin (), + expected_lis.end () ); + + // output iterator + (void)ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), + null_insert_iterator () ); // check interface + value_vector lis_out_iter; + std::back_insert_iterator< value_vector > end_out_iter = + ba::longest_increasing_subsequence_search ( + sequence.begin (), sequence.end (), + std::back_inserter ( lis_out_iter ), cmp ); + (void)end_out_iter; // ignore result + BOOST_CHECK_EQUAL_COLLECTIONS ( lis_out_iter.begin (), lis_out_iter.end (), + expected_lis.begin (), + expected_lis.end () ); +} - ba::longest_increasing_subsequence ls ( cmp ); - ResultContainer lis = ls ( sequence.begin (), sequence.end () ); +template < typename Container, typename Comparator > +void +check_lis_range ( const Container &sequence, const Container &expected_lis, + Comparator cmp ) +{ + typedef typename Container::const_iterator const_iterator; + typedef typename ba::longest_increasing_subsequence< + const_iterator >::value_vector value_vector; + boost::iterator_range< const_iterator > range ( sequence.begin (), + sequence.end () ); + (void)ba::longest_increasing_subsequence_search ( + range, ba::value_output_tag () ); // check interface + value_vector lis = ba::longest_increasing_subsequence_search ( + range, ba::value_output_tag (), cmp ); BOOST_CHECK_EQUAL_COLLECTIONS ( lis.begin (), lis.end (), expected_lis.begin (), expected_lis.end () ); - ResultContainer lis2; - ls ( sequence.begin (), sequence.end (), std::back_inserter(lis2) ); + (void)ba::longest_increasing_subsequence_search ( + range, null_insert_iterator () ); // check interface + value_vector lis2; + ba::longest_increasing_subsequence_search ( + range, std::back_inserter ( lis2 ), cmp ); + BOOST_CHECK_EQUAL_COLLECTIONS ( lis2.begin (), lis2.end (), + expected_lis.begin (), + expected_lis.end () ); +} + +template < typename Container, typename Comparator > +void +check_lis_pointer ( const Container &sequence, const Container &expected_lis, + Comparator cmp ) + +{ + typedef const typename Container::value_type *ptr_type; + typedef typename ba::longest_increasing_subsequence< + ptr_type >::value_vector value_vector; + ptr_type sBeg = sequence.size () == 0 ? NULL : &*sequence.begin (); + ptr_type sEnd = sBeg + sequence.size (); + + // TODO: move to separate test + (void)ba::longest_increasing_subsequence_search ( + sBeg, sEnd, + ba::value_output_tag () ); // check interface, ignore result + value_vector lis = ba::longest_increasing_subsequence_search ( + sBeg, sEnd, ba::value_output_tag (), cmp ); + BOOST_CHECK_EQUAL_COLLECTIONS ( + lis.begin (), lis.end (), expected_lis.begin (), expected_lis.end () ); + + (void)ba::longest_increasing_subsequence_search ( + sBeg, sEnd, + null_insert_iterator () ); // check interface, ignore result + value_vector lis2; + (void)ba::longest_increasing_subsequence_search ( + sBeg, sEnd, std::back_inserter ( lis2 ), cmp ); // ignore result + BOOST_CHECK_EQUAL_COLLECTIONS ( lis2.begin (), lis2.end (), + expected_lis.begin (), + expected_lis.end () ); +} + +template < typename Container, typename Comparator > +void +check_lis_object ( const Container &sequence, const Container &expected_lis, + Comparator cmp ) +{ + typedef typename Container::const_iterator const_iterator; + typedef typename ba::longest_increasing_subsequence< + const_iterator >::value_vector value_vector; + + ba::longest_increasing_subsequence< const_iterator > ls ( cmp ); + value_vector lis = + ls ( sequence.begin (), sequence.end (), ba::value_output_tag () ); BOOST_CHECK_EQUAL_COLLECTIONS ( - lis2.begin (), lis2.end (), expected_lis.begin (), expected_lis.end () ); + lis.begin (), lis.end (), expected_lis.begin (), expected_lis.end () ); + + value_vector lis2; + ls ( sequence.begin (), sequence.end (), std::back_inserter ( lis2 ) ); + BOOST_CHECK_EQUAL_COLLECTIONS ( lis2.begin (), lis2.end (), + expected_lis.begin (), + expected_lis.end () ); + // TODO: range-based make_* +} + +template < typename Container, typename Comparator > +void +check_one_iter ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Comparator cmp ) +{ + std::cout << "(Iterators) Sequence " << test_name << " is " + << sequence.size () << " elements long; " << std::endl; + check_length_iter ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); + check_lis_iter ( sequence, expected_lis, cmp ); +} + +template < typename Container, typename Comparator > +void +check_one_range ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Comparator cmp ) +{ + std::cout << "(Ranges) Sequence " << test_name << " is " << sequence.size () + << " elements long; " << std::endl; + check_length_range ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); + check_lis_range ( sequence, expected_lis, cmp ); +} + +template < typename Container, typename Comparator > +void +check_one_pointer ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Comparator cmp ) +{ + std::cout << "(Pointers) Sequence " << test_name << " is " + << sequence.size () << " elements long; " << std::endl; + check_length_pointer ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); + check_lis_pointer ( sequence, expected_lis, cmp ); } -template +template < typename Container, typename Comparator > +void +check_one_object ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Comparator cmp ) +{ + std::cout << "(Objects) Sequence " << test_name << " is " + << sequence.size () << " elements long; " << std::endl; + check_length_object ( sequence, expected_length, cmp ); + BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); + check_lis_object ( sequence, expected_lis, cmp ); +} + +template < typename Container, typename Comparator > +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis, + Comparator cmp ) +{ + check_one_iter ( test_name, sequence, expected_length, expected_lis, cmp ); + check_one_range ( test_name, sequence, expected_length, expected_lis, cmp ); + check_one_pointer ( test_name, sequence, expected_length, expected_lis, + cmp ); + check_one_object ( test_name, sequence, expected_length, expected_lis, + cmp ); +} + +template < typename Container > +void +check_one ( const std::string &test_name, const Container &sequence, + std::size_t expected_length, const Container &expected_lis ) +{ + typedef typename Container::value_type value_type; + // TODO: check again defaults + // check_one ( test_name, sequence, expected_length, expected_lis ); + check_one ( test_name, sequence, expected_length, expected_lis, + std::less< value_type > () ); +} + +// Multiple possible results + +template < typename Container, typename Comparator, + typename ContainerContainer > void check_lis ( const Container &sequence, const ContainerContainer &expected_lises, - Compare cmp ) + Comparator cmp ) { typedef typename Container::const_iterator const_iterator; - ba::longest_increasing_subsequence ls ( cmp ); - Container lis = ls ( sequence.begin (), sequence.end () ); + ba::longest_increasing_subsequence< const_iterator > ls ( cmp ); + Container lis = + ls ( sequence.begin (), sequence.end (), ba::value_output_tag () ); bool any_equal = false; for ( std::size_t i = 0; i < expected_lises.size (); ++i ) { @@ -104,43 +348,22 @@ check_lis ( const Container &sequence, const ContainerContainer &expected_lises, BOOST_CHECK ( any_equal ); } -template -void -check_one ( const std::string &test_name, const Container &sequence, - std::size_t expected_length, const Container &expected_lis, - Compare cmp ) -{ - BOOST_TEST_CHECKPOINT ( test_name ); - check_length ( sequence, expected_length, cmp ); - BOOST_REQUIRE_EQUAL ( expected_lis.size (), expected_length ); - check_lis ( sequence, expected_lis, cmp ); -} - -template +template < typename Container, typename Comparator, + typename ContainerContainer > void check_one ( const std::string &test_name, const Container &sequence, std::size_t expected_length, - const ContainerContainer &expected_lises, Compare cmp ) + const ContainerContainer &expected_lises, Comparator cmp ) { BOOST_TEST_CHECKPOINT ( test_name ); - check_length ( sequence, expected_length, cmp ); + check_length_iter ( sequence, expected_length, cmp ); for ( std::size_t i = 0; i < expected_lises.size (); ++i ) { BOOST_REQUIRE_EQUAL ( expected_lises[i].size (), expected_length ); } check_lis ( sequence, expected_lises, cmp ); } -template -void -check_one ( const std::string &test_name, const Container &sequence, - std::size_t expected_length, const Container &expected_lis ) -{ - typedef typename Container::value_type value_type; - check_one ( test_name, sequence, expected_length, expected_lis, - std::less () ); -} - -template +template < typename Container, typename ContainerContainer > void check_one ( const std::string &test_name, const Container &sequence, std::size_t expected_length, @@ -148,35 +371,27 @@ check_one ( const std::string &test_name, const Container &sequence, { typedef typename Container::value_type value_type; check_one ( test_name, sequence, expected_length, expected_lises, - std::less () ); + std::less< value_type > () ); } } -template +template < typename Container > void -ReadFromFile ( const char *name, std::back_insert_iterator inserter ) +ReadFromFile ( const char *name, + std::back_insert_iterator< Container > inserter ) { std::ifstream in ( name, std::ios_base::binary | std::ios_base::in ); - std::istream_iterator begin ( in ); - std::istream_iterator end; + std::istream_iterator< char, char > begin ( in ); + std::istream_iterator< char, char > end; std::copy ( begin, end, inserter ); } -template -std::string -make_str ( Iter first, std::size_t len ) -{ - std::string retVal ( len + 2, '\'' ); - std::copy ( first, first + len, retVal.begin () + 1 ); - return retVal; -} - BOOST_AUTO_TEST_CASE ( test_main ) { - typedef std::vector vec; - typedef std::vector res; - typedef std::vector resvec; + typedef std::vector< int > vec; + typedef vec res; + typedef std::vector< res > resvec; using std::string; using std::wstring;