File: restricted_function.cpp

package info (click to toggle)
boost1.88 1.88.0-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 576,932 kB
  • sloc: cpp: 4,149,234; xml: 136,789; ansic: 35,092; python: 33,910; asm: 5,698; sh: 4,604; ada: 1,681; makefile: 1,633; pascal: 1,139; perl: 1,124; sql: 640; yacc: 478; ruby: 271; java: 77; lisp: 24; csh: 6
file content (143 lines) | stat: -rw-r--r-- 4,568 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// Copyright Louis Dionne 2013-2022
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)

#include <boost/hana/all_of.hpp>
#include <boost/hana/assert.hpp>
#include <boost/hana/cartesian_product.hpp>
#include <boost/hana/contains.hpp>
#include <boost/hana/core/to.hpp>
#include <boost/hana/equal.hpp>
#include <boost/hana/functional/demux.hpp>
#include <boost/hana/fuse.hpp>
#include <boost/hana/integral_constant.hpp>
#include <boost/hana/minus.hpp>
#include <boost/hana/mod.hpp>
#include <boost/hana/not.hpp>
#include <boost/hana/not_equal.hpp>
#include <boost/hana/or.hpp>
#include <boost/hana/plus.hpp>
#include <boost/hana/set.hpp>
#include <boost/hana/transform.hpp>
#include <boost/hana/tuple.hpp>
namespace hana = boost::hana;
using namespace hana::literals;


// A function that can have an arbitrary compile-time set of values as a domain
// and co-domain. This is most likely purely of theoretical interest, but it
// allows creating functions with very complex domains and co-domains that are
// computed at compile-time.

struct Function { };

template <typename Domain, typename Codomain, typename F>
struct function_type {
    using hana_tag = Function;

    Domain domain_;
    Codomain codomain_;
    F f_;

    template <typename X>
    constexpr auto operator()(X x) const {
        BOOST_HANA_CONSTANT_ASSERT(boost::hana::contains(domain_, x));
        return f_(x);
    }
};

template <typename ...F, typename ...G>
constexpr auto operator==(function_type<F...> f, function_type<G...> g)
{ return hana::equal(f, g); }

template <typename ...F, typename ...G>
constexpr auto operator!=(function_type<F...> f, function_type<G...> g)
{ return hana::not_equal(f, g); }


auto function = [](auto domain, auto codomain) {
    return [=](auto definition) {
        return function_type<decltype(domain), decltype(codomain), decltype(definition)>{
            domain, codomain, definition
        };
    };
};

template <typename Function>
constexpr auto domain(Function f)
{ return f.domain_; }

template <typename Function>
constexpr auto codomain(Function f)
{ return f.codomain_; }

template <typename Function>
constexpr auto range(Function f) {
    // We must convert to hana::tuple first because hana::set is not a Functor
    return hana::to_set(hana::transform(hana::to_tuple(domain(f)), f));
}

template <typename P, typename Q>
constexpr auto implies(P p, Q q) {
    return hana::or_(hana::not_(p), q);
}

template <typename F>
constexpr auto is_injective(F f) {
    auto dom = hana::to_tuple(domain(f));
    auto pairs = hana::cartesian_product(hana::make_tuple(dom, dom));
    return hana::all_of(pairs, hana::fuse([&](auto x, auto y) {
        return implies(hana::not_equal(x, y), hana::not_equal(f(x), f(y)));
    }));
}

template <typename F>
constexpr auto is_onto(F f) {
    return codomain(f) == range(f);
}

namespace boost { namespace hana {
    template <>
    struct equal_impl<Function, Function> {
        template <typename F, typename G>
        static constexpr auto apply(F f, G g) {
            return domain(f) == domain(g) &&
                   hana::all_of(domain(f), hana::demux(hana::equal)(f, g));
        }
    };
}} // end namespace boost::hana

int main() {
    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))(
        [](auto x) { return x + 1_c; }
    );

    auto g = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(2_c, 3_c, 4_c))(
        [](auto x) { return x + 1_c; }
    );

    auto h = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(0_c, 1_c, 2_c))(
        [](auto x) { return x - 1_c; }
    );

    BOOST_HANA_CONSTANT_CHECK(f == g);
    BOOST_HANA_CONSTANT_CHECK(f != h);
    BOOST_HANA_CONSTANT_CHECK(f(1_c) == 2_c);

    BOOST_HANA_CONSTANT_CHECK(range(f) == hana::make_set(4_c, 3_c, 2_c));
    BOOST_HANA_CONSTANT_CHECK(range(g) == hana::make_set(2_c, 3_c, 4_c));
    BOOST_HANA_CONSTANT_CHECK(range(h) == hana::make_set(0_c, 1_c, 2_c));

    BOOST_HANA_CONSTANT_CHECK(hana::not_(is_onto(f)));
    BOOST_HANA_CONSTANT_CHECK(is_onto(g));
    BOOST_HANA_CONSTANT_CHECK(is_onto(h));

    auto even = function(hana::make_set(1_c, 2_c, 3_c), hana::make_set(hana::true_c, hana::false_c))(
        [](auto x) { return x % 2_c == 0_c; }
    );

    BOOST_HANA_CONSTANT_CHECK(is_injective(f));
    BOOST_HANA_CONSTANT_CHECK(is_injective(g));
    BOOST_HANA_CONSTANT_CHECK(is_injective(h));
    BOOST_HANA_CONSTANT_CHECK(hana::not_(is_injective(even)));
}