Chris@16
|
1 // Copyright 2004, 2005 The Trustees of Indiana University.
|
Chris@16
|
2
|
Chris@16
|
3 // Use, modification and distribution is subject to the Boost Software
|
Chris@16
|
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
5 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
6
|
Chris@16
|
7 // Authors: Nick Edmonds
|
Chris@16
|
8 // Andrew Lumsdaine
|
Chris@16
|
9 #ifndef BOOST_GRAPH_SSCA_GENERATOR_HPP
|
Chris@16
|
10 #define BOOST_GRAPH_SSCA_GENERATOR_HPP
|
Chris@16
|
11
|
Chris@16
|
12 #include <iterator>
|
Chris@16
|
13 #include <utility>
|
Chris@16
|
14 #include <vector>
|
Chris@16
|
15 #include <queue>
|
Chris@16
|
16 #include <boost/config.hpp>
|
Chris@16
|
17 #include <boost/random/uniform_int.hpp>
|
Chris@16
|
18 #include <boost/graph/graph_traits.hpp>
|
Chris@16
|
19 #include <boost/type_traits/is_base_and_derived.hpp>
|
Chris@16
|
20 #include <boost/type_traits/is_same.hpp>
|
Chris@16
|
21
|
Chris@16
|
22 enum Direction {FORWARD = 1, BACKWARD = 2, BOTH = FORWARD | BACKWARD};
|
Chris@16
|
23
|
Chris@16
|
24 namespace boost {
|
Chris@16
|
25
|
Chris@16
|
26 // This generator generates graphs according to the method specified
|
Chris@16
|
27 // in SSCA 1.1. Current versions of SSCA use R-MAT graphs
|
Chris@16
|
28
|
Chris@16
|
29 template<typename RandomGenerator, typename Graph>
|
Chris@16
|
30 class ssca_iterator
|
Chris@16
|
31 {
|
Chris@16
|
32 typedef typename graph_traits<Graph>::directed_category directed_category;
|
Chris@16
|
33 typedef typename graph_traits<Graph>::vertices_size_type
|
Chris@16
|
34 vertices_size_type;
|
Chris@16
|
35
|
Chris@16
|
36 public:
|
Chris@16
|
37 typedef std::input_iterator_tag iterator_category;
|
Chris@16
|
38 typedef std::pair<vertices_size_type, vertices_size_type> value_type;
|
Chris@16
|
39 typedef const value_type& reference;
|
Chris@16
|
40 typedef const value_type* pointer;
|
Chris@16
|
41 typedef void difference_type;
|
Chris@16
|
42
|
Chris@16
|
43 // No argument constructor, set to terminating condition
|
Chris@16
|
44 ssca_iterator()
|
Chris@16
|
45 : gen(), verticesRemaining(0) { }
|
Chris@16
|
46
|
Chris@16
|
47 // Initialize for edge generation
|
Chris@16
|
48 ssca_iterator(RandomGenerator& gen, vertices_size_type totVertices,
|
Chris@16
|
49 vertices_size_type maxCliqueSize, double probUnidirectional,
|
Chris@16
|
50 int maxParallelEdges, double probIntercliqueEdges)
|
Chris@16
|
51 : gen(&gen), totVertices(totVertices), maxCliqueSize(maxCliqueSize),
|
Chris@16
|
52 probUnidirectional(probUnidirectional), maxParallelEdges(maxParallelEdges),
|
Chris@16
|
53 probIntercliqueEdges(probIntercliqueEdges), currentClique(0),
|
Chris@16
|
54 verticesRemaining(totVertices)
|
Chris@16
|
55 {
|
Chris@16
|
56 cliqueNum = std::vector<int>(totVertices, -1);
|
Chris@16
|
57 current = std::make_pair(0,0);
|
Chris@16
|
58 }
|
Chris@16
|
59
|
Chris@16
|
60 reference operator*() const { return current; }
|
Chris@16
|
61 pointer operator->() const { return ¤t; }
|
Chris@16
|
62
|
Chris@16
|
63 ssca_iterator& operator++()
|
Chris@16
|
64 {
|
Chris@16
|
65 BOOST_USING_STD_MIN();
|
Chris@16
|
66 while (values.empty() && verticesRemaining > 0) { // If there are no values left, generate a new clique
|
Chris@16
|
67 uniform_int<vertices_size_type> clique_size(1, maxCliqueSize);
|
Chris@16
|
68 uniform_int<vertices_size_type> rand_vertex(0, totVertices-1);
|
Chris@16
|
69 uniform_int<int> num_parallel_edges(1, maxParallelEdges);
|
Chris@16
|
70 uniform_int<short> direction(0,1);
|
Chris@16
|
71 uniform_01<RandomGenerator> prob(*gen);
|
Chris@16
|
72 std::vector<vertices_size_type> cliqueVertices;
|
Chris@16
|
73
|
Chris@16
|
74 cliqueVertices.clear();
|
Chris@16
|
75 vertices_size_type size = min BOOST_PREVENT_MACRO_SUBSTITUTION (clique_size(*gen), verticesRemaining);
|
Chris@16
|
76 while (cliqueVertices.size() < size) {
|
Chris@16
|
77 vertices_size_type v = rand_vertex(*gen);
|
Chris@16
|
78 if (cliqueNum[v] == -1) {
|
Chris@16
|
79 cliqueNum[v] = currentClique;
|
Chris@16
|
80 cliqueVertices.push_back(v);
|
Chris@16
|
81 verticesRemaining--;
|
Chris@16
|
82 }
|
Chris@16
|
83 } // Nick: This is inefficient when only a few vertices remain...
|
Chris@16
|
84 // I should probably just select the remaining vertices
|
Chris@16
|
85 // in order when only a certain fraction remain.
|
Chris@16
|
86
|
Chris@16
|
87 typename std::vector<vertices_size_type>::iterator first, second;
|
Chris@16
|
88 for (first = cliqueVertices.begin(); first != cliqueVertices.end(); ++first)
|
Chris@16
|
89 for (second = first+1; second != cliqueVertices.end(); ++second) {
|
Chris@16
|
90 Direction d;
|
Chris@16
|
91 int edges;
|
Chris@16
|
92
|
Chris@16
|
93 d = prob() < probUnidirectional ? (direction(*gen) == 0 ? FORWARD : BACKWARD) : BOTH;
|
Chris@16
|
94
|
Chris@16
|
95 if (d & FORWARD) {
|
Chris@16
|
96 edges = num_parallel_edges(*gen);
|
Chris@16
|
97 for (int i = 0; i < edges; ++i)
|
Chris@16
|
98 values.push(std::make_pair(*first, *second));
|
Chris@16
|
99 }
|
Chris@16
|
100
|
Chris@16
|
101 if (d & BACKWARD) {
|
Chris@16
|
102 edges = num_parallel_edges(*gen);
|
Chris@16
|
103 for (int i = 0; i < edges; ++i)
|
Chris@16
|
104 values.push(std::make_pair(*second, *first));
|
Chris@16
|
105 }
|
Chris@16
|
106 }
|
Chris@16
|
107
|
Chris@16
|
108 if (verticesRemaining == 0) {
|
Chris@16
|
109 // Generate interclique edges
|
Chris@16
|
110 for (vertices_size_type i = 0; i < totVertices; ++i) {
|
Chris@16
|
111 double p = probIntercliqueEdges;
|
Chris@16
|
112 for (vertices_size_type d = 2; d < totVertices/2; d *= 2, p/= 2) {
|
Chris@16
|
113 vertices_size_type j = (i+d) % totVertices;
|
Chris@16
|
114 if (cliqueNum[j] != cliqueNum[i] && prob() < p) {
|
Chris@16
|
115 int edges = num_parallel_edges(*gen);
|
Chris@16
|
116 for (int i = 0; i < edges; ++i)
|
Chris@16
|
117 values.push(std::make_pair(i, j));
|
Chris@16
|
118 }
|
Chris@16
|
119 }
|
Chris@16
|
120 }
|
Chris@16
|
121 }
|
Chris@16
|
122
|
Chris@16
|
123 currentClique++;
|
Chris@16
|
124 }
|
Chris@16
|
125
|
Chris@16
|
126 if (!values.empty()) { // If we're not done return a value
|
Chris@16
|
127 current = values.front();
|
Chris@16
|
128 values.pop();
|
Chris@16
|
129 }
|
Chris@16
|
130
|
Chris@16
|
131 return *this;
|
Chris@16
|
132 }
|
Chris@16
|
133
|
Chris@16
|
134 ssca_iterator operator++(int)
|
Chris@16
|
135 {
|
Chris@16
|
136 ssca_iterator temp(*this);
|
Chris@16
|
137 ++(*this);
|
Chris@16
|
138 return temp;
|
Chris@16
|
139 }
|
Chris@16
|
140
|
Chris@16
|
141 bool operator==(const ssca_iterator& other) const
|
Chris@16
|
142 {
|
Chris@16
|
143 return verticesRemaining == other.verticesRemaining && values.empty() && other.values.empty();
|
Chris@16
|
144 }
|
Chris@16
|
145
|
Chris@16
|
146 bool operator!=(const ssca_iterator& other) const
|
Chris@16
|
147 { return !(*this == other); }
|
Chris@16
|
148
|
Chris@16
|
149 private:
|
Chris@16
|
150
|
Chris@16
|
151 // Parameters
|
Chris@16
|
152 RandomGenerator* gen;
|
Chris@16
|
153 vertices_size_type totVertices;
|
Chris@16
|
154 vertices_size_type maxCliqueSize;
|
Chris@16
|
155 double probUnidirectional;
|
Chris@16
|
156 int maxParallelEdges;
|
Chris@16
|
157 double probIntercliqueEdges;
|
Chris@16
|
158
|
Chris@16
|
159 // Internal data structures
|
Chris@16
|
160 std::vector<int> cliqueNum;
|
Chris@16
|
161 std::queue<value_type> values;
|
Chris@16
|
162 int currentClique;
|
Chris@16
|
163 vertices_size_type verticesRemaining;
|
Chris@16
|
164 value_type current;
|
Chris@16
|
165 };
|
Chris@16
|
166
|
Chris@16
|
167 } // end namespace boost
|
Chris@16
|
168
|
Chris@16
|
169 #endif // BOOST_GRAPH_SSCA_GENERATOR_HPP
|