Skip to content
Merged
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
19 changes: 19 additions & 0 deletions include/gl/util/ranges.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#pragma once

#include <algorithm>
#include <ranges>

namespace gl::util {
Expand All @@ -20,4 +21,22 @@ constexpr auto range_size(R&& r) {
return std::ranges::distance(std::begin(r), std::end(r));
}

template <std::ranges::forward_range R>
[[nodiscard]] constexpr bool is_constant(R&& range) noexcept {
if (std::ranges::empty(range))
return true;

return std::ranges::all_of(range, [target = *std::ranges::begin(range)](const auto& val) {
return val == target;
});
}

template <std::ranges::forward_range R>
[[nodiscard]] constexpr bool all_equal(R&& range, const std::ranges::range_value_t<R>& k) noexcept {
if (std::ranges::empty(range))
return true;

return std::ranges::all_of(range, [&k](const auto& val) { return val == k; });
}

} // namespace gl::util
201 changes: 201 additions & 0 deletions include/hgl/hypergraph.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@

#pragma once

#include "gl/types/types.hpp"
#include "hgl/constants.hpp"
#include "hgl/directional_tags.hpp"
#include "hgl/hypergraph_traits.hpp"
#include "hgl/util.hpp"

#include <algorithm>
#include <memory>
#include <set>
#include <type_traits>
Expand Down Expand Up @@ -452,6 +454,10 @@ class hypergraph final {
return this->degree(vertex.id());
}

[[nodiscard]] std::vector<types::size_type> degree_map() const {
return this->_impl.degree_map(this->_n_vertices);
}

