1use itertools::Itertools;
2use log::debug;
3use std::collections::{HashMap, HashSet};
4use std::fmt::Display;
5use std::iter::zip;
6
7use crate::graph_parser::deserialize_string_to_graph;
8
9#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10pub struct NamedNode {
11 pub(crate) id: usize,
12 pub(crate) name: String,
13 pub(crate) weight: i64,
14}
15
16#[derive(Clone, Debug, Hash, Eq, PartialEq)]
17pub struct Edge {
18 pub(crate) u: usize,
19 pub(crate) v: usize,
20}
21
22#[derive(Clone, Debug)]
23pub struct Graph {
24 pub(crate) vertices: Vec<NamedNode>,
25 pub(crate) edges: Vec<Edge>,
26}
27
28impl Ord for NamedNode {
29 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
30 match (self.weight, other.weight) {
31 (u, v) if u > v => std::cmp::Ordering::Greater,
32 (u, v) if u == v => std::cmp::Ordering::Equal,
33 (u, v) if u < v => std::cmp::Ordering::Less,
34 (_, _) => unreachable!(),
35 }
36 }
37}
38
39impl PartialOrd for NamedNode {
40 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
41 Some(self.cmp(other))
42 }
43}
44
45impl TryFrom<String> for Graph {
47 type Error = &'static str;
48
49 fn try_from(value: String) -> Result<Self, Self::Error> {
50 match deserialize_string_to_graph(&value) {
51 Ok(graph) => Ok(graph),
52 Err(err_tup) => {
53 debug!(
54 "Unable to parse string '{}' into graph because of errors.\n1.{}\n2.{}",
55 value, err_tup.0, err_tup.1
56 );
57 Err("Unable to parse string into graph.")
58 }
59 }
60 }
61}
62
63impl FromIterator<i64> for Graph {
65 fn from_iter<T: IntoIterator<Item = i64>>(iter: T) -> Self {
66 let v = iter.into_iter().collect_vec();
67 Graph::from(v)
68 }
69}
70
71impl From<Vec<i64>> for Graph {
72 fn from(value: Vec<i64>) -> Self {
73 Graph::new((0..value.len()).map(|x| x.to_string()).collect(), value)
74 }
75}
76
77impl From<Vec<(String, i64)>> for Graph {
78 fn from(value: Vec<(String, i64)>) -> Self {
79 Graph::new(
80 value.iter().map(|x| x.0.clone()).collect(),
81 value.iter().map(|x| x.1).collect(),
82 )
83 }
84}
85
86impl From<HashMap<String, i64>> for Graph {
87 fn from(value: HashMap<String, i64>) -> Self {
88 Graph::new(
89 value.keys().map(|k| k.to_owned()).collect_vec(),
90 value.values().map(|w| w.to_owned()).collect_vec(),
91 )
92 }
93}
94
95impl From<Vec<NamedNode>> for Graph {
96 fn from(value: Vec<NamedNode>) -> Self {
97 let edges = value
98 .iter()
99 .permutations(2)
100 .map(|uv| {
101 let u = uv.first().unwrap();
102 let v = uv.get(1).unwrap();
103 Edge { u: u.id, v: v.id }
104 })
105 .collect();
106 Graph {
107 vertices: value,
108 edges,
109 }
110 }
111}
112
113impl From<Vec<&NamedNode>> for Graph {
114 fn from(value: Vec<&NamedNode>) -> Self {
115 let edges = value
116 .iter()
117 .permutations(2)
118 .map(|uv| {
119 let u = uv.first().unwrap();
120 let v = uv.get(1).unwrap();
121 Edge { u: u.id, v: v.id }
122 })
123 .collect();
124 Graph {
125 vertices: value.into_iter().map(|x| x.to_owned()).collect(),
126 edges,
127 }
128 }
129}
130
131impl From<HashMap<(String, String), i64>> for Graph {
133 fn from(value: HashMap<(String, String), i64>) -> Self {
134 let mut unique_v: HashSet<String> = HashSet::new();
135 value.keys().for_each(|(s1, s2)| {
136 unique_v.insert(s1.to_string());
137 unique_v.insert(s2.to_string());
138 });
139 let mut name_weight_tup: HashMap<String, i64> =
140 unique_v.clone().into_iter().map(|x| (x, 0_i64)).collect();
141 for uv in unique_v.into_iter().permutations(2) {
142 let u: &String = uv.first().unwrap();
143 let v: &String = uv.get(1).unwrap();
144 let weight = value.get(&(u.to_string(), v.to_string())).unwrap_or(&0);
145 if let Some(x) = name_weight_tup.get_mut(u) {
146 *x -= weight;
147 }
148 if let Some(x) = name_weight_tup.get_mut(v) {
149 *x += weight;
150 }
151 }
152 Graph::from(name_weight_tup)
153 }
154}
155
156impl From<Vec<((String, String), i64)>> for Graph {
157 fn from(value: Vec<((String, String), i64)>) -> Self {
158 let map: HashMap<(String, String), i64> = value.into_iter().collect();
159 Graph::from(map)
160 }
161}
162
163#[allow(clippy::manual_try_fold)]
164impl Display for Graph {
165 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
166 let mut out = self.vertices.iter().fold(Ok(()), |acc, v| {
167 acc.and_then(|_| write!(f, "{}: {}; ", &v.name, &v.weight))
168 });
169 out = out.and_then(|_| writeln!(f));
170 out = out.and_then(|_| write!(f, "Edges: "));
171 self.edges.iter().fold(out, |acc, e| {
172 acc.and_then(|_| write!(f, "{} -> {}; ", &e.u, &e.v))
173 })
174 }
175}
176
177impl Graph {
178 pub(crate) fn new(names: Vec<String>, weights: Vec<i64>) -> Self {
179 assert!(
180 names.len() == weights.len(),
181 "The length of the names and weights must be the same."
182 );
183 let mut vertices: Vec<NamedNode> = vec![];
184 let mut edges: Vec<Edge> = vec![];
185 let mut id = 0;
186 for (name, weight) in zip(names, weights) {
187 vertices.push(NamedNode { id, name, weight });
188 id += 1;
189 }
190 for uv in (0..id).permutations(2) {
191 let u: usize = *uv.first().unwrap();
192 let v: usize = *uv.get(1).unwrap();
193 edges.push(Edge { u, v });
194 }
195 let g = Graph { vertices, edges };
196 debug!("Created following graph:\n{}", g.to_string());
197 g
198 }
199
200 #[allow(dead_code)]
201 pub(crate) fn get_node_from_name(&self, s: String) -> Option<&NamedNode> {
202 self.vertices.iter().find(|v| v.name == s)
203 }
204
205 pub(crate) fn get_node_from_id(&self, id: usize) -> Option<&NamedNode> {
206 self.vertices.iter().find(|v| v.id == id)
207 }
208
209 pub(crate) fn get_node_name(&self, id: usize) -> Option<String> {
210 self.vertices
211 .iter()
212 .find(|v| v.id == id)
213 .map(|v| v.name.clone())
214 }
215
216 pub(crate) fn get_node_name_or(&self, id: usize, or: String) -> String {
217 self.get_node_name(id).unwrap_or(or)
218 }
219
220 pub(crate) fn get_average_vertex_weight(&self) -> f64 {
221 self.vertices.iter().map(|v| v.weight).sum::<i64>() as f64 / (self.vertices.len() as f64)
222 }
223}