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