calyx_opt/analysis/
graph_coloring.rs1use calyx_utils::{Idx, WeightGraph};
2use itertools::Itertools;
3use petgraph::algo;
4use std::{
5 collections::{BTreeMap, HashMap},
6 fmt::Display,
7 hash::Hash,
8};
9
10pub struct GraphColoring<T> {
12 graph: WeightGraph<T>,
13 color_freq_map: HashMap<Idx, i64>,
17}
18
19impl<T, C> From<C> for GraphColoring<T>
20where
21 T: Hash + Eq + Ord,
22 C: Iterator<Item = T>,
23{
24 fn from(nodes: C) -> Self {
25 let graph = WeightGraph::from(nodes);
26 GraphColoring {
27 graph,
28 color_freq_map: HashMap::new(),
29 }
30 }
31}
32
33impl<'a, T> GraphColoring<T>
34where
35 T: 'a + Eq + Hash + Clone + Ord,
36{
37 #[inline(always)]
39 pub fn insert_conflict(&mut self, a: &T, b: &T) {
40 self.graph.add_edge(a, b);
41 }
42
43 pub fn insert_conflicts<C>(&mut self, items: C)
45 where
46 C: Iterator<Item = &'a T> + Clone,
47 {
48 self.graph.add_all_edges(items)
49 }
50
51 pub fn has_nodes(&self) -> bool {
52 self.graph.graph.node_count() > 0
53 }
54
55 fn increase_freq(&mut self, idx: Idx) {
57 self.color_freq_map
58 .entry(idx)
59 .and_modify(|v| *v += 1)
60 .or_insert(1);
61 }
62
63 pub fn get_share_freqs(&mut self) -> HashMap<i64, i64> {
65 let mut pdf: HashMap<i64, i64> = HashMap::new();
66 for value in self.color_freq_map.values() {
68 pdf.entry(*value).and_modify(|v| *v += 1).or_insert(1);
72 }
73 pdf
74 }
75
76 pub fn color_greedy(
81 &mut self,
82 bound: Option<i64>,
83 keep_self_color: bool,
84 ) -> HashMap<T, T> {
85 let mut all_colors: BTreeMap<Idx, i64> = BTreeMap::new();
86 let mut coloring: HashMap<Idx, Idx> = HashMap::new();
87 let always_share = bound.is_none();
88 let bound_if_exists = if always_share { 0 } else { bound.unwrap() };
90
91 let sccs = algo::tarjan_scc(&self.graph.graph);
93 for scc in sccs.into_iter().sorted_by(|a, b| b.len().cmp(&a.len())) {
95 let is_complete = scc.iter().all(|&idx| {
97 self.graph.graph.neighbors(idx).count() == scc.len() - 1
98 });
99 if is_complete {
102 let mut available_colors: Vec<_> =
103 all_colors.keys().cloned().collect_vec();
104
105 for nidx in scc.into_iter().sorted() {
107 if !available_colors.is_empty() {
108 let c = available_colors.remove(0);
109 coloring.insert(nidx, c);
110 self.increase_freq(c);
111 if let Some(num_used) = all_colors.get_mut(&c) {
112 *num_used += 1;
113 if !always_share && *num_used == bound_if_exists {
114 all_colors.remove(&c);
115 }
116 }
117 } else {
118 all_colors.insert(nidx, 1);
119 coloring.insert(nidx, nidx);
120 self.increase_freq(nidx);
121 if !always_share && bound_if_exists == 1 {
122 all_colors.remove(&nidx);
123 }
124 }
125 }
126 } else {
127 for nidx in scc.into_iter().sorted() {
128 let mut available_colors = all_colors.clone();
129 for item in self.graph.graph.neighbors(nidx) {
131 if coloring.contains_key(&item) {
133 available_colors.remove(&coloring[&item]);
135 }
136 }
137
138 let color = available_colors.iter().next();
139 match color {
140 Some((c, _)) => {
141 coloring.insert(nidx, *c);
142 self.increase_freq(*c);
143 if let Some(num_used) = all_colors.get_mut(c) {
144 *num_used += 1;
145 if !always_share && *num_used == bound_if_exists
146 {
147 all_colors.remove(c);
148 }
149 }
150 }
151 None => {
152 all_colors.insert(nidx, 1);
154 coloring.insert(nidx, nidx);
155 self.increase_freq(nidx);
156 if !always_share && bound_if_exists == 1 {
157 all_colors.remove(&nidx);
158 }
159 }
160 };
161 }
162 }
163 }
164
165 let rev_map = self.graph.reverse_index();
166 coloring
167 .into_iter()
168 .map(|(n1, n2)| (rev_map[&n1].clone(), rev_map[&n2].clone()))
169 .filter(|(a, b)| (a != b) || keep_self_color)
170 .collect()
171 }
172
173 pub fn reverse_coloring(coloring: &HashMap<T, T>) -> HashMap<T, Vec<T>> {
175 let mut rev_coloring: HashMap<T, Vec<T>> = HashMap::new();
176 for (node, color) in coloring {
177 rev_coloring
178 .entry(color.clone())
179 .or_default()
180 .push(node.clone());
181 }
182 rev_coloring
183 }
184 pub fn welsh_powell_coloring(&self) -> HashMap<T, T> {
185 let mut coloring: HashMap<T, T> = HashMap::new();
186
187 let mut degree_ordering: Vec<&T> = self
188 .graph
189 .nodes()
190 .sorted()
191 .sorted_by(|a, b| self.graph.degree(b).cmp(&self.graph.degree(a)))
192 .collect();
193
194 let rev_map = self.graph.reverse_index();
195 while !degree_ordering.is_empty() {
196 let head = degree_ordering.remove(0);
197 if !coloring.contains_key(head) {
199 coloring.insert(head.clone(), head.clone());
200 for &node in °ree_ordering {
201 if coloring.contains_key(node) {
202 continue;
203 }
204 if !self
205 .graph
206 .graph
207 .neighbors(self.graph.index_map[node])
208 .any(|x| coloring.get(&rev_map[&x]) == Some(head))
209 {
210 coloring.insert(node.clone(), head.clone());
211 }
212 }
213 }
214 }
215
216 coloring
217 }
218}
219
220impl<T: Eq + Hash + ToString + Clone + Ord> Display for GraphColoring<T> {
221 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
222 self.graph.to_string().fmt(f)
223 }
224}