1use std::collections::VecDeque;
15
16use crate::core::{Graph, IgraphError, IgraphResult, VertexId};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
23pub enum NeighborhoodMode {
24 Out,
27 In,
31 All,
34}
35
36pub fn neighborhood_size(graph: &Graph, order: i32) -> IgraphResult<Vec<u32>> {
66 neighborhood_size_with_mode(graph, order, NeighborhoodMode::All, 0)
67}
68
69pub fn neighborhood_size_with_mode(
112 graph: &Graph,
113 order: i32,
114 mode: NeighborhoodMode,
115 mindist: i32,
116) -> IgraphResult<Vec<u32>> {
117 if mindist < 0 {
118 return Err(IgraphError::InvalidArgument(format!(
119 "minimum distance must not be negative, got {mindist}"
120 )));
121 }
122 if order >= 0 && mindist > order {
123 return Err(IgraphError::InvalidArgument(format!(
124 "minimum distance must not exceed neighbourhood order ({order}), got {mindist}"
125 )));
126 }
127
128 let n = graph.vcount();
129 if n == 0 {
130 return Ok(Vec::new());
131 }
132 let n_us = n as usize;
133
134 let inf_order = order < 0;
138 let effective_order: i64 = if inf_order {
139 i64::from(n)
140 } else {
141 i64::from(order)
142 };
143 let mindist_i64 = i64::from(mindist);
144
145 let directed = graph.is_directed();
146 let mut added: Vec<u32> = vec![0; n_us];
149 let mut queue: VecDeque<(VertexId, i64)> = VecDeque::new();
150 let mut result: Vec<u32> = vec![0; n_us];
151
152 for src in 0..n {
153 let marker = src + 1;
154 added[src as usize] = marker;
155 let mut size: u32 = u32::from(mindist_i64 == 0);
156 queue.clear();
157 if effective_order > 0 {
158 queue.push_back((src, 0));
159 }
160
161 while let Some((actnode, actdist)) = queue.pop_front() {
162 let neis = neighbours_for(graph, actnode, mode, directed)?;
163 if actdist < effective_order - 1 {
164 for nei in neis {
165 if added[nei as usize] != marker {
166 added[nei as usize] = marker;
167 queue.push_back((nei, actdist + 1));
168 if actdist + 1 >= mindist_i64 {
169 size = size
170 .checked_add(1)
171 .ok_or(IgraphError::Internal("neighborhood size overflowed u32"))?;
172 }
173 }
174 }
175 } else {
176 for nei in neis {
178 if added[nei as usize] != marker {
179 added[nei as usize] = marker;
180 if actdist + 1 >= mindist_i64 {
181 size = size
182 .checked_add(1)
183 .ok_or(IgraphError::Internal("neighborhood size overflowed u32"))?;
184 }
185 }
186 }
187 }
188 }
189
190 result[src as usize] = size;
191 }
192
193 Ok(result)
194}
195
196pub fn neighborhood(graph: &Graph, order: i32) -> IgraphResult<Vec<Vec<u32>>> {
223 neighborhood_with_mode(graph, order, NeighborhoodMode::All, 0)
224}
225
226pub fn neighborhood_with_mode(
263 graph: &Graph,
264 order: i32,
265 mode: NeighborhoodMode,
266 mindist: i32,
267) -> IgraphResult<Vec<Vec<u32>>> {
268 if mindist < 0 {
269 return Err(IgraphError::InvalidArgument(format!(
270 "minimum distance must not be negative, got {mindist}"
271 )));
272 }
273 if order >= 0 && mindist > order {
274 return Err(IgraphError::InvalidArgument(format!(
275 "minimum distance must not exceed neighbourhood order ({order}), got {mindist}"
276 )));
277 }
278
279 let n = graph.vcount();
280 if n == 0 {
281 return Ok(Vec::new());
282 }
283 let n_us = n as usize;
284
285 let inf_order = order < 0;
286 let effective_order: i64 = if inf_order {
287 i64::from(n)
288 } else {
289 i64::from(order)
290 };
291 let mindist_i64 = i64::from(mindist);
292
293 let directed = graph.is_directed();
294 let mut added: Vec<u32> = vec![0; n_us];
295 let mut queue: VecDeque<(VertexId, i64)> = VecDeque::new();
296 let mut result: Vec<Vec<u32>> = Vec::with_capacity(n_us);
297
298 for src in 0..n {
299 let marker = src + 1;
300 added[src as usize] = marker;
301 let mut tmp: Vec<u32> = Vec::new();
302 if mindist_i64 == 0 {
303 tmp.push(src);
304 }
305 queue.clear();
306 if effective_order > 0 {
307 queue.push_back((src, 0));
308 }
309
310 while let Some((actnode, actdist)) = queue.pop_front() {
311 let neis = neighbours_for(graph, actnode, mode, directed)?;
312 if actdist < effective_order - 1 {
313 for nei in neis {
314 if added[nei as usize] != marker {
315 added[nei as usize] = marker;
316 queue.push_back((nei, actdist + 1));
317 if actdist + 1 >= mindist_i64 {
318 tmp.push(nei);
319 }
320 }
321 }
322 } else {
323 for nei in neis {
324 if added[nei as usize] != marker {
325 added[nei as usize] = marker;
326 if actdist + 1 >= mindist_i64 {
327 tmp.push(nei);
328 }
329 }
330 }
331 }
332 }
333
334 result.push(tmp);
335 }
336
337 Ok(result)
338}
339
340fn neighbours_for(
343 graph: &Graph,
344 v: VertexId,
345 mode: NeighborhoodMode,
346 directed: bool,
347) -> IgraphResult<Vec<VertexId>> {
348 if !directed {
349 return graph.neighbors(v);
350 }
351 match mode {
352 NeighborhoodMode::Out => graph.out_neighbors_vec(v),
353 NeighborhoodMode::In => graph.in_neighbors_vec(v),
354 NeighborhoodMode::All => {
355 let mut out = graph.out_neighbors_vec(v)?;
356 out.extend(graph.in_neighbors_vec(v)?);
357 Ok(out)
358 }
359 }
360}
361
362#[cfg(test)]
363mod tests {
364 use super::*;
365 use crate::Graph;
366
367 fn c_ref_graph() -> Graph {
371 let mut g = Graph::new(6, true).unwrap();
372 for (u, v) in [
373 (0, 1),
374 (0, 2),
375 (1, 1),
376 (1, 3),
377 (2, 0),
378 (2, 3),
379 (3, 4),
380 (3, 4),
381 ] {
382 g.add_edge(u, v).unwrap();
383 }
384 g
385 }
386
387 #[test]
388 fn empty_graph_returns_empty_vector() {
389 let g = Graph::with_vertices(0);
390 assert!(neighborhood_size(&g, 1).unwrap().is_empty());
391 }
392
393 #[test]
394 fn singleton_order_0_is_one() {
395 let g = Graph::with_vertices(1);
396 assert_eq!(neighborhood_size(&g, 0).unwrap(), vec![1]);
397 assert_eq!(neighborhood_size(&g, 5).unwrap(), vec![1]);
398 }
399
400 #[test]
401 fn no_edges_only_self_at_any_order() {
402 let g = Graph::with_vertices(4);
403 assert_eq!(neighborhood_size(&g, 0).unwrap(), vec![1, 1, 1, 1]);
404 assert_eq!(neighborhood_size(&g, 5).unwrap(), vec![1, 1, 1, 1]);
405 }
406
407 #[test]
408 fn ring_p5_matches_python_reference_order_1() {
409 let mut g = Graph::with_vertices(5);
412 for (u, v) in [(0, 1), (1, 2), (2, 3), (3, 4)] {
413 g.add_edge(u, v).unwrap();
414 }
415 assert_eq!(neighborhood_size(&g, 1).unwrap(), vec![2, 3, 3, 3, 2]);
416 }
417
418 #[test]
419 fn ring_p10_matches_python_order_1() {
420 let mut g = Graph::with_vertices(10);
421 for i in 0..9 {
422 g.add_edge(i, i + 1).unwrap();
423 }
424 assert_eq!(
425 neighborhood_size(&g, 1).unwrap(),
426 vec![2, 3, 3, 3, 3, 3, 3, 3, 3, 2]
427 );
428 }
429
430 #[test]
431 fn ring_p10_matches_python_order_3() {
432 let mut g = Graph::with_vertices(10);
433 for i in 0..9 {
434 g.add_edge(i, i + 1).unwrap();
435 }
436 assert_eq!(
437 neighborhood_size(&g, 3).unwrap(),
438 vec![4, 5, 6, 7, 7, 7, 7, 6, 5, 4]
439 );
440 }
441
442 #[test]
443 fn ring_p10_order_3_mindist_2_matches_python() {
444 let mut g = Graph::with_vertices(10);
445 for i in 0..9 {
446 g.add_edge(i, i + 1).unwrap();
447 }
448 assert_eq!(
449 neighborhood_size_with_mode(&g, 3, NeighborhoodMode::All, 2).unwrap(),
450 vec![2, 2, 3, 4, 4, 4, 4, 3, 2, 2]
451 );
452 }
453
454 #[test]
455 fn c_ref_order_0_is_self_only() {
456 let g = c_ref_graph();
457 assert_eq!(neighborhood_size(&g, 0).unwrap(), vec![1, 1, 1, 1, 1, 1]);
459 }
460
461 #[test]
462 fn c_ref_order_1_all_mode() {
463 let g = c_ref_graph();
464 assert_eq!(neighborhood_size(&g, 1).unwrap(), vec![3, 3, 3, 4, 2, 1]);
466 }
467
468 #[test]
469 fn c_ref_order_1_in_mode() {
470 let g = c_ref_graph();
471 assert_eq!(
473 neighborhood_size_with_mode(&g, 1, NeighborhoodMode::In, 0).unwrap(),
474 vec![2, 2, 2, 3, 2, 1]
475 );
476 }
477
478 #[test]
479 fn c_ref_order_10_all_mode_saturates() {
480 let g = c_ref_graph();
481 assert_eq!(neighborhood_size(&g, 10).unwrap(), vec![5, 5, 5, 5, 5, 1]);
483 }
484
485 #[test]
486 fn c_ref_order_2_mindist_2_out_mode() {
487 let g = c_ref_graph();
488 assert_eq!(
490 neighborhood_size_with_mode(&g, 2, NeighborhoodMode::Out, 2).unwrap(),
491 vec![1, 1, 2, 0, 0, 0]
492 );
493 }
494
495 #[test]
496 fn c_ref_order_4_mindist_4_all_mode_all_zero() {
497 let g = c_ref_graph();
498 assert_eq!(
500 neighborhood_size_with_mode(&g, 4, NeighborhoodMode::All, 4).unwrap(),
501 vec![0, 0, 0, 0, 0, 0]
502 );
503 }
504
505 #[test]
506 fn c_ref_infinite_order_out_mode() {
507 let g = c_ref_graph();
508 assert_eq!(
510 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::Out, 0).unwrap(),
511 vec![5, 3, 5, 2, 1, 1]
512 );
513 }
514
515 #[test]
516 fn c_ref_infinite_order_mindist_2_out_mode() {
517 let g = c_ref_graph();
518 assert_eq!(
520 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::Out, 2).unwrap(),
521 vec![2, 1, 2, 0, 0, 0]
522 );
523 }
524
525 #[test]
526 fn c_ref_infinite_order_mindist_2_in_mode() {
527 let g = c_ref_graph();
528 assert_eq!(
530 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::In, 2).unwrap(),
531 vec![0, 1, 0, 1, 3, 0]
532 );
533 }
534
535 #[test]
536 fn negative_mindist_errors() {
537 let g = Graph::with_vertices(3);
538 match neighborhood_size_with_mode(&g, 2, NeighborhoodMode::All, -1) {
539 Err(IgraphError::InvalidArgument(msg)) => assert!(msg.contains("negative")),
540 other => panic!("expected InvalidArgument for negative mindist, got {other:?}"),
541 }
542 }
543
544 #[test]
545 fn mindist_exceeding_finite_order_errors() {
546 let g = Graph::with_vertices(3);
547 match neighborhood_size_with_mode(&g, 2, NeighborhoodMode::All, 3) {
548 Err(IgraphError::InvalidArgument(msg)) => assert!(msg.contains("exceed")),
549 other => panic!("expected InvalidArgument for mindist > order, got {other:?}"),
550 }
551 }
552
553 #[test]
554 fn infinite_order_allows_any_mindist() {
555 let mut g = Graph::with_vertices(3);
557 g.add_edge(0, 1).unwrap();
558 g.add_edge(1, 2).unwrap();
559 assert_eq!(
561 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::All, 10).unwrap(),
562 vec![0, 0, 0]
563 );
564 }
565
566 #[test]
567 fn k4_complete_undirected_order_1() {
568 let mut g = Graph::with_vertices(4);
569 for u in 0..4 {
570 for v in (u + 1)..4 {
571 g.add_edge(u, v).unwrap();
572 }
573 }
574 assert_eq!(neighborhood_size(&g, 1).unwrap(), vec![4, 4, 4, 4]);
576 }
577
578 #[test]
579 fn directed_star_out_in_modes() {
580 let mut g = Graph::new(4, true).unwrap();
582 for v in [1, 2, 3] {
583 g.add_edge(0, v).unwrap();
584 }
585 assert_eq!(
587 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::Out, 0).unwrap(),
588 vec![4, 1, 1, 1]
589 );
590 assert_eq!(
592 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::In, 0).unwrap(),
593 vec![1, 2, 2, 2]
594 );
595 assert_eq!(
597 neighborhood_size_with_mode(&g, -1, NeighborhoodMode::All, 0).unwrap(),
598 vec![4, 4, 4, 4]
599 );
600 }
601
602 #[test]
603 fn self_loop_does_not_inflate_count() {
604 let mut g = Graph::with_vertices(3);
605 g.add_edge(0, 0).unwrap();
606 g.add_edge(0, 1).unwrap();
607 g.add_edge(1, 2).unwrap();
608 assert_eq!(neighborhood_size(&g, 1).unwrap(), vec![2, 3, 2]);
610 }
611
612 #[test]
613 fn multi_edge_does_not_double_count() {
614 let mut g = Graph::with_vertices(3);
615 g.add_edge(0, 1).unwrap();
616 g.add_edge(0, 1).unwrap();
617 g.add_edge(1, 2).unwrap();
618 assert_eq!(neighborhood_size(&g, 1).unwrap(), vec![2, 3, 2]);
619 }
620
621 #[test]
622 fn mindist_equals_order_counts_frontier_only() {
623 let mut g = Graph::with_vertices(5);
625 for (u, v) in [(0, 1), (1, 2), (2, 3), (3, 4)] {
626 g.add_edge(u, v).unwrap();
627 }
628 assert_eq!(
630 neighborhood_size_with_mode(&g, 2, NeighborhoodMode::All, 2).unwrap(),
631 vec![1, 1, 2, 1, 1]
632 );
633 }
634
635 fn sorted(mut v: Vec<u32>) -> Vec<u32> {
643 v.sort_unstable();
644 v
645 }
646
647 fn sorted_all(nbh: Vec<Vec<u32>>) -> Vec<Vec<u32>> {
648 nbh.into_iter().map(sorted).collect()
649 }
650
651 #[test]
652 fn neighborhood_empty_graph_returns_empty() {
653 let g = Graph::with_vertices(0);
654 assert!(neighborhood(&g, 1).unwrap().is_empty());
655 }
656
657 #[test]
658 fn neighborhood_singleton_order_0_is_self_only() {
659 let g = Graph::with_vertices(1);
660 assert_eq!(neighborhood(&g, 0).unwrap(), vec![vec![0]]);
661 assert_eq!(neighborhood(&g, 5).unwrap(), vec![vec![0]]);
662 }
663
664 #[test]
665 fn neighborhood_no_edges_returns_singletons() {
666 let g = Graph::with_vertices(3);
667 let n0 = neighborhood(&g, 0).unwrap();
668 assert_eq!(n0, vec![vec![0], vec![1], vec![2]]);
669 let n5 = neighborhood(&g, 5).unwrap();
670 assert_eq!(n5, vec![vec![0], vec![1], vec![2]]);
671 }
672
673 #[test]
674 fn neighborhood_p5_order_1_set_eq() {
675 let mut g = Graph::with_vertices(5);
677 for (u, v) in [(0, 1), (1, 2), (2, 3), (3, 4)] {
678 g.add_edge(u, v).unwrap();
679 }
680 let got = sorted_all(neighborhood(&g, 1).unwrap());
681 let exp: Vec<Vec<u32>> = vec![
682 vec![0, 1],
683 vec![0, 1, 2],
684 vec![1, 2, 3],
685 vec![2, 3, 4],
686 vec![3, 4],
687 ];
688 assert_eq!(got, exp);
689 }
690
691 #[test]
692 fn neighborhood_p5_order_2_set_eq() {
693 let mut g = Graph::with_vertices(5);
694 for (u, v) in [(0, 1), (1, 2), (2, 3), (3, 4)] {
695 g.add_edge(u, v).unwrap();
696 }
697 let got = sorted_all(neighborhood(&g, 2).unwrap());
698 let exp: Vec<Vec<u32>> = vec![
699 vec![0, 1, 2],
700 vec![0, 1, 2, 3],
701 vec![0, 1, 2, 3, 4],
702 vec![1, 2, 3, 4],
703 vec![2, 3, 4],
704 ];
705 assert_eq!(got, exp);
706 }
707
708 #[test]
709 fn neighborhood_c_ref_order_0_is_self_only() {
710 let g = c_ref_graph();
712 let got = neighborhood(&g, 0).unwrap();
713 let exp: Vec<Vec<u32>> = (0..6).map(|i| vec![i]).collect();
714 assert_eq!(got, exp);
715 }
716
717 #[test]
718 fn neighborhood_c_ref_order_1_all_set_eq() {
719 let g = c_ref_graph();
721 let got = sorted_all(neighborhood(&g, 1).unwrap());
722 let exp: Vec<Vec<u32>> = vec![
723 vec![0, 1, 2],
724 vec![0, 1, 3],
725 vec![0, 2, 3],
726 vec![1, 2, 3, 4],
727 vec![3, 4],
728 vec![5],
729 ];
730 assert_eq!(got, exp);
731 }
732
733 #[test]
734 fn neighborhood_c_ref_order_1_in_set_eq() {
735 let g = c_ref_graph();
737 let got = sorted_all(neighborhood_with_mode(&g, 1, NeighborhoodMode::In, 0).unwrap());
738 let exp: Vec<Vec<u32>> = vec![
739 vec![0, 2],
740 vec![0, 1],
741 vec![0, 2],
742 vec![1, 2, 3],
743 vec![3, 4],
744 vec![5],
745 ];
746 assert_eq!(got, exp);
747 }
748
749 #[test]
750 fn neighborhood_c_ref_order_10_all_saturates_set_eq() {
751 let g = c_ref_graph();
754 let got = sorted_all(neighborhood(&g, 10).unwrap());
755 let big: Vec<u32> = (0..5).collect();
756 let exp: Vec<Vec<u32>> = vec![
757 big.clone(),
758 big.clone(),
759 big.clone(),
760 big.clone(),
761 big,
762 vec![5],
763 ];
764 assert_eq!(got, exp);
765 }
766
767 #[test]
768 fn neighborhood_c_ref_order_2_mindist_2_out_set_eq() {
769 let g = c_ref_graph();
771 let got = sorted_all(neighborhood_with_mode(&g, 2, NeighborhoodMode::Out, 2).unwrap());
772 let exp: Vec<Vec<u32>> = vec![vec![3], vec![4], vec![1, 4], vec![], vec![], vec![]];
773 assert_eq!(got, exp);
774 }
775
776 #[test]
777 fn neighborhood_c_ref_order_4_mindist_4_all_empty() {
778 let g = c_ref_graph();
780 let got = neighborhood_with_mode(&g, 4, NeighborhoodMode::All, 4).unwrap();
781 let exp: Vec<Vec<u32>> = vec![vec![]; 6];
782 assert_eq!(got, exp);
783 }
784
785 #[test]
786 fn neighborhood_c_ref_infinite_order_out_set_eq() {
787 let g = c_ref_graph();
789 let got = sorted_all(neighborhood_with_mode(&g, -1, NeighborhoodMode::Out, 0).unwrap());
790 let exp: Vec<Vec<u32>> = vec![
791 vec![0, 1, 2, 3, 4],
792 vec![1, 3, 4],
793 vec![0, 1, 2, 3, 4],
794 vec![3, 4],
795 vec![4],
796 vec![5],
797 ];
798 assert_eq!(got, exp);
799 }
800
801 #[test]
802 fn neighborhood_c_ref_infinite_mindist_2_out_set_eq() {
803 let g = c_ref_graph();
805 let got = sorted_all(neighborhood_with_mode(&g, -1, NeighborhoodMode::Out, 2).unwrap());
806 let exp: Vec<Vec<u32>> = vec![vec![3, 4], vec![4], vec![1, 4], vec![], vec![], vec![]];
807 assert_eq!(got, exp);
808 }
809
810 #[test]
811 fn neighborhood_c_ref_infinite_mindist_2_in_set_eq() {
812 let g = c_ref_graph();
814 let got = sorted_all(neighborhood_with_mode(&g, -1, NeighborhoodMode::In, 2).unwrap());
815 let exp: Vec<Vec<u32>> = vec![vec![], vec![2], vec![], vec![0], vec![0, 1, 2], vec![]];
816 assert_eq!(got, exp);
817 }
818
819 #[test]
820 fn neighborhood_negative_mindist_errors() {
821 let g = Graph::with_vertices(3);
822 match neighborhood_with_mode(&g, 2, NeighborhoodMode::All, -1) {
823 Err(IgraphError::InvalidArgument(msg)) => assert!(msg.contains("negative")),
824 other => panic!("expected InvalidArgument for negative mindist, got {other:?}"),
825 }
826 }
827
828 #[test]
829 fn neighborhood_mindist_exceeds_order_errors() {
830 let g = Graph::with_vertices(3);
831 match neighborhood_with_mode(&g, 2, NeighborhoodMode::All, 3) {
832 Err(IgraphError::InvalidArgument(msg)) => assert!(msg.contains("exceed")),
833 other => panic!("expected InvalidArgument, got {other:?}"),
834 }
835 }
836
837 #[test]
838 fn neighborhood_lengths_match_neighborhood_size() {
839 let g = c_ref_graph();
842 for order in [0_i32, 1, 2, 3, 10, -1] {
843 for &mode in &[
844 NeighborhoodMode::Out,
845 NeighborhoodMode::In,
846 NeighborhoodMode::All,
847 ] {
848 for mindist in [0_i32, 1, 2] {
849 if order >= 0 && mindist > order {
850 continue;
851 }
852 let sizes = neighborhood_size_with_mode(&g, order, mode, mindist).unwrap();
853 let lists = neighborhood_with_mode(&g, order, mode, mindist).unwrap();
854 let list_lens: Vec<u32> = lists
855 .iter()
856 .map(|v| u32::try_from(v.len()).unwrap())
857 .collect();
858 assert_eq!(
859 sizes, list_lens,
860 "size/list-len mismatch at order={order} mode={mode:?} mindist={mindist}",
861 );
862 }
863 }
864 }
865 }
866
867 #[test]
868 fn neighborhood_self_loop_not_double_visited() {
869 let mut g = Graph::with_vertices(3);
870 g.add_edge(0, 0).unwrap();
871 g.add_edge(0, 1).unwrap();
872 g.add_edge(1, 2).unwrap();
873 let got = sorted_all(neighborhood(&g, 1).unwrap());
874 assert_eq!(got, vec![vec![0, 1], vec![0, 1, 2], vec![1, 2]]);
875 }
876
877 #[test]
878 fn neighborhood_multi_edge_not_double_visited() {
879 let mut g = Graph::with_vertices(3);
880 g.add_edge(0, 1).unwrap();
881 g.add_edge(0, 1).unwrap();
882 g.add_edge(1, 2).unwrap();
883 let got = sorted_all(neighborhood(&g, 1).unwrap());
884 assert_eq!(got, vec![vec![0, 1], vec![0, 1, 2], vec![1, 2]]);
885 }
886
887 #[test]
888 fn neighborhood_mindist_1_excludes_self() {
889 let mut g = Graph::with_vertices(5);
891 for (u, v) in [(0, 1), (1, 2), (2, 3), (3, 4)] {
892 g.add_edge(u, v).unwrap();
893 }
894 let got = sorted_all(neighborhood_with_mode(&g, 1, NeighborhoodMode::All, 1).unwrap());
895 assert_eq!(
896 got,
897 vec![vec![1], vec![0, 2], vec![1, 3], vec![2, 4], vec![3]]
898 );
899 for list in &got {
900 for (i, neighbors) in got.iter().enumerate() {
901 let i_u32 = u32::try_from(i).unwrap();
902 if std::ptr::eq(list, neighbors) {
903 assert!(!list.contains(&i_u32), "mindist=1 should exclude self");
904 }
905 }
906 }
907 }
908}