View Javadoc
1   /*
2    * Copyright (c) 2016, the JUNG Project and the Regents of the University 
3    * of California.  All rights reserved.
4    *
5    * This software is open-source under the BSD license; see
6    * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
7    */
8   package edu.uci.ics.jung.algorithms.generators.random;
9   
10  import java.util.HashSet;
11  
12  import com.google.common.base.Supplier;
13  
14  import edu.uci.ics.jung.graph.DirectedSparseGraph;
15  import edu.uci.ics.jung.graph.DirectedSparseMultigraph;
16  import edu.uci.ics.jung.graph.Graph;
17  import edu.uci.ics.jung.graph.SparseGraph;
18  import edu.uci.ics.jung.graph.SparseMultigraph;
19  import edu.uci.ics.jung.graph.UndirectedSparseGraph;
20  import edu.uci.ics.jung.graph.UndirectedSparseMultigraph;
21  import edu.uci.ics.jung.graph.util.EdgeType;
22  import edu.uci.ics.jung.graph.util.Pair;
23  import junit.framework.Test;
24  import junit.framework.TestCase;
25  import junit.framework.TestSuite;
26  
27  /**
28   * @author W. Giordano
29   * @author Scott White
30   * @author James Marchant
31   */
32  public class TestBarabasiAlbert extends TestCase {
33  	protected Supplier<Graph<Integer, Number>> graphFactory;
34  	protected Supplier<Integer> vertexFactory;
35  	protected Supplier<Number> edgeFactory;
36  
37  	protected int init_vertices = 1;
38  	protected int edges_to_add_per_timestep = 1;
39  	protected int random_seed = 0;
40  	protected int num_timesteps = 10;
41  	protected int num_tests = 10;
42  
43  	public static Test suite() {
44  		return new TestSuite(TestBarabasiAlbert.class);
45  	}
46  
47  	@Override
48  	protected void setUp() {
49  		graphFactory = new Supplier<Graph<Integer, Number>>() {
50  			public Graph<Integer, Number> get() {
51  				return new SparseMultigraph<Integer, Number>();
52  			}
53  		};
54  		vertexFactory = new Supplier<Integer>() {
55  			int count;
56  
57  			public Integer get() {
58  				return count++;
59  			}
60  		};
61  		edgeFactory = new Supplier<Number>() {
62  			int count;
63  
64  			public Number get() {
65  				return count++;
66  			}
67  		};
68  	}
69  
70  	private Graph<Integer, Number> generateAndTestSizeOfBarabasiAlbertGraph(
71  			Supplier<Graph<Integer, Number>> graphFactory, Supplier<Integer> vertexFactory,
72  			Supplier<Number> edgeFactory, int init_vertices, int edges_to_add_per_timestep, int random_seed,
73  			int num_tests) {
74  		BarabasiAlbertGenerator<Integer, Number> generator = new BarabasiAlbertGenerator<Integer, Number>(graphFactory,
75  				vertexFactory, edgeFactory, init_vertices, edges_to_add_per_timestep, random_seed,
76  				new HashSet<Integer>());
77  
78  		Graph<Integer, Number> graph = null;
79  		// test the graph size over {@code num_tests} intervals of {@code
80  		// num_timesteps} timesteps
81  		for (int i = 1; i <= num_tests; i++) {
82  			generator.evolveGraph(num_timesteps);
83  			graph = generator.get();
84  			assertEquals(graph.getVertexCount(), (i * num_timesteps) + init_vertices);
85  			assertEquals(graph.getEdgeCount(), edges_to_add_per_timestep * (i * num_timesteps));
86  		}
87  
88  		return graph;
89  	}
90  
91  	public void testMultigraphCreation() {
92  		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
93  				edges_to_add_per_timestep, random_seed, num_tests);
94  	}
95  
96  	public void testDirectedMultigraphCreation() {
97  		graphFactory = new Supplier<Graph<Integer, Number>>() {
98  			public Graph<Integer, Number> get() {
99  				return new DirectedSparseMultigraph<Integer, Number>();
100 			}
101 		};
102 
103 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
104 				edges_to_add_per_timestep, random_seed, num_tests);
105 	}
106 
107 	public void testUndirectedMultigraphCreation() {
108 		graphFactory = new Supplier<Graph<Integer, Number>>() {
109 			public Graph<Integer, Number> get() {
110 				return new UndirectedSparseMultigraph<Integer, Number>();
111 			}
112 		};
113 
114 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
115 				edges_to_add_per_timestep, random_seed, num_tests);
116 	}
117 
118 	public void testGraphCreation() {
119 		graphFactory = new Supplier<Graph<Integer, Number>>() {
120 			public Graph<Integer, Number> get() {
121 				return new SparseGraph<Integer, Number>();
122 			}
123 		};
124 
125 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
126 				edges_to_add_per_timestep, random_seed, num_tests);
127 	}
128 
129 	public void testDirectedGraphCreation() {
130 		graphFactory = new Supplier<Graph<Integer, Number>>() {
131 			public Graph<Integer, Number> get() {
132 				return new DirectedSparseGraph<Integer, Number>();
133 			}
134 		};
135 
136 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
137 				edges_to_add_per_timestep, random_seed, num_tests);
138 	}
139 
140 	public void testUndirectedGraphCreation() {
141 		graphFactory = new Supplier<Graph<Integer, Number>>() {
142 			public Graph<Integer, Number> get() {
143 				return new UndirectedSparseGraph<Integer, Number>();
144 			}
145 		};
146 
147 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
148 				edges_to_add_per_timestep, random_seed, num_tests);
149 	}
150 
151 	/**
152 	 * Due to the way the Barabasi-Albert algorithm works there should be no
153 	 * opportunities for the generation of self-loops within the graph.
154 	 */
155 	public void testNoSelfLoops() {
156 		graphFactory = new Supplier<Graph<Integer, Number>>() {
157 			public Graph<Integer, Number> get() {
158 				return new UndirectedSparseGraph<Integer, Number>() {
159 					private static final long serialVersionUID = 1L;
160 
161 					/**
162 					 * This anonymous class works as an UndirectedSparseGraph
163 					 * but will not accept edges that connect a vertex to
164 					 * itself.
165 					 */
166 					@Override
167 					public boolean addEdge(Number edge, Pair<? extends Integer> endpoints, EdgeType edgeType) {
168 						if (endpoints == null)
169 							throw new IllegalArgumentException("endpoints may not be null");
170 
171 						Integer v1 = endpoints.getFirst();
172 						Integer v2 = endpoints.getSecond();
173 
174 						if (v1.equals(v2))
175 							throw new IllegalArgumentException("No self-loops");
176 						else
177 							return super.addEdge(edge, endpoints, edgeType);
178 					}
179 				};
180 			}
181 		};
182 
183 		generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices,
184 				edges_to_add_per_timestep, random_seed, num_tests);
185 	}
186 
187 	public void testPreconditions() {
188 		// test init_vertices = 0
189 		try {
190 			generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, 0,
191 					edges_to_add_per_timestep, random_seed, num_tests);
192 			fail();
193 		} catch (IllegalArgumentException e) {
194 		}
195 
196 		// test negative init_vertices
197 		try {
198 			generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, -1,
199 					edges_to_add_per_timestep, random_seed, num_tests);
200 			fail();
201 		} catch (IllegalArgumentException e) {
202 		}
203 
204 		// test edges_to_add_per_timestep = 0
205 		try {
206 			generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices, 0,
207 					random_seed, num_tests);
208 			fail();
209 		} catch (IllegalArgumentException e) {
210 		}
211 
212 		// test negative edges_to_add_per_timestep
213 		try {
214 			generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, init_vertices, -1,
215 					random_seed, num_tests);
216 			fail();
217 		} catch (IllegalArgumentException e) {
218 		}
219 
220 		// test edges_to_add_per_timestep > init_vertices
221 		try {
222 			generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory, edgeFactory, 2, 3, random_seed,
223 					num_tests);
224 			fail();
225 		} catch (IllegalArgumentException e) {
226 		}
227 	}
228 
229 	/**
230 	 * Every node should have an out-degree AT LEAST equal to the number of
231 	 * edges added per timestep (dependent on if it is directed or undirected).
232 	 */
233 	public void testEveryNodeHasCorrectMinimumNumberOfEdges() {
234 		Graph<Integer, Number> graph = generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory,
235 				edgeFactory, init_vertices, edges_to_add_per_timestep, random_seed, num_tests);
236 
237 		for (Integer v : graph.getVertices()) {
238 			assertTrue(graph.outDegree(v) >= edges_to_add_per_timestep);
239 		}
240 	}
241 
242 	/**
243 	 * Check that not every edge goes to one node; the in-degree of any node
244 	 * should be strictly less than the number of edges.
245 	 */
246 	public void testNotEveryEdgeToOneNode() {
247 		Graph<Integer, Number> graph = generateAndTestSizeOfBarabasiAlbertGraph(graphFactory, vertexFactory,
248 				edgeFactory, init_vertices, edges_to_add_per_timestep, random_seed, num_tests);
249 
250 		for (Integer v : graph.getVertices()) {
251 			assertTrue(graph.inDegree(v) < graph.getEdgeCount());
252 		}
253 	}
254 }