aGrUM  0.20.3
a C++ library for (probabilistic) graphical models
undiGraph.cpp
Go to the documentation of this file.
1 /**
2  *
3  * Copyright (c) 2005-2021 by Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
4  * info_at_agrum_dot_org
5  *
6  * This library is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library. If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 
22 /** @file
23  * @brief Source implementation of Base classes for undirected graphs
24  *
25  * @author Pierre-Henri WUILLEMIN(@LIP6) & Christophe GONZALES(@AMU)
26  *
27  */
28 #include <agrum/tools/graphs/undiGraph.h>
29 
30 #ifdef GUM_NO_INLINE
31 # include <agrum/tools/graphs/undiGraph_inl.h>
32 #endif // GUM_NOINLINE
33 #include "graphElements.h"
34 #include <cstdio>
35 #include <iostream>
36 
37 namespace gum {
38 
39  UndiGraph::UndiGraph(Size nodes_size,
40  bool nodes_resize_policy,
41  Size edges_size,
42  bool edges_resize_policy) :
43  NodeGraphPart(nodes_size, nodes_resize_policy),
44  EdgeGraphPart(edges_size, edges_resize_policy) {
45  GUM_CONSTRUCTOR(UndiGraph);
46  }
47 
48  UndiGraph::UndiGraph(const UndiGraph& g) : NodeGraphPart(g), EdgeGraphPart(g) {
49  GUM_CONS_CPY(UndiGraph);
50  }
51 
52  UndiGraph::~UndiGraph() {
53  GUM_DESTRUCTOR(UndiGraph);
54  ;
55  }
56 
57  bool UndiGraph::hasUndirectedCycle() const {
58  List< std::pair< NodeId, NodeId > > open_nodes;
59  NodeProperty< bool > examined_nodes = nodesProperty(false);
60  std::pair< NodeId, NodeId > thePair;
61  NodeId current, from_current;
62 
63  for (const auto node: nodes()) {
64  // check if the node has already been examined (if this is not the case,
65  // this means that we are on a new connected component)
66  if (!examined_nodes[node]) {
67  // indicates that we are examining a new node
68  examined_nodes[node] = true;
69 
70  // check recursively all the nodes of node's connected component
71  thePair.first = node;
72  thePair.second = node;
73  open_nodes.insert(thePair);
74 
75  while (!open_nodes.empty()) {
76  // get a node to propagate
77  thePair = open_nodes.front();
78  open_nodes.popFront();
79 
80  current = thePair.first;
81  from_current = thePair.second;
82 
83  // check the neighbours
84  for (const auto new_node: neighbours(current))
85 
86  // avoid to check the node we are coming from
87  if (new_node != from_current) {
88  if (examined_nodes[new_node])
89  return true;
90  else {
91  examined_nodes[new_node] = true;
92  thePair.first = new_node;
93  thePair.second = current;
94  open_nodes.insert(thePair);
95  }
96  }
97  }
98  }
99  }
100 
101  return false;
102  }
103 
104  std::string UndiGraph::toString() const {
105  std::string s = NodeGraphPart::toString();
106  s += " , ";
107  s += EdgeGraphPart::toString();
108  return s;
109  }
110 
111  std::string UndiGraph::toDot() const {
112  std::stringstream output;
113  std::stringstream nodeStream;
114  std::stringstream edgeStream;
115  List< NodeId > treatedNodes;
116  output << "digraph \""
117  << "no_name\" {" << std::endl
118  << "edge [dir=none]" << std::endl;
119  nodeStream << "node [shape = ellipse];" << std::endl;
120  std::string tab = " ";
121 
122  for (const auto node: nodes()) {
123  nodeStream << tab << node << ";";
124 
125  if (neighbours(node).size() > 0)
126  for (const auto nei: neighbours(node))
127  if (!treatedNodes.exists(nei))
128  edgeStream << tab << node << " -> " << nei << ";" << std::endl;
129 
130  treatedNodes.insert(node);
131  }
132 
133  output << nodeStream.str() << std::endl << edgeStream.str() << std::endl << "}" << std::endl;
134 
135  return output.str();
136  }
137 
138  /// returns the partial graph formed by the nodes given in parameter
139  UndiGraph UndiGraph::partialUndiGraph(NodeSet nodes) {
140  UndiGraph partialGraph;
141 
142  for (const auto node: nodes) {
143  partialGraph.addNodeWithId(node);
144 
145  for (const auto nei: neighbours(node))
146  if (nodes.contains(nei) && partialGraph.existsNode(nei)) partialGraph.addEdge(node, nei);
147  }
148 
149  return partialGraph;
150  }
151 
152  NodeProperty< NodeId > UndiGraph::nodes2ConnectedComponent() const {
153  NodeProperty< NodeId > res;
154 
155  NodeId numCC = 0;
156  for (const auto node: nodes()) {
157  if (res.exists(node)) continue;
158  NodeSet nodes{node};
159  while (!nodes.empty()) {
160  auto actual = *(nodes.begin());
161  nodes.erase(actual);
162  res.insert(actual, numCC);
163  for (const auto nei: neighbours(actual)) {
164  if (!res.exists(nei))
165  if (!nodes.exists(nei)) nodes.insert(nei);
166  }
167  }
168  numCC += 1;
169  }
170 
171  return res;
172  }
173 
174  /// for friendly displaying the content of undirected graphs
175  std::ostream& operator<<(std::ostream& stream, const UndiGraph& g) {
176  stream << g.toString();
177  return stream;
178  }
179 
180 } /* namespace gum */