|
5 | 5 | #pragma once |
6 | 6 |
|
7 | 7 | #include "gl/attributes/force_inline.hpp" |
| 8 | +#include "gl/traits.hpp" |
8 | 9 | #include "gl/types/core.hpp" |
9 | 10 | #include "hgl/constants.hpp" |
10 | 11 | #include "hgl/directional_tags.hpp" |
11 | 12 | #include "hgl/hypergraph_traits.hpp" |
12 | 13 | #include "hgl/impl/impl_tags.hpp" |
| 14 | +#include "hgl/io.hpp" |
13 | 15 | #include "hgl/util.hpp" |
14 | 16 |
|
15 | 17 | #include <algorithm> |
@@ -131,7 +133,7 @@ class hypergraph final { |
131 | 133 |
|
132 | 134 | // --- vertex methods --- |
133 | 135 |
|
134 | | - [[nodiscard]] gl_attr_force_inline auto vertices() noexcept { |
| 136 | + [[nodiscard]] gl_attr_force_inline auto vertices() const noexcept { |
135 | 137 | return this->vertex_ids() | std::views::transform(this->_create_vertex_descriptor()); |
136 | 138 | } |
137 | 139 |
|
@@ -258,7 +260,7 @@ class hypergraph final { |
258 | 260 |
|
259 | 261 | // --- hyperedge methods --- |
260 | 262 |
|
261 | | - [[nodiscard]] gl_attr_force_inline auto hyperedges() noexcept { |
| 263 | + [[nodiscard]] gl_attr_force_inline auto hyperedges() const noexcept { |
262 | 264 | return this->hyperedge_ids() | std::views::transform(this->_create_hyperedge_descriptor()); |
263 | 265 | } |
264 | 266 |
|
@@ -517,14 +519,14 @@ class hypergraph final { |
517 | 519 | return this->_impl.degree_map(this->_n_vertices); |
518 | 520 | } |
519 | 521 |
|
520 | | - [[nodiscard]] gl_attr_force_inline auto out_hyperedges(const id_type vertex_id) |
| 522 | + [[nodiscard]] gl_attr_force_inline auto out_hyperedges(const id_type vertex_id) const |
521 | 523 | requires std::same_as<directional_tag, bf_directed_t> |
522 | 524 | { |
523 | 525 | return this->out_hyperedge_ids(vertex_id) |
524 | 526 | | std::views::transform(this->_create_hyperedge_descriptor()); |
525 | 527 | } |
526 | 528 |
|
527 | | - [[nodiscard]] gl_attr_force_inline auto out_hyperedges(const vertex_type& vertex) |
| 529 | + [[nodiscard]] gl_attr_force_inline auto out_hyperedges(const vertex_type& vertex) const |
528 | 530 | requires std::same_as<directional_tag, bf_directed_t> |
529 | 531 | { |
530 | 532 | return this->out_hyperedges(vertex.id()); |
@@ -562,14 +564,14 @@ class hypergraph final { |
562 | 564 | return this->_impl.out_degree_map(this->_n_vertices); |
563 | 565 | } |
564 | 566 |
|
565 | | - [[nodiscard]] gl_attr_force_inline auto in_hyperedges(const id_type vertex_id) |
| 567 | + [[nodiscard]] gl_attr_force_inline auto in_hyperedges(const id_type vertex_id) const |
566 | 568 | requires std::same_as<directional_tag, bf_directed_t> |
567 | 569 | { |
568 | 570 | return this->in_hyperedge_ids(vertex_id) |
569 | 571 | | std::views::transform(this->_create_hyperedge_descriptor()); |
570 | 572 | } |
571 | 573 |
|
572 | | - [[nodiscard]] gl_attr_force_inline auto in_hyperedges(const vertex_type& vertex) |
| 574 | + [[nodiscard]] gl_attr_force_inline auto in_hyperedges(const vertex_type& vertex) const |
573 | 575 | requires std::same_as<directional_tag, bf_directed_t> |
574 | 576 | { |
575 | 577 | return this->in_hyperedges(vertex.id()); |
@@ -607,12 +609,13 @@ class hypergraph final { |
607 | 609 | return this->_impl.in_degree_map(this->_n_vertices); |
608 | 610 | } |
609 | 611 |
|
610 | | - [[nodiscard]] auto incident_vertices(const id_type hyperedge_id) { |
| 612 | + [[nodiscard]] auto incident_vertices(const id_type hyperedge_id) const { |
611 | 613 | return this->incident_vertex_ids(hyperedge_id) |
612 | 614 | | std::views::transform(this->_create_vertex_descriptor()); |
613 | 615 | } |
614 | 616 |
|
615 | | - [[nodiscard]] gl_attr_force_inline auto incident_vertices(const hyperedge_type& hyperedge) { |
| 617 | + [[nodiscard]] gl_attr_force_inline auto incident_vertices(const hyperedge_type& hyperedge |
| 618 | + ) const { |
616 | 619 | return this->incident_vertices(hyperedge.id()); |
617 | 620 | } |
618 | 621 |
|
@@ -640,14 +643,14 @@ class hypergraph final { |
640 | 643 | return this->_impl.hyperedge_size_map(this->_n_hyperedges); |
641 | 644 | } |
642 | 645 |
|
643 | | - [[nodiscard]] gl_attr_force_inline auto tail_vertices(const id_type hyperedge_id) |
| 646 | + [[nodiscard]] gl_attr_force_inline auto tail_vertices(const id_type hyperedge_id) const |
644 | 647 | requires std::same_as<directional_tag, bf_directed_t> |
645 | 648 | { |
646 | 649 | return this->tail_vertex_ids(hyperedge_id) |
647 | 650 | | std::views::transform(this->_create_vertex_descriptor()); |
648 | 651 | } |
649 | 652 |
|
650 | | - [[nodiscard]] gl_attr_force_inline auto tail_vertices(const hyperedge_type& hyperedge) |
| 653 | + [[nodiscard]] gl_attr_force_inline auto tail_vertices(const hyperedge_type& hyperedge) const |
651 | 654 | requires std::same_as<directional_tag, bf_directed_t> |
652 | 655 | { |
653 | 656 | return this->tail_vertices(hyperedge.id()); |
@@ -685,14 +688,14 @@ class hypergraph final { |
685 | 688 | return this->_impl.tail_size_map(this->_n_hyperedges); |
686 | 689 | } |
687 | 690 |
|
688 | | - [[nodiscard]] gl_attr_force_inline auto head_vertices(const id_type hyperedge_id) |
| 691 | + [[nodiscard]] gl_attr_force_inline auto head_vertices(const id_type hyperedge_id) const |
689 | 692 | requires std::same_as<directional_tag, bf_directed_t> |
690 | 693 | { |
691 | 694 | return this->head_vertex_ids(hyperedge_id) |
692 | 695 | | std::views::transform(this->_create_vertex_descriptor()); |
693 | 696 | } |
694 | 697 |
|
695 | | - [[nodiscard]] gl_attr_force_inline auto head_vertices(const hyperedge_type& hyperedge) |
| 698 | + [[nodiscard]] gl_attr_force_inline auto head_vertices(const hyperedge_type& hyperedge) const |
696 | 699 | requires std::same_as<directional_tag, bf_directed_t> |
697 | 700 | { |
698 | 701 | return this->head_vertices(hyperedge.id()); |
@@ -753,6 +756,80 @@ class hypergraph final { |
753 | 756 | return lhs._impl == rhs._impl; |
754 | 757 | } |
755 | 758 |
|
| 759 | + // --- I/O utility --- |
| 760 | + |
| 761 | + struct hyperedge_formatter { |
| 762 | + public: |
| 763 | + const hypergraph& hg; |
| 764 | + const hyperedge_type& hyperedge; |
| 765 | + |
| 766 | + friend std::ostream& operator<<(std::ostream& os, const hyperedge_formatter& proxy) |
| 767 | + requires std::same_as<directional_tag, undirected_t> |
| 768 | + { |
| 769 | + using io::detail::option_bit; |
| 770 | + const bool with_props = |
| 771 | + io::is_option_set(os, option_bit::with_connection_properties) |
| 772 | + and traits::c_writable<hyperedge_properties_type>; |
| 773 | + |
| 774 | + if (io::is_option_set(os, option_bit::verbose)) { |
| 775 | + os << "[id: " << proxy.hyperedge.id() << " | vertices: " |
| 776 | + << io::set_formatter(proxy.hg.incident_vertex_ids(proxy.hyperedge.id())); |
| 777 | + if (with_props) |
| 778 | + os << " | " << proxy.hyperedge.properties(); |
| 779 | + os << ']'; |
| 780 | + } |
| 781 | + else { // concise |
| 782 | + os << io::set_formatter(proxy.hg.incident_vertex_ids(proxy.hyperedge.id())); |
| 783 | + if (with_props) |
| 784 | + os << '[' << proxy.hyperedge.properties() << ']'; |
| 785 | + } |
| 786 | + |
| 787 | + return os; |
| 788 | + } |
| 789 | + |
| 790 | + friend std::ostream& operator<<(std::ostream& os, const hyperedge_formatter& proxy) |
| 791 | + requires std::same_as<directional_tag, bf_directed_t> |
| 792 | + { |
| 793 | + using io::detail::option_bit; |
| 794 | + const bool with_props = |
| 795 | + io::is_option_set(os, option_bit::with_connection_properties) |
| 796 | + and traits::c_writable<hyperedge_properties_type>; |
| 797 | + |
| 798 | + if (io::is_option_set(os, option_bit::verbose)) { |
| 799 | + os << "[id: " << proxy.hyperedge.id() << " | tail: " |
| 800 | + << io::set_formatter(proxy.hg.tail_vertex_ids(proxy.hyperedge.id())) |
| 801 | + << ", head: " |
| 802 | + << io::set_formatter(proxy.hg.head_vertex_ids(proxy.hyperedge.id())); |
| 803 | + if (with_props) |
| 804 | + os << " | " << proxy.hyperedge.properties(); |
| 805 | + os << "]"; |
| 806 | + } |
| 807 | + else { // concise |
| 808 | + os << '(' << io::set_formatter(proxy.hg.tail_vertex_ids(proxy.hyperedge.id())) |
| 809 | + << " -> " << io::set_formatter(proxy.hg.head_vertex_ids(proxy.hyperedge.id())) |
| 810 | + << ')'; |
| 811 | + if (with_props) |
| 812 | + os << '[' << proxy.hyperedge.properties() << ']'; |
| 813 | + } |
| 814 | + |
| 815 | + return os; |
| 816 | + } |
| 817 | + }; |
| 818 | + |
| 819 | + [[nodiscard]] hyperedge_formatter display(const hyperedge_type& hyperedge) const { |
| 820 | + return hyperedge_formatter{*this, hyperedge}; |
| 821 | + } |
| 822 | + |
| 823 | + friend std::ostream& operator<<(std::ostream& os, const hypergraph& hg) { |
| 824 | + // if (gl::io::is_option_set(os, gl::io::detail::option_bit::gsf)) |
| 825 | + // return hg._gsf_write(os); |
| 826 | + |
| 827 | + if (gl::io::is_option_set(os, gl::io::detail::option_bit::verbose)) |
| 828 | + return hg._verbose_write(os); |
| 829 | + |
| 830 | + return hg._concise_write(os); |
| 831 | + } |
| 832 | + |
756 | 833 | // --- friend declarations --- |
757 | 834 |
|
758 | 835 | template <traits::c_hypergraph Hypergraph> |
@@ -824,34 +901,81 @@ class hypergraph final { |
824 | 901 |
|
825 | 902 | // --- transformations --- |
826 | 903 |
|
827 | | - gl_attr_force_inline auto _create_vertex_descriptor() noexcept |
| 904 | + gl_attr_force_inline auto _create_vertex_descriptor() const noexcept |
828 | 905 | requires(traits::c_empty_properties<vertex_properties_type>) |
829 | 906 | { |
830 | 907 | return [](const id_type id) { return vertex_type{id}; }; |
831 | 908 | } |
832 | 909 |
|
833 | | - gl_attr_force_inline auto _create_vertex_descriptor() noexcept |
| 910 | + gl_attr_force_inline auto _create_vertex_descriptor() const noexcept |
834 | 911 | requires(traits::c_non_empty_properties<vertex_properties_type>) |
835 | 912 | { |
836 | 913 | return [&pmap = this->_vertex_properties](const id_type id) { |
837 | 914 | return vertex_type{id, *pmap[to_idx(id)]}; |
838 | 915 | }; |
839 | 916 | } |
840 | 917 |
|
841 | | - gl_attr_force_inline auto _create_hyperedge_descriptor() noexcept |
| 918 | + gl_attr_force_inline auto _create_hyperedge_descriptor() const noexcept |
842 | 919 | requires(traits::c_empty_properties<hyperedge_properties_type>) |
843 | 920 | { |
844 | 921 | return [](const id_type id) { return hyperedge_type{id}; }; |
845 | 922 | } |
846 | 923 |
|
847 | | - gl_attr_force_inline auto _create_hyperedge_descriptor() noexcept |
| 924 | + gl_attr_force_inline auto _create_hyperedge_descriptor() const noexcept |
848 | 925 | requires(traits::c_non_empty_properties<hyperedge_properties_type>) |
849 | 926 | { |
850 | 927 | return [&pmap = this->_hyperedge_properties](const id_type id) { |
851 | 928 | return hyperedge_type{id, *pmap[to_idx(id)]}; |
852 | 929 | }; |
853 | 930 | } |
854 | 931 |
|
| 932 | + // --- I/O utility --- |
| 933 | + |
| 934 | + std::ostream& _verbose_write(std::ostream& os) const { |
| 935 | + using enum io::detail::option_bit; |
| 936 | + using fmt_traits = io::detail::hypergraph_fmt_traits<directional_tag>; |
| 937 | + |
| 938 | + os << "type: " << fmt_traits::type << ", |V| = " << this->order() |
| 939 | + << ", |E| = " << this->size() << '\n'; |
| 940 | + |
| 941 | + const bool with_v_props = |
| 942 | + io::is_option_set(os, with_vertex_properties) |
| 943 | + and traits::c_writable<vertex_properties_type>; |
| 944 | + if (with_v_props) { |
| 945 | + os << "vertices:\n"; |
| 946 | + for (const auto& vertex : this->vertices()) |
| 947 | + os << " - " << vertex << '\n'; |
| 948 | + } |
| 949 | + |
| 950 | + os << "hyperedges:\n"; |
| 951 | + for (const auto& edge : this->hyperedges()) |
| 952 | + os << " - " << this->display(edge) << '\n'; |
| 953 | + |
| 954 | + return os; |
| 955 | + } |
| 956 | + |
| 957 | + std::ostream& _concise_write(std::ostream& os) const { |
| 958 | + using enum io::detail::option_bit; |
| 959 | + |
| 960 | + const bool with_v_props = |
| 961 | + io::is_option_set(os, with_vertex_properties) |
| 962 | + and traits::c_writable<vertex_properties_type>; |
| 963 | + if (with_v_props) { |
| 964 | + os << "V :"; |
| 965 | + for (const auto& vertex : this->vertices()) |
| 966 | + os << " " << vertex; |
| 967 | + } |
| 968 | + else { |
| 969 | + os << "|V| = " << this->order(); |
| 970 | + } |
| 971 | + |
| 972 | + os << "\nE:\n"; |
| 973 | + for (const auto& edge : this->hyperedges()) |
| 974 | + os << this->display(edge) << '\n'; |
| 975 | + |
| 976 | + return os; |
| 977 | + } |
| 978 | + |
855 | 979 | // --- data members --- |
856 | 980 |
|
857 | 981 | size_type _n_vertices = 0uz; |
|
0 commit comments