Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SetTheoretic] Add SetTheoretic concept #364

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions example/misc/infinite_set.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
#include <boost/hana/functional/compose.hpp>
#include <boost/hana/functional/partial.hpp>
#include <boost/hana/fwd/ap.hpp>
#include <boost/hana/fwd/difference.hpp>
#include <boost/hana/fwd/equal.hpp>
#include <boost/hana/fwd/find_if.hpp>
#include <boost/hana/fwd/intersection.hpp>
#include <boost/hana/fwd/lift.hpp>
#include <boost/hana/fwd/set.hpp>
#include <boost/hana/fwd/union.hpp>
#include <boost/hana/if.hpp>
#include <boost/hana/is_subset.hpp>
Expand Down Expand Up @@ -48,6 +51,9 @@ constexpr auto doubleton(X x, Y y) {
}

namespace boost { namespace hana {
//////////////////////////////////////////////////////////////////////////
// SetTheoretic
//////////////////////////////////////////////////////////////////////////
template <>
struct union_impl<infinite_set_tag> {
template <typename Xs, typename Ys>
Expand All @@ -56,6 +62,22 @@ namespace boost { namespace hana {
}
};

template <>
struct difference_impl<infinite_set_tag> {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ldionne
This actually doesn't seem good to me logically. Although infinite set had union function implemented, we can't call it, because apparantly, union requires the class to be SetTheoretic meaning it requires minimal definition - all 3 functions union, intersection & difference. But, mathematically, it seems accurate though.
Any thoughts ?

template <typename Xs, typename Ys>
static constexpr auto apply(Xs xs, Ys ys) {
return difference_impl<set_tag>(xs, ys);
}
};
shreyans800755 marked this conversation as resolved.
Show resolved Hide resolved

template <>
struct intersection_impl<infinite_set_tag> {
template <typename Xs, typename Ys>
static constexpr auto apply(Xs xs, Ys ys) {
return intersection_impl<set_tag>(xs, ys);
}
};

//////////////////////////////////////////////////////////////////////////
// Comparable
//////////////////////////////////////////////////////////////////////////
Expand Down
1 change: 1 addition & 0 deletions include/boost/hana/concept.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Distributed under the Boost Software License, Version 1.0.
#include <boost/hana/concept/ring.hpp>
#include <boost/hana/concept/searchable.hpp>
#include <boost/hana/concept/sequence.hpp>
#include <boost/hana/concept/set_theoretic.hpp>
#include <boost/hana/concept/struct.hpp>

#endif // !BOOST_HANA_CONCEPT_HPP
36 changes: 36 additions & 0 deletions include/boost/hana/concept/set_theoretic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*!
@file
Defines `boost::hana::SetTheoretic`.

@copyright Shreyans Doshi 2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/

#ifndef BOOST_HANA_CONCEPT_SET_THEORETIC_HPP
#define BOOST_HANA_CONCEPT_SET_THEORETIC_HPP

#include <boost/hana/fwd/concept/set_theoretic.hpp>

#include <boost/hana/config.hpp>
#include <boost/hana/core/default.hpp>
#include <boost/hana/core/tag_of.hpp>
#include <boost/hana/detail/integral_constant.hpp>
#include <boost/hana/difference.hpp>
#include <boost/hana/intersection.hpp>
#include <boost/hana/symmetric_difference.hpp>
#include <boost/hana/union.hpp>


BOOST_HANA_NAMESPACE_BEGIN
template <typename STh>
struct SetTheoretic
: hana::integral_constant<bool,
!is_default<difference_impl<typename tag_of<STh>::type>>::value &&
!is_default<intersection_impl<typename tag_of<STh>::type>>::value &&
!is_default<union_impl<typename tag_of<STh>::type>>::value
>
{ };
BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_CONCEPT_SET_THEORETIC_HPP
17 changes: 14 additions & 3 deletions include/boost/hana/difference.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Distributed under the Boost Software License, Version 1.0.

#include <boost/hana/fwd/difference.hpp>

#include <boost/hana/concept/set_theoretic.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/core/dispatch.hpp>
#include <boost/hana/erase_key.hpp>
Expand All @@ -21,11 +22,21 @@ BOOST_HANA_NAMESPACE_BEGIN
//! @cond
template <typename Xs, typename Ys>
constexpr auto difference_t::operator()(Xs&& xs, Ys&& ys) const {
using S = typename hana::tag_of<Xs>::type;
using Difference = BOOST_HANA_DISPATCH_IF(difference_impl<S>,
true
using TX = typename hana::tag_of<Xs>::type;
using TY = typename hana::tag_of<Ys>::type;
using Difference = BOOST_HANA_DISPATCH_IF(difference_impl<TX>,
hana::SetTheoretic<TX>::value &&
std::is_same<TX, TY>::value
);

#ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
static_assert(hana::SetTheoretic<TX>::value,
"hana::difference(xs, ys) requires 'xs' to be SetTheoretic");

static_assert(std::is_same<TX, TY>::value,
"hana::difference(xs, ys) requires 'xs' and 'ys' to be of the same type");
#endif

return Difference::apply(static_cast<Xs&&>(xs), static_cast<Ys&&>(ys));
}
//! @endcond
Expand Down
35 changes: 35 additions & 0 deletions include/boost/hana/fwd/concept/set_theoretic.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*!
@file
Forward declares `boost::hana::SetTheoretic`.

@copyright Shreyans Doshi 2017
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt)
*/

#ifndef BOOST_HANA_FWD_CONCEPT_SET_THEORETIC_HPP
#define BOOST_HANA_FWD_CONCEPT_SET_THEORETIC_HPP

#include <boost/hana/config.hpp>


BOOST_HANA_NAMESPACE_BEGIN
//! @ingroup group-concepts
//! @defgroup group-SetTheoretic SetTheoretic
//! The `SetTheoretic` concept represents data structures supporting
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Defining the concept as "things that have the methods that the concept provides" is kind of circular, and not very useful IMO. Also, you're not defining laws for the concept. I'd go for a brief like this instead:

The SetTheoretic concept represents data structures that support an algebra of sets.

Then, I'd make some comments about what the concept is at a high level, and why it's useful. I'd also give the laws that the concept must follow, e.g. probably the ones on the Wikipedia page.

Other comments:

