33 #endif // GUM_NOINLINE 35 #ifndef DOXYGEN_SHOULD_SKIP_THIS 48 bool nodes_resize_policy,
50 bool edges_resize_policy) :
51 NodeGraphPart(nodes_size, nodes_resize_policy),
52 UndiGraph(nodes_size, nodes_resize_policy, edges_size, edges_resize_policy) {
54 GUM_CONSTRUCTOR(CliqueGraph);
62 __cliques(from.__cliques), __separators(from.__separators) {
64 GUM_CONS_CPY(CliqueGraph);
71 GUM_DESTRUCTOR(CliqueGraph);
77 const NodeId node2)
const {
80 std::vector< NodeId > path =
81 undirectedPath(container(node1), container(node2));
85 while ((path.size() >= 2) && (clique(path[path.size() - 2]).contains(node2)))
88 while ((path.size() >= 2) && (clique(path[1]).contains(node1)))
89 path.erase(path.begin());
100 NodeSet& clique = __cliques[clique_id];
103 if (clique.contains(node_id)) {
105 "the clique set already contains the node " << node_id);
108 clique.insert(node_id);
111 for (
const auto nei: neighbours(clique_id))
112 if (__cliques[nei].contains(node_id))
113 __separators[Edge(nei, clique_id)].insert(node_id);
120 NodeSet& clique = __cliques[clique_id];
123 if (clique.contains(node_id)) {
124 clique.
erase(node_id);
127 for (
const auto nei: neighbours(clique_id)) {
128 Edge edge(nei, clique_id);
130 if (__separators[edge].contains(node_id))
131 __separators[edge].erase(node_id);
141 CliqueGraph::__RunningIntersect& infos_DFS)
const {
144 const NodeSet& nodes_clique = __cliques[clique];
146 for (
const auto node: nodes_clique)
147 if (infos_DFS.nodes_other_components.contains(node))
return false;
151 for (
const auto node: nodes_clique)
152 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
153 infos_DFS.cliques_DFS_chain[clique].
erase(node);
157 if (infos_DFS.visited_cliques.contains(clique))
return true;
160 for (
const auto node: nodes_clique)
161 if (!infos_DFS.nodes_DFS_seen.contains(node))
162 infos_DFS.nodes_DFS_seen.insert(node);
165 infos_DFS.visited_cliques.insert(clique);
170 for (
const auto otherID: neighbours(clique))
171 if (otherID != from) {
174 const Edge edge(otherID, clique);
175 const NodeSet& from_separ = __separators[edge];
177 for (
const auto node: nodes_clique) {
178 if (!from_separ.contains(node))
179 infos_DFS.nodes_DFS_forbidden.
insert(node);
183 if (!__runningIntersectionDFS(otherID, clique, infos_DFS))
return false;
186 for (
const auto node: nodes_clique)
187 infos_DFS.nodes_DFS_forbidden.erase(node);
192 for (
const auto node: nodes_clique) {
193 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
194 infos_DFS.cliques_DFS_chain[clique].erase(node);
203 if (neighbours(clique).size() <= 1)
204 for (
const auto node: nodes_clique)
205 if (!infos_DFS.nodes_DFS_forbidden.contains(node))
206 infos_DFS.nodes_DFS_forbidden.insert(node);
216 __RunningIntersect infos_DFS;
217 infos_DFS.cliques_DFS_chain = __cliques;
220 for (
const auto DFSnode: nodes())
221 if (!infos_DFS.visited_cliques.contains(DFSnode)) {
223 infos_DFS.nodes_DFS_forbidden.clear();
226 infos_DFS.nodes_DFS_seen.clear();
230 if (!__runningIntersectionDFS(DFSnode, DFSnode, infos_DFS))
return false;
235 for (
const auto node: infos_DFS.nodes_DFS_seen)
236 if (!infos_DFS.nodes_other_components.contains(node))
237 infos_DFS.nodes_other_components.insert(node);
242 for (
const auto& elt: infos_DFS.cliques_DFS_chain)
243 if (!elt.second.empty())
return false;
252 if (UndiGraph::operator!=(from))
return false;
255 for (
const auto& elt: __cliques)
256 if (elt.second != from.__cliques[elt.first])
return false;
262 std::stringstream stream;
263 stream <<
"list of nodes:" << std::endl;
265 for (
const auto node: nodes()) {
266 stream <<
" -- node: " << node << std::endl <<
" clique:";
268 for (
const auto cliq: clique(node))
269 stream <<
" " << cliq;
274 stream <<
"\n\nlist of edges:\n";
276 for (
const auto edge: edges())
277 stream << edge <<
" ";
282 const std::string expandCliqueContent(
const NodeSet& clique) {
283 std::stringstream stream;
286 for (
auto node: clique) {
287 if (!first) { stream <<
"-"; }
295 const std::string expandClique(
const NodeId n,
const NodeSet& clique) {
296 std::stringstream stream;
297 stream <<
'(' << n <<
") " << expandCliqueContent(clique);
300 const std::string expandSeparator(
const NodeId n1,
304 std::stringstream stream;
305 stream << expandClique(n1, clique1) <<
"^" << expandClique(n2, clique2);
310 std::stringstream stream;
311 stream <<
"graph {" << std::endl;
312 stream <<
" node [style=\"filled\", fontcolor=\"black\"];" << std::endl;
315 for (
auto node: nodes()) {
316 std::string nom =
'"' + expandClique(node, clique(node)) +
'"';
317 stream <<
" " << nom <<
" [label=\"" << expandCliqueContent(clique(node))
318 <<
"\",fillcolor =\"burlywood\"];" << std::endl;
324 for (
auto edge: edges()) {
326 << expandSeparator(edge.first(),
327 clique(edge.first()),
329 clique(edge.second()))
330 <<
"\" [label=\"" << expandCliqueContent(separator(edge)) <<
"\"" 331 <<
",shape=box,fillcolor=\"palegreen\",fontsize=8," 339 for (
auto edge: edges())
340 stream <<
" \"" << expandClique(edge.first(), clique(edge.first()))
342 << expandSeparator(edge.first(),
343 clique(edge.first()),
345 clique(edge.second()))
346 <<
"\"--\"" << expandClique(edge.second(), clique(edge.second()))
347 <<
"\";" << std::endl;
349 stream <<
"}" << std::endl;
356 std::ostream&
operator<<(std::ostream& stream,
const CliqueGraph& graph) {
357 stream << graph.toString();
bool operator==(const CliqueGraph &from) const
checks whether two clique graphs are equal
Set< NodeId > NodeSet
Some typdefs and define for shortcuts ...
virtual const std::string toDot() const
friendly displays the content of the CliqueGraph in DOT format
void erase(const Key &k)
Erases an element from the set.
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
bool __runningIntersectionDFS(const NodeId clique, const NodeId from, __RunningIntersect &infos_DFS) const
function used for the computation of the running intersection property
virtual ~CliqueGraph()
destructor
std::ostream & operator<<(std::ostream &output, const BayesNet< GUM_SCALAR > &bn)
Prints map's DAG in output using the Graphviz-dot format.
virtual void addToClique(const NodeId clique_id, const NodeId node_id)
changes the set of nodes included into a given clique and returns the new set
virtual const std::string toString() const
friendly displays the content of the CliqueGraph
std::vector< NodeId > containerPath(const NodeId node1, const NodeId node2) const
returns a path from a clique containing node1 to a clique containing node2
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
std::size_t Size
In aGrUM, hashed values are unsigned long int.
virtual void eraseFromClique(const NodeId clique_id, const NodeId node_id)
remove a node from a clique
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.
Size NodeId
Type for node ids.
void insert(const Key &k)
Inserts a new element into the set.
bool hasRunningIntersection() const
indicates whether the running intersection property holds
#define GUM_ERROR(type, msg)
Copyright 2005-2019 Pierre-Henri WUILLEMIN et Christophe GONZALES (LIP6) {prenom.nom}_at_lip6.fr.