GraphLab: Distributed Graph-Parallel API  2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vertex_set.hpp
1 /*
2  * Copyright (c) 2009 Carnegie Mellon University.
3  * All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing,
12  * software distributed under the License is distributed on an "AS
13  * IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
14  * express or implied. See the License for the specific language
15  * governing permissions and limitations under the License.
16  *
17  * For more about this software visit:
18  *
19  * http://www.graphlab.ml.cmu.edu
20  *
21  */
22 
23 
24 
25 #ifndef GRAPHLAB_GRAPH_VERTEX_SET_HPP
26 #define GRAPHLAB_GRAPH_VERTEX_SET_HPP
27 
28 #include <graphlab/util/dense_bitset.hpp>
29 #include <graphlab/graph/graph_basic_types.hpp>
30 #include <graphlab/rpc/buffered_exchange.hpp>
31 #include <graphlab/macros_def.hpp>
32 
33 namespace graphlab {
34 
35 /**
36  * \brief Describes a set of vertices
37  *
38  * The vertex_set describes a set of vertices upon which
39  * union / intersection / difference can be performed.
40  * These sets can then be passed into graph aggregate operations
41  * such as distributed_graph::map_reduce_vertices to perform aggregates
42  * over \b subsets of vertices or edges. Engines also permit signalling of
43  * sets of vertices through
44  * \ref graphlab::iengine::signal_all(const vertex_set& vset, const message_type& message, const std::string& order) "signal_all()".
45  *
46  * \ref distributed_graph::complete_set() and \ref distributed_graph::empty_set()
47  * provide two convenient functions to obtain a full or an empty set of
48  * vertices.
49  * \code
50  * vertex_set all = graph.complete_set();
51  * vertex_set empty = graph.empty_set();
52  * \endcode
53  *
54  * \ref distributed_graph::select() can be used to obtain a restriction of the
55  * set of vertices. For instance if vertices contain an integer, the following
56  * code will construct a set of vertices containing only vertices with data
57  * which are a multiple of 2.
58  *
59  * \code
60  * bool is_multiple_of_2(const graph_type::vertex_type& vertex) {
61  * return vertex.data() % 2 == 0;
62  * }
63  * vertex_set even_vertices = graph.select(is_multiple_of_2);
64  * \endcode
65  * For more details see \ref distributed_graph::select()
66  *
67  * The size of the vertex set can only be queried through the graph using
68  * \ref distributed_graph::vertex_set_size();
69  *
70  */
71 class vertex_set {
72  private:
73  /**
74  * Used only if \ref lazy is false.
75  * If \ref lazy is false, this must be the same size as the graph's
76  * graphlab::distributed_graph::num_local_vertices().
77  * The invariant is that the bit value of each mirror vertex must be the
78  * same value as the bit value on their corresponding master vertices.
79  */
80  mutable dense_bitset localvset;
81 
82  /**
83  * Used only if \ref lazy is set.
84  * If is_complete_set is true, this set describes the set of all vertices.
85  * If is_complete set is false, this set describes the empty set.
86  */
87  bool is_complete_set;
88 
89  /**
90  * If set, the localvset is empty and not used.
91  * instead, \ref is_complete_set will define the set of vertices.
92  */
93  mutable bool lazy;
94 
95 
96  /**
97  * \internal
98  * \brief Returns a const reference to the underlying bitset.
99  */
100  template <typename DGraphType>
101  const dense_bitset& get_lvid_bitset(const DGraphType& dgraph) const {
102  if (lazy) make_explicit(dgraph);
103  return localvset;
104  }
105 
106 
107  /**
108  * \internal
109  * Sets a bit in the bitset without local threading
110  * synchronization. vertex set must be made explicit. This call does not
111  * perform remote synchronization and addititional distributed
112  * synchronization calls must be made to restore datastructure invariants.
113  */
114  inline void set_lvid_unsync(lvid_type lvid) {
115  ASSERT_FALSE(lazy);
116  localvset.set_bit_unsync(lvid);
117  }
118 
119 
120  /**
121  * \internal
122  * Sets a bit in the bitset with local threading
123  * synchronization. vertex set must be made explicit. This call does not
124  * perform remote synchronization and addititional distributed
125  * synchronization calls must be made to restore datastructure invariants.
126  */
127  inline void set_lvid(lvid_type lvid) {
128  ASSERT_FALSE(lazy);
129  localvset.set_bit(lvid);
130  }
131 
132  /**
133  * \internal
134  * Makes the internal representation explicit by clearing the lazy flag
135  * and filling the bitset.
136  */
137  template <typename DGraphType>
138  void make_explicit(const DGraphType& dgraph) const {
139  if (lazy) {
140  localvset.resize(dgraph.num_local_vertices());
141  if (is_complete_set) {
142  localvset.fill();
143  }
144  else {
145  localvset.clear();
146  }
147  lazy = false;
148  }
149  }
150 
151  /**
152  * \internal
153  * Copies the master state to each mirror.
154  * Restores the datastructure invariants.
155  */
156  template <typename DGraphType>
157  void synchronize_master_to_mirrors(DGraphType& dgraph,
158  buffered_exchange<vertex_id_type>& exchange) {
159  if (lazy) {
160  make_explicit(dgraph);
161  return;
162  }
163  foreach(size_t lvid, localvset) {
164  typename DGraphType::local_vertex_type lvtx = dgraph.l_vertex(lvid);
165  if (lvtx.owned()) {
166  // send to mirrors
167  vertex_id_type gvid = lvtx.global_id();
168  foreach(size_t proc, lvtx.mirrors()) {
169  exchange.send(proc, gvid);
170  }
171  }
172  else {
173  localvset.clear_bit_unsync(lvid);
174  }
175  }
176  exchange.flush();
177 
178  typename buffered_exchange<vertex_id_type>::buffer_type recv_buffer;
179  procid_t sending_proc;
180 
181  while(exchange.recv(sending_proc, recv_buffer)) {
182  foreach(vertex_id_type gvid, recv_buffer) {
183  localvset.set_bit_unsync(dgraph.vertex(gvid).local_id());
184  }
185  recv_buffer.clear();
186  }
187  }
188 
189 
190  /**
191  * \internal
192  * Let the master state be the logical OR of the mirror states.
193  */
194  template <typename DGraphType>
195  void synchronize_mirrors_to_master_or(DGraphType& dgraph,
196  buffered_exchange<vertex_id_type>& exchange) {
197  if (lazy) {
198  make_explicit(dgraph);
199  return;
200  }
201  foreach(size_t lvid, localvset) {
202  typename DGraphType::local_vertex_type lvtx = dgraph.l_vertex(lvid);
203  if (!lvtx.owned()) {
204  // send to master
205  vertex_id_type gvid = lvtx.global_id();
206  exchange.send(lvtx.owner(), gvid);
207  }
208  }
209  exchange.flush();
210 
211  typename buffered_exchange<vertex_id_type>::buffer_type recv_buffer;
212  procid_t sending_proc;
213 
214  while(exchange.recv(sending_proc, recv_buffer)) {
215  foreach(vertex_id_type gvid, recv_buffer) {
216  localvset.set_bit_unsync(dgraph.vertex(gvid).local_id());
217  }
218  recv_buffer.clear();
219  }
220  }
221 
222  template <typename VertexType, typename EdgeType>
223  friend class distributed_graph;
224 
225  public:
226  /// default constructor which constructs an empty set.
227  vertex_set():is_complete_set(false), lazy(true){}
228 
229 
230  /** Constructs a completely empty, or a completely full vertex set
231  * \param complete If set to true, creates a set of all vertices.
232  * If set to false, creates an empty set.
233  */
234  explicit vertex_set(bool complete):is_complete_set(complete),lazy(true){}
235 
236  /// copy constructor
237  inline vertex_set(const vertex_set& other):
238  localvset(other.localvset),
239  is_complete_set(other.is_complete_set),
240  lazy(other.lazy) {}
241 
242  /// copyable
243  inline vertex_set& operator=(const vertex_set& other) {
244  localvset = other.localvset;
245  is_complete_set = other.is_complete_set;
246  lazy = other.lazy;
247  return *this;
248  }
249 
250  /**
251  * \internal
252  * Queries if a local vertex ID is contained within the vertex set
253  */
254  inline bool l_contains(lvid_type lvid) const {
255  if (lazy) return is_complete_set;
256  if (lvid < localvset.size()) {
257  return localvset.get(lvid);
258  }
259  else {
260  return false;
261  }
262  }
263 
264  /**
265  * \brief Takes the set intersection of two vertex sets.
266  *
267  * \code
268  * vertex_set intersection_result = a & b;
269  * \endcode
270  * A vertex is in \c intersection_result if and only if the vertex is in
271  * \b both set \c a and set \c b.
272  */
273  inline vertex_set operator&(const vertex_set& other) const {
274  vertex_set ret = (*this);
275  ret &= other;
276  return ret;
277  }
278 
279  /**
280  * \brief Takes the set union of two vertex sets.
281  *
282  * \code
283  * vertex_set union_result = a | b;
284  * \endcode
285  * A vertex is in \c union_result if and only if the vertex is in
286  * \b either of set \c a and set \c b.
287  *
288  */
289  inline vertex_set operator|(const vertex_set& other) const {
290  vertex_set ret = (*this);
291  ret |= other;
292  return ret;
293  }
294 
295 
296  /**
297  * \brief Takes the set difference of two vertex sets.
298  *
299  * \code
300  * vertex_set difference_result = a - b;
301  * \endcode
302  * A vertex is in \c difference_result if and only if the vertex is in
303  * set a and not in set b.
304  *
305  * Equivalent to:
306  *
307  * \code
308  * vertex_set inv_b = ~b;
309  * vertex_set difference_result = a & inv_b;
310  * \endcode
311  */
312  inline vertex_set operator-(const vertex_set& other) const {
313  vertex_set ret = (*this);
314  ret -= other;
315  return ret;
316  }
317 
318 
319  /**
320  * \brief Takes the set intersection of the current vertex set with another
321  * vertex set.
322  *
323  * \code
324  * a &= b;
325  * \endcode
326  * A vertex is in the resultant \c a if and only if the vertex was in
327  * \b both set \c a and set \c b.
328  */
329  inline vertex_set& operator&=(const vertex_set& other) {
330  if (lazy) {
331  if (is_complete_set) (*this) = other;
332  else (*this) = vertex_set(false);
333  }
334  else if (other.lazy) {
335  if (other.is_complete_set) /* no op */;
336  else (*this) = vertex_set(false);
337  }
338  else {
339  localvset &= other.localvset;
340  }
341  return *this;
342  }
343 
344  /**
345  * \brief Takes the set union of the current vertex set with another
346  * vertex set.
347  *
348  * \code
349  * a |= b;
350  * \endcode
351  * A vertex is in the resultant \c a if and only if the vertex was in
352  * \b either set \c a and set \c b.
353  */
354  inline vertex_set& operator|=(const vertex_set& other) {
355  if (lazy) {
356  if (is_complete_set) (*this) = vertex_set(true);
357  else (*this) = other;
358  }
359  else if (other.lazy) {
360  if (other.is_complete_set) (*this) = vertex_set(true);
361  else /* no op */;
362  }
363  else {
364  localvset |= other.localvset;
365  }
366  return *this;
367  }
368 
369  /**
370  * \brief Takes the set difference of the current vertex set with another
371  * vertex set.
372  *
373  * \code
374  * a -= b;
375  * \endcode
376  * A vertex is in the resultant \c a if and only if the vertex was in
377  * set \c a but not in set \c b.
378  *
379  * Conceptually equivalent to
380  * \code
381  * a &= ~b;
382  * \endcode
383  */
384  inline vertex_set& operator-=(const vertex_set& other) {
385  if (lazy) {
386  if (is_complete_set) (*this) = ~other;
387  else (*this) = vertex_set(false);
388  }
389  else if (other.lazy) {
390  if (other.is_complete_set) (*this) = vertex_set(false);
391  else /* no op */;
392  }
393  else {
394  localvset -= other.localvset;
395  }
396  return *this;
397  }
398 
399  /**
400  * \brief Returns the inverse of the current set.
401  *
402  * \code
403  * vertex_set inv_b = ~b;
404  * \endcode
405  * A vertex is in \c inv_b if and only if it is not in \c b
406  */
407  inline vertex_set operator~() const {
408  vertex_set ret(*this);
409  ret.invert();
410  return ret;
411  }
412 
413  /**
414  * \brief Inverts the current set in-place.
415  *
416  * \code
417  * b.invert();
418  * \endcode
419  * A vertex is in the result \c b if and only if it is not in \c b
420  */
421  inline void invert() {
422  if (lazy) {
423  is_complete_set = !is_complete_set;
424  }
425  else {
426  localvset.invert();
427  }
428  }
429 
430 
431 };
432 
433 
434 } // namespace graphlab
435 #include <graphlab/macros_undef.hpp>
436 #endif