[[nodiscard]] auto outgoing_hyperedges(const types::id_type vertex_id)
requires std::same_as<directional_tag, bf_directed_t>
{
Expand Down Expand Up @@ -479,6 +485,12 @@ class hypergraph final {
return this->out_degree(vertex.id());
}

[[nodiscard]] std::vector<types::size_type> out_degree_map() const
requires std::same_as<directional_tag, bf_directed_t>
{
return this->_impl.out_degree_map(this->_n_vertices);
}

[[nodiscard]] auto incoming_hyperedges(const types::id_type vertex_id)
requires std::same_as<directional_tag, bf_directed_t>
{
Expand Down Expand Up @@ -506,6 +518,12 @@ class hypergraph final {
return this->in_degree(vertex.id());
}

[[nodiscard]] std::vector<types::size_type> in_degree_map() const
requires std::same_as<directional_tag, bf_directed_t>
{
return this->_impl.in_degree_map(this->_n_vertices);
}

[[nodiscard]] auto incident_vertices(const types::id_type hyperedge_id) {
this->_verify_hyperedge_id(hyperedge_id);
return this->_impl.incident_vertices(hyperedge_id)
Expand All @@ -527,6 +545,10 @@ class hypergraph final {
return this->hyperedge_size(hyperedge.id());
}

[[nodiscard]] std::vector<types::size_type> hyperedge_size_map() const {
return this->_impl.hyperedge_size_map(this->_n_hyperedges);
}

[[nodiscard]] auto tail_vertices(const types::id_type hyperedge_id)
requires std::same_as<directional_tag, bf_directed_t>
{
Expand Down Expand Up @@ -555,6 +577,12 @@ class hypergraph final {
return this->tail_size(hyperedge.id());
}

[[nodiscard]] std::vector<types::size_type> tail_size_map() const
requires std::same_as<directional_tag, bf_directed_t>
{
return this->_impl.tail_size_map(this->_n_hyperedges);
}

[[nodiscard]] auto head_vertices(const types::id_type hyperedge_id)
requires std::same_as<directional_tag, bf_directed_t>
{
Expand Down Expand Up @@ -583,6 +611,12 @@ class hypergraph final {
return this->head_size(hyperedge.id());
}

[[nodiscard]] std::vector<types::size_type> head_size_map() const
requires std::same_as<directional_tag, bf_directed_t>
{
return this->_impl.head_size_map(this->_n_hyperedges);
}

private:
// --- vertex methods ---

Expand Down Expand Up @@ -659,4 +693,171 @@ class hypergraph final {
[[no_unique_address]] hyperedge_properties_map_type _hyperedge_properties{};
};

// --- general hypergraph utility ---

namespace type_traits {

template <typename G>
concept c_hypergraph = c_instantiation_of<G, hypergraph>;

template <typename G>
concept c_undirected_hypergraph =
c_hypergraph<G> and std::same_as<typename G::directional_tag, undirected_t>;

template <typename G>
concept c_bf_directed_hypergraph =
c_hypergraph<G> and std::same_as<typename G::directional_tag, bf_directed_t>;

} // namespace type_traits

// --- degree bounds ---

[[nodiscard]] types::size_type max_degree(const type_traits::c_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.degree_map();
return degrees.empty() ? 0uz : *std::ranges::max_element(degrees);
}

[[nodiscard]] types::size_type min_degree(const type_traits::c_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.degree_map();
return degrees.empty() ? 0uz : *std::ranges::min_element(degrees);
}

[[nodiscard]] types::size_type max_out_degree(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.out_degree_map();
return degrees.empty() ? 0uz : *std::ranges::max_element(degrees);
}

[[nodiscard]] types::size_type min_out_degree(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.out_degree_map();
return degrees.empty() ? 0uz : *std::ranges::min_element(degrees);
}

[[nodiscard]] types::size_type max_in_degree(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.in_degree_map();
return degrees.empty() ? 0uz : *std::ranges::max_element(degrees);
}

[[nodiscard]] types::size_type min_in_degree(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto degrees = hypergraph.in_degree_map();
return degrees.empty() ? 0uz : *std::ranges::min_element(degrees);
}

// --- hyperedge size bounds ---

[[nodiscard]] types::size_type rank(const type_traits::c_hypergraph auto& hypergraph) noexcept {
const auto sizes = hypergraph.hyperedge_size_map();
return sizes.empty() ? 0uz : *std::ranges::max_element(sizes);
}

[[nodiscard]] types::size_type corank(const type_traits::c_hypergraph auto& hypergraph) noexcept {
const auto sizes = hypergraph.hyperedge_size_map();
return sizes.empty() ? 0uz : *std::ranges::min_element(sizes);
}

[[nodiscard]] types::size_type max_tail_size(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto sizes = hypergraph.tail_size_map();
return sizes.empty() ? 0uz : *std::ranges::max_element(sizes);
}

[[nodiscard]] types::size_type min_tail_size(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto sizes = hypergraph.tail_size_map();
return sizes.empty() ? 0uz : *std::ranges::min_element(sizes);
}

[[nodiscard]] types::size_type max_head_size(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto sizes = hypergraph.head_size_map();
return sizes.empty() ? 0uz : *std::ranges::max_element(sizes);
}

[[nodiscard]] types::size_type min_head_size(
const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
const auto sizes = hypergraph.head_size_map();
return sizes.empty() ? 0uz : *std::ranges::min_element(sizes);
}

// --- regularity ---

[[nodiscard]] bool is_regular(
const type_traits::c_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.degree_map(), k);
}

[[nodiscard]] bool is_regular(const type_traits::c_hypergraph auto& hypergraph) noexcept {
return util::is_constant(hypergraph.degree_map());
}

[[nodiscard]] bool is_out_regular(
const type_traits::c_bf_directed_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.out_degree_map(), k);
}

[[nodiscard]] bool is_out_regular(const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
return util::is_constant(hypergraph.out_degree_map());
}

[[nodiscard]] bool is_in_regular(
const type_traits::c_bf_directed_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.in_degree_map(), k);
}

[[nodiscard]] bool is_in_regular(const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
return util::is_constant(hypergraph.in_degree_map());
}

// --- uniformity ---

[[nodiscard]] bool is_uniform(
const type_traits::c_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.hyperedge_size_map(), k);
}

[[nodiscard]] bool is_uniform(const type_traits::c_hypergraph auto& hypergraph) noexcept {
return util::is_constant(hypergraph.hyperedge_size_map());
}

[[nodiscard]] bool is_tail_uniform(
const type_traits::c_bf_directed_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.tail_size_map(), k);
}

[[nodiscard]] bool is_tail_uniform(const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
return util::is_constant(hypergraph.tail_size_map());
}

[[nodiscard]] bool is_head_uniform(
const type_traits::c_bf_directed_hypergraph auto& hypergraph, const types::size_type k
) noexcept {
return util::all_equal(hypergraph.head_size_map(), k);
}

[[nodiscard]] bool is_head_uniform(const type_traits::c_bf_directed_hypergraph auto& hypergraph
) noexcept {
return util::is_constant(hypergraph.head_size_map());
}

} // namespace hgl
Loading