ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
Graph.h
Go to the documentation of this file.
1/**
2 * @file Graph.h
3 * @brief Undirected graph used in tree-decomposition computations.
4 *
5 * Originally taken and adapted from https://github.com/smaniu/treewidth
6 *
7 * @c Graph is a mutable, adjacency-list-based undirected (or directed)
8 * graph over @c unsigned @c long node IDs. It is used during the
9 * tree-decomposition algorithm to represent the "primal graph" of a
10 * @c BooleanCircuit: nodes correspond to gates and edges connect gates
11 * that are connected by a wire.
12 *
13 * The mutating operations (@c remove_node, @c fill, @c contract_edge)
14 * are used by the elimination-ordering heuristic implemented in
15 * @c PermutationStrategy and @c TreeDecomposition.
16 */
17#ifndef Graph_h
18#define Graph_h
19#include <cstdlib>
20#include <unordered_map>
21#include <unordered_set>
22#include <cassert>
23
24#include "BooleanCircuit.h"
25
26/**
27 * @brief Mutable adjacency-list graph over unsigned-long node IDs.
28 *
29 * Supports both directed and undirected edges, node/edge removal,
30 * clique-fill operations, and edge contraction, as needed by the
31 * min-fill tree-decomposition algorithm.
32 */
33class Graph {
34private:
35std::unordered_map<unsigned long, std::unordered_set<unsigned long> > adj_list; ///< Adjacency lists
36std::unordered_set<unsigned long> node_set; ///< Set of all node IDs
37unsigned long num_edges = 0; ///< Current edge count
38
39public:
40/**
41 * @brief Construct the primal graph of a @c BooleanCircuit.
42 *
43 * Each gate (except @c UNDETERMINED and @c MULVAR) becomes a node.
44 * Each wire between two gates becomes an undirected edge.
45 *
46 * @param bc The Boolean circuit whose structure defines the graph.
47 */
49{
50 for(gate_t g1{0}; g1<bc.getNbGates(); ++g1) {
51 // We do not take into account these gates, which have no purpose
52 // in the circuit
54 continue;
55
56 add_node(static_cast<unsigned long>(g1));
57 for(auto g2: bc.getWires(g1))
58 add_edge(static_cast<unsigned long>(g1), static_cast<unsigned long>(g2), true);
59 }
60}
61
62/**
63 * @brief Add an edge between @p src and @p tgt.
64 *
65 * If the edge already exists the call is a no-op. Both endpoint nodes
66 * are added to @c node_set if not already present.
67 *
68 * @param src Source node.
69 * @param tgt Target node.
70 * @param undirected If @c true, also add the reverse edge.
71 */
72void add_edge(unsigned long src, unsigned long tgt, bool undirected=true){
73 if(!has_edge(src, tgt)) {
74 node_set.insert(src);
75 node_set.insert(tgt);
76 adj_list[src].insert(tgt);
77 if(undirected) adj_list[tgt].insert(src);
78 num_edges++;
79 }
80};
81
82/**
83 * @brief Add @p node to the graph (no edges).
84 * @param node Node ID to insert.
85 */
86void add_node(unsigned long node){
87 node_set.insert(node);
88}
89
90/**
91 * @brief Remove @p node and all its incident edges.
92 *
93 * @param node Node ID to remove.
94 * @return The adjacency set of @p node before removal.
95 */
96std::unordered_set<unsigned long> remove_node(unsigned long node){
97 node_set.erase(node);
98 for(auto neighbour:adj_list[node]) {
99 adj_list[neighbour].erase(node);
100 num_edges--;
101 }
102 auto it = adj_list.find(node);
103 auto adjacency_list = std::move(it->second);
104 adj_list.erase(it);
105 return adjacency_list;
106}
107
108/**
109 * @brief Test whether two nodes share more than @p k-1 common neighbours.
110 *
111 * Used by the min-fill heuristic to decide whether eliminating a node
112 * improves the treewidth bound.
113 *
114 * @param k Treewidth bound being tested.
115 * @param n1 First node.
116 * @param n2 Second node.
117 * @return @c true if the common-neighbour count exceeds @p k-1.
118 */
119bool neighbour_improved(unsigned k,unsigned long n1, unsigned long n2){
120 bool retval = false;
121 auto &neigh1 = get_neighbours(n1);
122 auto &neigh2 = get_neighbours(n2);
123
124 unsigned long count = 0;
125 if (neigh1.size()>k-1 && neigh2.size()>k-1) {
126 for (auto nn1:neigh1) {
127 for (auto nn2:neigh2) {
128 if (nn1==nn2) {
129 count = count+1;
130 break;
131 }
132
133 }
134 }
135 }
136 if (count > k-1) {
137 retval = true;
138 }
139
140 return retval;
141}
142
143/**
144 * @brief Add all missing edges within @p nodes (clique fill).
145 *
146 * Connects every pair of nodes in @p nodes that is not already connected,
147 * making the subgraph induced by @p nodes into a clique.
148 *
149 * @param nodes Set of node IDs to fill.
150 * @param undirected If @c true, add edges in both directions.
151 */
152void fill(const std::unordered_set<unsigned long>& nodes, \
153 bool undirected=true){
154 for(auto src: nodes)
155 for(auto tgt: nodes)
156 if(undirected) {
157 if(src<tgt)
158 add_edge(src, tgt, undirected);
159 }
160 else{
161 if(src!=tgt)
162 add_edge(src, tgt, undirected);
163 }
164
165}
166
167/**
168 * @brief Contract the edge (src, tgt) by merging @p tgt into @p src.
169 *
170 * All edges from @p tgt are redirected to @p src, then @p tgt is removed.
171 *
172 * @param src The node that survives the contraction.
173 * @param tgt The node to be merged into @p src.
174 */
175void contract_edge(unsigned long src, unsigned long tgt){
176 for(auto v:get_neighbours(tgt))
177 if((v!=src)&&!has_edge(src,v)) add_edge(src,v);
178 remove_node(tgt);
179}
180
181/**
182 * @brief Return @c true if @p node has any adjacent edges.
183 * @param node Node to query.
184 * @return @c true if the adjacency list contains an entry for @p node.
185 */
186bool has_neighbours(unsigned long node) const {
187 return adj_list.find(node)!=adj_list.end();
188}
189
190/**
191 * @brief Return @c true if @p node is present in the graph.
192 * @param node Node to query.
193 * @return @c true if @p node exists in the node set.
194 */
195bool has_node(unsigned long node) const {
196 return node_set.find(node)!=node_set.end();
197}
198
199/**
200 * @brief Return @c true if a directed edge from @p src to @p tgt exists.
201 * @param src Source node.
202 * @param tgt Target node.
203 * @return @c true if the edge @p src → @p tgt is present.
204 */
205bool has_edge(unsigned long src, unsigned long tgt) {
206 bool retval = false;
207 if(has_neighbours(src)) {
208 auto &neigh = get_neighbours(src);
209 retval = neigh.find(tgt)!=neigh.end();
210 }
211 return retval;
212}
213
214/**
215 * @brief Return the neighbour set of @p node.
216 *
217 * @p node must be present in the graph (asserted in debug builds).
218 *
219 * @param node Node to query.
220 * @return Const reference to the adjacency set.
221 */
222const std::unordered_set<unsigned long> &get_neighbours(unsigned long node) const {
223 assert(has_node(node));
224
225 return (adj_list.find(node))->second;
226}
227
228/**
229 * @brief Return the set of all node IDs in the graph.
230 * @return Const reference to the node set.
231 */
232const std::unordered_set<unsigned long> &get_nodes() const {
233 return node_set;
234}
235
236/**
237 * @brief Return the number of nodes in the graph.
238 * @return Total node count.
239 */
240unsigned long number_nodes() const {
241 return node_set.size();
242}
243
244/**
245 * @brief Return the number of edges in the graph.
246 * @return Total edge count.
247 */
248unsigned long number_edges() const {
249 return num_edges;
250}
251};
252
253
254#endif /* Graph_h */
Boolean provenance circuit with support for knowledge compilation.
@ MULVAR
Auxiliary gate grouping all MULIN siblings.
@ UNDETERMINED
Placeholder gate whose type has not been set yet.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:48
Boolean circuit for provenance formula evaluation.
std::vector< gate_t > & getWires(gate_t g)
Return a mutable reference to the child-wire list of gate g.
Definition Circuit.h:139
gateType getGateType(gate_t g) const
Return the type of gate g.
Definition Circuit.h:129
std::vector< gate_t >::size_type getNbGates() const
Return the total number of gates in the circuit.
Definition Circuit.h:102
Mutable adjacency-list graph over unsigned-long node IDs.
Definition Graph.h:33
void add_edge(unsigned long src, unsigned long tgt, bool undirected=true)
Add an edge between src and tgt.
Definition Graph.h:72
void fill(const std::unordered_set< unsigned long > &nodes, bool undirected=true)
Add all missing edges within nodes (clique fill).
Definition Graph.h:152
bool has_node(unsigned long node) const
Return true if node is present in the graph.
Definition Graph.h:195
std::unordered_set< unsigned long > node_set
Set of all node IDs.
Definition Graph.h:36
void add_node(unsigned long node)
Add node to the graph (no edges).
Definition Graph.h:86
unsigned long number_edges() const
Return the number of edges in the graph.
Definition Graph.h:248
const std::unordered_set< unsigned long > & get_nodes() const
Return the set of all node IDs in the graph.
Definition Graph.h:232
void contract_edge(unsigned long src, unsigned long tgt)
Contract the edge (src, tgt) by merging tgt into src.
Definition Graph.h:175
bool has_edge(unsigned long src, unsigned long tgt)
Return true if a directed edge from src to tgt exists.
Definition Graph.h:205
bool has_neighbours(unsigned long node) const
Return true if node has any adjacent edges.
Definition Graph.h:186
std::unordered_set< unsigned long > remove_node(unsigned long node)
Remove node and all its incident edges.
Definition Graph.h:96
unsigned long num_edges
Current edge count.
Definition Graph.h:37
const std::unordered_set< unsigned long > & get_neighbours(unsigned long node) const
Return the neighbour set of node.
Definition Graph.h:222
bool neighbour_improved(unsigned k, unsigned long n1, unsigned long n2)
Test whether two nodes share more than k-1 common neighbours.
Definition Graph.h:119
std::unordered_map< unsigned long, std::unordered_set< unsigned long > > adj_list
Adjacency lists.
Definition Graph.h:35
Graph(const BooleanCircuit &bc)
Construct the primal graph of a BooleanCircuit.
Definition Graph.h:48
unsigned long number_nodes() const
Return the number of nodes in the graph.
Definition Graph.h:240