1use super::{read_dimacs, Error as DimacsError};
18
19use crate::{Buildable, Builder};
20
21use std::cmp::{max, min};
22use std::collections::HashSet;
23use std::f64;
24use std::fs;
25use std::io::{BufRead, BufReader};
26
27#[derive(Copy, Clone, PartialEq, Debug)]
29pub enum Metric {
30 LINF,
32 L(f64),
34 L2S,
36}
37
38#[derive(PartialEq, Debug)]
40pub enum Param {
41 MinLength(f64),
43 MaxLength(f64),
45}
46
47pub fn read<G>(fname: &str) -> Result<(G, Vec<f64>), DimacsError>
52where
53 G: Buildable,
54{
55 read_from_buf(&mut BufReader::new(fs::File::open(fname)?))
56}
57
58pub fn read_from_buf<R, G>(buf: &mut R) -> Result<(G, Vec<f64>), DimacsError>
62where
63 R: BufRead,
64 G: Buildable,
65{
66 let mut g = G::new_builder();
67 let mut weights = vec![];
68 let mut nnodes = 0;
69 let mut nedges = 0;
70 let mut gnodes = vec![];
71 let mut nodes = HashSet::new();
72 let mut edges = HashSet::new();
73 let mut dim = 0;
74 let mut metric = None;
75 let mut vertices = vec![];
76 let mut minlength = None;
77 let mut maxlength = None;
78
79 let mut start = true;
80 read_dimacs(buf, &mut |d, toks| {
81 if start {
82 if d != 'p' {
83 return Err(DimacsError::Format {
84 line: toks.line,
85 msg: format!("expected problem line starting with 'p', got: {}", d),
86 });
87 }
88 let edge = toks.next().unwrap_or("end of line");
89 if edge != "edge" {
90 return Err(DimacsError::Format {
91 line: toks.line,
92 msg: format!("expected 'edge' in p line, got: {}", edge),
93 });
94 }
95 nnodes = toks.number()?;
96 nedges = toks.number()?;
97 toks.end()?;
98
99 g.reserve(nnodes, nedges);
100 gnodes = g.add_nodes(nnodes);
101 weights.clear();
102 weights.resize(nnodes, 0.0);
103
104 start = false;
105 } else {
106 match d {
107 'n' => {
108 let id: usize = toks.number()?;
109 let val = toks.number()?;
110 toks.end()?;
111 if id < 1 || id > nnodes {
112 return Err(DimacsError::Format {
113 line: toks.line,
114 msg: format!("invalid node id {} (must be <= {})", id, nnodes),
115 });
116 }
117 if !nodes.insert(id) {
118 return Err(DimacsError::Format {
119 line: toks.line,
120 msg: format!("duplicate node id {}", id),
121 });
122 }
123 weights[id - 1] = val;
124 }
125 'e' => {
126 let u: usize = toks.number()?;
127 let v: usize = toks.number()?;
128 toks.end()?;
129 if u < 1 || u > nnodes {
130 return Err(DimacsError::Format {
131 line: toks.line,
132 msg: format!("invalid node id {} in edge", u),
133 });
134 }
135 if v < 1 || v > nnodes {
136 return Err(DimacsError::Format {
137 line: toks.line,
138 msg: format!("invalid node id {} in edge", v),
139 });
140 }
141 if u == v {
142 return Err(DimacsError::Format {
143 line: toks.line,
144 msg: format!("invalid loop ({},{}) in edge", u, u),
145 });
146 }
147 if !edges.insert((min(u, v), max(u, v))) {
148 return Err(DimacsError::Format {
149 line: toks.line,
150 msg: format!("duplicate edge ({},{})", u, v),
151 });
152 }
153 g.add_edge(gnodes[u - 1], gnodes[v - 1]);
154 }
155 'd' => {
156 let d: usize = toks.number()?;
157 let m = match toks.next() {
158 Some("LINF") => Metric::LINF,
159 Some("L2S") => Metric::L2S,
160 Some(m) if !m.is_empty() && m.starts_with('L') => {
161 let p: f64 = match m[1..].parse() {
162 Ok(x) => x,
163 Err(_) => {
164 return Err(DimacsError::Format {
165 line: toks.line,
166 msg: "invalid norm".to_string(),
167 });
168 }
169 };
170 if p <= 0.0 {
171 return Err(DimacsError::Format {
172 line: toks.line,
173 msg: format!("p of p-norm must be > 0 (got: {})", p),
174 });
175 }
176 Metric::L(p)
177 }
178 Some(_) => {
179 return Err(DimacsError::Format {
180 line: toks.line,
181 msg: "invalid norm".to_string(),
182 });
183 }
184 None => {
185 return Err(DimacsError::Format {
186 line: toks.line,
187 msg: "missing norm".to_string(),
188 });
189 }
190 };
191 toks.end()?;
192
193 if d < 1 {
194 return Err(DimacsError::Format {
195 line: toks.line,
196 msg: format!("invalid dimension {} < 1", d),
197 });
198 }
199 if dim > 0 {
200 return Err(DimacsError::Format {
201 line: toks.line,
202 msg: "duplicate dimension".to_string(),
203 });
204 }
205
206 dim = d;
207 metric = Some(m);
208 vertices.reserve(nnodes);
209 }
210 'v' => {
211 if dim == 0 {
212 return Err(DimacsError::Format {
213 line: toks.line,
214 msg: "missing dimension line before vertex line".to_string(),
215 });
216 }
217
218 let mut vs: Vec<f64> = Vec::new();
219 for _ in 0..dim {
220 vs.push(toks.number()?);
221 }
222 toks.end()?;
223
224 if dim != vs.len() {
225 return Err(DimacsError::Format {
226 line: toks.line,
227 msg: format!("vertex line has too many entries {} (expected: {})", vs.len(), dim),
228 });
229 }
230
231 vertices.push(vs);
232 }
233 'x' => {
234 let par = toks.str()?;
235 let l: f64 = toks.number()?;
236 toks.end()?;
237 match par {
238 "MINLENGTH" => {
239 if minlength.is_some() {
240 return Err(DimacsError::Format {
241 line: toks.line,
242 msg: "duplicate parameter MINLENGTH".to_string(),
243 });
244 }
245 minlength = Some(l)
246 }
247 "MAXLENGTH" => {
248 if maxlength.is_some() {
249 return Err(DimacsError::Format {
250 line: toks.line,
251 msg: "duplicate parameter MAXLENGTH".to_string(),
252 });
253 }
254 maxlength = Some(l)
255 }
256 _ => {
257 return Err(DimacsError::Format {
258 line: toks.line,
259 msg: format!("unknown parameter {}", par),
260 });
261 }
262 };
263 }
264 _ => {
265 return Err(DimacsError::Format {
266 line: toks.line,
267 msg: format!("invalid command {}", d),
268 });
269 }
270 }
271 }
272
273 Ok(())
274 })?;
275
276 if dim > 0 {
278 let metric = metric.unwrap();
279 let minl = match minlength {
280 Some(l) => l,
281 _ => 0.0,
282 };
283 let maxl = match maxlength {
284 Some(l) => l,
285 _ => f64::INFINITY,
286 };
287 for u in 0..nnodes {
288 for v in u + 1..nnodes {
289 let d = dist(&vertices[u], &vertices[v], metric);
290 if !edges.contains(&(u + 1, v + 1)) {
292 if d >= minl && d <= maxl {
294 return Err(DimacsError::Format {
295 line: 0,
296 msg: format!("edge ({},{}) should be contained in the graph", u, v),
297 });
298 }
299 } else {
300 if d < minl {
302 return Err(DimacsError::Format {
303 line: 0,
304 msg: format!("edge ({},{}) should not be contained in the graph (too short)", u, v),
305 });
306 }
307 if d > maxl {
308 return Err(DimacsError::Format {
309 line: 0,
310 msg: format!("edge ({},{}) should not be contained in the graph (too long)", u, v),
311 });
312 }
313 }
314 }
315 }
316 }
317
318 Ok((g.into_graph(), weights))
319}
320
321fn dist(x: &[f64], y: &[f64], metric: Metric) -> f64 {
322 let mut d: f64 = 0.0;
323 match metric {
324 Metric::LINF => {
325 for i in 0..x.len() {
326 d = f64::max(d, f64::abs(x[i] - y[i]));
327 }
328 }
329 Metric::L2S => {
330 for i in 0..x.len() {
331 d += (x[i] - y[i]) * (x[i] - y[i]);
332 }
333 }
334 Metric::L(p) => {
335 for i in 0..x.len() {
336 d += (x[i] - y[i]).abs().powf(p);
337 }
338 d = d.powf(1.0 / p);
339 }
340 }
341 d
342}
343
344#[cfg(test)]
345mod tests {
346 use super::read_dimacs;
347 use super::read_from_buf;
348 use crate::traits::{FiniteGraph, IndexGraph, Undirected};
349 use crate::LinkedListGraph;
350 use std::io::Cursor;
351
352 #[test]
353 fn test_read() {
354 let file = "
355c some comment
356
357p edge 12 5
358";
359 read_dimacs(&mut Cursor::new(file), &mut |c, toks| {
360 assert_eq!(c, 'p');
361 assert_eq!(toks.next(), Some("edge"));
362 assert_eq!(toks.number::<usize>().unwrap(), 12);
363 assert_eq!(toks.number::<usize>().unwrap(), 5);
364 assert_eq!(toks.next(), None);
365 Ok(())
366 })
367 .unwrap();
368 }
369
370 #[test]
371 fn parse_file_test() {
372 let file = "c this is a test file
373
374p edge 6 9
375 n 1 12
376n 6 42.23
377
378c there might be empty lines
379
380e 1 4
381e 1 5
382e 1 6
383e 2 4
384e 2 5
385e 2 6
386e 3 4
387e 3 5
388e 3 6
389
390d 2 L2
391v 1 1
392v 1 2
393v 1 3
394v 10 1
395v 10 2
396v 10 3
397
398x MINLENGTH 5
399x MAXLENGTH 100
400
401c end of the file
402";
403 let (g, weights) = read_from_buf::<_, LinkedListGraph>(&mut Cursor::new(file)).unwrap();
404
405 assert_eq!(g.num_nodes(), 6);
406 assert_eq!(g.num_edges(), 9);
407
408 for u in 0..3 {
409 let mut vs: Vec<_> = g.neighs(g.id2node(u)).map(|(_, v)| g.node_id(v)).collect();
410 vs.sort();
411 assert_eq!(vs, vec![3, 4, 5]);
412 }
413
414 for v in 3..6 {
415 let mut vs: Vec<_> = g.neighs(g.id2node(v)).map(|(_, v)| g.node_id(v)).collect();
416 vs.sort();
417 assert_eq!(vs, vec![0, 1, 2]);
418 }
419
420 for u in g.nodes() {
421 match (g.node_id(u), weights[g.node_id(u)]) {
422 (0, w) => assert_eq!(w, 12.0),
423 (5, w) => assert_eq!(w, 42.23),
424 (_, w) => assert_eq!(w, 0.0),
425 }
426 }
427 }
428}