57#ifndef DOXYGEN_SHOULD_SKIP_THIS
70 bool nodes_resize_policy,
72 bool edges_resize_policy) :
74 UndiGraph(nodes_size, nodes_resize_policy, edges_size, edges_resize_policy) {
76 GUM_CONSTRUCTOR(CliqueGraph)
81 CliqueGraph::CliqueGraph(
const CliqueGraph& from) :
84 _cliques_(from._cliques_), _separators_(from._separators_) {
85 GUM_CONS_CPY(CliqueGraph)
90 CliqueGraph::~CliqueGraph() {
91 GUM_DESTRUCTOR(CliqueGraph)
97 std::vector< NodeId > CliqueGraph::containerPath(
const NodeId node1,
const NodeId node2)
const {
100 std::vector< NodeId > path = undirectedPath(container(node1), container(node2));
104 while ((path.size() >= 2) && (clique(path[path.size() - 2]).contains(node2)))
107 while ((path.size() >= 2) && (clique(path[1]).contains(node1)))
108 path.erase(path.begin());
117 void CliqueGraph::addToClique(
const NodeId clique_id,
const NodeId node_id) {
119 NodeSet& clique = _cliques_[clique_id];
122 if (clique.contains(node_id)) {
129 for (
const auto nei: neighbours(clique_id))
130 if (_cliques_[nei].contains(node_id)) _separators_[Edge(nei, clique_id)].insert(node_id);
135 void CliqueGraph::eraseFromClique(
const NodeId clique_id,
const NodeId node_id) {
137 NodeSet& clique = _cliques_[clique_id];
140 if (clique.contains(node_id)) {
141 clique.erase(node_id);
144 for (
const auto nei: neighbours(clique_id)) {
145 Edge edge(nei, clique_id);
147 if (_separators_[edge].contains(node_id)) _separators_[edge].erase(node_id);
154 bool CliqueGraph::_runningIntersectionDFS_(
const NodeId clique,
156 CliqueGraph::_RunningIntersect_& infos_DFS)
const {
159 const NodeSet& nodes_clique = _cliques_[clique];
161 for (
const auto node: nodes_clique)
162 if (infos_DFS.nodes_other_components.contains(node))
return false;
166 for (
const auto node: nodes_clique)
167 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
168 infos_DFS.cliques_DFS_chain[clique].
erase(node);
172 if (infos_DFS.visited_cliques.contains(clique))
return true;
175 for (
const auto node: nodes_clique)
176 if (!infos_DFS.nodes_DFS_seen.contains(node)) infos_DFS.nodes_DFS_seen.insert(node);
179 infos_DFS.visited_cliques.insert(clique);
184 for (
const auto otherID: neighbours(clique))
185 if (otherID != from) {
188 const Edge edge(otherID, clique);
189 const NodeSet& from_separ = _separators_[edge];
191 for (
const auto node: nodes_clique) {
192 if (!from_separ.contains(node)) infos_DFS.nodes_DFS_forbidden.insert(node);
196 if (!_runningIntersectionDFS_(otherID, clique, infos_DFS))
return false;
199 for (
const auto node: nodes_clique)
200 infos_DFS.nodes_DFS_forbidden.
erase(node);
205 for (
const auto node: nodes_clique) {
206 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
207 infos_DFS.cliques_DFS_chain[clique].erase(node);
216 if (neighbours(clique).size() <= 1)
217 for (
const auto node: nodes_clique)
218 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
219 infos_DFS.nodes_DFS_forbidden.insert(node);
227 bool CliqueGraph::hasRunningIntersection()
const {
229 _RunningIntersect_ infos_DFS;
230 infos_DFS.cliques_DFS_chain = _cliques_;
233 for (
const auto DFSnode: nodes())
234 if (!infos_DFS.visited_cliques.contains(DFSnode)) {
236 infos_DFS.nodes_DFS_forbidden.clear();
239 infos_DFS.nodes_DFS_seen.clear();
243 if (!_runningIntersectionDFS_(DFSnode, DFSnode, infos_DFS))
return false;
248 for (
const auto node: infos_DFS.nodes_DFS_seen)
249 if (!infos_DFS.nodes_other_components.contains(node))
250 infos_DFS.nodes_other_components.insert(node);
255 for (
const auto& [node, nodes]: infos_DFS.cliques_DFS_chain)
256 if (!nodes.empty())
return false;
263 bool CliqueGraph::operator==(
const CliqueGraph& from)
const {
265 if (UndiGraph::operator!=(from))
return false;
268 for (
const auto& [node, nodes]: _cliques_)
269 if (nodes != from._cliques_[node])
return false;
274 std::string CliqueGraph::toString()
const {
275 std::stringstream stream;
276 stream <<
"list of nodes:" << std::endl;
278 for (
const auto node: nodes()) {
279 stream <<
" -- node: " << node << std::endl <<
" clique:";
281 for (
const auto cliq: clique(node))
282 stream <<
" " << cliq;
287 stream <<
"\n\nlist of edges:\n";
289 for (
const auto& edge: edges())
290 stream << edge <<
" ";
295 std::string expandCliqueContent(
const NodeSet& clique,
const std::string& delim =
"-") {
296 std::stringstream stream;
299 std::vector< NodeId > sorted(clique.begin(), clique.end());
300 std::sort(sorted.begin(), sorted.end());
301 for (
auto node: sorted) {
302 if (!first) { stream << delim; }
311 std::string expandCliqueTooltip(
const NodeSet& clique) {
312 std::stringstream stream;
313 stream <<
"size : " << clique.size() <<
"\\n" << expandCliqueContent(clique,
"\\n");
317 std::string expandClique(
const NodeId n,
const NodeSet& clique) {
318 std::stringstream stream;
319 stream <<
'(' << n <<
") " << expandCliqueContent(clique);
323 std::string expandSeparator(
const NodeId n1,
324 const NodeSet& clique1,
326 const NodeSet& clique2) {
327 std::stringstream stream;
328 stream << expandClique(n1, clique1) <<
"^" << expandClique(n2, clique2);
332 std::string CliqueGraph::toDot()
const {
333 std::stringstream stream;
334 stream <<
"graph {" << std::endl;
335 stream << R
"( node [style="filled", fontcolor="black"];)" << std::endl;
338 for (
auto node: nodes()) {
339 std::string nom =
'"' + expandClique(node, clique(node)) +
'"';
340 stream <<
" " << nom <<
" [label=\"" << expandCliqueContent(clique(node)) <<
"\",tooltip=\""
341 << expandCliqueTooltip(clique(node)) << R
"(",fillcolor ="burlywood"];)" << std::endl;
347 for (
const auto& edge: edges()) {
349 << expandSeparator(edge.first(),
350 clique(edge.first()),
352 clique(edge.second()))
353 <<
"\" [label=\"" << expandCliqueContent(separator(edge)) <<
"\",tooltip=\""
354 << expandCliqueTooltip(separator(edge))
355 << R
"(",shape=box,fillcolor="palegreen",fontsize=8,width=0,height=0];)" << std::endl;
361 for (
const auto& edge: edges())
362 stream <<
" \"" << expandClique(edge.first(), clique(edge.first())) <<
"\"--\""
363 << expandSeparator(edge.first(),
364 clique(edge.first()),
366 clique(edge.second()))
367 <<
"\"--\"" << expandClique(edge.second(), clique(edge.second())) <<
"\";"
370 stream <<
"}" << std::endl;
375 std::string CliqueGraph::mapToDot(
double scaleClique,
378 const std::string& colorClique,
379 const std::string& colorSep)
const {
380 std::stringstream stream;
381 stream <<
"graph {" << std::endl;
382 stream <<
" bgcolor=transparent;" << std::endl;
383 stream <<
" layout=neato;" << std::endl << std::endl;
384 stream <<
" node [shape=point,style=filled, fillcolor =" << colorClique <<
"];" << std::endl;
385 stream <<
" edge [len=" << lenEdge <<
"];" << std::endl << std::endl;
388 for (
auto node: nodes()) {
389 const auto& clik = clique(node);
390 stream <<
" " << node <<
" [tooltip=\"" << expandCliqueTooltip(clik)
391 <<
"\", width=" << scaleClique *
double(clik.size()) <<
"];" << std::endl;
394 stream <<
" node [shape=square,style=filled, fillcolor =" << colorSep <<
",label=\"\"];"
399 for (
const auto& edge: edges()) {
401 const auto sep = clique(edge.first()) * clique(edge.second());
402 stream <<
" \"" << edge.first() <<
"~" << edge.second() <<
"\" [tooltip=\""
403 << expandCliqueTooltip(sep) <<
"\""
404 <<
", width=" << scaleSep *
double(sep.size()) <<
"];" << std::endl;
406 stream <<
" \"" << edge.first() <<
"\"--\"" << edge.first() <<
"~" << edge.second()
407 <<
"\"--\"" << edge.second() <<
"\";" << std::endl
411 stream <<
"}" << std::endl;
418 std::ostream&
operator<<(std::ostream& stream,
const CliqueGraph& graph) {
419 stream << graph.toString();
CliqueGraph(Size nodes_size=HashTableConst::default_size, bool nodes_resize_policy=true, Size edges_size=HashTableConst::default_size, bool edges_resize_policy=true)
basic constructor: creates an empty clique graph
Exception : a similar element already exists.
Class for node sets in graph.
void insert(const Key &k)
Inserts a new element into the set.
void erase(const Key &k)
Erases an element from the set.
Base class for undirected graphs.
Basic class for all graphs of cliques (join trees, etc).
inline source of basic clique graphs
#define GUM_ERROR(type, msg)
std::size_t Size
In aGrUM, hashed values are unsigned long int.
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
gum is the global namespace for all aGrUM entities
std::ostream & operator<<(std::ostream &out, const TiXmlNode &base)