dataset/random_term_generator.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef RANDOM_TERM_GENERATOR_HH
00018 # define RANDOM_TERM_GENERATOR_HH
00019 
00020 # include "../utils/call_with.hh"
00021 # include <tuple>
00022 # include <functional>
00023 # include <vector>
00024 # include <cassert>
00025 # include <random>
00026 # include <type_traits>
00027 # include "../type_traits/try_first.hh"
00028 # include "../wrappers/function_wrappers.hh"
00029 # include "position.hh"
00030 # include "dataset.hh"
00031 
00032 namespace catsfoot {
00033   namespace details {
00034     template <typename T, typename... Functions>
00035     struct number_function_returns;
00036 
00038     template <typename T>
00039     struct number_function_returns<T> {
00040       static const size_t value = 0u;
00041     };
00042 
00044     template <typename T, typename... Args, typename... Functions>
00045     struct number_function_returns<T, std::function<T(Args...)>,
00046                                    Functions...> {
00047       static const size_t value =
00048         number_function_returns<T, Functions...>::value + 1;
00049     };
00050 
00052     template <typename T, typename... Args, typename... Functions>
00053     struct number_function_returns<T, std::function<const T&(Args...)>,
00054                                    Functions...> {
00055       static const size_t value =
00056         number_function_returns<T, Functions...>::value + 1;
00057     };
00058 
00060     template <typename T, typename... Args, typename... Functions>
00061     struct number_function_returns<T, std::function<T&(Args...)>,
00062                                    Functions...> {
00063       static const size_t value =
00064         number_function_returns<T, Functions...>::value + 1;
00065     };
00066 
00068     template <typename T, typename... Args, typename... Functions>
00069     struct number_function_returns<T, std::function<T&&(Args...)>,
00070                                    Functions...> {
00071       static const size_t value =
00072         number_function_returns<T, Functions...>::value + 1;
00073     };
00074 
00076     template <typename T, typename Ret, typename... Args,
00077               typename... Functions>
00078     struct number_function_returns<T, std::function<Ret(Args...)>,
00079                                    Functions...> {
00080       static const size_t value =
00081         number_function_returns<T, Functions...>::value;
00082     };
00083 
00084     template <typename T, typename... Functions>
00085     struct number_ground_terms;
00086 
00088     template <typename T>
00089     struct number_ground_terms<T> {
00090       static const size_t value = 0u;
00091     };
00092 
00094     template <typename T, typename... Functions>
00095     struct number_ground_terms<T, std::function<T()>,
00096                                    Functions...> {
00097       static const size_t value =
00098         number_ground_terms<T, Functions...>::value + 1;
00099     };
00100 
00102     template <typename T, typename... Functions>
00103     struct number_ground_terms<T, std::function<const T&()>,
00104                                    Functions...> {
00105       static const size_t value =
00106         number_ground_terms<T, Functions...>::value + 1;
00107     };
00108 
00110     template <typename T, typename... Functions>
00111     struct number_ground_terms<T, std::function<T&()>,
00112                                    Functions...> {
00113       static const size_t value =
00114         number_ground_terms<T, Functions...>::value + 1;
00115     };
00116 
00118     template <typename T, typename... Functions>
00119     struct number_ground_terms<T, std::function<T&&()>,
00120                                    Functions...> {
00121       static const size_t value =
00122         number_ground_terms<T, Functions...>::value + 1;
00123     };
00124 
00126     template <typename T, typename Ret, typename... Args,
00127               typename... Functions>
00128     struct number_ground_terms<T, std::function<Ret(Args...)>,
00129                                    Functions...> {
00130       static const size_t value =
00131         number_ground_terms<T, Functions...>::value;
00132     };
00133   }
00134 
00138   template <typename... Types>
00139   struct term_generator_builder {
00140   private:
00141     size_t size;
00142   public:
00143     term_generator_builder(size_t size = 200u): size(size) {}
00144 
00145     template <typename Generator, typename... Functions>
00146     struct generator {
00147     private:
00148       size_t size;
00149       Generator& g;
00150       std::tuple<Functions...> functions;
00151       std::tuple<std::vector<Types>...> terms;
00152 
00153     public:
00154       template <typename... F>
00155       generator(size_t size, Generator& g, F&&... functions):
00156         size(size), g(g), functions(std::forward<F>(functions)...) {
00157       }
00158 
00159     private:
00160       template <typename Return>
00161       Return call_this_one(std::function<Return()>& f) {
00162         return f();
00163       }
00164 
00165       template <typename Return>
00166       Return&& call_this_one(std::function<Return&&()>& f) {
00167         return std::move(f());
00168       }
00169 
00170       template <typename Return>
00171       Return& call_this_one(std::function<Return&()>& f) {
00172         return f();
00173       }
00174 
00175       template <typename Return>
00176       const Return&& call_this_one(std::function<const Return&()>& f) {
00177         return f();
00178       }
00179 
00180       template <typename Return, typename... Args,
00181                 typename... Bound, typename = typename
00182                 std::enable_if<sizeof...(Bound) < sizeof...(Args)>::type>
00183       Return call_this_one(std::function<Return(Args...)>& f,
00184                            Bound&... bound...) {
00185         typedef typename
00186           std::decay<
00187             typename std::tuple_element<sizeof...(Bound),
00188                                         std::tuple<Args...> >::type
00189             >::type
00190           that_arg;
00191         std::vector<that_arg>&
00192           l = std::get<details::position<that_arg, Types...>::value>(terms);
00193 
00194         if (l.size() == 0) {
00195           return call_this_one(f, bound..., generate<that_arg>(-1));
00196         }
00197         if (std::is_same<that_arg, Return>::value) {
00198           // It is not safe to insert new elements.
00199           return call_this_one(f, bound...,
00200                                          l[std::uniform_int_distribution<size_t>
00201                                            (0, l.size()-1)(g)]);
00202         }
00203         return call_this_one(f, bound..., generate<that_arg>());
00204       }
00205 
00206       template <typename Return, typename... Args,
00207                 typename... Bound, typename = typename
00208                 std::enable_if<sizeof...(Bound) < sizeof...(Args)>::type>
00209       Return&& call_this_one(std::function<Return&&(Args...)>& f,
00210                            Bound&... bound...) {
00211         typedef typename
00212           std::decay<
00213             typename std::tuple_element<sizeof...(Bound),
00214                                         std::tuple<Args...> >::type
00215             >::type
00216           that_arg;
00217         std::vector<that_arg>&
00218           l = std::get<details::position<that_arg, Types...>::value>(terms);
00219 
00220         if (l.size() == 0) {
00221           return call_this_one(f, bound..., generate<that_arg>(-1));
00222         }
00223         if (std::is_same<that_arg, Return>::value) {
00224           // It is not safe to insert new elements.
00225           return call_this_one(f, bound...,
00226                                          l[std::uniform_int_distribution<size_t>
00227                                            (0, l.size()-1)(g)]);
00228         }
00229         return call_this_one(f, bound..., generate<that_arg>());
00230       }
00231 
00232       template <typename Return, typename... Args,
00233                 typename... Bound, typename = typename
00234                 std::enable_if<sizeof...(Bound) < sizeof...(Args)>::type>
00235       const Return& call_this_one(std::function<const Return&(Args...)>& f,
00236                            Bound&... bound...) {
00237         typedef typename
00238           std::decay<
00239             typename std::tuple_element<sizeof...(Bound),
00240                                         std::tuple<Args...> >::type
00241             >::type
00242           that_arg;
00243         std::vector<that_arg>&
00244           l = std::get<details::position<that_arg, Types...>::value>(terms);
00245 
00246         if (l.size() == 0) {
00247           return std::move(call_this_one(f, bound..., generate<that_arg>(-1)));
00248         }
00249         if (std::is_same<that_arg, Return>::value) {
00250           // It is not safe to insert new elements.
00251           return call_this_one(f, bound...,
00252                                l[std::uniform_int_distribution<size_t>
00253                                  (0, l.size()-1)(g)]);
00254         }
00255         return call_this_one(f, bound..., generate<that_arg>());
00256       }
00257 
00258       template <typename Return, typename... Args,
00259                 typename... Bound, typename = typename
00260                 std::enable_if<sizeof...(Bound) < sizeof...(Args)>::type>
00261       Return& call_this_one(std::function<Return&(Args...)>& f,
00262                            Bound&... bound...) {
00263         typedef typename
00264           std::decay<
00265             typename std::tuple_element<sizeof...(Bound),
00266                                         std::tuple<Args...> >::type
00267             >::type
00268           that_arg;
00269         std::vector<that_arg>&
00270           l = std::get<details::position<that_arg, Types...>::value>(terms);
00271 
00272         if (l.size() == 0) {
00273           return call_this_one(f, bound..., generate<that_arg>(-1));
00274         }
00275         if (std::is_same<that_arg, Return>::value) {
00276           // It is not safe to insert new elements.
00277           return call_this_one(f, bound...,
00278                                l[std::uniform_int_distribution<size_t>
00279                                  (0, l.size()-1)(g)]);
00280         }
00281         // Because we are returning a reference, it is good to say that we want to
00282         // force to call any function to ensure a new value.
00283         return call_this_one(f, bound..., generate<that_arg>(0));
00284       }
00285 
00286       template <typename Return, typename... Args, typename ...Bound,
00287                 typename = typename
00288                 std::enable_if<sizeof...(Bound) == sizeof...(Args)>::type>
00289       Return call_this_one(std::function<Return(Args...)>& f,
00290                              Bound&... bound) {
00291         return f(bound...);
00292       }
00293 
00294       template <typename Return>
00295       Return call(selector<Return>, size_t) {
00296         assert(false);
00297       }
00298 
00299       template <typename Return, typename... FS,
00300                 typename... Args>
00301       Return call(selector<Return>, size_t fun_to_call,
00302                     std::function<Return(Args...)>& f,
00303                     FS... fs) {
00304         if (fun_to_call == 0) {
00305           return call_this_one(f);
00306         } else {
00307           return call
00308             (selector<Return>(),
00309              fun_to_call-1, fs...);
00310         }
00311       }
00312 
00313       template <typename Return, typename... FS,
00314                 typename... Args>
00315       Return call(selector<Return>, size_t fun_to_call,
00316                   std::function<Return&(Args...)>& f,
00317                   FS... fs) {
00318         if (fun_to_call == 0) {
00319           return call_this_one(f);
00320         } else {
00321           return call
00322             (selector<Return>(),
00323              fun_to_call-1, fs...);
00324         }
00325       }
00326 
00327       template <typename Return, typename... FS,
00328                 typename... Args>
00329       Return call(selector<Return>, size_t fun_to_call,
00330                   std::function<const Return&(Args...)>& f,
00331                   FS... fs) {
00332         if (fun_to_call == 0) {
00333           return call_this_one(f);
00334         } else {
00335           return call
00336             (selector<Return>(),
00337              fun_to_call-1, fs...);
00338         }
00339       }
00340 
00341       template <typename Return, typename... FS,
00342                 typename... Args>
00343       Return call(selector<Return>, size_t fun_to_call,
00344                   std::function<Return&&(Args...)>& f,
00345                   FS... fs) {
00346         if (fun_to_call == 0) {
00347           return std::move(call_this_one(f));
00348         } else {
00349           return std::move(call
00350             (selector<Return>(),
00351              fun_to_call-1, fs...));
00352         }
00353       }
00354 
00355       template <typename Return,
00356                 typename OtherReturn, typename... FS,
00357                 typename... Args>
00358       Return call(selector<Return>, size_t fun_to_call,
00359                     std::function<OtherReturn(Args...)>&,
00360                     FS... fs) {
00361         return call
00362           (selector<Return>(),
00363            fun_to_call, fs...);
00364       }
00365 
00366     public:
00367       template <typename Return,
00368                 bool moveable = is_constructible<Return(const Return&)>::value ||
00369                 is_constructible<Return(Return&&)>::value>
00370       struct random_container {
00371       private:
00372         generator<Generator, Functions...>* upper;
00373       public:
00374         random_container(generator<Generator, Functions...>& upper)
00375           : upper(&upper) {}
00376         struct iterator {
00377         private:
00378           generator<Generator, Functions...>* upper;
00379           size_t pos;
00380 
00381         public:
00382           iterator(generator<Generator, Functions...>& upper,
00383                    size_t pos = 0u):
00384             upper(&upper),
00385             pos(pos) {
00386             if (pos == this->upper->size)
00387               return ;
00388             std::vector<Return>& l =
00389               std::get<details::position<Return, Types...>::value>
00390               (this->upper->terms);
00391             while (l.size() <= pos)
00392               this->upper->template generate<Return>();
00393           }
00394           iterator(const iterator& other):
00395             upper(other.upper),
00396             pos(other.pos) {}
00397           Return& operator*() const {
00398             std::vector<Return>& l =
00399               std::get<details::position<Return, Types...>::value>
00400               (upper->terms);
00401             return l[pos];
00402           }
00403           iterator& operator++() {
00404             ++pos;
00405             std::vector<Return>& l =
00406               std::get<details::position<Return, Types...>::value>
00407               (upper->terms);
00408             while (l.size() <= pos)
00409               upper->template generate<Return>();
00410             return *this;
00411           }
00412           iterator& operator++(int) {
00413             iterator ret(*this);
00414             ++*this;
00415             return *this;
00416           }
00417           bool operator==(const iterator& other) const {
00418             return pos == other.pos;
00419           }
00420           bool operator!=(const iterator& other) const {
00421             return pos != other.pos;
00422           }
00423 
00424           iterator& operator=(iterator&& other) {
00425             std::swap(upper, other.upper);
00426             std::swap(pos, other.pos);
00427             return *this;
00428           }
00429 
00430           iterator& operator=(const iterator& other) {
00431             return *this = iterator(other);
00432           }
00433         };
00434         iterator begin() {
00435           return iterator(*upper, 0);
00436         }
00437         iterator end() {
00438           return iterator(*upper, upper->size);
00439         }
00440       };
00441 
00442       template <typename Return>
00443       struct random_container<Return, false> {
00444       private:
00445         generator<Generator, Functions...>* upper;
00446       public:
00447         random_container(generator<Generator, Functions...>& upper)
00448           : upper(&upper) {}
00449         struct iterator {
00450         private:
00451           generator<Generator, Functions...>* upper;
00452           size_t pos;
00453 
00454         public:
00455           iterator(generator<Generator, Functions...>& upper,
00456                    size_t pos = 0u):
00457             upper(&upper),
00458             pos(pos) {
00459           }
00460           iterator(const iterator& other):
00461             upper(other.upper),
00462             pos(other.pos) {}
00463           Return& operator*() const {
00464             return const_cast<iterator*>(this)->upper->template generate<Return>();
00465           }
00466           iterator& operator++() {
00467             ++pos;
00468             return *this;
00469           }
00470           iterator& operator++(int) {
00471             iterator ret(*this);
00472             ++*this;
00473             return *this;
00474           }
00475           bool operator==(const iterator& other) const {
00476             return pos == other.pos;
00477           }
00478           bool operator!=(const iterator& other) const {
00479             return pos != other.pos;
00480           }
00481 
00482           iterator& operator=(iterator&& other) {
00483             std::swap(upper, other.upper);
00484             std::swap(pos, other.pos);
00485             return *this;
00486           }
00487 
00488           iterator& operator=(const iterator& other) {
00489             return *this = iterator(other);
00490           }
00491         };
00492         iterator begin() {
00493           return iterator(*upper, 0);
00494         }
00495         iterator end() {
00496           return iterator(*upper, upper->size);
00497         }
00498       };
00499 
00500       template <typename Return,
00501                 typename NonRefReturn = typename std::decay<Return>
00502                 ::type,
00503                 typename = typename details::position<NonRefReturn, Types...>::type
00504                 >
00505       random_container<NonRefReturn> get(selector<Return>) {
00506         return random_container<NonRefReturn>(*this);
00507       }
00508 
00509       template <typename Return,
00510                 typename = typename
00511                 std::enable_if<is_constructible<Return(const Return&)>::value ||
00512                                is_constructible<Return(Return&&)>::value>::type>
00513       Return& generate(int prob = 1) {
00514         static_assert(details::number_function_returns
00515                       <Return, Functions...>::value > 0,
00516                       "No function with such return");
00517         //FIXME: Check that some ground terms are accessible.
00518 
00519         std::vector<Return>& l =
00520           std::get<details::position<Return, Types...>::value>(terms);
00521         if (!l.empty()) {
00522           if (prob < 0) {
00523             return l[std::uniform_int_distribution<size_t>
00524                      (0, l.size()-1)(g)];
00525           }
00526           if (prob > 0)
00527             if (std::uniform_int_distribution<int>(0,prob)(g)) {
00528               return l[std::uniform_int_distribution<size_t>
00529                        (0, l.size()-1)(g)];
00530             }
00531         }
00532 
00533         size_t fun_to_call =
00534           std::uniform_int_distribution<size_t>
00535           (0, details::number_function_returns<Return,
00536                                                Functions...>::value-1)(g);
00537         Return ret = call_with([this, fun_to_call] (Functions&...
00538                                                     funs) {
00539                                  return this->call
00540                                  (selector<Return>(),
00541                                   fun_to_call,
00542                                   funs...);
00543                                }, functions);
00544 
00545         l.push_back(std::move(ret));
00546         return l.back();
00547       }
00548 
00549       template <typename Return,
00550                 typename = typename
00551                 std::enable_if<!(is_constructible<Return(const Return&)>::value ||
00552                                  is_constructible<Return(Return&&)>::value)>::type,
00553                 typename = void>
00554       Return& generate(int = 1) {
00555         static_assert(details::number_function_returns
00556                       <Return, Functions...>::value > 0,
00557                       "No function with such return");
00558         size_t fun_to_call =
00559           std::uniform_int_distribution<size_t>
00560           (0, details::number_function_returns<Return&,
00561                                                Functions...>::value-1)(g);
00562 
00563         return call_with([this, fun_to_call] (Functions&...
00564                                               funs) -> Return& {
00565                            return this->call
00566                              (selector<Return&>(),
00567                               fun_to_call,
00568                               funs...);
00569                          }, functions);
00570       }
00571 
00572     };
00573 
00578     template <typename Generator, typename... Functions>
00579     generator<Generator, typename wrapped<Functions>::type...>
00580     operator()(Generator& g, Functions&&... functions) const {
00581       return generator<Generator, typename std::decay<typename wrapped<Functions>::type>::type...>
00582         (size, g, wrap(std::forward<Functions>(functions))...);
00583     }
00584   };
00585 
00586 }
00587 
00588 #endif