1use crate::core::{Graph, IgraphError, IgraphResult};
24
25pub fn famous(name: &str) -> IgraphResult<Graph> {
56 for &(candidate, data) in TABLE {
57 if name.eq_ignore_ascii_case(candidate) {
58 return materialize(data);
59 }
60 }
61 Err(IgraphError::InvalidArgument(format!(
62 "famous: '{name}' is not a known graph; see famous_names() for the list"
63 )))
64}
65
66#[must_use]
78pub fn famous_names() -> &'static [&'static str] {
79 &[
80 "bull",
81 "chvatal",
82 "coxeter",
83 "cubical",
84 "diamond",
85 "dodecahedron",
86 "folkman",
87 "franklin",
88 "frucht",
89 "grotzsch",
90 "heawood",
91 "herschel",
92 "house",
93 "housex",
94 "icosahedron",
95 "krackhardt_kite",
96 "levi",
97 "mcgee",
98 "meredith",
99 "noperfectmatching",
100 "nonline",
101 "octahedron",
102 "petersen",
103 "robertson",
104 "smallestcyclicgroup",
105 "tetrahedron",
106 "thomassen",
107 "tutte",
108 "uniquely3colorable",
109 "walther",
110 "zachary",
111 ]
112}
113
114fn materialize(data: &[u32]) -> IgraphResult<Graph> {
115 let vcount = data[0];
116 let ecount = data[1] as usize;
117 let directed = data[2] != 0;
118
119 let expected_len =
120 3usize
121 .checked_add(ecount.checked_mul(2).ok_or_else(|| {
122 IgraphError::InvalidArgument("famous: edge buffer overflow".into())
123 })?)
124 .ok_or_else(|| IgraphError::InvalidArgument("famous: edge buffer overflow".into()))?;
125 if data.len() != expected_len {
126 return Err(IgraphError::InvalidArgument(format!(
127 "famous: data length mismatch (expected {expected_len}, got {})",
128 data.len()
129 )));
130 }
131
132 let mut g = Graph::new(vcount, directed)?;
133 let edges: Vec<(u32, u32)> = data[3..]
134 .chunks_exact(2)
135 .map(|pair| (pair[0], pair[1]))
136 .collect();
137 g.add_edges(edges)?;
138 Ok(g)
139}
140
141#[allow(clippy::type_complexity)]
145const TABLE: &[(&str, &[u32])] = &[
146 ("bull", DATA_BULL),
147 ("chvatal", DATA_CHVATAL),
148 ("coxeter", DATA_COXETER),
149 ("cubical", DATA_CUBICAL),
150 ("diamond", DATA_DIAMOND),
151 ("dodecahedral", DATA_DODECAHEDRON),
152 ("dodecahedron", DATA_DODECAHEDRON),
153 ("folkman", DATA_FOLKMAN),
154 ("franklin", DATA_FRANKLIN),
155 ("frucht", DATA_FRUCHT),
156 ("groetzsch", DATA_GROTZSCH),
157 ("grotzsch", DATA_GROTZSCH),
158 ("heawood", DATA_HEAWOOD),
159 ("herschel", DATA_HERSCHEL),
160 ("house", DATA_HOUSE),
161 ("housex", DATA_HOUSEX),
162 ("icosahedral", DATA_ICOSAHEDRON),
163 ("icosahedron", DATA_ICOSAHEDRON),
164 ("krackhardt_kite", DATA_KRACKHARDT_KITE),
165 ("levi", DATA_LEVI),
166 ("mcgee", DATA_MCGEE),
167 ("meredith", DATA_MEREDITH),
168 ("noperfectmatching", DATA_NOPERFECTMATCHING),
169 ("nonline", DATA_NONLINE),
170 ("octahedral", DATA_OCTAHEDRON),
171 ("octahedron", DATA_OCTAHEDRON),
172 ("petersen", DATA_PETERSEN),
173 ("robertson", DATA_ROBERTSON),
174 ("smallestcyclicgroup", DATA_SMALLESTCYCLICGROUP),
175 ("tetrahedral", DATA_TETRAHEDRON),
176 ("tetrahedron", DATA_TETRAHEDRON),
177 ("thomassen", DATA_THOMASSEN),
178 ("tutte", DATA_TUTTE),
179 ("uniquely3colorable", DATA_UNIQUELY3COLORABLE),
180 ("walther", DATA_WALTHER),
181 ("zachary", DATA_ZACHARY),
182];
183
184#[rustfmt::skip]
191const DATA_BULL: &[u32] = &[
192 5, 5, 0,
193 0, 1, 0, 2, 1, 2, 1, 3, 2, 4,
194];
195
196#[rustfmt::skip]
197const DATA_CHVATAL: &[u32] = &[
198 12, 24, 0,
199 5, 6, 6, 7, 7, 8, 8, 9, 5, 9, 4, 5, 4, 8, 2, 8, 2, 6, 0, 6, 0, 9, 3, 9, 3, 7,
200 1, 7, 1, 5, 1, 10, 4, 10, 4, 11, 2, 11, 0, 10, 0, 11, 3, 11, 3, 10, 1, 2,
201];
202
203#[rustfmt::skip]
204const DATA_COXETER: &[u32] = &[
205 28, 42, 0,
206 0, 1, 0, 2, 0, 7, 1, 4, 1, 13, 2, 3, 2, 8, 3, 6, 3, 9, 4, 5, 4, 12, 5, 6, 5,
207 11, 6, 10, 7, 19, 7, 24, 8, 20, 8, 23, 9, 14, 9, 22, 10, 15, 10, 21, 11, 16,
208 11, 27, 12, 17, 12, 26, 13, 18, 13, 25, 14, 17, 14, 18, 15, 18, 15, 19, 16, 19,
209 16, 20, 17, 20, 21, 23, 21, 26, 22, 24, 22, 27, 23, 25, 24, 26, 25, 27,
210];
211
212#[rustfmt::skip]
213const DATA_CUBICAL: &[u32] = &[
214 8, 12, 0,
215 0, 1, 1, 2, 2, 3, 0, 3, 4, 5, 5, 6, 6, 7, 4, 7, 0, 4, 1, 5, 2, 6, 3, 7,
216];
217
218#[rustfmt::skip]
219const DATA_DIAMOND: &[u32] = &[
220 4, 5, 0,
221 0, 1, 0, 2, 1, 2, 1, 3, 2, 3,
222];
223
224#[rustfmt::skip]
225const DATA_DODECAHEDRON: &[u32] = &[
226 20, 30, 0,
227 0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 10, 5, 11, 6,
228 10, 6, 14, 7, 13, 7, 14, 8, 12, 8, 13, 9, 11, 9, 12, 10, 15, 11, 16, 12, 17,
229 13, 18, 14, 19, 15, 16, 15, 19, 16, 17, 17, 18, 18, 19,
230];
231
232#[rustfmt::skip]
233const DATA_FOLKMAN: &[u32] = &[
234 20, 40, 0,
235 0, 5, 0, 8, 0, 10, 0, 13, 1, 7, 1, 9, 1, 12, 1, 14, 2, 6, 2, 8, 2, 11, 2, 13,
236 3, 5, 3, 7, 3, 10, 3, 12, 4, 6, 4, 9, 4, 11, 4, 14, 5, 15, 5, 19, 6, 15, 6, 16,
237 7, 16, 7, 17, 8, 17, 8, 18, 9, 18, 9, 19, 10, 15, 10, 19, 11, 15, 11, 16, 12,
238 16, 12, 17, 13, 17, 13, 18, 14, 18, 14, 19,
239];
240
241#[rustfmt::skip]
242const DATA_FRANKLIN: &[u32] = &[
243 12, 18, 0,
244 0, 1, 0, 2, 0, 6, 1, 3, 1, 7, 2, 4, 2, 10, 3, 5, 3, 11, 4, 5, 4, 6, 5, 7, 6, 8,
245 7, 9, 8, 9, 8, 11, 9, 10, 10, 11,
246];
247
248#[rustfmt::skip]
249const DATA_FRUCHT: &[u32] = &[
250 12, 18, 0,
251 0, 1, 0, 2, 0, 11, 1, 3, 1, 6, 2, 5, 2, 10, 3, 4, 3, 6, 4, 8, 4, 11, 5, 9, 5,
252 10, 6, 7, 7, 8, 7, 9, 8, 9, 10, 11,
253];
254
255#[rustfmt::skip]
256const DATA_GROTZSCH: &[u32] = &[
257 11, 20, 0,
258 0, 1, 0, 2, 0, 7, 0, 10, 1, 3, 1, 6, 1, 9, 2, 4, 2, 6, 2, 8, 3, 4, 3, 8, 3, 10,
259 4, 7, 4, 9, 5, 6, 5, 7, 5, 8, 5, 9, 5, 10,
260];
261
262#[rustfmt::skip]
263const DATA_HEAWOOD: &[u32] = &[
264 14, 21, 0,
265 0, 1, 0, 5, 0, 13, 1, 2, 1, 10, 2, 3, 2, 7, 3, 4, 3, 12, 4, 5, 4, 9, 5, 6, 6,
266 7, 6, 11, 7, 8, 8, 9, 8, 13, 9, 10, 10, 11, 11, 12, 12, 13,
267];
268
269#[rustfmt::skip]
270const DATA_HERSCHEL: &[u32] = &[
271 11, 18, 0,
272 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 6, 1, 7, 2, 10, 3, 9, 4, 8, 4, 9, 5, 8,
273 5, 10, 6, 8, 6, 9, 7, 8, 7, 10,
274];
275
276#[rustfmt::skip]
277const DATA_HOUSE: &[u32] = &[
278 5, 6, 0,
279 0, 1, 0, 2, 1, 3, 2, 3, 2, 4, 3, 4,
280];
281
282#[rustfmt::skip]
283const DATA_HOUSEX: &[u32] = &[
284 5, 8, 0,
285 0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4,
286];
287
288#[rustfmt::skip]
289const DATA_ICOSAHEDRON: &[u32] = &[
290 12, 30, 0,
291 0, 1, 0, 2, 0, 3, 0, 4, 0, 8, 1, 2, 1, 6, 1, 7, 1, 8, 2, 4, 2, 5, 2, 6, 3, 4,
292 3, 8, 3, 9, 3, 11, 4, 5, 4, 11, 5, 6, 5, 10, 5, 11, 6, 7, 6, 10, 7, 8, 7, 9, 7,
293 10, 8, 9, 9, 10, 9, 11, 10, 11,
294];
295
296#[rustfmt::skip]
297const DATA_KRACKHARDT_KITE: &[u32] = &[
298 10, 18, 0,
299 0, 1, 0, 2, 0, 3, 0, 5, 1, 3, 1, 4, 1, 6, 2, 3, 2, 5, 3, 4, 3, 5, 3, 6, 4, 6, 5, 6, 5, 7, 6, 7, 7, 8, 8, 9,
300];
301
302#[rustfmt::skip]
303const DATA_LEVI: &[u32] = &[
304 30, 45, 0,
305 0, 1, 0, 7, 0, 29, 1, 2, 1, 24, 2, 3, 2, 11, 3, 4, 3, 16, 4, 5, 4, 21, 5, 6, 5,
306 26, 6, 7, 6, 13, 7, 8, 8, 9, 8, 17, 9, 10, 9, 22, 10, 11, 10, 27, 11, 12, 12,
307 13, 12, 19, 13, 14, 14, 15, 14, 23, 15, 16, 15, 28, 16, 17, 17, 18, 18, 19, 18,
308 25, 19, 20, 20, 21, 20, 29, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
309 28, 28, 29,
310];
311
312#[rustfmt::skip]
313const DATA_MCGEE: &[u32] = &[
314 24, 36, 0,
315 0, 1, 0, 7, 0, 23, 1, 2, 1, 18, 2, 3, 2, 14, 3, 4, 3, 10, 4, 5, 4, 21, 5, 6, 5,
316 17, 6, 7, 6, 13, 7, 8, 8, 9, 8, 20, 9, 10, 9, 16, 10, 11, 11, 12, 11, 23, 12,
317 13, 12, 19, 13, 14, 14, 15, 15, 16, 15, 22, 16, 17, 17, 18, 18, 19, 19, 20, 20,
318 21, 21, 22, 22, 23,
319];
320
321#[rustfmt::skip]
322const DATA_MEREDITH: &[u32] = &[
323 70, 140, 0,
324 0, 4, 0, 5, 0, 6, 1, 4, 1, 5, 1, 6, 2, 4, 2, 5, 2, 6, 3, 4, 3, 5, 3, 6, 7, 11,
325 7, 12, 7, 13, 8, 11, 8, 12, 8, 13, 9, 11, 9, 12, 9, 13, 10, 11, 10, 12, 10, 13,
326 14, 18, 14, 19, 14, 20, 15, 18, 15, 19, 15, 20, 16, 18, 16, 19, 16, 20, 17, 18,
327 17, 19, 17, 20, 21, 25, 21, 26, 21, 27, 22, 25, 22, 26, 22, 27, 23, 25, 23, 26,
328 23, 27, 24, 25, 24, 26, 24, 27, 28, 32, 28, 33, 28, 34, 29, 32, 29, 33, 29, 34,
329 30, 32, 30, 33, 30, 34, 31, 32, 31, 33, 31, 34, 35, 39, 35, 40, 35, 41, 36, 39,
330 36, 40, 36, 41, 37, 39, 37, 40, 37, 41, 38, 39, 38, 40, 38, 41, 42, 46, 42, 47,
331 42, 48, 43, 46, 43, 47, 43, 48, 44, 46, 44, 47, 44, 48, 45, 46, 45, 47, 45, 48,
332 49, 53, 49, 54, 49, 55, 50, 53, 50, 54, 50, 55, 51, 53, 51, 54, 51, 55, 52, 53,
333 52, 54, 52, 55, 56, 60, 56, 61, 56, 62, 57, 60, 57, 61, 57, 62, 58, 60, 58, 61,
334 58, 62, 59, 60, 59, 61, 59, 62, 63, 67, 63, 68, 63, 69, 64, 67, 64, 68, 64, 69,
335 65, 67, 65, 68, 65, 69, 66, 67, 66, 68, 66, 69, 2, 50, 1, 51, 9, 57, 8, 58, 16,
336 64, 15, 65, 23, 36, 22, 37, 30, 43, 29, 44, 3, 21, 7, 24, 14, 31, 0, 17, 10,
337 28, 38, 42, 35, 66, 59, 63, 52, 56, 45, 49,
338];
339
340#[rustfmt::skip]
341const DATA_NOPERFECTMATCHING: &[u32] = &[
342 16, 27, 0,
343 0, 1, 0, 2, 0, 3, 1, 2, 1, 3, 2, 3, 2, 4, 3, 4, 4, 5, 5, 6, 5, 7, 6, 12, 6, 13,
344 7, 8, 7, 9, 8, 9, 8, 10, 8, 11, 9, 10, 9, 11, 10, 11, 12, 13, 12, 14, 12, 15,
345 13, 14, 13, 15, 14, 15,
346];
347
348#[rustfmt::skip]
349const DATA_NONLINE: &[u32] = &[
350 50, 72, 0,
351 0, 1, 0, 2, 0, 3, 4, 6, 4, 7, 5, 6, 5, 7, 6, 7, 7, 8, 9, 11, 9, 12, 9, 13, 10,
352 11, 10, 12, 10, 13, 11, 12, 11, 13, 12, 13, 14, 15, 15, 16, 15, 17, 16, 17, 16,
353 18, 17, 18, 18, 19, 20, 21, 20, 22, 20, 23, 21, 22, 21, 23, 21, 24, 22, 23, 22,
354 24, 24, 25, 26, 27, 26, 28, 26, 29, 27, 28, 27, 29, 27, 30, 27, 31, 28, 29, 28,
355 30, 28, 31, 30, 31, 32, 34, 32, 35, 32, 36, 33, 34, 33, 35, 33, 37, 34, 35, 36,
356 37, 38, 39, 38, 40, 38, 43, 39, 40, 39, 41, 39, 42, 39, 43, 40, 41, 41, 42, 42,
357 43, 44, 45, 44, 46, 45, 46, 45, 47, 46, 47, 46, 48, 47, 48, 47, 49, 48, 49,
358];
359
360#[rustfmt::skip]
361const DATA_OCTAHEDRON: &[u32] = &[
362 6, 12, 0,
363 0, 1, 0, 2, 1, 2, 3, 4, 3, 5, 4, 5, 0, 3, 0, 5, 1, 3, 1, 4, 2, 4, 2, 5,
364];
365
366#[rustfmt::skip]
367const DATA_PETERSEN: &[u32] = &[
368 10, 15, 0,
369 0, 1, 0, 4, 0, 5, 1, 2, 1, 6, 2, 3, 2, 7, 3, 4, 3, 8, 4, 9, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9,
370];
371
372#[rustfmt::skip]
373const DATA_ROBERTSON: &[u32] = &[
374 19, 38, 0,
375 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12,
376 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 0, 18, 0, 4, 4, 9, 9, 13, 13,
377 17, 2, 17, 2, 6, 6, 10, 10, 15, 0, 15, 1, 8, 8, 16, 5, 16, 5, 12, 1, 12, 7, 18,
378 7, 14, 3, 14, 3, 11, 11, 18,
379];
380
381#[rustfmt::skip]
382const DATA_SMALLESTCYCLICGROUP: &[u32] = &[
383 9, 15, 0,
384 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 1, 2, 1, 3, 1, 7, 1, 8, 2, 5, 2, 6, 2, 7, 3, 8,
385 4, 5, 6, 7,
386];
387
388#[rustfmt::skip]
389const DATA_TETRAHEDRON: &[u32] = &[
390 4, 6, 0,
391 0, 3, 1, 3, 2, 3, 0, 1, 1, 2, 0, 2,
392];
393
394#[rustfmt::skip]
395const DATA_THOMASSEN: &[u32] = &[
396 34, 52, 0,
397 0, 2, 0, 3, 1, 3, 1, 4, 2, 4, 5, 7, 5, 8, 6, 8, 6, 9, 7, 9, 10, 12, 10, 13, 11,
398 13, 11, 14, 12, 14, 15, 17, 15, 18, 16, 18, 16, 19, 17, 19, 9, 19, 4, 14, 24,
399 25, 25, 26, 20, 26, 20, 21, 21, 22, 22, 23, 23, 27, 27, 28, 28, 29, 29, 30, 30,
400 31, 31, 32, 32, 33, 24, 33, 5, 24, 6, 25, 7, 26, 8, 20, 0, 20, 1, 21, 2, 22, 3,
401 23, 10, 27, 11, 28, 12, 29, 13, 30, 15, 30, 16, 31, 17, 32, 18, 33,
402];
403
404#[rustfmt::skip]
405const DATA_TUTTE: &[u32] = &[
406 46, 69, 0,
407 0, 10, 0, 11, 0, 12, 1, 2, 1, 7, 1, 19, 2, 3, 2, 41, 3, 4, 3, 27, 4, 5, 4, 33,
408 5, 6, 5, 45, 6, 9, 6, 29, 7, 8, 7, 21, 8, 9, 8, 22, 9, 24, 10, 13, 10, 14, 11,
409 26, 11, 28, 12, 30, 12, 31, 13, 15, 13, 21, 14, 15, 14, 18, 15, 16, 16, 17, 16,
410 20, 17, 18, 17, 23, 18, 24, 19, 25, 19, 40, 20, 21, 20, 22, 22, 23, 23, 24, 25,
411 26, 25, 38, 26, 34, 27, 28, 27, 39, 28, 34, 29, 30, 29, 44, 30, 35, 31, 32, 31,
412 35, 32, 33, 32, 42, 33, 43, 34, 36, 35, 37, 36, 38, 36, 39, 37, 42, 37, 44, 38,
413 40, 39, 41, 40, 41, 42, 43, 43, 45, 44, 45,
414];
415
416#[rustfmt::skip]
417const DATA_UNIQUELY3COLORABLE: &[u32] = &[
418 12, 22, 0,
419 0, 1, 0, 3, 0, 6, 0, 8, 1, 4, 1, 7, 1, 9, 2, 3, 2, 6, 2, 7, 2, 9, 2, 11, 3, 4,
420 3, 10, 4, 5, 4, 11, 5, 6, 5, 7, 5, 8, 5, 10, 8, 11, 9, 10,
421];
422
423#[rustfmt::skip]
424const DATA_WALTHER: &[u32] = &[
425 25, 31, 0,
426 0, 1, 1, 2, 1, 8, 2, 3, 2, 13, 3, 4, 3, 16, 4, 5, 5, 6, 5, 19, 6, 7, 6, 20, 7,
427 21, 8, 9, 8, 13, 9, 10, 9, 22, 10, 11, 10, 20, 11, 12, 13, 14, 14, 15, 14, 23,
428 15, 16, 15, 17, 17, 18, 18, 19, 18, 24, 20, 24, 22, 23, 23, 24,
429];
430
431#[rustfmt::skip]
432const DATA_ZACHARY: &[u32] = &[
433 34, 78, 0,
434 0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0, 7, 0, 8,
435 0, 10, 0, 11, 0, 12, 0, 13, 0, 17, 0, 19, 0, 21, 0, 31,
436 1, 2, 1, 3, 1, 7, 1, 13, 1, 17, 1, 19, 1, 21, 1, 30,
437 2, 3, 2, 7, 2, 27, 2, 28, 2, 32, 2, 9, 2, 8, 2, 13,
438 3, 7, 3, 12, 3, 13, 4, 6, 4, 10, 5, 6, 5, 10, 5, 16,
439 6, 16, 8, 30, 8, 32, 8, 33, 9, 33, 13, 33, 14, 32, 14, 33,
440 15, 32, 15, 33, 18, 32, 18, 33, 19, 33, 20, 32, 20, 33,
441 22, 32, 22, 33, 23, 25, 23, 27, 23, 32, 23, 33, 23, 29,
442 24, 25, 24, 27, 24, 31, 25, 31, 26, 29, 26, 33, 27, 33,
443 28, 31, 28, 33, 29, 32, 29, 33, 30, 32, 30, 33, 31, 32, 31, 33,
444 32, 33,
445];
446
447#[cfg(test)]
448mod tests {
449 use super::*;
450 use std::collections::BTreeSet;
451
452 fn canonical_edge_set(g: &Graph) -> BTreeSet<(u32, u32)> {
453 let mut s = BTreeSet::new();
454 for v in 0..g.vcount() {
455 for &u in &g.neighbors(v).expect("neighbors") {
456 if v <= u {
457 s.insert((v, u));
458 } else {
459 s.insert((u, v));
460 }
461 }
462 }
463 s
464 }
465
466 #[test]
467 fn unknown_name_errors() {
468 assert!(famous("nonexistent").is_err());
469 assert!(famous("").is_err());
470 }
471
472 #[test]
473 fn names_are_case_insensitive() {
474 let p1 = famous("PETERSEN").expect("upper");
475 let p2 = famous("Petersen").expect("title");
476 let p3 = famous("petersen").expect("lower");
477 let p4 = famous("PeTeRsEn").expect("mixed");
478 for p in [&p2, &p3, &p4] {
479 assert_eq!(p1.vcount(), p.vcount());
480 assert_eq!(p1.ecount(), p.ecount());
481 assert_eq!(canonical_edge_set(&p1), canonical_edge_set(p));
482 }
483 }
484
485 #[test]
486 fn aliases_match_primary() {
487 let pairs = [
488 ("dodecahedral", "dodecahedron"),
489 ("grotzsch", "groetzsch"),
490 ("icosahedral", "icosahedron"),
491 ("octahedral", "octahedron"),
492 ("tetrahedral", "tetrahedron"),
493 ];
494 for (a, b) in pairs {
495 let ga = famous(a).expect(a);
496 let gb = famous(b).expect(b);
497 assert_eq!(ga.vcount(), gb.vcount(), "{a} vs {b} vcount");
498 assert_eq!(ga.ecount(), gb.ecount(), "{a} vs {b} ecount");
499 assert_eq!(canonical_edge_set(&ga), canonical_edge_set(&gb));
500 }
501 }
502
503 #[test]
504 fn every_name_in_table_builds() {
505 for name in famous_names() {
506 let g = famous(name).unwrap_or_else(|_| panic!("famous({name}) failed"));
507 assert!(g.vcount() > 0, "{name} should have at least one vertex");
508 assert!(!g.is_directed(), "{name} should be undirected");
509 }
510 }
511
512 #[test]
513 fn vertex_and_edge_counts_match_data_table() {
514 let cases = [
516 ("bull", 5, 5),
517 ("chvatal", 12, 24),
518 ("coxeter", 28, 42),
519 ("cubical", 8, 12),
520 ("diamond", 4, 5),
521 ("dodecahedron", 20, 30),
522 ("folkman", 20, 40),
523 ("franklin", 12, 18),
524 ("frucht", 12, 18),
525 ("grotzsch", 11, 20),
526 ("heawood", 14, 21),
527 ("herschel", 11, 18),
528 ("house", 5, 6),
529 ("housex", 5, 8),
530 ("icosahedron", 12, 30),
531 ("krackhardt_kite", 10, 18),
532 ("levi", 30, 45),
533 ("mcgee", 24, 36),
534 ("meredith", 70, 140),
535 ("noperfectmatching", 16, 27),
536 ("nonline", 50, 72),
537 ("octahedron", 6, 12),
538 ("petersen", 10, 15),
539 ("robertson", 19, 38),
540 ("smallestcyclicgroup", 9, 15),
541 ("tetrahedron", 4, 6),
542 ("thomassen", 34, 52),
543 ("tutte", 46, 69),
544 ("uniquely3colorable", 12, 22),
545 ("walther", 25, 31),
546 ("zachary", 34, 78),
547 ];
548 for (name, v, e) in cases {
549 let g = famous(name).expect(name);
550 assert_eq!(g.vcount(), v, "{name} vcount");
551 assert_eq!(g.ecount(), e, "{name} ecount");
552 }
553 }
554
555 #[test]
556 fn bull_has_expected_edges() {
557 let bull = famous("bull").expect("bull");
558 let want: BTreeSet<(u32, u32)> = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 4)]
559 .into_iter()
560 .collect();
561 assert_eq!(canonical_edge_set(&bull), want);
562 }
563
564 #[test]
565 fn tetrahedron_is_k4() {
566 let g = famous("tetrahedron").expect("t");
568 let want: BTreeSet<(u32, u32)> = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
569 .into_iter()
570 .collect();
571 assert_eq!(canonical_edge_set(&g), want);
572 }
573
574 #[test]
575 fn petersen_is_3_regular() {
576 let g = famous("petersen").expect("p");
577 for v in 0..g.vcount() {
578 assert_eq!(g.neighbors(v).unwrap().len(), 3, "vertex {v} degree");
579 }
580 }
581
582 #[test]
583 fn no_self_loops_in_undirected_famous() {
584 for name in famous_names() {
585 let g = famous(name).unwrap();
586 for v in 0..g.vcount() {
587 for &u in &g.neighbors(v).unwrap() {
588 assert_ne!(v, u, "{name} has self-loop at {v}");
589 }
590 }
591 }
592 }
593
594 #[test]
595 fn famous_names_match_table_canonical_entries() {
596 let names: BTreeSet<&str> = famous_names().iter().copied().collect();
598 assert_eq!(names.len(), famous_names().len(), "no duplicate names");
599 for n in &names {
601 assert!(
602 famous(n).is_ok(),
603 "famous_names() entry '{n}' is not accepted"
604 );
605 }
606 }
607}