libsemigroups  v3.3.0
C++ library for semigroups and monoids
Loading...
Searching...
No Matches
dot.hpp
1//
2// libsemigroups - C++ library for semigroups and monoids
3// Copyright (C) 2023-2025 James D. Mitchell
4//
5// This program is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with this program. If not, see <http://www.gnu.org/licenses/>.
17//
18
19#ifndef LIBSEMIGROUPS_DOT_HPP_
20#define LIBSEMIGROUPS_DOT_HPP_
21
22#include <array> // for array
23#include <cstddef> // for size_t
24#include <map> // for map, operator!=, __map_const_...
25#include <string> // for basic_string, operator<, oper...
26#include <string_view> // for basic_string_view
27#include <utility> // for forward, move etc
28#include <vector> // for vector
29
30#include "exception.hpp" // for LIBSEMIGROUPS_EXCEPTION
31#include "libsemigroups/bipart.hpp"
32#include "ranges.hpp" // for LIBSEMIGROUPS_EXCEPTION
33
34#include "detail/fmt.hpp" // for format
35#include "detail/report.hpp" // for LIBSEMIGROUPS_EXCEPTION
36
37namespace libsemigroups {
38
39#ifndef LIBSEMIGROUPS_PARSED_BY_DOXYGEN
40 namespace detail {
41
42 inline std::string const& dot_to_string(std::string const& x) {
43 return x;
44 }
45
46 inline std::string& dot_to_string(std::string& x) {
47 return x;
48 }
49
50 inline std::string&& dot_to_string(std::string&& x) {
51 return std::move(x);
52 }
53
54 inline std::string dot_to_string(char const* x) {
55 return std::string(x);
56 }
57
58 inline std::string dot_to_string(std::string_view x) {
59 return std::string(x);
60 }
61
62 template <typename Thing>
63 std::string dot_to_string(Thing&& thing) {
65 }
66
67 } // namespace detail
68
69#endif // LIBSEMIGROUPS_PARSED_BY_DOXYGEN
70
92
116 class Dot {
117 public:
123 struct Node {
126
129
142 template <typename Thing>
143 explicit Node(Thing&& thing)
144 : attrs(), name(detail::dot_to_string(std::forward<Thing>(thing))) {}
145
147 Node() = default;
148
150 Node(Node const&) = default;
151
153 Node(Node&&) = default;
154
156 Node& operator=(Node const&) = default;
157
159 Node& operator=(Node&&) = default;
160
161 ~Node();
162
184 template <typename Thing1, typename Thing2>
185 Node& add_attr(Thing1&& key, Thing2&& val) {
186 auto key_str = detail::dot_to_string(std::forward<Thing1>(key));
187 auto val_str = detail::dot_to_string(std::forward<Thing2>(val));
188
189 add_or_replace_attr(attrs, key_str, val_str);
190 return *this;
191 }
192 };
193
199 struct Edge {
213 template <typename Thing1, typename Thing2>
214 Edge(Thing1&& h, Thing2&& t)
215 : attrs(),
216 head(detail::dot_to_string(std::forward<Thing1>(h))),
217 tail(detail::dot_to_string(std::forward<Thing2>(t))) {}
218
240 template <typename Thing1, typename Thing2>
241 Edge& add_attr(Thing1&& key, Thing2&& val) {
242 auto key_str = detail::dot_to_string(std::forward<Thing1>(key));
243 auto val_str = detail::dot_to_string(std::forward<Thing2>(val));
244
245 add_or_replace_attr(attrs, key_str, val_str);
246 return *this;
247 }
248
250 Edge() = default;
251
253 Edge(Edge const&) = default;
254
256 Edge(Edge&&) = default;
257
259 Edge& operator=(Edge const&) = default;
260
262 Edge& operator=(Edge&&) = default;
263
264 ~Edge();
265
268
271
274 };
275
277 enum class Kind {
285 };
286
291 = {"#00ff00", "#ff00ff", "#007fff", "#ff7f00", "#7fbf7f", "#4604ac",
292 "#de0328", "#19801d", "#d881f5", "#00ffff", "#ffff00", "#00ff7f",
293 "#ad5867", "#85f610", "#84e9f5", "#f5c778", "#207090", "#764ef3",
294 "#7b4c00", "#0000ff", "#b80c9a", "#601045", "#29b7c0", "#839f12"};
295
296 private:
298 std::vector<Edge> _edges;
299 Kind _kind{Kind::digraph};
300 std::string _name;
302 std::vector<Dot> _subgraphs;
303
304 public:
307
309 Dot(Dot const&);
310
313
315 Dot& operator=(Dot const&);
316
319
320 ~Dot();
321
330 Dot& kind(Kind val) noexcept {
331 _kind = val;
332 return *this;
333 }
334
341 Kind kind() const noexcept {
342 return _kind;
343 }
344
350 Dot& name(std::string const& val) {
351 _name = val;
352 return *this;
353 }
354
360 std::string const& name() const noexcept {
361 return _name;
362 }
363
373 auto nodes() noexcept {
374 return rx::iterator_range(_nodes.begin(), _nodes.end())
375 | rx::transform([](auto& pair) -> Node& { return pair.second; });
376 }
377
387 auto nodes() const noexcept {
388 return rx::iterator_range(_nodes.begin(), _nodes.end())
389 | rx::transform(
390 [](auto& pair) -> Node const& { return pair.second; });
391 }
392
403 return _edges;
404 }
405
415 std::vector<Edge> const& edges() const noexcept {
416 return _edges;
417 }
418
430 return _subgraphs;
431 }
432
443 std::vector<Dot> const& subgraphs() const noexcept {
444 return _subgraphs;
445 }
446
458 return _attrs;
459 }
460
482
485
507 template <typename Thing1, typename Thing2>
508 Dot& add_attr(Thing1&& key, Thing2&& val) {
509 auto key_str = detail::dot_to_string(std::forward<Thing1>(key));
510 auto val_str = detail::dot_to_string(std::forward<Thing2>(val));
511
512 add_or_replace_attr(_attrs, key_str, val_str);
513 return *this;
514 }
515
535 template <typename Thing>
536 Dot& add_attr(Thing&& key) {
537 add_or_replace_attr(_attrs, key, "");
538 return *this;
539 }
540
549 [[nodiscard]] bool is_node(std::string const& name) const {
550 return _nodes.count(name);
551 }
552
564 template <typename Thing,
565 typename std::enable_if_t<
566 !std::is_same_v<std::decay_t<Thing>, std::string>>>
567 [[nodiscard]] bool is_node(Thing&& thing) const {
568 return is_node(detail::dot_to_string(std::forward<Thing>(thing)));
569 }
570
586 template <typename Thing>
587 Node& add_node(Thing&& thing) {
588 auto name_str = detail::dot_to_string(std::forward<Thing>(thing));
589 auto [it, inserted] = _nodes.emplace(name_str, Node(name_str));
590 if (!inserted) {
591 LIBSEMIGROUPS_EXCEPTION("there is already a node named {}!", name_str);
592 }
593 return it->second;
594 }
595
611 template <typename Thing>
612 Node& node(Thing&& thing) {
613 auto name_str = detail::dot_to_string(std::forward<Thing>(thing));
614 auto it = _nodes.find(name_str);
615 if (it == _nodes.cend()) {
616 LIBSEMIGROUPS_EXCEPTION("there is no node named {}!", name_str);
617 }
618 return it->second;
619 }
620
638 template <typename Thing1, typename Thing2>
639 Edge& add_edge(Thing1&& head, Thing2&& tail) {
640 auto head_str = detail::dot_to_string(std::forward<Thing1>(head));
641 auto tail_str = detail::dot_to_string(std::forward<Thing2>(tail));
642 throw_if_not_node(head_str);
643 throw_if_not_node(tail_str);
644 _edges.emplace_back(head_str, tail_str);
645 return _edges.back();
646 }
647
668 template <typename Thing1, typename Thing2>
669 Edge& edge(Thing1&& head, Thing2&& tail) {
670 auto head_str = detail::dot_to_string(std::forward<Thing1>(head));
671 auto tail_str = detail::dot_to_string(std::forward<Thing2>(tail));
672 throw_if_not_node(head_str);
673 throw_if_not_node(tail_str);
674 auto it = std::find_if(_edges.begin(), _edges.end(), [&](Edge const& e) {
675 return e.head == head_str && e.tail == tail_str;
676 });
677 if (it == _edges.cend()) {
679 "there is no edges from {} to {}!", head_str, tail_str);
680 }
681 return *it;
682 }
683
695
696 private:
697 void throw_if_not_node(std::string const& s);
698
699 std::string_view edge_string() const noexcept;
700
701 static void add_or_replace_attr(std::map<std::string, std::string>& attrs,
702 std::string const& key,
703 std::string const& val);
704 }; // class Dot
705
716 std::string to_human_readable_repr(Dot const& d);
717
728 std::string to_human_readable_repr(Dot::Node const& n);
729
740 std::string to_human_readable_repr(Dot::Edge const& e);
741
754 std::string const& sep = "::");
755
756} // namespace libsemigroups
757#endif // LIBSEMIGROUPS_DOT_HPP_
bool is_node(Thing &&thing) const
Check if there is a node with name obtained from an object.
Definition dot.hpp:567
auto nodes() noexcept
Returns a range object of references to the current nodes.
Definition dot.hpp:373
Dot & add_subgraph(Dot const &subgraph)
Add a Dot object as a subgraph.
auto nodes() const noexcept
Returns a range object of const references to the current nodes.
Definition dot.hpp:387
std::vector< Dot > const & subgraphs() const noexcept
Returns a const reference to the vector of subgraphs.
Definition dot.hpp:443
std::string to_human_readable_repr(Dot const &d)
Return a human readable representation of a Dot object.
Dot & add_attr(Thing &&key)
Add an attribute to the graph.
Definition dot.hpp:536
Node & node(Thing &&thing)
Return a node from the represented graph.
Definition dot.hpp:612
std::vector< Edge > & edges() noexcept
Returns a reference to the vector of edges.
Definition dot.hpp:402
Dot & add_subgraph(Dot &&subgraph)
Add a Dot object as a subgraph.
Dot & operator=(Dot &&)
Default move assignment operator.
static constexpr std::array< std::string_view, 24 > colors
An array of default HTML/hex colours.
Definition dot.hpp:291
Dot & add_attr(Thing1 &&key, Thing2 &&val)
Add an attribute to the graph.
Definition dot.hpp:508
Dot(Dot &&)
Default move constructor.
Dot(Dot const &)
Default copy constructor.
std::map< std::string, std::string > const & attrs() const noexcept
Returns a const reference to the map of attributes.
Definition dot.hpp:457
Node & add_node(Thing &&thing)
Add a node to the represented graph.
Definition dot.hpp:587
Dot()
Default constructor.
Dot & kind(Kind val) noexcept
Set the kind of the represented graph.
Definition dot.hpp:330
Edge & add_edge(Thing1 &&head, Thing2 &&tail)
Add an edge with given head and tail.
Definition dot.hpp:639
Dot & name(std::string const &val)
Set the name of the represented graph.
Definition dot.hpp:350
Dot & operator=(Dot const &)
Default copy assignment operator.
Kind
The kind of object represented.
Definition dot.hpp:277
@ subgraph
Definition dot.hpp:284
@ digraph
Value indicating that the represented graph has directed edges ->.
Definition dot.hpp:279
@ graph
Value indicating that the represented graph has undirected edges --.
Definition dot.hpp:281
std::string to_string() const
Convert a Dot object to a string.
bool is_node(std::string const &name) const
Check if there is a node with a given name.
Definition dot.hpp:549
std::vector< Dot > & subgraphs() noexcept
Returns a reference to the vector of subgraphs.
Definition dot.hpp:429
std::string const & name() const noexcept
Get the current name of the represented graph.
Definition dot.hpp:360
Edge & edge(Thing1 &&head, Thing2 &&tail)
Returns the first edge with given head and tail.
Definition dot.hpp:669
std::vector< Edge > const & edges() const noexcept
Returns a const reference to the vector of edges.
Definition dot.hpp:415
Kind kind() const noexcept
Get the kind of the represented graph.
Definition dot.hpp:341
T find_if(T... args)
T forward(T... args)
#define LIBSEMIGROUPS_EXCEPTION(...)
Throw a LibsemigroupsException.
Definition exception.hpp:99
T move(T... args)
Namespace for everything in the libsemigroups library.
Definition action.hpp:44
This nested struct represents an edge in the represented graph.
Definition dot.hpp:199
std::string head
Name of the head of the edge.
Definition dot.hpp:270
Edge(Thing1 &&h, Thing2 &&t)
Construct from head and tail.
Definition dot.hpp:214
Edge & add_attr(Thing1 &&key, Thing2 &&val)
Add an attribute to an edge.
Definition dot.hpp:241
std::map< std::string, std::string > attrs
Map of attributes.
Definition dot.hpp:267
Edge & operator=(Edge &&)=default
Default move assignment.
std::string tail
Name of the tail of the edge.
Definition dot.hpp:273
std::string to_human_readable_repr(Dot::Edge const &e)
Return a human readable representation of a Dot::Edge object.
Edge & operator=(Edge const &)=default
Default copy assignment.
Edge()=default
Default constructor.
Edge(Edge &&)=default
Default move constructor.
Edge(Edge const &)=default
Default copy constructor.
This nested struct represents a node in the represented graph.
Definition dot.hpp:123
Node & operator=(Node &&)=default
Default move assignment.
Node(Node &&)=default
Default move constructor.
Node(Thing &&thing)
Construct from anything.
Definition dot.hpp:143
Node()=default
Default constructor.
std::map< std::string, std::string > attrs
Map containing the attributes of the Node.
Definition dot.hpp:125
std::string name
The name of the node.
Definition dot.hpp:128
Node(Node const &)=default
Default copy constructor.
Node & operator=(Node const &)=default
Default copy assignment.
std::string to_human_readable_repr(Dot::Node const &n)
Return a human readable representation of a Dot::Node object.
Node & add_attr(Thing1 &&key, Thing2 &&val)
Add an attribute to a node.
Definition dot.hpp:185
T to_string(T... args)