restricted_function.cpp 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. // Copyright Louis Dionne 2013-2017
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
  4. #include <boost/hana/all_of.hpp>
  5. #include <boost/hana/assert.hpp>
  6. #include <boost/hana/cartesian_product.hpp>
  7. #include <boost/hana/contains.hpp>
  8. #include <boost/hana/core/to.hpp>
  9. #include <boost/hana/equal.hpp>
  10. #include <boost/hana/functional/demux.hpp>
  11. #include <boost/hana/fuse.hpp>
  12. #include <boost/hana/integral_constant.hpp>
  13. #include <boost/hana/minus.hpp>
  14. #include <boost/hana/mod.hpp>
  15. #include <boost/hana/not.hpp>
  16. #include <boost/hana/not_equal.hpp>
  17. #include <boost/hana/or.hpp>
  18. #include <boost/hana/plus.hpp>
  19. #include <boost/hana/set.hpp>
  20. #include <boost/hana/transform.hpp>
  21. #include <boost/hana/tuple.hpp>
  22. namespace hana = boost::hana;
  23. using namespace hana::literals;
  24. // A function that can have an arbitrary compile-time set of values as a domain
  25. // and co-domain. This is most likely purely of theoretical interest, but it
  26. // allows creating functions with very complex domains and co-domains that are
  27. // computed at compile-time.
  28. struct Function { };
  29. template <typename Domain, typename Codomain, typename F>
  30. struct function_type {
  31. using hana_tag = Function;
  32. Domain domain_;
  33. Codomain codomain_;
  34. F f_;
  35. template <typename X>
  36. constexpr auto operator()(X x) const {
  37. BOOST_HANA_CONSTANT_ASSERT(boost::hana::contains(domain_, x));
  38. return f_(x);
  39. }
  40. };
  41. template <typename ...F, typename ...G>
  42. constexpr auto operator==(function_type<F...> f, function_type<G...> g)
  43. { return hana::equal(f, g); }
  44. template <typename ...F, typename ...G>
  45. constexpr auto operator!=(function_type<F...> f, function_type<G...> g)
  46. { return hana::not_equal(f, g); }
  47. auto function = [](auto domain, auto codomain) {
  48. return [=](auto definition) {
  49. return function_type<decltype(domain), decltype(codomain), decltype(definition)>{
  50. domain, codomain, definition
  51. };
  52. };
  53. };
  54. template <typename Function>
  55. constexpr auto domain(Function f)
  56. { return f.domain_; }
  57. template <typename Function>
  58. constexpr auto codomain(Function f)
  59. { return f.codomain_; }
  60. template <typename Function>
  61. constexpr auto range(Function f) {
  62. // We must convert to hana::tuple first because hana::set is not a Functor
  63. return hana::to_set(hana::transform(hana::to_tuple(domain(f)), f));
  64. }
  65. template <typename P, typename Q>
  66. constexpr auto implies(P p, Q q) {
  67. return hana::or_(hana::not_(p), q);
  68. }
  69. template <typename F>
  70. constexpr auto is_injective(F f) {
  71. auto dom = hana::to_tuple(domain(f));
  72. auto pairs = hana::cartesian_product(hana::make_tuple(dom, dom));
  73. return hana::all_of(pairs, hana::fuse([&](auto x, auto y) {
  74. return implies(hana::not_equal(x, y), hana::not_equal(f(x), f(y)));
  75. }));
  76. }
  77. template <typename F>
  78. constexpr auto is_onto(F f) {
  79. return codomain(f) == range(f);
  80. }
  81. namespace boost { namespace hana {
  82. template <>
  83. struct equal_impl<Function, Function> {
  84. template <typename F, typename G>
  85. static constexpr auto apply(F f, G g) {
  86. return domain(f) == domain(g) &&
  87. hana::all_of(domain(f), hana::demux(hana::equal)(f, g));
  88. }
  89. };
  90. }} // end namespace boost::hana
  91. int main() {
  92. auto f = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(1_c, 2_c, 3_c, 4_c, 5_c, 6_c))(
  93. [](auto x) { return x + 1_c; }
  94. );
  95. auto g = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(2_c, 3_c, 4_c))(
  96. [](auto x) { return x + 1_c; }
  97. );
  98. auto h = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(0_c, 1_c, 2_c))(
  99. [](auto x) { return x - 1_c; }
  100. );
  101. BOOST_HANA_CONSTANT_CHECK(f == g);
  102. BOOST_HANA_CONSTANT_CHECK(f != h);
  103. BOOST_HANA_CONSTANT_CHECK(f(1_c) == 2_c);
  104. BOOST_HANA_CONSTANT_CHECK(range(f) == hana::make_set(4_c, 3_c, 2_c));
  105. BOOST_HANA_CONSTANT_CHECK(range(g) == hana::make_set(2_c, 3_c, 4_c));
  106. BOOST_HANA_CONSTANT_CHECK(range(h) == hana::make_set(0_c, 1_c, 2_c));
  107. BOOST_HANA_CONSTANT_CHECK(hana::not_(is_onto(f)));
  108. BOOST_HANA_CONSTANT_CHECK(is_onto(g));
  109. BOOST_HANA_CONSTANT_CHECK(is_onto(h));
  110. auto even = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(hana::true_c, hana::false_c))(
  111. [](auto x) { return x % 2_c == 0_c; }
  112. );
  113. BOOST_HANA_CONSTANT_CHECK(is_injective(f));
  114. BOOST_HANA_CONSTANT_CHECK(is_injective(g));
  115. BOOST_HANA_CONSTANT_CHECK(is_injective(h));
  116. BOOST_HANA_CONSTANT_CHECK(hana::not_(is_injective(even)));
  117. }