19 #if _MSVC_LANG < 201703L
20 #error This libary requires C++17 Standard (Visual Studio 2017).
24 #if __cplusplus < 201703
25 #error This library requires C++17 Standard (GNU g++ version 8.0 or clang++ version 8.0 above)
56 return (direction & 1) != 0;
61 return (weighted & 2) != 0;
71 template<
int DirectedEdge,
typename NodeIndexType,
typename... Types>
class edge;
74 template<
int DirectedEdge,
typename EdgeNodeIndexType>
75 class edge<DirectedEdge, EdgeNodeIndexType>
77 template<int, int,
typename,
typename,
typename,
template<
typename,
typename...>
class,
78 template<
typename,
typename...>
class,
template<
typename,
typename...>
class>
friend class graph;
84 static constexpr int directed_edge = DirectedEdge;
85 static constexpr node_index_t invalid_node_index = tpf::type_max_v<node_index_t>;
98 template<
typename IndexType_1,
typename IndexType_2>
99 edge(IndexType_1 index_1, IndexType_2 index_2,
bool bForceDirection =
false) noexcept
101 set(index_1, index_2, bForceDirection);
105 const node_index_t&
node_1() const noexcept{
return std::get<edge_index::index_node_1>(this->m_edge); }
108 const node_index_t&
node_2() const noexcept {
return std::get<edge_index::index_node_2>(this->m_edge); }
110 template<
typename IndexType_1,
typename IndexType_2>
111 edge&
set(IndexType_1 index_1, IndexType_2 index_2,
bool bForceDirection =
false) noexcept
127 template<
typename IndexType>
131 return this->node_2();
133 return this->node_1();
135 return invalid_node_index;
140 if(lhs.node_1() == rhs.node_1())
142 if(lhs.node_2() == rhs.node_2())
144 else if(lhs.node_2() < rhs.node_2())
149 else if(lhs.node_1() < rhs.node_1() )
159 return compare_edges(lhs, rhs) < 0;
163 struct strong_compare
167 return compare_edges(lhs, rhs) < 0;
171 inline static constexpr weak_compare weak_comparator{};
172 inline static constexpr strong_compare strong_comparator{};
176 return compare_edges(lhs, rhs) < 0;
181 return compare_edges(lhs, rhs) > 0;
186 return compare_edges(lhs, rhs) == 0;
191 return compare_edges(lhs, rhs) != 0;
196 if(
this != std::addressof(rhs))
198 this->m_edge.swap(rhs.m_edge);
216 os <<
"( "<<e.node_1()<<
", "<<e.node_2() <<
" )";
223 template<
int DirectedEdge,
typename EdgeNodeIndexType,
typename EdgeWeightType>
224 class edge<DirectedEdge, EdgeNodeIndexType, EdgeWeightType>
226 template<int, int,
typename,
typename,
typename,
template<
typename,
typename...>
class,
227 template<
typename,
typename...>
class,
template<
typename,
typename...>
class>
friend class graph;
234 static constexpr int directed_edge = DirectedEdge;
235 static constexpr node_index_t invalid_node_index = tpf::type_max_v<node_index_t>;
237 enum edge_index:
size_t{ index_node_1, index_node_2, index_weight };
248 template<
typename IndexType_1,
typename IndexType_2,
typename WeightType>
249 edge(IndexType_1 index_1, IndexType_2 index_2, WeightType weight,
bool bForceDirection =
false) noexcept
251 set(index_1, index_2, weight, bForceDirection);
254 weight_t&
weight() noexcept {
return std::get<edge_index::index_weight>(this->m_edge); };
255 const weight_t&
weight() const noexcept {
return std::get<edge_index::index_weight>(this->m_edge); };
258 const node_index_t&
node_1() const noexcept{
return std::get<edge_index::index_node_1>(this->m_edge); }
261 const node_index_t&
node_2() const noexcept {
return std::get<edge_index::index_node_2>(this->m_edge); }
263 template<
typename IndexType_1,
typename IndexType_2,
typename WeightType>
264 edge&
set(IndexType_1 index_1, IndexType_2 index_2, WeightType weight,
bool bForceDirection =
false) noexcept
283 if(lhs.node_1() == rhs.node_1())
285 if(lhs.node_2() == rhs.node_2())
287 else if(lhs.node_2() < rhs.node_2())
292 else if(lhs.node_1() < rhs.node_1() )
300 auto weak_compare = weak_compare_edges(lhs, rhs);
306 auto diff = lhs.weight() - rhs.weight();
307 return (diff == 0 ? 0: (diff < 0 ? -1: 1));
315 return weak_compare_edges(lhs, rhs) < 0;
319 struct strong_compare
323 return strong_compare_edges(lhs, rhs) < 0;
327 inline static constexpr weak_compare weak_comparator{};
328 inline static constexpr strong_compare strong_comparator{};
330 template<
typename IndexType>
334 return this->node_2();
336 return this->node_1();
338 return invalid_node_index;
343 return strong_compare_edges(lhs, rhs) < 0;
348 return strong_compare_edges(lhs, rhs) > 0;
354 return strong_compare_edges(lhs, rhs) == 0;
359 return strong_compare_edges(lhs, rhs) != 0;
364 if(
this != std::addressof(rhs))
365 this->m_edge.swap(rhs.m_edge);
381 os <<
"( "<<e.node_1()<<
", "<<e.node_2() <<
" | "<<e.weight() <<
" )";
386 template<
int EdgeDirected,
typename EdgeIndexType,
typename... EdgeTypes,
387 template<
typename,
typename...>
class ContainerType,
typename... Types>
389 (
tpf::sstream& os,
const ContainerType<
edge<EdgeDirected, EdgeIndexType, EdgeTypes...>, Types...>& edges)
393 os <<
"{ }";
return os;
397 auto last_edge = edges.cend();
398 std::advance(last_edge, -1);
400 for(
auto itr = edges.cbegin(); itr != last_edge; ++itr)
409 template<
typename EdgeType,
typename IndexType_1,
typename IndexType_2,
typename WeightType>
410 EdgeType
make_edge(IndexType_1 index_1, IndexType_2 index_2, WeightType weight,
bool bForceDirection =
false)
412 return EdgeType{ index_1, index_2, weight, bForceDirection};
415 template<
typename EdgeType,
typename IndexType_1,
typename IndexType_2>
416 EdgeType
make_edge(IndexType_1 index_1, IndexType_2 index_2,
bool bForceDirection =
false)
418 return EdgeType{ index_1, index_2, bForceDirection};
421 template<
int DirectedEdge,
int EdgePlurality,
422 typename ElementType,
typename NodeIndexType,
typename EdgeWeightType,
423 template<
typename,
typename...>
class NodeContainerType,
424 template<
typename,
typename...>
class IndexContainerType,
425 template<
typename,
typename...>
class EdgeContainerType>
428 template<int,
typename,
typename...>
friend class edge;
454 using node_ref_t = std::tuple<ElementType&, index_container_t&>;
457 using node_info_t = std::tuple<const ElementType&, const_ref_element_container_t>;
478 return this->m_values;
483 return tpf::get_element<const node_container_t&>(this->m_nodes, node_index);
488 return tpf::get_element<node_container_t&>(this->m_nodes, node_index);
493 return tpf::get_element<edge_container_t&>(this->m_edges, (
size_t)index);
498 return tpf::get_element<const edge_container_t&>(this->m_edges, (
size_t)index);
510 for(
auto& end_node: node_indices)
512 auto e = make_edge<edge_type_t>(node_index, end_node,
edge_weight_t{});
516 if(index < this->m_edges.size())
518 edge_indices.emplace_back((
index_t)index);
531 for(
auto& end_node: node_indices)
535 auto e = make_edge<edge_type_t>(node_index, end_node,
edge_weight_t{});
539 if(index < this->m_edges.size())
541 edge_indices.emplace_back((
index_t)index);
548 auto begin() {
return this->m_nodes.begin(); }
549 auto end() {
return this->m_nodes.end(); }
551 auto cbegin() {
return this->m_nodes.cbegin(); }
552 auto cend() {
return this->m_nodes.cend(); }
554 bool empty()
const {
return this->m_nodes.empty(); }
558 return tpf::get_element<node_container_t&>(m_nodes, node_index);
563 return tpf::get_element<const node_container_t&>(m_nodes, node_index);
572 auto indices = tpf::get_element<node_container_t&>(m_nodes, node_index);
574 for(
auto& idx: indices)
576 auto& value = tpf::get_element<element_container_t&>(m_values, idx);
577 elements.emplace_back(
std::ref(value));
586 auto indices = tpf::get_element<const node_container_t&>(m_nodes, node_index);
588 for(
auto& idx: indices)
590 auto& value = tpf::get_element<const element_container_t&>(m_values, idx);
591 elements.emplace_back(std::cref(value));
599 return tpf::get_element<element_container_t&>(m_values, node_index);
604 return tpf::get_element<const element_container_t&>(m_values, node_index);
607 template<
typename IndexType_1,
typename IndexType_2>
610 auto e = make_edge<edge_type_t>(index_1, index_2,
edge_weight_t{});
614 template<
typename IndexType_1,
typename IndexType_2,
typename WeightType>
617 auto e = make_edge<edge_type_t>(index_1, index_2, weight);
632 auto indices = tpf::get_element<const node_container_t&>(m_nodes, node_index);
634 for(
auto& idx: indices)
636 auto& value = tpf::get_element<const element_container_t&>(m_values, idx);
637 elements.emplace_back(std::cref(value));
640 return {
node_value(node_index), std::move(elements) };
645 os <<
"node_" << index;
return os;
650 bool bProportional =
false,
const char* color=
"black")
const
652 auto e = make_edge<edge_type_t>(index_1, index_2,
edge_weight_t{});
654 auto [success, iterator] =
659 os <<
" [ dir = none, color = \""<< color <<
"\", label = \" "
660 << iterator->weight() <<
" \"] ;";
679 size_t size = this->m_nodes.size();
681 for(
size_t i=0; i <
size; ++i)
688 using set_t = std::vector<index_t>;
689 using sets_t = std::vector<set_t>;
693 for(
size_t i = 0; i <
size; ++i)
696 for(
const auto& v: nodes)
728 std::vector<index_t> visit_order;
735 if(visit_order.size() > 1)
739 for(
size_t i = 1; i < visit_order.size(); ++i )
745 os <<
" [ color = blue ] ; \n";
756 os <<
"digraph G {\n";
759 os <<
"label=\"Breadth First Search\"\n";
761 os <<
"label=\"Depth First Search\"\n";
773 size_t size = this->m_nodes.size();
775 for(
size_t i=0; i <
size; ++i)
782 for(
const auto&
edge: this->m_edges)
791 os <<
"dir = none, ";
793 os <<
"label = \" " <<
edge.weight() <<
" \"];";
803 const std::string& graph_title =
"Plain Graph",
804 const std::string& graph_style =
"",
805 const std::string& best_viewed =
"dot")
const
809 os <<
"digraph G {\n\n";
811 if(graph_style !=
"")
812 os << graph_style <<
"\n";
815 os << graph_title <<
"\\nBest Viewed: ";
816 os << best_viewed <<
"\";\n\n";
832 os <<
"digraph G {\n";
833 os <<
"label=\"Plain Graph\"\n";
845 os <<
"digraph G {\n";
848 os <<
"label=\"Breadth First Search\"\n";
850 os <<
"label=\"Depth First Search\"\n";
862 size_t size() {
return this->m_nodes.size(); }
867 size_t size = this->m_nodes.size();
868 for(
const auto&
node: this->m_nodes)
870 for(
const auto& e:
node)
875 msg <<
"node " <<
node <<
" has an adjacent vertex " << e
876 <<
" (max node index " << (
size - 1)
877 <<
") which does not exist in the node list ";
885 template<
typename EleType,
typename Type,
typename... Types>
888 auto v = tpf::make_random_access_container<IndexContainerType>((NodeIndexType)std::forward<Type>(index0),
889 (NodeIndexType)std::forward<Types>(indices)...);
892 this->m_nodes.emplace_back(std::move(v));
893 this->m_values.emplace_back(std::forward<EleType>(value));
908 template<
typename IndexType_1,
typename IndexType_2,
typename... WeightType>
911 size_t size = this->m_nodes.size();
913 if( (
size_t)index_1 >=
size)
917 msg <<
"The edge (" << index_1 <<
", " << index_2
918 <<
") is not VALID, its first vertex index "<< index_1
919 <<
" is out of range (max node index " << (
size-1) <<
").";
924 if( (
size_t)index_2 >=
size)
928 msg <<
"The edge (" << index_1 <<
", " << index_2
929 <<
") is not VALID, its second vertex index "<< index_2
930 <<
" is out of range (max node index " << (
size-1) <<
").";
937 static_assert(
sizeof...(WeightType) == 1,
"Weight of edge should be specified");
939 auto e = make_edge<edge_type_t>(index_1, index_2, weight...);
948 if(e == *iterator)
return;
951 msg <<
"new edge " << e <<
" is different from the existing edge "
952 << *iterator <<
".\nMultiple different edges incident on the same node pairs are not allowed in a signle-edged graph.";
961 if(already_exists)
return;
971 this->m_edges.push_back(std::move(e));
976 static_assert(
sizeof...(WeightType) == 0,
"Weight of edge is not allowed");
978 auto e = make_edge<edge_type_t>(index_1, index_2);
981 if(already_exists)
return;
983 this->m_edges.push_back(std::move(e));
990 return node_ref_t{ tpf::get_element<element_container_t&>(this->m_values, node_index),
991 tpf::get_element<node_container_t&>(this->m_nodes, node_index) };
996 return const_node_ref_t{ tpf::get_element<const element_container_t&>(this->m_values, node_index),
997 tpf::get_element<const node_container_t&>(this->m_nodes, node_index) };
1005 std::deque<index_t> queue;
1006 std::vector<char> visited(m_nodes.size());
1007 std::vector<index_t> traversal;
1009 for(
auto& v: visited) v = 0;
1010 queue.push_back(start);
1012 visited[(size_t)start] = 1;
1014 while(!queue.empty())
1016 auto p = queue.front();
1019 traversal.push_back(p);
1022 for(
auto&
node: node_list)
1024 if(visited[(
size_t)
node] == 0)
1026 queue.push_back(
node);
1027 visited[(size_t)
node] = 1;
1037 std::vector<char>& visited,
1038 size_t node_index)
const
1043 for(
const auto&
node: node_list)
1045 if(visited[(
size_t)
node] != 1)
1047 stack.push_front(
node);
1048 visited[(size_t)
node] = 1;
1055 visited.push_back(index);
1057 auto itr = std::find(unvisited.cbegin(), unvisited.cend(), index);
1059 if(itr != unvisited.end()) unvisited.erase(itr);
1064 size_t size = this->m_values.size();
1066 if((
size_t)index < this->m_values.size())
1074 size_t size = indices.size();
1077 for(
const auto& index: indices)
1079 if((
size_t)index < this->m_values.size())
1081 names.emplace_back(e);
1085 names.emplace_back(
"Unvisited");
1098 size_t size = this->m_nodes.size();
1101 std::iota(unvisited.begin(), unvisited.end(), 0);
1108 auto max_weight = tpf::type_max_v<edge_weight_t>;
1109 auto max_index = tpf::type_max_v<index_t>;
1111 for(
size_t i=0; i <
size; ++i)
1113 if(i != (
size_t)start_node)
1115 shortest_distances.emplace_back(max_weight);
1116 previous_vertices.emplace_back(max_index);
1121 previous_vertices.emplace_back(start_node);
1127 for(
auto edge_index: edge_indices)
1132 shortest_distances[(size_t)other_node] =
edge.weight();
1134 previous_vertices[(size_t)other_node] = (
index_t)start_node;
1137 this->
move_vertex(visited, unvisited, start_node);
1139 while(!unvisited.empty())
1142 edge_weight_t start_weight = shortest_distances[(size_t)start_node];
1146 for(
auto edge_index: edge_indices)
1151 auto new_weight = start_weight +
edge.weight();
1153 if( new_weight < shortest_distances[(
size_t)other_node])
1155 shortest_distances[(size_t)other_node] = new_weight;
1156 previous_vertices[(size_t)other_node] = (
index_t)start_node;
1160 this->
move_vertex(visited, unvisited, start_node);
1163 return {visited, shortest_distances,
1164 previous_vertices, shortest_distances[(size_t)visited.back()]};
1171 std::deque<edge_type_t> itinerary;
1173 while(start_node != end_node)
1175 auto distance = distances[(size_t)end_node];
1177 auto prev_idx = previous_node[end_node];
1179 auto e = make_edge<edge_type_t>(prev_idx, end_node, distance,
true);
1181 itinerary.push_front(e);
1183 end_node = prev_idx;
1186 for(
const auto&
edge: itinerary)
1192 os <<
" [ style = dashed, color= blue, fontcolor = blue, ";
1194 os <<
"label = \" " <<
edge.weight() <<
" \"];";
1207 const std::string& graph_title =
"Shortest Path";
1208 const std::string& graph_style =
"pack=100;\npackmode=array;\nedge [len=2];";
1209 const std::string& best_viewed =
"neato or osage";
1211 os <<
"digraph G {\n\n";
1213 if(graph_style !=
"")
1214 os << graph_style <<
"\n";
1217 os << graph_title <<
"\\nBest Viewed: ";
1218 os << best_viewed <<
"\";\n\n";
1224 draw_edge_list(os, visited, distances, previous_node, start_node, end_node);
1236 auto endlL =
"\n\n";
1238 auto start_itr = std::find(this->m_values.cbegin(), this->m_values.cend(), start_pos);
1239 auto end_itr = std::find(this->m_values.cbegin(), this->m_values.cend(), end_pos);
1241 if(start_itr == this->m_values.cend())
1243 stream << start_pos <<
" is not in the node list";
1247 if(end_itr == this->m_values.cend())
1249 stream << end_pos <<
" is not in the node list";
1253 index_t start_node = std::distance(this->m_values.cbegin(), start_itr);
1254 index_t end_node = std::distance(this->m_values.cbegin(), end_itr);
1259 auto [route, distances, previous_node, shortest] =
1264 stream <<
"from "<< this->
translate(start_node) <<
" : " << distances <<
endl;
1267 stream <<
"Shortest distance from " << this->
translate(start_node) <<
" to "
1268 << this->
translate(end_node) <<
" is " << distances[(size_t)end_node];
1282 std::deque<index_t> stack;
1283 std::vector<char> visited(this->m_nodes.size());
1284 std::vector<index_t> traversal;
1286 for(
auto& v: visited) v = 0;
1290 while(!stack.empty())
1292 traversal.push_back(stack.front());
1294 push_stack(stack, visited, (
size_t)traversal.back());
1303 if(g.m_nodes.empty())
1312 auto last_itr = g.m_nodes.cend();
1320 for(
auto itr = g.m_nodes.cbegin(); itr != g.m_nodes.cend(); ++itr)
1321 os << std::setw(3) << index <<
" - ("
1322 << tpf::get_element<const element_container_t&>(g.m_values, index++)<<
") " << *itr <<
"\n";
1326 os << g.m_edges <<
"\n";
1335 typename ElementType =
const char*,
typename NodeIndexType = int,
1336 typename EdgeWeightType = float,
1337 template<
typename,
typename...>
class NodeContainerType = std::list,
1338 template<
typename,
typename...>
class IndexContainerType = std::vector,
1339 template<
typename,
typename...>
class EdgeContainerType = std::vector>
1340 using graph_t =
graph<DirectedEdge, EdgePlurality, ElementType, NodeIndexType, EdgeWeightType,
1341 NodeContainerType, IndexContainerType, EdgeContainerType>;
reference_wrapper< Type > ref(Type &val) noexcept
const edge_tuple_t & get() const noexcept
node_index_t & node_1() noexcept
weight_t & weight() noexcept
edge & set(IndexType_1 index_1, IndexType_2 index_2, WeightType weight, bool bForceDirection=false) noexcept
EdgeNodeIndexType node_index_t
std::tuple< node_index_t, node_index_t, weight_t > edge_tuple_t
node_index_t other_node(IndexType node_index) const noexcept
friend tpf::sstream & operator<<(tpf::sstream &os, const edge &e)
edge(const edge &)=default
const node_index_t & node_2() const noexcept
friend void swap(edge &lhs, edge &rhs) noexcept
static int weak_compare_edges(const edge &lhs, const edge &rhs)
const weight_t & weight() const noexcept
edge(IndexType_1 index_1, IndexType_2 index_2, WeightType weight, bool bForceDirection=false) noexcept
const node_index_t & node_1() const noexcept
edge_tuple_t & get() noexcept
static int strong_compare_edges(const edge &lhs, const edge &rhs)
void swap(edge &rhs) noexcept
node_index_t & node_2() noexcept
edge(const edge &)=default
static int compare_edges(const edge &lhs, const edge &rhs)
node_index_t other_node(IndexType node_index) const noexcept
node_index_t & node_2() noexcept
edge & set(IndexType_1 index_1, IndexType_2 index_2, bool bForceDirection=false) noexcept
const edge_tuple_t & get() const noexcept
node_index_t & node_1() noexcept
std::tuple< node_index_t, node_index_t > edge_tuple_t
const node_index_t & node_1() const noexcept
edge(IndexType_1 index_1, IndexType_2 index_2, bool bForceDirection=false) noexcept
friend void swap(edge &lhs, edge &rhs) noexcept
EdgeNodeIndexType node_index_t
void swap(edge &rhs) noexcept
edge_tuple_t & get() noexcept
const node_index_t & node_2() const noexcept
std::tuple< const ElementType &, const index_container_t & > const_node_ref_t
void draw_shortest_path(tpf::sstream &os, const indices_t &visited, const distances_t &distances, const indices_t &previous_node, index_t start_node, index_t end_node) const
auto adjacent_node_values(size_t node_index) const
shortest_path_t shortest_path(index_t start_node=0, index_t end_node=0) const
const node_container_t & node_lists() const
NodeContainerType< index_container_t > node_container_t
decltype(auto) get_node_indices(index_t node_index)
void integrity_check_nodes_throws() const
tpf::sstream & get_node_name(tpf::sstream &os, size_t index) const
void push_stack(std::deque< index_t > &stack, std::vector< char > &visited, size_t node_index) const
auto operator[](size_t node_index)
auto get_edge_range_iterators(IndexType_1 index_1, IndexType_2 index_2) const
NodeContainerType< element_t > element_container_t
static constexpr int edge_multiplicity
auto get_edge_range_iterators(IndexType_1 index_1, IndexType_2 index_2, WeightType weight) const
const edge_container_t & edges() const noexcept
tpf::sstream & get_edge_definition(tpf::sstream &os, node_index_t index_1, node_index_t index_2, bool bProportional=false, const char *color="black") const
std::vector< edge_weight_t > distances_t
decltype(auto) get_edge(index_t index) const
tpf::sstream & draw_edge_list(tpf::sstream &os, const indices_t &visited, const distances_t &distances, const indices_t &previous_node, index_t start_node, index_t end_node) const
auto adjacent_node_values(size_t node_index)
std::string draw_graph_traversal(visit_mode vmode=visit_mode::visit_dfs) const
std::vector< index_t > indices_t
indices_t get_edge_indices(index_t node_index, const indices_t &visited) const
node_info_t node_info(size_t node_index) const
void emplace_back_node(EleType &&value, Type &&index0, Types &&... indices)
std::vector< index_t > traverse_dfs(index_t start=0) const
decltype(auto) get_node_indices(index_t node_index) const
auto is_in_edge_list(const edge_type_t &e, bool bStrongCompare=false) const noexcept
std::string draw_graph(const std::string &graph_title="Plain Graph", const std::string &graph_style="", const std::string &best_viewed="dot") const
tpf::sstream & get_node_definition(tpf::sstream &os, size_t index) const
NodeContainerType< std::reference_wrapper< element_t > > ref_element_container_t
std::tuple< ElementType &, index_container_t & > node_ref_t
std::string build_graph(visit_mode vmode=visit_mode::graph) const
tpf::sstream & draw_graph_edges(tpf::sstream &os) const
decltype(auto) adjacency_node_list(size_t node_index) const
decltype(auto) get_edge(index_t index)
friend tpf::sstream & operator<<(tpf::sstream &os, const graph &g)
void emplace_back_edge(IndexType_1 index_1, IndexType_2 index_2, WeightType... weight)
std::string shortest_path_report(element_t start_pos, element_t end_pos) const
const element_container_t & values() const
IndexContainerType< index_t > index_container_t
EdgeContainerType< edge_type_t > edge_container_t
NodeContainerType< std::reference_wrapper< const element_t > > const_ref_element_container_t
node_names_t translate(const indices_t &indices) const
std::vector< index_t > traverse_bfs(index_t start=0) const
NodeIndexType node_index_t
EdgeWeightType edge_weight_t
std::tuple< const ElementType &, const_ref_element_container_t > node_info_t
decltype(auto) adjacency_node_list(size_t node_index)
indices_t get_edge_indices(index_t node_index) const
decltype(auto) node_value(size_t node_index)
auto operator[](size_t node_index) const
edge_container_t & edges() noexcept
tpf::sstream & build_graph_edges(tpf::sstream &os, visit_mode vmode=visit_mode::graph, bool bProportional=false) const
decltype(auto) node_value(size_t node_index) const
std::tuple< indices_t, distances_t, indices_t, edge_weight_t > shortest_path_t
auto get_edge_range_iterators(const edge_type_t &e, bool bStrongCompare=false) const
const element_container_t & get_node_values() const
static constexpr int directed_edge
std::vector< ElementType > node_names_t
void move_vertex(indices_t &visited, indices_t &unvisited, index_t index) const
element_t translate(index_t index) const
friend tpf::sstream & operator<<(tpf::sstream &os, const graph &g)
bool operator==(rational< L > const &lhs, rational< R > const &rhs)
constexpr bool is_weighted(int weighted)
EdgeType make_edge(IndexType_1 index_1, IndexType_2 index_2, WeightType weight, bool bForceDirection=false)
constexpr bool is_directed(int direction)
string_stream & operator>(string_stream &os, Type &&arg)
string_stream & operator<(string_stream &os, Type &&arg)
Implements set operations.
types::enable_if_container_type_t< ContainerType< EleType, Types... >, size_t > minimum_value_index(const ContainerType< EleType, Types... > &container)
types::enable_if_container_type_t< ContainerType< EleType, Types... >, bool > is_in_container(const EleType &ele, const ContainerType< EleType, Types... > &container)
types::enable_if_container_type_t< ContainerType< EleType, Types... >, bool > operator!=(const ContainerType< EleType, Types... > &left, const ContainerType< EleType, Types... > &right)
types::enable_if_container_type_t< ContainerType< EleType, Types... >, bool > sort_in_place(ContainerType< EleType, Types... > &container, sort_order order=sort_order::ascending, sort_method method=sort_method::size)
Includes subnamespace conversion.
auto find_range_iterators(ForwardIterator first, ForwardIterator last, const EleType &value, CompareCallbackType &&compare_callback=CompareCallbackType{})
auto minimum(Type_1 a, Type_2 b)
typename SetTagType::set_t set_t
auto binary_find_index(ForwardIterator first, ForwardIterator last, const EleType &value, CompareCallbackType &&compare_callback=CompareCallbackType{})
auto binary_find_bool_iterator_pair(ForwardIterator first, ForwardIterator last, const EleType &value, CompareCallbackType &&compare_callback=CompareCallbackType{})
auto maximum(Type_1 a, Type_2 b)
decltype(auto) get_element(ContainerType container, IndexType index)
typename SetTagType::sets_t sets_t
bool operator()(const edge &lhs, const edge &rhs) const
bool operator()(const edge &lhs, const edge &rhs) const
bool operator()(const edge &lhs, const edge &rhs) const
bool operator()(const edge &lhs, const edge &rhs) const
static constexpr int undirected
static constexpr int directed
static constexpr int undirected_unweighted
static constexpr int weighted_undirected
static constexpr int directed_weighted
static constexpr int undirected_weighted
static constexpr int weighted_directed
static constexpr int unweighted_undirected
static constexpr int directed_unweighted
static constexpr int weighted
static constexpr int unweighted_directed
static constexpr int single_edged
static constexpr int plural_edged
static constexpr int weighted_edge
Implements set operations.
#define Tpf_ThrowDebugException(debug_message)
Throw a debug_exception with message as argument.