27 #include <agrum/tools/graphs/cliqueGraph.h> 31 # include <agrum/tools/graphs/cliqueGraph_inl.h> 34 #ifndef DOXYGEN_SHOULD_SKIP_THIS 46 CliqueGraph::CliqueGraph(Size nodes_size,
47 bool nodes_resize_policy,
49 bool edges_resize_policy) :
50 NodeGraphPart(nodes_size, nodes_resize_policy),
51 UndiGraph(nodes_size, nodes_resize_policy, edges_size, edges_resize_policy) {
53 GUM_CONSTRUCTOR(CliqueGraph);
58 CliqueGraph::CliqueGraph(
const CliqueGraph& from) :
61 _cliques_(from._cliques_), _separators_(from._separators_) {
62 GUM_CONS_CPY(CliqueGraph);
67 CliqueGraph::~CliqueGraph() {
68 GUM_DESTRUCTOR(CliqueGraph);
74 std::vector< NodeId > CliqueGraph::containerPath(
const NodeId node1,
const NodeId node2)
const {
77 std::vector< NodeId > path = undirectedPath(container(node1), container(node2));
81 while ((path.size() >= 2) && (clique(path[path.size() - 2]).contains(node2)))
84 while ((path.size() >= 2) && (clique(path[1]).contains(node1)))
85 path.erase(path.begin());
94 void CliqueGraph::addToClique(
const NodeId clique_id,
const NodeId node_id) {
96 NodeSet& clique = _cliques_[clique_id];
99 if (clique.contains(node_id)) {
100 GUM_ERROR(DuplicateElement,
"the clique set already contains the node " << node_id)
103 clique.insert(node_id);
106 for (
const auto nei: neighbours(clique_id))
107 if (_cliques_[nei].contains(node_id)) _separators_[Edge(nei, clique_id)].insert(node_id);
112 void CliqueGraph::eraseFromClique(
const NodeId clique_id,
const NodeId node_id) {
114 NodeSet& clique = _cliques_[clique_id];
117 if (clique.contains(node_id)) {
118 clique.erase(node_id);
121 for (
const auto nei: neighbours(clique_id)) {
122 Edge edge(nei, clique_id);
124 if (_separators_[edge].contains(node_id)) _separators_[edge].erase(node_id);
131 bool CliqueGraph::_runningIntersectionDFS_(
const NodeId clique,
133 CliqueGraph::_RunningIntersect_& infos_DFS)
const {
136 const NodeSet& nodes_clique = _cliques_[clique];
138 for (
const auto node: nodes_clique)
139 if (infos_DFS.nodes_other_components.contains(node))
return false;
143 for (
const auto node: nodes_clique)
144 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
145 infos_DFS.cliques_DFS_chain[clique].erase(node);
149 if (infos_DFS.visited_cliques.contains(clique))
return true;
152 for (
const auto node: nodes_clique)
153 if (!infos_DFS.nodes_DFS_seen.contains(node)) infos_DFS.nodes_DFS_seen.insert(node);
156 infos_DFS.visited_cliques.insert(clique);
161 for (
const auto otherID: neighbours(clique))
162 if (otherID != from) {
165 const Edge edge(otherID, clique);
166 const NodeSet& from_separ = _separators_[edge];
168 for (
const auto node: nodes_clique) {
169 if (!from_separ.contains(node)) infos_DFS.nodes_DFS_forbidden.insert(node);
173 if (!_runningIntersectionDFS_(otherID, clique, infos_DFS))
return false;
176 for (
const auto node: nodes_clique)
177 infos_DFS.nodes_DFS_forbidden.erase(node);
182 for (
const auto node: nodes_clique) {
183 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
184 infos_DFS.cliques_DFS_chain[clique].erase(node);
193 if (neighbours(clique).size() <= 1)
194 for (
const auto node: nodes_clique)
195 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
196 infos_DFS.nodes_DFS_forbidden.insert(node);
204 bool CliqueGraph::hasRunningIntersection()
const {
206 _RunningIntersect_ infos_DFS;
207 infos_DFS.cliques_DFS_chain = _cliques_;
210 for (
const auto DFSnode: nodes())
211 if (!infos_DFS.visited_cliques.contains(DFSnode)) {
213 infos_DFS.nodes_DFS_forbidden.clear();
216 infos_DFS.nodes_DFS_seen.clear();
220 if (!_runningIntersectionDFS_(DFSnode, DFSnode, infos_DFS))
return false;
225 for (
const auto node: infos_DFS.nodes_DFS_seen)
226 if (!infos_DFS.nodes_other_components.contains(node))
227 infos_DFS.nodes_other_components.insert(node);
232 for (
const auto& elt: infos_DFS.cliques_DFS_chain)
233 if (!elt.second.empty())
return false;
240 bool CliqueGraph::operator==(
const CliqueGraph& from)
const {
242 if (UndiGraph::operator!=(from))
return false;
245 for (
const auto& elt: _cliques_)
246 if (elt.second != from._cliques_[elt.first])
return false;
251 std::string CliqueGraph::toString()
const {
252 std::stringstream stream;
253 stream <<
"list of nodes:" << std::endl;
255 for (
const auto node: nodes()) {
256 stream <<
" -- node: " << node << std::endl <<
" clique:";
258 for (
const auto cliq: clique(node))
259 stream <<
" " << cliq;
264 stream <<
"\n\nlist of edges:\n";
266 for (
const auto& edge: edges())
267 stream << edge <<
" ";
272 const std::string expandCliqueContent(
const NodeSet& clique) {
273 std::stringstream stream;
276 for (
auto node: clique) {
277 if (!first) { stream <<
"-"; }
285 const std::string expandClique(
const NodeId n,
const NodeSet& clique) {
286 std::stringstream stream;
287 stream <<
'(' << n <<
") " << expandCliqueContent(clique);
290 const std::string expandSeparator(
const NodeId n1,
291 const NodeSet& clique1,
293 const NodeSet& clique2) {
294 std::stringstream stream;
295 stream << expandClique(n1, clique1) <<
"^" << expandClique(n2, clique2);
299 std::string CliqueGraph::toDot()
const {
300 std::stringstream stream;
301 stream <<
"graph {" << std::endl;
302 stream <<
" node [style=\"filled\", fontcolor=\"black\"];" << std::endl;
305 for (
auto node: nodes()) {
306 std::string nom =
'"' + expandClique(node, clique(node)) +
'"';
307 stream <<
" " << nom <<
" [label=\"" << expandCliqueContent(clique(node))
308 <<
"\",fillcolor =\"burlywood\"];" << std::endl;
314 for (
const auto& edge: edges()) {
316 << expandSeparator(edge.first(),
317 clique(edge.first()),
319 clique(edge.second()))
320 <<
"\" [label=\"" << expandCliqueContent(separator(edge)) <<
"\"" 321 <<
",shape=box,fillcolor=\"palegreen\",fontsize=8," 329 for (
const auto& edge: edges())
330 stream <<
" \"" << expandClique(edge.first(), clique(edge.first())) <<
"\"--\"" 331 << expandSeparator(edge.first(),
332 clique(edge.first()),
334 clique(edge.second()))
335 <<
"\"--\"" << expandClique(edge.second(), clique(edge.second())) <<
"\";" 338 stream <<
"}" << std::endl;
345 std::ostream& operator<<(std::ostream& stream,
const CliqueGraph& graph) {
346 stream << graph.toString();