00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #ifndef CONGRUENCE_HH
00018 # define CONGRUENCE_HH
00019
00020 # include "../concept/concept_tools.hh"
00021 # include "../concept/concepts.hh"
00022 # include "../axioms/axioms.hh"
00023 # include "../utils/call_with.hh"
00024 # include <type_traits>
00025
00026 namespace catsfoot {
00027
00030 template <typename T, typename Rel>
00031 struct equivalence: public concept {
00032 typedef concept_list<
00033 is_callable<Rel(T, T)>,
00034 std::is_convertible<typename is_callable<Rel(T, T)>::result_type,
00035 bool>
00036 > requirements;
00037
00038 static void reflexivity(const Rel& rel, const T& a) {
00039 axiom_assert(rel(a,a));
00040 }
00041
00042 static void symmetry(const Rel& rel,
00043 const T& a, const T& b) {
00044 if (rel(a, b))
00045 axiom_assert(rel(b, a));
00046 }
00047
00048 static void transitivity(const Rel& rel,
00049 const T& a, const T& b, const T& c) {
00050 if (rel(a, b) && rel(b, c))
00051 axiom_assert(rel(a, c));
00052 }
00053
00054 AXIOMS(reflexivity, symmetry, transitivity);
00055 };
00056
00059 template <typename T>
00060 struct equivalence_eq: public concept {
00061 typedef concept_list<
00062 equality<T>,
00063 equivalence<T, op_eq>
00064 > requirements;
00065 };
00066
00068 template <typename T>
00069 struct verified<equivalence_eq<T> >:
00070 public verified<equivalence<T, op_eq> > {
00071 };
00072
00074 template <typename T>
00075 struct verified<equivalence<T, op_eq> >
00076 #ifndef DOC_GEN
00077 : public verified<equivalence_eq<T> >
00078 #endif
00079 {
00080 };
00081
00084 template <typename Rel, typename... E,
00085 typename Index = std::integral_constant<size_t, 0>,
00086 typename = typename std::enable_if
00087 <(Index::value == sizeof...(E))>::type,
00088 typename = void>
00089 bool
00090 tuple_rel(Rel, const std::tuple<E...>&, const std::tuple<E...>&,
00091 Index = Index())
00092 {
00093 return true;
00094 }
00095
00098 template <typename Rel, typename... E,
00099 typename Index = std::integral_constant<size_t, 0>,
00100 typename
00101 #ifndef DOC_GEN
00102 = typename
00103 std::enable_if
00104 <(Index::value < sizeof...(E))>::type
00105 #endif
00106 >
00107 bool
00108 tuple_rel(Rel rel, const std::tuple<E...>& a,
00109 const std::tuple<E...>& b, Index = Index()) {
00110 return rel(std::get<Index::value>(a), std::get<Index::value>(b))
00111 && tuple_rel(rel, a, b,
00112 std::integral_constant<size_t, Index::value + 1>{});
00113 }
00114
00117 template <typename Rel, typename Op, typename... Args>
00118 struct congruence: public concept {
00119
00120 typedef concept_list<
00121 equivalence<Args, Rel>...,
00122 is_callable<Op(Args...)>,
00123 equivalence<typename is_callable<Op(Args...)>::result_type,
00124 Rel>
00125 > requirements;
00126
00127 static void congruence_axiom(const std::tuple<Args...>& args1,
00128 const std::tuple<Args...>& args2,
00129 const Op& op,
00130 const Rel& rel) {
00131 if (tuple_rel(rel, args1, args2))
00132 axiom_assert(rel(call_with(op,args1), call_with(op,args2)));
00133 }
00134
00135 AXIOMS(congruence_axiom);
00136 };
00137
00140 template <typename T, typename... Args>
00141 struct congruence_eq: public concept {
00142 typedef concept_list<
00143 congruence<op_eq, T, Args...>
00144 > requirements;
00145 };
00146
00148 template <typename T, typename... Args>
00149 struct verified<congruence_eq<T, Args...> >:
00150 public verified<congruence<op_eq, T, Args...> > {
00151 };
00152
00154 template <typename T, typename... Args>
00155 struct verified<congruence<op_eq, T, Args...> >
00156 #ifndef DOC_GEN
00157 : public verified<congruence_eq<T, Args...> >
00158 #endif
00159 {
00160 };
00161
00162 }
00163
00164 #endif