1use foldhash::fast::RandomState;
14use priority_queue::PriorityQueue;
15use std::cmp::Ordering;
16use std::cmp::Reverse;
17use std::convert::Infallible;
18use std::hash::Hash;
19
20use crate::dictmap::*;
21use crate::line_graph::line_graph;
22
23use hashbrown::{HashMap, HashSet};
24use indexmap::IndexSet;
25use petgraph::graph::NodeIndex;
26use petgraph::visit::{
27 EdgeCount, EdgeIndexable, EdgeRef, GraphBase, GraphProp, IntoEdges, IntoNeighborsDirected,
28 IntoNodeIdentifiers, NodeCount, NodeIndexable,
29};
30use petgraph::{Incoming, Outgoing};
31use rayon::prelude::*;
32
33pub fn two_color<G>(graph: G) -> Option<DictMap<G::NodeId, u8>>
67where
68 G: NodeIndexable
69 + IntoNodeIdentifiers
70 + IntoNeighborsDirected
71 + GraphBase
72 + GraphProp
73 + NodeCount,
74 <G as GraphBase>::NodeId: std::cmp::Eq + Hash,
75{
76 let mut colors = DictMap::with_capacity(graph.node_count());
77 for node in graph.node_identifiers() {
78 if colors.contains_key(&node) {
79 continue;
80 }
81 let mut queue = vec![node];
82 colors.insert(node, 1);
83 while let Some(v) = queue.pop() {
84 let v_color: u8 = *colors.get(&v).unwrap();
85 let color: u8 = 1 - v_color;
86 for w in graph
87 .neighbors_directed(v, Outgoing)
88 .chain(graph.neighbors_directed(v, Incoming))
89 {
90 if let Some(color_w) = colors.get(&w) {
91 if *color_w == v_color {
92 return None;
93 }
94 } else {
95 colors.insert(w, color);
96 queue.push(w);
97 }
98 }
99 }
100 }
101 Some(colors)
102}
103
104#[derive(Clone, PartialEq)]
106pub enum ColoringStrategy {
107 Degree,
108 Saturation,
109 IndependentSet,
110}
111
112fn inner_greedy_node_color<G, F, E>(
113 graph: G,
114 preset_color_fn: F,
115 strategy: ColoringStrategy,
116) -> Result<DictMap<G::NodeId, usize>, E>
117where
118 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
119 G::NodeId: Hash + Eq + Send + Sync,
120 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
121{
122 match strategy {
123 ColoringStrategy::Degree => inner_greedy_node_color_strategy_degree(graph, preset_color_fn),
124 ColoringStrategy::Saturation => {
125 inner_greedy_node_color_strategy_saturation(graph, preset_color_fn)
126 }
127 ColoringStrategy::IndependentSet => {
128 inner_greedy_node_color_strategy_independent_set(graph, preset_color_fn)
129 }
130 }
131}
132
133fn inner_greedy_node_color_strategy_degree<G, F, E>(
134 graph: G,
135 mut preset_color_fn: F,
136) -> Result<DictMap<G::NodeId, usize>, E>
137where
138 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
139 G::NodeId: Hash + Eq + Send + Sync,
140 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
141{
142 let mut colors: DictMap<G::NodeId, usize> = DictMap::with_capacity(graph.node_count());
143 let mut node_vec: Vec<G::NodeId> = Vec::with_capacity(graph.node_count());
144 let mut sort_map: HashMap<G::NodeId, usize> = HashMap::with_capacity(graph.node_count());
145 for k in graph.node_identifiers() {
146 if let Some(color) = preset_color_fn(k)? {
147 colors.insert(k, color);
148 continue;
149 }
150 node_vec.push(k);
151 sort_map.insert(k, graph.edges(k).count());
152 }
153 node_vec.par_sort_by_key(|k| Reverse(sort_map.get(k)));
154
155 for node in node_vec {
156 let mut neighbor_colors: HashSet<usize> = HashSet::new();
157 for edge in graph.edges(node) {
158 let target = edge.target();
159 let existing_color = match colors.get(&target) {
160 Some(color) => color,
161 None => continue,
162 };
163 neighbor_colors.insert(*existing_color);
164 }
165 let mut current_color: usize = 0;
166 loop {
167 if !neighbor_colors.contains(¤t_color) {
168 break;
169 }
170 current_color += 1;
171 }
172 colors.insert(node, current_color);
173 }
174 Ok(colors)
175}
176
177#[derive(Clone, Eq, PartialEq)]
183struct SaturationStrategyData {
184 degree: usize,
186 saturation: usize,
188}
189
190impl Ord for SaturationStrategyData {
191 fn cmp(&self, other: &SaturationStrategyData) -> Ordering {
192 self.saturation
193 .cmp(&other.saturation)
194 .then_with(|| self.degree.cmp(&other.degree))
195 }
196}
197
198impl PartialOrd for SaturationStrategyData {
199 fn partial_cmp(&self, other: &SaturationStrategyData) -> Option<Ordering> {
200 Some(self.cmp(other))
201 }
202}
203
204fn inner_greedy_node_color_strategy_saturation<G, F, E>(
205 graph: G,
206 mut preset_color_fn: F,
207) -> Result<DictMap<G::NodeId, usize>, E>
208where
209 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
210 G::NodeId: Hash + Eq + Send + Sync,
211 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
212{
213 let mut colors: DictMap<G::NodeId, usize> = DictMap::with_capacity(graph.node_count());
214 let mut nbd_colors: HashMap<G::NodeId, HashSet<usize>> = graph
215 .node_identifiers()
216 .map(|k| (k, HashSet::new()))
217 .collect();
218
219 let mut pq: PriorityQueue<G::NodeId, SaturationStrategyData> =
220 PriorityQueue::with_capacity(graph.node_count());
221
222 for k in graph.node_identifiers() {
224 if let Some(color) = preset_color_fn(k)? {
225 colors.insert(k, color);
226 for v in graph.neighbors(k) {
227 nbd_colors.get_mut(&v).unwrap().insert(color);
228 }
229 }
230 }
231
232 for k in graph.node_identifiers() {
234 if colors.get(&k).is_none() {
235 let degree = graph
236 .neighbors(k)
237 .filter(|v| colors.get(v).is_none())
238 .count();
239 let saturation = nbd_colors.get(&k).unwrap().len();
240 pq.push(k, SaturationStrategyData { degree, saturation });
241 }
242 }
243
244 while let Some((k, _)) = pq.pop() {
246 let neighbor_colors = nbd_colors.get(&k).unwrap();
247 let mut current_color: usize = 0;
248 while neighbor_colors.contains(¤t_color) {
249 current_color += 1;
250 }
251
252 colors.insert(k, current_color);
253 for v in graph.neighbors(k) {
254 if colors.get(&v).is_none() {
255 nbd_colors.get_mut(&v).unwrap().insert(current_color);
256 let (_, vdata) = pq.get(&v).unwrap();
257
258 pq.push(
259 v,
260 SaturationStrategyData {
261 degree: vdata.degree - 1,
262 saturation: nbd_colors.get(&v).unwrap().len(),
263 },
264 );
265 }
266 }
267 }
268
269 Ok(colors)
270}
271
272fn inner_greedy_node_color_strategy_independent_set<G, F, E>(
273 graph: G,
274 mut preset_color_fn: F,
275) -> Result<DictMap<G::NodeId, usize>, E>
276where
277 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
278 G::NodeId: Hash + Eq + Send + Sync,
279 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
280{
281 let mut colors: DictMap<G::NodeId, usize> = DictMap::with_capacity(graph.node_count());
282
283 let mut preset: HashSet<G::NodeId> = HashSet::new();
284 let mut unprocessed: IndexSet<G::NodeId, RandomState> =
285 IndexSet::with_hasher(RandomState::default());
286
287 for k in graph.node_identifiers() {
289 if let Some(color) = preset_color_fn(k)? {
290 colors.insert(k, color);
291 preset.insert(k);
292 } else {
293 unprocessed.insert(k);
294 }
295 }
296
297 let mut current_color = 0;
298 while !unprocessed.is_empty() {
299 let mut remaining: IndexSet<G::NodeId, RandomState> =
300 IndexSet::with_hasher(RandomState::default());
301
302 for k in &preset {
304 if colors.get(k) == Some(¤t_color) {
305 for u in graph.neighbors(*k) {
306 if unprocessed.swap_take(&u).is_some() {
307 remaining.insert(u);
308 }
309 }
310 }
311 }
312
313 while !unprocessed.is_empty() {
315 let k = *unprocessed.iter().next().unwrap();
318 colors.insert(k, current_color);
319 unprocessed.swap_remove(&k);
320 for u in graph.neighbors(k) {
321 if unprocessed.swap_take(&u).is_some() {
322 remaining.insert(u);
323 }
324 }
325 }
326
327 unprocessed = remaining;
328 current_color += 1;
329 }
330
331 Ok(colors)
332}
333
334pub fn greedy_node_color<G>(graph: G) -> DictMap<G::NodeId, usize>
373where
374 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
375 G::NodeId: Hash + Eq + Send + Sync,
376{
377 inner_greedy_node_color(
378 graph,
379 |_| Ok::<Option<usize>, Infallible>(None),
380 ColoringStrategy::Degree,
381 )
382 .unwrap()
383}
384
385pub fn greedy_node_color_with_preset_colors<G, F, E>(
436 graph: G,
437 preset_color_fn: F,
438) -> Result<DictMap<G::NodeId, usize>, E>
439where
440 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
441 G::NodeId: Hash + Eq + Send + Sync,
442 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
443{
444 inner_greedy_node_color(graph, preset_color_fn, ColoringStrategy::Degree)
445}
446
447pub fn greedy_node_color_with_coloring_strategy<G, F, E>(
503 graph: G,
504 preset_color_fn: F,
505 strategy: ColoringStrategy,
506) -> Result<DictMap<G::NodeId, usize>, E>
507where
508 G: NodeCount + IntoNodeIdentifiers + IntoEdges,
509 G::NodeId: Hash + Eq + Send + Sync,
510 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
511{
512 inner_greedy_node_color(graph, preset_color_fn, strategy)
513}
514
515pub fn greedy_edge_color<G>(graph: G) -> DictMap<G::EdgeId, usize>
549where
550 G: EdgeCount + IntoNodeIdentifiers + IntoEdges,
551 G::EdgeId: Hash + Eq,
552{
553 let (new_graph, edge_to_node_map): (
554 petgraph::graph::UnGraph<(), ()>,
555 HashMap<G::EdgeId, NodeIndex>,
556 ) = line_graph(&graph, || (), || ());
557
558 let colors = greedy_node_color(&new_graph);
559
560 let mut edge_colors: DictMap<G::EdgeId, usize> = DictMap::with_capacity(graph.edge_count());
561
562 for edge in graph.edge_references() {
563 let edge_index = edge.id();
564 let node_index = edge_to_node_map.get(&edge_index).unwrap();
565 let edge_color = colors.get(node_index).unwrap();
566 edge_colors.insert(edge_index, *edge_color);
567 }
568
569 edge_colors
570}
571
572pub fn greedy_edge_color_with_coloring_strategy<G, F, E>(
611 graph: G,
612 preset_color_fn: F,
613 strategy: ColoringStrategy,
614) -> Result<DictMap<G::EdgeId, usize>, E>
615where
616 G: EdgeCount + IntoNodeIdentifiers + IntoEdges,
617 G::EdgeId: Hash + Eq,
618 F: Fn(G::EdgeId) -> Result<Option<usize>, E>,
619{
620 let (new_graph, edge_to_node_map): (
621 petgraph::graph::UnGraph<(), ()>,
622 HashMap<G::EdgeId, NodeIndex>,
623 ) = line_graph(&graph, || (), || ());
624
625 let node_to_edge_map: HashMap<&NodeIndex, &G::EdgeId> =
626 edge_to_node_map.iter().map(|(k, v)| (v, k)).collect();
627 let new_graph_preset_color_fn =
628 |x: NodeIndex| preset_color_fn(**node_to_edge_map.get(&x).unwrap());
629
630 let colors = inner_greedy_node_color(&new_graph, new_graph_preset_color_fn, strategy)?;
631
632 let mut edge_colors: DictMap<G::EdgeId, usize> = DictMap::with_capacity(graph.edge_count());
633
634 for edge in graph.edge_references() {
635 let edge_index = edge.id();
636 let node_index = edge_to_node_map.get(&edge_index).unwrap();
637 let edge_color = colors.get(node_index).unwrap();
638 edge_colors.insert(edge_index, *edge_color);
639 }
640
641 Ok(edge_colors)
642}
643
644struct MisraGries<G: GraphBase> {
645 graph: G,
647 max_node_degree: usize,
649 colors: Vec<Option<usize>>,
651 node_used_colors: Vec<HashSet<usize>>,
653}
654
655impl<G> MisraGries<G>
656where
657 G: EdgeIndexable + IntoEdges + NodeIndexable + IntoNodeIdentifiers,
658{
659 pub fn new(graph: G) -> Self {
660 let colors = vec![None; graph.edge_bound()];
661 let max_node_degree = graph
662 .node_identifiers()
663 .map(|node| graph.edges(node).count())
664 .max()
665 .unwrap_or(0);
666 let empty_set = HashSet::new();
667 let node_used_colors = vec![empty_set; graph.node_bound()];
668
669 MisraGries {
670 graph,
671 max_node_degree,
672 colors,
673 node_used_colors,
674 }
675 }
676
677 fn update_edge_colors(&mut self, new_colors: &Vec<(G::EdgeRef, usize)>) {
680 for (e, _) in new_colors {
682 if let Some(old_color) = self.get_edge_color(*e) {
683 self.remove_node_used_color(e.source(), old_color);
684 self.remove_node_used_color(e.target(), old_color);
685 }
686 }
687 for (e, c) in new_colors {
689 self.add_node_used_color(e.source(), *c);
690 self.add_node_used_color(e.target(), *c);
691 }
692 for (e, c) in new_colors {
693 self.colors[EdgeIndexable::to_index(&self.graph, e.id())] = Some(*c);
694 }
695 }
696
697 fn add_node_used_color(&mut self, u: G::NodeId, c: usize) {
699 let uindex = NodeIndexable::to_index(&self.graph, u);
700 self.node_used_colors[uindex].insert(c);
701 }
702
703 fn remove_node_used_color(&mut self, u: G::NodeId, c: usize) {
705 let uindex = NodeIndexable::to_index(&self.graph, u);
706 self.node_used_colors[uindex].remove(&c);
707 }
708
709 fn get_edge_color(&self, e: G::EdgeRef) -> Option<usize> {
711 self.colors[EdgeIndexable::to_index(&self.graph, e.id())]
712 }
713
714 fn get_used_colors(&self, u: G::NodeId) -> &HashSet<usize> {
716 let uindex = NodeIndexable::to_index(&self.graph, u);
717 &self.node_used_colors[uindex]
718 }
719
720 fn get_free_color(&self, u: G::NodeId) -> usize {
722 let used_colors = self.get_used_colors(u);
723 let free_color: usize = (0..self.max_node_degree + 1)
724 .position(|color| !used_colors.contains(&color))
725 .unwrap();
726 free_color
727 }
728
729 fn is_free_color(&self, u: G::NodeId, c: usize) -> bool {
731 !self.get_used_colors(u).contains(&c)
732 }
733
734 fn get_maximal_fan(&self, e: G::EdgeRef, u: G::NodeId, v: G::NodeId) -> Vec<G::EdgeRef> {
736 let mut fan: Vec<G::EdgeRef> = vec![e];
737
738 let mut neighbors: Vec<G::EdgeRef> = self.graph.edges(u).collect();
739
740 let mut last_node_in_fan = v;
741 neighbors.remove(
742 neighbors
743 .iter()
744 .position(|x| x.target() == last_node_in_fan)
745 .unwrap(),
746 );
747
748 let mut fan_extended: bool = true;
749 while fan_extended {
750 fan_extended = false;
751
752 for edge in &neighbors {
753 if let Some(color) = self.get_edge_color(*edge) {
754 if self.is_free_color(last_node_in_fan, color) {
755 fan.push(*edge);
756 last_node_in_fan = edge.target();
757 fan_extended = true;
758 neighbors.remove(
759 neighbors
760 .iter()
761 .position(|x| x.target() == last_node_in_fan)
762 .unwrap(),
763 );
764 break;
765 }
766 }
767 }
768 }
769
770 fan
771 }
772
773 fn flip_color(&self, c: usize, d: usize, e: usize) -> usize {
775 if e == c {
776 d
777 } else {
778 c
779 }
780 }
781
782 fn get_cdu_path(&self, u: G::NodeId, c: usize, d: usize) -> Vec<(G::EdgeRef, usize)> {
784 let mut path: Vec<(G::EdgeRef, usize)> = Vec::new();
785 let mut cur_node = u;
786 let mut cur_color = c;
787 let mut path_extended = true;
788
789 while path_extended {
790 path_extended = false;
791 for edge in self.graph.edges(cur_node) {
792 if let Some(color) = self.get_edge_color(edge) {
793 if color == cur_color {
794 path_extended = true;
795 path.push((edge, cur_color));
796 cur_node = edge.target();
797 cur_color = self.flip_color(c, d, cur_color);
798 break;
799 }
800 }
801 }
802 }
803 path
804 }
805
806 pub fn run_algorithm(&mut self) -> &Vec<Option<usize>> {
808 for edge in self.graph.edge_references() {
809 let u: G::NodeId = edge.source();
810 let v: G::NodeId = edge.target();
811 let fan = self.get_maximal_fan(edge, u, v);
812 let c = self.get_free_color(u);
813 let d = self.get_free_color(fan.last().unwrap().target());
814
815 let cdu_path = self.get_cdu_path(u, d, c);
817
818 let mut new_cdu_path_colors: Vec<(G::EdgeRef, usize)> =
820 Vec::with_capacity(cdu_path.len());
821 for (cdu_edge, color) in cdu_path {
822 let flipped_color = self.flip_color(c, d, color);
823 new_cdu_path_colors.push((cdu_edge, flipped_color));
824 }
825 self.update_edge_colors(&new_cdu_path_colors);
826
827 let mut w = 0;
829 for (i, x) in fan.iter().enumerate() {
830 if self.is_free_color(x.target(), d) {
831 w = i;
832 break;
833 }
834 }
835
836 let mut new_fan_colors: Vec<(G::EdgeRef, usize)> = Vec::with_capacity(w + 1);
838 for i in 1..w + 1 {
839 let next_color = self.get_edge_color(fan[i]).unwrap();
840 new_fan_colors.push((fan[i - 1], next_color));
841 }
842 new_fan_colors.push((fan[w], d));
843 self.update_edge_colors(&new_fan_colors);
844 }
845
846 &self.colors
847 }
848}
849
850pub fn misra_gries_edge_color<G>(graph: G) -> DictMap<G::EdgeId, usize>
890where
891 G: EdgeIndexable + IntoEdges + EdgeCount + NodeIndexable + IntoNodeIdentifiers,
892 G::EdgeId: Eq + Hash,
893{
894 let mut mg: MisraGries<G> = MisraGries::new(graph);
895 let colors = mg.run_algorithm();
896
897 let mut edge_colors: DictMap<G::EdgeId, usize> = DictMap::with_capacity(graph.edge_count());
898 for edge in graph.edge_references() {
899 let edge_index = edge.id();
900 let color = colors[EdgeIndexable::to_index(&graph, edge_index)].unwrap();
901 edge_colors.insert(edge_index, color);
902 }
903 edge_colors
904}
905
906#[cfg(test)]
907mod test_node_coloring {
908 use crate::coloring::{
909 greedy_node_color, greedy_node_color_with_coloring_strategy, two_color, ColoringStrategy,
910 };
911 use crate::dictmap::*;
912 use crate::generators::{complete_graph, cycle_graph, heavy_hex_graph, path_graph};
913 use std::convert::Infallible;
914 use std::hash::Hash;
915
916 use crate::petgraph::graph::NodeIndex;
917 use crate::petgraph::prelude::*;
918 use crate::petgraph::Undirected;
919 use petgraph::visit::{IntoEdgeReferences, IntoNodeIdentifiers};
920
921 fn check_node_colors<G>(graph: G, colors: &DictMap<G::NodeId, usize>)
923 where
924 G: IntoNodeIdentifiers + IntoEdgeReferences,
925 G::NodeId: Hash + Eq + Send + Sync,
926 {
927 for k in graph.node_identifiers() {
929 if !colors.contains_key(&k) {
930 panic!("Problem: some nodes have no color assigned.");
931 } else {
932 println!("Valid color: ok");
933 }
934 }
935
936 for e in graph.edge_references() {
938 if colors.get(&e.source()) == colors.get(&e.target()) {
939 panic!("Problem: same color for connected nodes.");
940 } else {
941 println!("Connected nodes: ok");
942 }
943 }
944 }
945
946 fn check_preset_colors<G, F, E>(
948 graph: G,
949 colors: &DictMap<G::NodeId, usize>,
950 mut preset_color_fn: F,
951 ) where
952 G: IntoNodeIdentifiers + IntoEdgeReferences,
953 G::NodeId: Hash + Eq + Send + Sync,
954 F: FnMut(G::NodeId) -> Result<Option<usize>, E>,
955 {
956 for k in graph.node_identifiers() {
958 if let Ok(Some(color)) = preset_color_fn(k) {
959 if *colors.get(&k).unwrap() != color {
960 panic!("Problem: colors are different from preset vales.");
961 } else {
962 println!("Preset values: ok");
963 }
964 }
965 }
966 }
967
968 #[test]
969 fn test_legacy_greedy_node_color_empty_graph() {
970 let graph = Graph::<(), (), Undirected>::new_undirected();
972 let colors = greedy_node_color(&graph);
973 let expected_colors: DictMap<NodeIndex, usize> = [].into_iter().collect();
974 assert_eq!(colors, expected_colors);
975 }
976
977 #[test]
978 fn test_legacy_greedy_node_color_simple_graph() {
979 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (0, 2)]);
981 let colors = greedy_node_color(&graph);
982 let expected_colors: DictMap<NodeIndex, usize> = [
983 (NodeIndex::new(0), 0),
984 (NodeIndex::new(1), 1),
985 (NodeIndex::new(2), 1),
986 ]
987 .into_iter()
988 .collect();
989 assert_eq!(colors, expected_colors);
990 }
991
992 #[test]
993 fn test_legacy_greedy_node_color_simple_graph_large_degree() {
994 let graph = Graph::<(), (), Undirected>::from_edges([
996 (0, 1),
997 (0, 2),
998 (0, 2),
999 (0, 2),
1000 (0, 2),
1001 (0, 2),
1002 ]);
1003 let colors = greedy_node_color(&graph);
1004 let expected_colors: DictMap<NodeIndex, usize> = [
1005 (NodeIndex::new(0), 0),
1006 (NodeIndex::new(1), 1),
1007 (NodeIndex::new(2), 1),
1008 ]
1009 .into_iter()
1010 .collect();
1011 assert_eq!(colors, expected_colors);
1012 }
1013
1014 #[test]
1015 fn test_greedy_node_color_empty_graph() {
1016 let graph = Graph::<(), (), Undirected>::new_undirected();
1018 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1019
1020 for strategy in [
1021 ColoringStrategy::Degree,
1022 ColoringStrategy::Saturation,
1023 ColoringStrategy::IndependentSet,
1024 ] {
1025 let colors =
1026 greedy_node_color_with_coloring_strategy(&graph, preset_color_fn, strategy);
1027 let expected_colors: DictMap<NodeIndex, usize> = [].into_iter().collect();
1028 assert_eq!(colors, Ok(expected_colors));
1029 }
1030 }
1031
1032 #[test]
1033 fn test_greedy_node_color_simple_graph() {
1034 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (0, 2)]);
1036 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1037 let colors = greedy_node_color_with_coloring_strategy(
1038 &graph,
1039 preset_color_fn,
1040 ColoringStrategy::Degree,
1041 );
1042 let expected_colors: DictMap<NodeIndex, usize> = [
1043 (NodeIndex::new(0), 0),
1044 (NodeIndex::new(1), 1),
1045 (NodeIndex::new(2), 1),
1046 ]
1047 .into_iter()
1048 .collect();
1049 assert_eq!(colors, Ok(expected_colors));
1050 }
1051
1052 #[test]
1053 fn test_greedy_node_color_simple_graph_large_degree() {
1054 let graph = Graph::<(), (), Undirected>::from_edges([
1056 (0, 1),
1057 (0, 2),
1058 (0, 2),
1059 (0, 2),
1060 (0, 2),
1061 (0, 2),
1062 ]);
1063 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1064 let colors = greedy_node_color_with_coloring_strategy(
1065 &graph,
1066 preset_color_fn,
1067 ColoringStrategy::Degree,
1068 );
1069 let expected_colors: DictMap<NodeIndex, usize> = [
1070 (NodeIndex::new(0), 0),
1071 (NodeIndex::new(1), 1),
1072 (NodeIndex::new(2), 1),
1073 ]
1074 .into_iter()
1075 .collect();
1076 assert_eq!(colors, Ok(expected_colors));
1077 }
1078
1079 #[test]
1080 fn test_greedy_node_color_saturation() {
1081 let graph = Graph::<(), (), Undirected>::from_edges([
1083 (0, 1),
1084 (0, 2),
1085 (0, 3),
1086 (3, 4),
1087 (4, 5),
1088 (5, 6),
1089 (5, 7),
1090 ]);
1091
1092 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1093 let colors = greedy_node_color_with_coloring_strategy(
1094 &graph,
1095 preset_color_fn,
1096 ColoringStrategy::Saturation,
1097 )
1098 .unwrap();
1099 check_node_colors(&graph, &colors);
1100
1101 let expected_colors: DictMap<NodeIndex, usize> = [
1102 (NodeIndex::new(0), 0),
1103 (NodeIndex::new(1), 1),
1104 (NodeIndex::new(2), 1),
1105 (NodeIndex::new(3), 1),
1106 (NodeIndex::new(4), 0),
1107 (NodeIndex::new(5), 1),
1108 (NodeIndex::new(6), 0),
1109 (NodeIndex::new(7), 0),
1110 ]
1111 .into_iter()
1112 .collect();
1113 assert_eq!(colors, expected_colors);
1114 }
1115
1116 #[test]
1117 fn test_greedy_node_color_saturation_and_preset() {
1118 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (0, 2), (2, 3), (2, 4)]);
1120
1121 let preset_color_fn = |node_idx: NodeIndex| -> Result<Option<usize>, Infallible> {
1122 if node_idx.index() == 0 {
1123 Ok(Some(1))
1124 } else {
1125 Ok(None)
1126 }
1127 };
1128
1129 let colors = greedy_node_color_with_coloring_strategy(
1130 &graph,
1131 preset_color_fn,
1132 ColoringStrategy::Saturation,
1133 )
1134 .unwrap();
1135 check_node_colors(&graph, &colors);
1136 check_preset_colors(&graph, &colors, preset_color_fn);
1137
1138 let expected_colors: DictMap<NodeIndex, usize> = [
1139 (NodeIndex::new(0), 1),
1140 (NodeIndex::new(1), 0),
1141 (NodeIndex::new(2), 0),
1142 (NodeIndex::new(3), 1),
1143 (NodeIndex::new(4), 1),
1144 ]
1145 .into_iter()
1146 .collect();
1147 assert_eq!(colors, expected_colors);
1148 }
1149
1150 #[test]
1151 fn test_greedy_node_color_independent_set() {
1152 let graph = Graph::<(), (), Undirected>::from_edges([
1154 (0, 1),
1155 (0, 2),
1156 (0, 3),
1157 (3, 4),
1158 (4, 5),
1159 (5, 6),
1160 (5, 7),
1161 ]);
1162
1163 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1164 let colors = greedy_node_color_with_coloring_strategy(
1165 &graph,
1166 preset_color_fn,
1167 ColoringStrategy::IndependentSet,
1168 )
1169 .unwrap();
1170 check_node_colors(&graph, &colors);
1171
1172 let expected_colors: DictMap<NodeIndex, usize> = [
1173 (NodeIndex::new(0), 0),
1174 (NodeIndex::new(1), 1),
1175 (NodeIndex::new(2), 1),
1176 (NodeIndex::new(3), 1),
1177 (NodeIndex::new(4), 0),
1178 (NodeIndex::new(5), 1),
1179 (NodeIndex::new(6), 0),
1180 (NodeIndex::new(7), 0),
1181 ]
1182 .into_iter()
1183 .collect();
1184 assert_eq!(colors, expected_colors);
1185 }
1186
1187 #[test]
1188 fn test_greedy_node_color_independent_set_and_preset() {
1189 let graph = Graph::<(), (), Undirected>::from_edges([
1191 (0, 1),
1192 (0, 2),
1193 (0, 3),
1194 (3, 4),
1195 (4, 5),
1196 (5, 6),
1197 (5, 7),
1198 ]);
1199
1200 let preset_color_fn = |node_idx: NodeIndex| -> Result<Option<usize>, Infallible> {
1201 if node_idx.index() == 0 {
1202 Ok(Some(1))
1203 } else if node_idx.index() == 3 {
1204 Ok(Some(0))
1205 } else {
1206 Ok(None)
1207 }
1208 };
1209
1210 let colors = greedy_node_color_with_coloring_strategy(
1211 &graph,
1212 preset_color_fn,
1213 ColoringStrategy::IndependentSet,
1214 )
1215 .unwrap();
1216 check_node_colors(&graph, &colors);
1217 check_preset_colors(&graph, &colors, preset_color_fn);
1218
1219 let expected_colors: DictMap<NodeIndex, usize> = [
1220 (NodeIndex::new(0), 1),
1221 (NodeIndex::new(1), 0),
1222 (NodeIndex::new(2), 0),
1223 (NodeIndex::new(3), 0),
1224 (NodeIndex::new(4), 1),
1225 (NodeIndex::new(5), 2),
1226 (NodeIndex::new(6), 0),
1227 (NodeIndex::new(7), 0),
1228 ]
1229 .into_iter()
1230 .collect();
1231 assert_eq!(colors, expected_colors);
1232 }
1233
1234 #[test]
1235 fn test_two_color_directed() {
1236 let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)];
1237
1238 let graph = DiGraph::<i32, i32>::from_edges(edge_list);
1239 let coloring = two_color(&graph).unwrap();
1240 let mut expected_colors = DictMap::new();
1241 expected_colors.insert(NodeIndex::new(0), 1);
1242 expected_colors.insert(NodeIndex::new(1), 0);
1243 expected_colors.insert(NodeIndex::new(2), 1);
1244 expected_colors.insert(NodeIndex::new(3), 0);
1245 expected_colors.insert(NodeIndex::new(4), 1);
1246 assert_eq!(coloring, expected_colors)
1247 }
1248
1249 #[test]
1250 fn test_two_color_directed_not_bipartite() {
1251 let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)];
1252
1253 let graph = DiGraph::<i32, i32>::from_edges(edge_list);
1254 let coloring = two_color(&graph);
1255 assert_eq!(None, coloring)
1256 }
1257
1258 #[test]
1259 fn test_two_color_undirected_not_bipartite() {
1260 let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 0), (3, 1)];
1261
1262 let graph = UnGraph::<i32, i32>::from_edges(edge_list);
1263 let coloring = two_color(&graph);
1264 assert_eq!(None, coloring)
1265 }
1266
1267 #[test]
1268 fn test_two_color_directed_with_isolates() {
1269 let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)];
1270
1271 let mut graph = DiGraph::<i32, i32>::from_edges(edge_list);
1272 graph.add_node(10);
1273 graph.add_node(11);
1274 let coloring = two_color(&graph).unwrap();
1275 let mut expected_colors = DictMap::new();
1276 expected_colors.insert(NodeIndex::new(0), 1);
1277 expected_colors.insert(NodeIndex::new(1), 0);
1278 expected_colors.insert(NodeIndex::new(2), 1);
1279 expected_colors.insert(NodeIndex::new(3), 0);
1280 expected_colors.insert(NodeIndex::new(4), 1);
1281 expected_colors.insert(NodeIndex::new(5), 1);
1282 expected_colors.insert(NodeIndex::new(6), 1);
1283 assert_eq!(coloring, expected_colors)
1284 }
1285
1286 #[test]
1287 fn test_two_color_undirected_with_isolates() {
1288 let edge_list = vec![(0, 1), (1, 2), (2, 3), (3, 4)];
1289
1290 let mut graph = UnGraph::<i32, i32>::from_edges(edge_list);
1291 graph.add_node(10);
1292 graph.add_node(11);
1293 let coloring = two_color(&graph).unwrap();
1294 let mut expected_colors = DictMap::new();
1295 expected_colors.insert(NodeIndex::new(0), 1);
1296 expected_colors.insert(NodeIndex::new(1), 0);
1297 expected_colors.insert(NodeIndex::new(2), 1);
1298 expected_colors.insert(NodeIndex::new(3), 0);
1299 expected_colors.insert(NodeIndex::new(4), 1);
1300 expected_colors.insert(NodeIndex::new(5), 1);
1301 expected_colors.insert(NodeIndex::new(6), 1);
1302 assert_eq!(coloring, expected_colors)
1303 }
1304
1305 #[test]
1306 fn test_path_graph() {
1307 let graph: petgraph::graph::UnGraph<(), ()> =
1308 path_graph(Some(7), None, || (), || (), false).unwrap();
1309 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1310
1311 for strategy in [
1312 ColoringStrategy::Degree,
1313 ColoringStrategy::Saturation,
1314 ColoringStrategy::IndependentSet,
1315 ] {
1316 let colors =
1317 greedy_node_color_with_coloring_strategy(&graph, preset_color_fn, strategy)
1318 .unwrap();
1319 check_node_colors(&graph, &colors);
1320 }
1321 }
1322
1323 #[test]
1324 fn test_cycle_graph() {
1325 let graph: petgraph::graph::UnGraph<(), ()> =
1326 cycle_graph(Some(15), None, || (), || (), false).unwrap();
1327 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1328
1329 for strategy in [
1330 ColoringStrategy::Degree,
1331 ColoringStrategy::Saturation,
1332 ColoringStrategy::IndependentSet,
1333 ] {
1334 let colors =
1335 greedy_node_color_with_coloring_strategy(&graph, preset_color_fn, strategy)
1336 .unwrap();
1337 check_node_colors(&graph, &colors);
1338 }
1339 }
1340
1341 #[test]
1342 fn test_heavy_hex_graph() {
1343 let graph: petgraph::graph::UnGraph<(), ()> =
1344 heavy_hex_graph(7, || (), || (), false).unwrap();
1345 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1346
1347 for strategy in [
1348 ColoringStrategy::Degree,
1349 ColoringStrategy::Saturation,
1350 ColoringStrategy::IndependentSet,
1351 ] {
1352 let colors =
1353 greedy_node_color_with_coloring_strategy(&graph, preset_color_fn, strategy)
1354 .unwrap();
1355 check_node_colors(&graph, &colors);
1356 }
1357 }
1358
1359 #[test]
1360 fn test_complete_graph() {
1361 let graph: petgraph::graph::UnGraph<(), ()> =
1362 complete_graph(Some(10), None, || (), || ()).unwrap();
1363 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1364
1365 for strategy in [
1366 ColoringStrategy::Degree,
1367 ColoringStrategy::Saturation,
1368 ColoringStrategy::IndependentSet,
1369 ] {
1370 let colors =
1371 greedy_node_color_with_coloring_strategy(&graph, preset_color_fn, strategy)
1372 .unwrap();
1373 check_node_colors(&graph, &colors);
1374 }
1375 }
1376}
1377
1378#[cfg(test)]
1379mod test_edge_coloring {
1380 use crate::coloring::{
1381 greedy_edge_color, greedy_edge_color_with_coloring_strategy, ColoringStrategy,
1382 };
1383 use crate::dictmap::DictMap;
1384 use crate::petgraph::Graph;
1385 use std::convert::Infallible;
1386
1387 use petgraph::graph::{edge_index, EdgeIndex};
1388 use petgraph::Undirected;
1389
1390 #[test]
1391 fn test_legacy_greedy_edge_color_empty_graph() {
1392 let graph = Graph::<(), (), Undirected>::new_undirected();
1394 let colors = greedy_edge_color(&graph);
1395 let expected_colors: DictMap<EdgeIndex, usize> = [].into_iter().collect();
1396 assert_eq!(colors, expected_colors);
1397 }
1398
1399 #[test]
1400 fn test_legacy_greedy_edge_color_simple_graph() {
1401 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3)]);
1403 let colors = greedy_edge_color(&graph);
1404 let expected_colors: DictMap<EdgeIndex, usize> = [
1405 (EdgeIndex::new(0), 1),
1406 (EdgeIndex::new(1), 0),
1407 (EdgeIndex::new(2), 1),
1408 ]
1409 .into_iter()
1410 .collect();
1411 assert_eq!(colors, expected_colors);
1412 }
1413
1414 #[test]
1415 fn test_legacy_greedy_edge_color_graph_with_removed_edges() {
1416 let mut graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0)]);
1418 graph.remove_edge(edge_index(1));
1419 let colors = greedy_edge_color(&graph);
1420 let expected_colors: DictMap<EdgeIndex, usize> = [
1421 (EdgeIndex::new(0), 1),
1422 (EdgeIndex::new(1), 0),
1423 (EdgeIndex::new(2), 1),
1424 ]
1425 .into_iter()
1426 .collect();
1427 assert_eq!(colors, expected_colors);
1428 }
1429
1430 #[test]
1431 fn test_greedy_edge_color_empty_graph() {
1432 let graph = Graph::<(), (), Undirected>::new_undirected();
1434 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1435
1436 let colors = greedy_edge_color_with_coloring_strategy(
1437 &graph,
1438 preset_color_fn,
1439 ColoringStrategy::Degree,
1440 )
1441 .unwrap();
1442 let expected_colors: DictMap<EdgeIndex, usize> = [].into_iter().collect();
1443 assert_eq!(colors, expected_colors);
1444 }
1445
1446 #[test]
1447 fn test_greedy_edge_color_simple_graph() {
1448 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3)]);
1450 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1451
1452 let colors = greedy_edge_color_with_coloring_strategy(
1453 &graph,
1454 preset_color_fn,
1455 ColoringStrategy::Degree,
1456 )
1457 .unwrap();
1458 let expected_colors: DictMap<EdgeIndex, usize> = [
1459 (EdgeIndex::new(0), 1),
1460 (EdgeIndex::new(1), 0),
1461 (EdgeIndex::new(2), 1),
1462 ]
1463 .into_iter()
1464 .collect();
1465 assert_eq!(colors, expected_colors);
1466 }
1467
1468 #[test]
1469 fn test_greedy_edge_color_graph_with_removed_edges() {
1470 let mut graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0)]);
1472 graph.remove_edge(edge_index(1));
1473
1474 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1475
1476 let colors = greedy_edge_color_with_coloring_strategy(
1477 &graph,
1478 preset_color_fn,
1479 ColoringStrategy::Degree,
1480 )
1481 .unwrap();
1482
1483 let expected_colors: DictMap<EdgeIndex, usize> = [
1484 (EdgeIndex::new(0), 1),
1485 (EdgeIndex::new(1), 0),
1486 (EdgeIndex::new(2), 1),
1487 ]
1488 .into_iter()
1489 .collect();
1490 assert_eq!(colors, expected_colors);
1491 }
1492
1493 #[test]
1494 fn test_greedy_edge_color_degree() {
1495 let graph =
1497 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1498 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1499
1500 let colors = greedy_edge_color_with_coloring_strategy(
1501 &graph,
1502 preset_color_fn,
1503 ColoringStrategy::Degree,
1504 )
1505 .unwrap();
1506 let expected_colors: DictMap<EdgeIndex, usize> = [
1507 (EdgeIndex::new(0), 1),
1508 (EdgeIndex::new(1), 0),
1509 (EdgeIndex::new(2), 1),
1510 (EdgeIndex::new(3), 0),
1511 (EdgeIndex::new(4), 2),
1512 ]
1513 .into_iter()
1514 .collect();
1515 assert_eq!(colors, expected_colors);
1516 }
1517
1518 #[test]
1519 fn test_greedy_edge_color_degree_with_preset() {
1520 let graph =
1522 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1523
1524 let preset_color_fn = |node_idx: EdgeIndex| -> Result<Option<usize>, Infallible> {
1525 if node_idx.index() == 1 {
1526 Ok(Some(1))
1527 } else {
1528 Ok(None)
1529 }
1530 };
1531
1532 let colors = greedy_edge_color_with_coloring_strategy(
1533 &graph,
1534 preset_color_fn,
1535 ColoringStrategy::Degree,
1536 )
1537 .unwrap();
1538 let expected_colors: DictMap<EdgeIndex, usize> = [
1539 (EdgeIndex::new(0), 0),
1540 (EdgeIndex::new(1), 1),
1541 (EdgeIndex::new(2), 0),
1542 (EdgeIndex::new(3), 1),
1543 (EdgeIndex::new(4), 2),
1544 ]
1545 .into_iter()
1546 .collect();
1547 assert_eq!(colors, expected_colors);
1548 }
1549
1550 #[test]
1551 fn test_greedy_edge_color_saturation() {
1552 let graph =
1554 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1555 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1556
1557 let colors = greedy_edge_color_with_coloring_strategy(
1558 &graph,
1559 preset_color_fn,
1560 ColoringStrategy::Saturation,
1561 )
1562 .unwrap();
1563 let expected_colors: DictMap<EdgeIndex, usize> = [
1564 (EdgeIndex::new(0), 1),
1565 (EdgeIndex::new(1), 0),
1566 (EdgeIndex::new(2), 1),
1567 (EdgeIndex::new(3), 0),
1568 (EdgeIndex::new(4), 2),
1569 ]
1570 .into_iter()
1571 .collect();
1572 assert_eq!(colors, expected_colors);
1573 }
1574
1575 #[test]
1576 fn test_greedy_edge_color_saturation_with_preset() {
1577 let graph =
1579 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1580
1581 let preset_color_fn = |node_idx: EdgeIndex| -> Result<Option<usize>, Infallible> {
1582 if node_idx.index() == 1 {
1583 Ok(Some(1))
1584 } else if node_idx.index() == 4 {
1585 Ok(Some(0))
1586 } else {
1587 Ok(None)
1588 }
1589 };
1590
1591 let colors = greedy_edge_color_with_coloring_strategy(
1592 &graph,
1593 preset_color_fn,
1594 ColoringStrategy::Saturation,
1595 )
1596 .unwrap();
1597 let expected_colors: DictMap<EdgeIndex, usize> = [
1598 (EdgeIndex::new(0), 0),
1599 (EdgeIndex::new(1), 1),
1600 (EdgeIndex::new(2), 2),
1601 (EdgeIndex::new(3), 1),
1602 (EdgeIndex::new(4), 0),
1603 ]
1604 .into_iter()
1605 .collect();
1606 assert_eq!(colors, expected_colors);
1607 }
1608
1609 #[test]
1610 fn test_greedy_edge_color_independent_set() {
1611 let graph =
1613 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1614 let preset_color_fn = |_| Ok::<Option<usize>, Infallible>(None);
1615
1616 let colors = greedy_edge_color_with_coloring_strategy(
1617 &graph,
1618 preset_color_fn,
1619 ColoringStrategy::IndependentSet,
1620 )
1621 .unwrap();
1622 let expected_colors: DictMap<EdgeIndex, usize> = [
1623 (EdgeIndex::new(0), 0),
1624 (EdgeIndex::new(1), 1),
1625 (EdgeIndex::new(2), 2),
1626 (EdgeIndex::new(3), 1),
1627 (EdgeIndex::new(4), 0),
1628 ]
1629 .into_iter()
1630 .collect();
1631 assert_eq!(colors, expected_colors);
1632 }
1633
1634 #[test]
1635 fn test_greedy_edge_color_independent_set_with_preset() {
1636 let graph =
1638 Graph::<(), (), Undirected>::from_edges([(0, 1), (1, 2), (2, 3), (3, 0), (2, 4)]);
1639
1640 let preset_color_fn = |node_idx: EdgeIndex| -> Result<Option<usize>, Infallible> {
1641 if node_idx.index() == 1 {
1642 Ok(Some(0))
1643 } else if node_idx.index() == 4 {
1644 Ok(Some(2))
1645 } else {
1646 Ok(None)
1647 }
1648 };
1649
1650 let colors = greedy_edge_color_with_coloring_strategy(
1651 &graph,
1652 preset_color_fn,
1653 ColoringStrategy::IndependentSet,
1654 )
1655 .unwrap();
1656 let expected_colors: DictMap<EdgeIndex, usize> = [
1657 (EdgeIndex::new(0), 1),
1658 (EdgeIndex::new(1), 0),
1659 (EdgeIndex::new(2), 1),
1660 (EdgeIndex::new(3), 0),
1661 (EdgeIndex::new(4), 2),
1662 ]
1663 .into_iter()
1664 .collect();
1665 assert_eq!(colors, expected_colors);
1666 }
1667}
1668
1669#[cfg(test)]
1670mod test_misra_gries_edge_coloring {
1671 use crate::coloring::misra_gries_edge_color;
1672 use crate::dictmap::DictMap;
1673 use crate::generators::{complete_graph, cycle_graph, heavy_hex_graph, path_graph};
1674 use crate::petgraph::Graph;
1675
1676 use hashbrown::HashSet;
1677 use petgraph::graph::EdgeIndex;
1678 use petgraph::visit::{EdgeRef, IntoEdges, IntoNodeIdentifiers, NodeIndexable};
1679 use petgraph::Undirected;
1680 use std::fmt::Debug;
1681 use std::hash::Hash;
1682
1683 fn check_edge_coloring<G>(graph: G, colors: &DictMap<G::EdgeId, usize>)
1684 where
1685 G: NodeIndexable + IntoEdges + IntoNodeIdentifiers,
1686 G::EdgeId: Eq + Hash + Debug,
1687 {
1688 for edge in graph.edge_references() {
1690 if !colors.contains_key(&edge.id()) {
1691 panic!("Problem: edge {:?} has no color assigned.", &edge.id());
1692 }
1693 }
1694
1695 let mut max_color = 0;
1699 let mut max_node_degree = 0;
1700 let node_indices: Vec<G::NodeId> = graph.node_identifiers().collect();
1701 for node in node_indices {
1702 let mut cur_node_degree = 0;
1703 let mut used_colors: HashSet<usize> = HashSet::new();
1704 for edge in graph.edges(node) {
1705 let color = colors.get(&edge.id()).unwrap();
1706 used_colors.insert(*color);
1707 cur_node_degree += 1;
1708 if max_color < *color {
1709 max_color = *color;
1710 }
1711 }
1712 if used_colors.len() < cur_node_degree {
1713 panic!(
1714 "Problem: node {:?} does not have enough colors.",
1715 NodeIndexable::to_index(&graph, node)
1716 );
1717 }
1718
1719 if cur_node_degree > max_node_degree {
1720 max_node_degree = cur_node_degree
1721 }
1722 }
1723
1724 if max_color > max_node_degree {
1727 panic!(
1728 "Problem: too many colors are used ({} colors used, {} max node degree)",
1729 max_color + 1,
1730 max_node_degree
1731 );
1732 }
1733 }
1734
1735 #[test]
1736 fn test_simple_graph() {
1737 let graph = Graph::<(), (), Undirected>::from_edges([(0, 1), (0, 2), (0, 3), (3, 4)]);
1738 let colors = misra_gries_edge_color(&graph);
1739 check_edge_coloring(&graph, &colors);
1740
1741 let expected_colors: DictMap<EdgeIndex, usize> = [
1742 (EdgeIndex::new(0), 0),
1743 (EdgeIndex::new(1), 2),
1744 (EdgeIndex::new(2), 1),
1745 (EdgeIndex::new(3), 3),
1746 ]
1747 .into_iter()
1748 .collect();
1749 assert_eq!(colors, expected_colors);
1750 }
1751
1752 #[test]
1753 fn test_path_graph() {
1754 let graph: petgraph::graph::UnGraph<(), ()> =
1755 path_graph(Some(7), None, || (), || (), false).unwrap();
1756 let colors = misra_gries_edge_color(&graph);
1757 check_edge_coloring(&graph, &colors);
1758 }
1759
1760 #[test]
1761 fn test_cycle_graph() {
1762 let graph: petgraph::graph::UnGraph<(), ()> =
1763 cycle_graph(Some(15), None, || (), || (), false).unwrap();
1764 let colors = misra_gries_edge_color(&graph);
1765 check_edge_coloring(&graph, &colors);
1766 }
1767
1768 #[test]
1769 fn test_heavy_hex_graph() {
1770 let graph: petgraph::graph::UnGraph<(), ()> =
1771 heavy_hex_graph(7, || (), || (), false).unwrap();
1772 let colors = misra_gries_edge_color(&graph);
1773 check_edge_coloring(&graph, &colors);
1774 }
1775
1776 #[test]
1777 fn test_complete_graph() {
1778 let graph: petgraph::graph::UnGraph<(), ()> =
1779 complete_graph(Some(10), None, || (), || ()).unwrap();
1780 let colors = misra_gries_edge_color(&graph);
1781 check_edge_coloring(&graph, &colors);
1782 }
1783}