  • One thing that must be thought about is the relationship between this concept and Searchable. Indeed, Searchable provides is_subset; it seems clear that there's an interesting mathematical link between both, and it should be explored, explained and some laws should be surfaced for data structures that are both Searchable and SetTheoretic.
  • You should also think about automatically-provided models and document them, if you can find some. What I mean here is that you should try to see whether satisfying some other concept(s) makes it possible to satisfy SetTheoretic automatically. When this is the case, Hana usually provides such a definition and documents it (e.g. Foldable for any Iterable).
  • The methods should be documented like normal methods that are tied to a concept, not individually for map and set.

I know this may seem like a lot, but this is what a concept in Hana is; it's not only a syntactical construction, it's also a tool to reason mathematically about programs, which requires a little more work to define than "loose" concepts that don't have clear semantics, if I may put it that way.

If there are things where you really don't know what to do, let me know and I'll try to make some time for researching the topic to try and provide some guidance.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense for SetTheoretic to have its own accessors? Something like get<T>(set) == at_key(set, T{}) would be very useful for set and it would be a way of making SetTheoretic provide an implementation for Searchable.

It might even simplify implementation of these functions assuming "keys" are strictly looked up at compile-time. Hmm.. that might also require something like the keys function that map has.

Also perhaps it should be just hana::Set.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TLDR is that they would only have to implement those accessors and not the union, intersection,... algorithms directly

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From what I see it does not necessarily make sense to have SetTheoretic be related to Searchable if the goal is to create a generic thing that supports the algebra of sets.

You can make plenty of things that support the algebra of sets that it does not make sense to be Searchable.

For example: a string of bits:

1010 union 0001 => 1011
1010 intersection 1000 => 1000
1010 difference 1000 => 0010
1010 symmetric_difference 1001 => 0011

Anyways......thats just the way I see it.......
@ldionne @ricejasonf @shreyans800755

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DarthRubik I don't believe we are trying to couple Set with Searchable, but types that satisfy Searchable can be made to implement the needed functions for Set. For your string of bits you would probably implement those functions directly.

//! algebra of sets.
//!
//! Minimal complete definition
//! ---------------------------
//! `union_`, `intersection`, `difference` and `symmetric_difference`
shreyans800755 marked this conversation as resolved.
Show resolved Hide resolved
//!
//! Concrete models
//! ---------------
//! `hana::set`, `hana::map`
//!
//!
template <typename STh>
struct SetTheoretic;
BOOST_HANA_NAMESPACE_END

#endif // !BOOST_HANA_FWD_CONCEPT_SET_THEORETIC_HPP
17 changes: 14 additions & 3 deletions include/boost/hana/intersection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Distributed under the Boost Software License, Version 1.0.

#include <boost/hana/fwd/intersection.hpp>

#include <boost/hana/concept/set_theoretic.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/core/dispatch.hpp>

Expand All @@ -20,11 +21,21 @@ BOOST_HANA_NAMESPACE_BEGIN
//! @cond
template <typename Xs, typename Ys>
constexpr auto intersection_t::operator()(Xs&& xs, Ys&& ys) const {
using S = typename hana::tag_of<Xs>::type;
using Intersection = BOOST_HANA_DISPATCH_IF(intersection_impl<S>,
true
using TX = typename hana::tag_of<Xs>::type;
using TY = typename hana::tag_of<Ys>::type;
using Intersection = BOOST_HANA_DISPATCH_IF(intersection_impl<TX>,
hana::SetTheoretic<TX>::value &&
std::is_same<TX, TY>::value
);

#ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
static_assert(hana::SetTheoretic<TX>::value,
"hana::intersection(xs, ys) requires 'xs' to be SetTheoretic");

static_assert(std::is_same<TX, TY>::value,
"hana::intersection(xs, ys) requires 'xs' and 'ys' to be of the same type");
#endif

return Intersection::apply(static_cast<Xs&&>(xs), static_cast<Ys&&>(ys));
}
//! @endcond
Expand Down
17 changes: 14 additions & 3 deletions include/boost/hana/union.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Distributed under the Boost Software License, Version 1.0.

#include <boost/hana/fwd/union.hpp>

#include <boost/hana/concept/set_theoretic.hpp>
#include <boost/hana/config.hpp>
#include <boost/hana/core/dispatch.hpp>

Expand All @@ -20,11 +21,21 @@ BOOST_HANA_NAMESPACE_BEGIN
//! @cond
template <typename Xs, typename Ys>
constexpr auto union_t::operator()(Xs&& xs, Ys&& ys) const {
using S = typename hana::tag_of<Xs>::type;
using Union = BOOST_HANA_DISPATCH_IF(union_impl<S>,
true
using TX = typename hana::tag_of<Xs>::type;
using TY = typename hana::tag_of<Ys>::type;
using Union = BOOST_HANA_DISPATCH_IF(union_impl<TX>,
hana::SetTheoretic<TX>::value &&
std::is_same<TX, TY>::value
);

#ifndef BOOST_HANA_CONFIG_DISABLE_CONCEPT_CHECKS
static_assert(hana::SetTheoretic<TX>::value,
"hana::union_(xs, ys) requires 'xs' to be SetTheoretic");

static_assert(std::is_same<TX, TY>::value,
"hana::union_(xs, ys) requires 'xs' and 'ys' to be of the same type");
#endif

return Union::apply(static_cast<Xs&&>(xs), static_cast<Ys&&>(ys));
}
//! @endcond
Expand Down