1 /*
2 * GraphMaker.cpp
3 *
4 * Created on: June 16, 2010
5 * Author: bedutra
6 */
7
8
9
10 #include "GraphMaker.h"
11 #include "BuildHypersimplexEdgePolytope.h" //needed to make Kneser Graph.
12
13 using namespace std;
14
15
GraphMaker()16 GraphMaker::GraphMaker()
17 {
18 numVertex = 0;
19 srand(time(0));
20 }//graphMaker()
21
22
23
24 /**
25 * Adds the edge (v1, v2) or (v2, v1) to the graph if the edge does not already exist.
26 * @return bool: true of new edge added, false if edge already exists.
27 */
addEdgeInOrder(const int v1,const int v2)28 bool GraphMaker::addEdgeInOrder(const int v1, const int v2)
29 {
30 if (v1 <= v2 )
31 {
32 if (find(edges[v1].begin(), edges[v1].end(), v2) == edges[v1].end())
33 {
34 edges[v1].push_back(v2);
35 return true;
36 }//not found. so add it.
37 else
38 return false;
39 }
40 else
41 return addEdgeInOrder(v2, v1);
42 }//addEdgeInOrder
43
44 /**
45 * Returns a const reference to the edges structure.
46 */
getEdges() const47 const vector< vector<int> > & GraphMaker::getEdges() const
48 {
49 return edges;
50 }//getEdges
51
52
53 /**
54 * Makes a rectangle graph:
55 * 0 1 2 3
56 * 4 5 6 7
57 * 8 9 10 11
58 * Each node is connected to its neighbors to the top/bottom and left/right with no wrapping (4 and 7 are not connected but 4 and 5 are).
59 */
makeCheckerboard(const int row,const int col)60 void GraphMaker::makeCheckerboard(const int row, const int col)
61 {
62
63 if ( row <= 1 || col <= 1)
64 {
65 cout << "makeLinearGraph(): please give a row/col larger than 1" << endl;
66 return;
67 }//if crapy size.
68
69 numVertex = row * col;
70 edges.clear();
71 edges.resize(numVertex);
72 for(int k = 0; k < numVertex; ++k) edges[k].clear();
73
74 //How to think about edges: consider a row x col matrix (with index starting at zero!)
75 // we save this 2D matrix in 1D array using row-first order. So the (a, b) element of
76 // the matrix (again, index starts at 0) is saved in location row*a + b
77
78 //first process a (row-1)x(col -1) grid and then fix the right and lower edges.
79 for(int currentRow = 0; currentRow < row - 1; ++currentRow )
80 {
81 for(int currentCol = 0; currentCol < col - 1; ++currentCol)
82 {
83 int rowIndex = currentRow * col;
84
85 edges[rowIndex + currentCol].push_back(rowIndex + currentCol + 1);
86 edges[rowIndex + currentCol].push_back((currentRow + 1)*col + currentCol);
87 }//for currentCol
88 }//for currentRow
89
90 //now fix the right edge
91 for(int currentRow = 0; currentRow < row -1; ++currentRow)
92 {
93 edges[currentRow*col + col - 1].push_back((currentRow + 1)*col + col -1);
94 }//for currentRow
95
96 //now fix the bottom edge.
97 for(int currentCol = 0; currentCol < col -1; ++currentCol)
98 {
99 edges[(row -1)*col + currentCol].push_back((row - 1)*col + currentCol + 1);
100 }//for currentCol
101 }//makeCheckerboard()
102
103
104 /**
105 * Make a graph in the form 0-1-2-3-4-5-0 (so it loops around) and place a edge
106 * from every offset many to an other center node number 6.
107 *
108 * @parm size: number of vertices in the graph
109 * @parm offset: over offset many vertices will be connected to the center node (if offset = 1,
110 * then every node on the outer circle will be connected to the center node!)
111 */
makeCircleWithCenter(const int size,const int offset)112 void GraphMaker::makeCircleWithCenter(const int size, const int offset)
113 {
114
115 if ( size <= 3)
116 {
117 cout << "makeLinearGraph(): please give a size larger than 3" << endl;
118 return;
119 }//if crapy size.
120
121 numVertex = size;
122 edges.clear();
123 edges.resize(numVertex);
124 for(int k = 0; k < numVertex; ++k) edges[k].clear();
125
126 //cout << "got here 1" << endl;
127 //cout << "edges.size()=" << edges.size() << endl;
128 //cout << "edges.cap() =" << edges.capacity() << endl;
129 for(int k = 0; k < numVertex - 2; k++)
130 {
131 //cout << "k=" << k << "numVertex=" << numVertex << endl;
132 cout << "edges[k].zize() = " << edges[k].size() << endl;
133 edges[k].push_back(k + 1);
134 }
135 //cout << "got here 1.2" << endl;
136 edges[0].push_back(numVertex -2);
137 //cout << "got here 2" << endl;
138 for(int k = 0; k < numVertex - 1; k++)
139 {
140 if ( k % offset == 0)
141 {
142 edges[k].push_back(numVertex - 1);
143 }//add edge.
144 }//for each node on the circle.
145
146 }//makeCircleWithCenter()
147
148 /**
149 * Make a graph in the form 0-1-2-3-4-5-0 (so it loops around)
150 */
makeCircleGraph(const int size)151 void GraphMaker::makeCircleGraph(const int size)
152 {
153
154 if ( size <= 2)
155 {
156 cout << "makeLinearGraph(): please give a size larger than 2" << endl;
157 return;
158 }//if crapy size.
159
160 numVertex = size;
161 edges.clear();
162 edges.resize(numVertex);
163 for(int k = 0; k < numVertex; ++k) edges[k].clear();
164
165 for(int k = 0; k < numVertex - 1; k++)
166 {
167 edges[k].push_back(k + 1);
168 }
169
170 edges[0].push_back(numVertex -1);
171 }//makeCircleGraph()
172
173 /**
174 * Kneser graph KG(n,k) is the graph whose vertices correspond to the k-element subsets of a set of n elements, and where two vertices are connected if and only if the two corresponding sets are disjoint
175 */
makeKneserGraph(const int setSize,const int subSetSize)176 void GraphMaker::makeKneserGraph(const int setSize, const int subSetSize)
177 {
178 BuildHypersimplexEdgePolytope hPoly;
179 vector< vector<mpq_class> > points;
180 vector<mpq_class> startingPoint;
181 bool match;
182
183 hPoly.generatePoints(setSize, subSetSize);
184
185 if (subSetSize > (setSize +1)/2)
186 {
187 cout << "subsetSize too large, no edges can exist" << endl;
188 return;
189 }//too large.
190
191 numVertex = nchoosek(setSize, subSetSize);
192 edges.clear();
193 edges.resize(numVertex);
194
195 if ( setSize <= subSetSize)
196 {
197 cout << "subset size is too big" << endl;
198 return;
199 }//if too big.
200
201 //set the starting point to 11111....11000....0.
202 startingPoint.resize(setSize);
203 for(int i = 0; i < subSetSize; ++i)
204 startingPoint[i] = 1;
205 for(int i = subSetSize; i < setSize; ++i)
206 startingPoint[i] = 0;
207
208 hPoly.addToPoints(points, startingPoint, 0, true);
209 //ok, points now contains all subsets of size subSetSize from a set of setSize.
210
211 // for(int i = 0; i < points.size(); ++i)
212 // {
213 // cout << i << ") ";
214 // for(int k = 0; k < setSize; ++k)
215 // cout << " " << points[i][k];
216 // cout << endl;
217 // }//print points out.
218
219 for(size_t i = 0; i < points.size(); ++i)
220 for(size_t k = i + 1; k < points.size(); ++k)
221 {
222 match = false;
223 for(int curElement = 0; curElement < setSize && ! match; ++curElement)
224 if ( points[i][curElement] == 1 && points[i][curElement] == points[k][curElement])
225 match = true;
226
227 if ( match == false)
228 {
229 //cout << "match = " << match << endl;
230 edges[i].push_back(k);
231 }
232 }//for k. check to see if point[i] and point[k] intercept.
233 }//makeKneserGraph
234
235
236
237 /**
238 * Make a graph in the form: 0-1-2-3-4-5
239 */
makeLinearGraph(const int size)240 void GraphMaker::makeLinearGraph(const int size)
241 {
242 if ( size <= 1)
243 {
244 cout << "makeLinearGraph(): please give a size larger than 1" << endl;
245 return;
246 }//if crapy size.
247
248 numVertex = size;
249 edges.clear();
250 edges.resize(numVertex);
251 for(int k = 0; k < numVertex; ++k) edges[k].clear();
252
253 for(int k = 0; k < numVertex - 1; k++)
254 {
255 edges[k].push_back(k + 1);
256 }
257
258 }//makeLinearGraph
259
260
261 /**
262 * Makes the classical well-known Petersen Graph (10 vertices) starting at vertex 0.
263 */
makePetersenGraph()264 void GraphMaker::makePetersenGraph()
265 {
266 numVertex = 10;
267 edges.clear();
268 edges.resize(numVertex);
269
270 makePetersenSubGraph(0);
271 }//makePertersonGraph
272
273 /**
274 * This function could change over time.
275 */
makePetersenFunGraph(const int num)276 void GraphMaker::makePetersenFunGraph(const int num)
277 {
278 edges.clear();
279 numVertex = 10 * num;
280 edges.resize(10 * num);
281
282 //make a couble disjoing petersen graphs.
283 for(int i = 0; i < num; ++i)
284 makePetersenSubGraph(i*10);
285
286 }//makePetersenFunGraph
287
288 /**
289 * Makes a petersen graph starting at vertex startVertex
290 * This is helpful if you want to add a Petersen graph to an existing graph.
291 */
makePetersenSubGraph(const int startVertex)292 void GraphMaker::makePetersenSubGraph(const int startVertex)
293 {
294 for(int i = startVertex; i < startVertex + 4; ++i)
295 edges[i].push_back(i+1);
296 edges[startVertex].push_back(startVertex + 4);
297
298 for(int i = startVertex; i < startVertex + 5; ++i)
299 edges[i].push_back(i + 5);
300 for(int i = startVertex + 5; i < startVertex + 8; ++i)
301 edges[i].push_back(i + 2);
302 for(int i = startVertex + 5; i < startVertex + 7; ++i)
303 edges[i].push_back(i + 3);
304 }//makePertersonSubGraph
305
306 /**
307 * Will make two (simple) graphs of size/2 with edgeCount/2 edges that are not connected to each other.
308 * These two graphs may or may not further be connected.
309 */
makeRandomDisconnectedGraph(const int size,const int edgeCount)310 void GraphMaker::makeRandomDisconnectedGraph(const int size, const int edgeCount)
311 {
312
313 int vertexG1, vertexG2, edgeG1, edgeG2; //size and edgeCount of graph 1 and 2
314 int v1, v2, currentEdgeCount;
315
316 if ( size < 4)
317 {
318 cout << "please give a size larger than 4";
319 return;
320 }
321
322 numVertex = size;
323 edges.clear();
324 edges.resize(numVertex);
325
326 //find the size and edgeCount of the first graph.
327 vertexG1 = (int)((size + 1 )/2); //round up.
328 vertexG2 = size / 2;
329
330 //find the size and edgeCount of the 2nd graph.
331 edgeG1 = (int)((edgeCount + 1 )/2); //round up.
332 edgeG2 = edgeCount / 2;
333
334 cout << vertexG1 << "::" << edgeG1 << ", " << vertexG2 << "::" << edgeG2 << endl;
335 currentEdgeCount = 0;
336 while ( currentEdgeCount < edgeG1)
337 {
338 v1 = rand() % vertexG1;
339 v2 = rand() % vertexG1;
340 if ( v1 == v2) continue; //try again. Keep the graph simple.
341
342 if ( addEdgeInOrder(v1, v2) == true)
343 {
344 //cout << "1) v1=" << v1 << ", v2=" << v2 << endl;
345 ++currentEdgeCount;
346 }
347 }//while not done making graph.
348
349 //cout << "got here" << endl;
350 currentEdgeCount = 0;
351 while ( currentEdgeCount < edgeG2)
352 {
353 v1 = (rand() % vertexG2) + vertexG1;
354 v2 = (rand() % vertexG2) + vertexG1 ;
355
356 if ( v1 == v2) continue; //try again. Keep the graph simple.
357
358 if ( addEdgeInOrder(v1, v2) == true)
359 {
360 //cout << "2) v1=" << v1 << ", v2=" << v2 << endl;
361 ++currentEdgeCount;
362 }
363 }//while not done making graph.
364
365 }//makeRandomDisconnectedGraph
366
367 /**
368 * Makes a random connected simple graph.
369 */
makeRandomConnectedGraph(const int size,const int edgeCount)370 void GraphMaker::makeRandomConnectedGraph(const int size, const int edgeCount)
371 {
372 int v1, v2, currentEdgeCount = 0;
373
374 if ( size <= 2 || size > edgeCount+1 || edgeCount > size*(size -1)/2)
375 {
376 cout << "makeLinearGraph(): please give a size larger than 2 or an edgeCount >= size or you have too many edges" << endl;
377 return;
378 }//if bad size.
379
380 numVertex = size;
381 edges.clear();
382 edges.resize(numVertex);
383 for(int k = 0; k < numVertex; ++k) edges[k].clear();
384
385 //first, make a random min. spanning tree.
386 makeRandomSpanningTree();
387 currentEdgeCount = numVertex -1;
388
389 cout << "spanning tree:" << endl;
390 printEdges();
391 //cout << "now filling rest of quota" << endl;
392
393 while ( currentEdgeCount < edgeCount)
394 {
395 //pick two vertices and try them.
396 v1 = rand() % numVertex;
397 v2 = rand() % numVertex;
398 if ( v1 == v2)
399 continue; //try again.
400
401 //cout << "going to try v1, v2=" << v1 << ", " << v2 << endl;
402 //printEdges();
403 //cout << endl;
404 if ( addEdgeInOrder(v1, v2) == true)
405 ++currentEdgeCount;
406
407 }//while, keep adding more edges.
408
409 //cout << "full graph" << endl;
410 //printEdges();
411
412 }//makeRandomConnectedGraph()
413
414
415 /**
416 * Make sure the graph is connected.
417 */
makeRandomSpanningTree()418 void GraphMaker::makeRandomSpanningTree()
419 {
420 vector<int> unusedVertices(numVertex-1);
421 vector<int> usedVertices;
422 int currentUsedVertex, currentUnusedVertexIndex, lastUnused = numVertex - 2;
423
424 for(int i = 0; i < numVertex-1; ++i)
425 unusedVertices[i] = i;
426 usedVertices.push_back(numVertex -1);
427
428 while(lastUnused >= 0)
429 {
430 currentUsedVertex = usedVertices[rand() % usedVertices.size()];
431 currentUnusedVertexIndex = rand() % (lastUnused +1);
432
433 //move the vertex we wish to add to the end of the unusedVertices vector (by end, I mean to lastUnused).
434 // lastUnused will be decremented later, so we will never see it again!
435 swap(unusedVertices[currentUnusedVertexIndex], unusedVertices[lastUnused]);
436 usedVertices.push_back(unusedVertices[lastUnused]);
437
438 //now add the edge (currentusedVertex, unusedVertices[lastUnused]) to the graph, saving the smaller in the outer vertex.
439 addEdgeInOrder(currentUsedVertex, unusedVertices[lastUnused]);
440 --lastUnused;
441 }//while
442 }//makeRandomSpanningTree()
443
444
445 /*
446 * Ask the user for input. Does not require the end graph to be connected or simple.
447 */
makeYourOwnGraph()448 void GraphMaker::makeYourOwnGraph()
449 {
450 int v1, v2;
451
452 cout << "One past the largest graph vertex number >> ";
453 cin >> numVertex;
454
455 edges.clear();
456 edges.resize(numVertex);
457 for(int i = 0; i < numVertex; ++i) edges[i].clear();
458
459 while (true)
460 {
461 cout << "Enter -1 or vertex_1 vertex_2 >> ";
462 cin >> v1;
463 if ( v1 == -1)
464 break;
465 cin >> v2;
466
467 if ( v1 >= numVertex || v2 >= numVertex || v1 < 0 || v2 < 0)
468 {
469 cout << "vertex number too large or too small" << endl;
470 continue;
471 }//if too large/small
472
473 if ( false == addEdgeInOrder(v1, v2))
474 cout << "That edge already exists" << endl;
475 }//add another edge.
476
477 }//makeYourOwnGraph()
478
479
480 /**
481 * returns "n choose k"
482 */
nchoosek(const int n1,const int k1)483 int GraphMaker::nchoosek(const int n1, const int k1)
484 {
485 mpz_class n(n1), k(k1), topProduct(1), bottomProduct(1);
486 mpq_class ans;
487 if ( n1 < k1 )
488 {
489 cout << "nchoosek() bad input" << endl;
490 return -1;
491 }//error
492
493 for(mpz_class i(0); i < k; ++i)
494 {
495 topProduct *= ( n - i);
496 }
497 for(mpz_class i(1); i <= k; ++i)
498 {
499 bottomProduct *= i;
500 }
501
502 ans = mpq_class(topProduct, bottomProduct);
503 ans.canonicalize();
504
505 return ((int) ans.get_num().get_si());
506 }//nchoosek()
507
508 /**
509 * Prints the current edges.
510 */
printEdges() const511 void GraphMaker::printEdges() const
512 {
513 cout << "numVertex=" << numVertex << endl;
514 for(int i = 0; i < numVertex; ++i)
515 {
516 for(int k = 0; k < (int) edges[i].size(); ++k)
517 cout << "( " << i << ", " << edges[i][k] << ")" << endl;
518 }//for i
519
520 }//printEdges
521
522