summaryrefslogtreecommitdiffstats
path: root/src/boost/libs/multi_index/example/rearrange.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/boost/libs/multi_index/example/rearrange.cpp')
-rw-r--r--src/boost/libs/multi_index/example/rearrange.cpp265
1 files changed, 265 insertions, 0 deletions
diff --git a/src/boost/libs/multi_index/example/rearrange.cpp b/src/boost/libs/multi_index/example/rearrange.cpp
new file mode 100644
index 000000000..31388513d
--- /dev/null
+++ b/src/boost/libs/multi_index/example/rearrange.cpp
@@ -0,0 +1,265 @@
+/* Boost.MultiIndex example of use of rearrange facilities.
+ *
+ * Copyright 2003-2015 Joaquin M Lopez Munoz.
+ * 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)
+ *
+ * See http://www.boost.org/libs/multi_index for library home page.
+ */
+
+#if !defined(NDEBUG)
+#define BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING
+#define BOOST_MULTI_INDEX_ENABLE_SAFE_MODE
+#endif
+
+#include <boost/config.hpp>
+#include <boost/detail/iterator.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/random_access_index.hpp>
+#include <boost/random/binomial_distribution.hpp>
+#include <boost/random/uniform_real.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <vector>
+
+#if !defined(BOOST_NO_CXX11_HDR_RANDOM)
+#include <random>
+#endif
+
+using boost::multi_index_container;
+using namespace boost::multi_index;
+
+/* We model a card deck with a random access array containing
+ * card numbers (from 0 to 51), supplemented with an additional
+ * index which retains the start ordering.
+ */
+
+class deck
+{
+ BOOST_STATIC_CONSTANT(std::size_t,num_cards=52);
+
+ typedef multi_index_container<
+ int,
+ indexed_by<
+ random_access<>, /* base index */
+ random_access<> /* "start" index */
+ >
+ > container_type;
+ container_type cont;
+
+public:
+ deck()
+ {
+ cont.reserve(num_cards);
+ get<1>(cont).reserve(num_cards);
+ for(std::size_t i=0;i<num_cards;++i)cont.push_back(i);
+ }
+
+ typedef container_type::iterator iterator;
+ typedef container_type::size_type size_type;
+
+ iterator begin()const{return cont.begin();}
+ iterator end()const{return cont.end();}
+ size_type size()const{return cont.size();}
+
+ template<typename InputIterator>
+ void rearrange(InputIterator it)
+ {
+ cont.rearrange(it);
+ }
+
+ void reset()
+ {
+ /* simply rearrange the base index like the start index */
+
+ cont.rearrange(get<1>(cont).begin());
+ }
+
+ std::size_t position(int i)const
+ {
+ /* The position of a card in the deck is calculated by locating
+ * the card through the start index (which is ordered), projecting
+ * to the base index and diffing with the begin position.
+ * Resulting complexity: constant.
+ */
+
+ return project<0>(cont,get<1>(cont).begin()+i)-cont.begin();
+ }
+
+ std::size_t rising_sequences()const
+ {
+ /* Iterate through all cards and increment the sequence count
+ * when the current position is left to the previous.
+ * Resulting complexity: O(n), n=num_cards.
+ */
+
+ std::size_t s=1;
+ std::size_t last_pos=0;
+
+ for(std::size_t i=0;i<num_cards;++i){
+ std::size_t pos=position(i);
+ if(pos<last_pos)++s;
+ last_pos=pos;
+ }
+
+ return s;
+ }
+};
+
+/* A vector of reference_wrappers to deck elements can be used
+ * as a view to the deck container.
+ * We use a special implicit_reference_wrapper having implicit
+ * ctor from its base type, as this simplifies the use of generic
+ * techniques on the resulting data structures.
+ */
+
+template<typename T>
+class implicit_reference_wrapper:public boost::reference_wrapper<T>
+{
+private:
+ typedef boost::reference_wrapper<T> super;
+public:
+ implicit_reference_wrapper(T& t):super(t){}
+};
+
+typedef std::vector<implicit_reference_wrapper<const int> > deck_view;
+
+/* Riffle shuffle is modeled like this: A cut is selected in the deck
+ * following a binomial distribution. Then, cards are randomly selected
+ * from one packet or the other with probability proportional to
+ * packet size.
+ */
+
+template<typename RandomAccessIterator,typename OutputIterator>
+void riffle_shuffle(
+ RandomAccessIterator first,RandomAccessIterator last,
+ OutputIterator out)
+{
+ static boost::mt19937 rnd_gen;
+
+ typedef typename boost::detail::iterator_traits<
+ RandomAccessIterator>::difference_type difference_type;
+ typedef boost::binomial_distribution<
+ difference_type> rnd_cut_select_type;
+ typedef boost::uniform_real<> rnd_deck_select_type;
+
+ rnd_cut_select_type cut_select(last-first);
+ RandomAccessIterator middle=first+cut_select(rnd_gen);
+ difference_type s0=middle-first;
+ difference_type s1=last-middle;
+ rnd_deck_select_type deck_select;
+
+ while(s0!=0&&s1!=0){
+ if(deck_select(rnd_gen)<(double)s0/(s0+s1)){
+ *out++=*first++;
+ --s0;
+ }
+ else{
+ *out++=*middle++;
+ --s1;
+ }
+ }
+ std::copy(first,first+s0,out);
+ std::copy(middle,middle+s1,out);
+}
+
+struct riffle_shuffler
+{
+ void operator()(deck& d)const
+ {
+ dv.clear();
+ dv.reserve(d.size());
+ riffle_shuffle(
+ d.begin(),d.end(),std::back_inserter(dv)); /* do the shuffling */
+ d.rearrange(dv.begin()); /* apply to the deck */
+ }
+
+private:
+ mutable deck_view dv;
+};
+
+/* A truly random shuffle (up to stdlib implementation quality) using
+ * std::shuffle.
+ */
+
+struct random_shuffler
+{
+ void operator()(deck& d)
+ {
+ dv.clear();
+ dv.reserve(d.size());
+ std::copy(d.begin(),d.end(),std::back_inserter(dv));
+ shuffle_view();
+ d.rearrange(dv.begin()); /* apply to the deck */
+ }
+
+private:
+ deck_view dv;
+
+#if !defined(BOOST_NO_CXX11_HDR_RANDOM)
+ std::mt19937 e;
+
+ void shuffle_view()
+ {
+ std::shuffle(dv.begin(),dv.end(),e);
+ }
+#else
+ /* for pre-C++11 compilers we use std::random_shuffle */
+
+ void shuffle_view()
+ {
+ std::random_shuffle(dv.begin(),dv.end());
+ }
+#endif
+};
+
+/* Repeat a given shuffling algorithm repeats_num times
+ * and obtain the resulting rising sequences number. Average
+ * for tests_num trials.
+ */
+
+template<typename Shuffler>
+double shuffle_test(
+ unsigned int repeats_num,unsigned int tests_num
+ BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Shuffler))
+{
+ deck d;
+ Shuffler sh;
+ unsigned long total=0;
+
+ for(unsigned int n=0;n<tests_num;++n){
+ for(unsigned m=0;m<repeats_num;++m)sh(d);
+ total+=d.rising_sequences();
+ d.reset();
+ }
+
+ return (double)total/tests_num;
+}
+
+int main()
+{
+ unsigned rifs_num=0;
+ unsigned tests_num=0;
+
+ std::cout<<"number of riffle shuffles (vg 5):";
+ std::cin>>rifs_num;
+ std::cout<<"number of tests (vg 1000):";
+ std::cin>>tests_num;
+
+ std::cout<<"shuffling..."<<std::endl;
+
+ std::cout<<"riffle shuffling\n"
+ " avg number of rising sequences: "
+ <<shuffle_test<riffle_shuffler>(rifs_num,tests_num)
+ <<std::endl;
+
+ std::cout<<"random shuffling\n"
+ " avg number of rising sequences: "
+ <<shuffle_test<random_shuffler>(1,tests_num)
+ <<std::endl;
+
+ return 0;
+}