1use std::cmp::Ordering;
14use std::hash::Hash;
15use std::vec::IntoIter;
16
17use hashbrown::{hash_map::Entry, HashMap};
18use petgraph::{
19 visit::{
20 EdgeCount, EdgeRef, GraphBase, GraphProp, IntoEdges, IntoNodeIdentifiers, NodeCount,
21 Visitable,
22 },
23 Undirected,
24};
25
26use crate::traversal::{depth_first_search, DfsEvent};
27
28type Edge<G> = (<G as GraphBase>::NodeId, <G as GraphBase>::NodeId);
29
30fn modify_if_min<K, V>(xs: &mut HashMap<K, V>, key: K, val: V)
31where
32 K: Hash + Eq,
33 V: Ord + Copy,
34{
35 xs.entry(key).and_modify(|e| {
36 if val < *e {
37 *e = val;
38 }
39 });
40}
41
42fn edges_filtered_and_sorted_by<G, P, F, K>(
43 graph: G,
44 a: G::NodeId,
45 filter: P,
46 compare: F,
47) -> IntoIter<Edge<G>>
48where
49 G: IntoEdges,
50 P: Fn(&Edge<G>) -> bool,
51 F: Fn(&Edge<G>) -> K,
52 K: Ord,
53{
54 let mut edges = graph
55 .edges(a)
56 .filter_map(|edge| {
57 let e = (edge.source(), edge.target());
58 filter(&e).then_some(e)
59 })
60 .collect::<Vec<_>>();
61 edges.sort_by_key(compare);
62 edges.dedup();
64 edges.into_iter()
65}
66
67fn is_target<G: GraphBase>(edge: Option<&Edge<G>>, v: G::NodeId) -> Option<&Edge<G>> {
68 edge.filter(|e| e.1 == v)
69}
70
71#[derive(Clone, Copy, PartialEq, PartialOrd)]
72struct Interval<T> {
73 inner: Option<(T, T)>,
74}
75
76impl<T> Default for Interval<T> {
77 fn default() -> Self {
78 Interval { inner: None }
79 }
80}
81
82impl<T> Interval<T> {
83 fn new(low: T, high: T) -> Self {
84 Interval {
85 inner: Some((low, high)),
86 }
87 }
88
89 fn is_empty(&self) -> bool {
90 self.inner.is_none()
91 }
92
93 fn unwrap(self) -> (T, T) {
94 self.inner.unwrap()
95 }
96
97 fn low(&self) -> Option<&T> {
98 match self.inner {
99 Some((ref low, _)) => Some(low),
100 None => None,
101 }
102 }
103
104 fn high(&self) -> Option<&T> {
105 match self.inner {
106 Some((_, ref high)) => Some(high),
107 None => None,
108 }
109 }
110
111 fn as_ref(&mut self) -> Option<&(T, T)> {
112 self.inner.as_ref()
113 }
114
115 fn as_mut(&mut self) -> Option<&mut (T, T)> {
116 self.inner.as_mut()
117 }
118
119 fn as_mut_low(&mut self) -> Option<&mut T> {
120 match self.inner {
121 Some((ref mut low, _)) => Some(low),
122 None => None,
123 }
124 }
125}
126
127impl<T> Interval<(T, T)>
128where
129 T: Copy + Hash + Eq,
130{
131 fn conflict<G>(&self, lr_state: &LRState<G>, edge: Edge<G>) -> bool
133 where
134 G: GraphBase<NodeId = T>,
135 {
136 match self.inner {
137 Some((_, ref h)) => lr_state.lowpt.get(h) > lr_state.lowpt.get(&edge),
138 _ => false,
139 }
140 }
141}
142
143#[derive(Clone, Copy, PartialEq, PartialOrd)]
144struct ConflictPair<T> {
145 left: Interval<T>,
146 right: Interval<T>,
147}
148
149impl<T> Default for ConflictPair<T> {
150 fn default() -> Self {
151 ConflictPair {
152 left: Interval::default(),
153 right: Interval::default(),
154 }
155 }
156}
157
158impl<T> ConflictPair<T> {
159 fn new(left: Interval<T>, right: Interval<T>) -> Self {
160 ConflictPair { left, right }
161 }
162
163 fn swap(&mut self) {
164 std::mem::swap(&mut self.left, &mut self.right)
165 }
166
167 fn is_empty(&self) -> bool {
168 self.left.is_empty() && self.right.is_empty()
169 }
170}
171
172impl<T> ConflictPair<(T, T)>
173where
174 T: Copy + Hash + Eq,
175{
176 fn lowest<G>(&self, lr_state: &LRState<G>) -> usize
178 where
179 G: GraphBase<NodeId = T>,
180 {
181 match (self.left.low(), self.right.low()) {
182 (Some(l_low), Some(r_low)) => lr_state.lowpt[l_low].min(lr_state.lowpt[r_low]),
183 (Some(l_low), None) => lr_state.lowpt[l_low],
184 (None, Some(r_low)) => lr_state.lowpt[r_low],
185 (None, None) => usize::MAX,
186 }
187 }
188}
189
190enum Sign {
191 Plus,
192 Minus,
193}
194
195enum LRTestDfsEvent<N> {
198 Finish(N),
199 TreeEdge(N, N),
200 BackEdge(N, N),
201 FinishEdge(N, N),
202}
203
204struct NonPlanar {}
206
207struct LRState<G: GraphBase>
208where
209 G::NodeId: Hash + Eq,
210{
211 graph: G,
212 roots: Vec<G::NodeId>,
214 height: HashMap<G::NodeId, usize>,
216 eparent: HashMap<G::NodeId, Edge<G>>,
218 lowpt: HashMap<Edge<G>, usize>,
220 lowpt_2: HashMap<Edge<G>, usize>,
222 lowpt_edge: HashMap<Edge<G>, Edge<G>>,
224 nesting_depth: HashMap<Edge<G>, usize>,
226 stack: Vec<ConflictPair<Edge<G>>>,
228 stack_emarker: HashMap<Edge<G>, ConflictPair<Edge<G>>>,
230 eref: HashMap<Edge<G>, Edge<G>>,
232 side: HashMap<Edge<G>, Sign>,
234}
235
236impl<G> LRState<G>
237where
238 G: GraphBase + NodeCount + EdgeCount + IntoEdges + Visitable,
239 G::NodeId: Hash + Eq,
240{
241 fn new(graph: G) -> Self {
242 let num_nodes = graph.node_count();
243 let num_edges = graph.edge_count();
244
245 LRState {
246 graph,
247 roots: Vec::new(),
248 height: HashMap::with_capacity(num_nodes),
249 eparent: HashMap::with_capacity(num_edges),
250 lowpt: HashMap::with_capacity(num_edges),
251 lowpt_2: HashMap::with_capacity(num_edges),
252 lowpt_edge: HashMap::with_capacity(num_edges),
253 nesting_depth: HashMap::with_capacity(num_edges),
254 stack: Vec::new(),
255 stack_emarker: HashMap::with_capacity(num_edges),
256 eref: HashMap::with_capacity(num_edges),
257 side: graph
258 .edge_references()
259 .map(|e| ((e.source(), e.target()), Sign::Plus))
260 .collect(),
261 }
262 }
263
264 fn lr_orientation_visitor(&mut self, event: DfsEvent<G::NodeId, &G::EdgeWeight>) {
265 match event {
266 DfsEvent::Discover(v, _) => {
267 if let Entry::Vacant(entry) = self.height.entry(v) {
268 entry.insert(0);
269 self.roots.push(v);
270 }
271 }
272 DfsEvent::TreeEdge(v, w, _) => {
273 let ei = (v, w);
274 let v_height = self.height[&v];
275 let w_height = v_height + 1;
276
277 self.eparent.insert(w, ei);
278 self.height.insert(w, w_height);
279 self.lowpt.insert(ei, v_height);
281 self.lowpt_2.insert(ei, w_height);
282 }
283 DfsEvent::BackEdge(v, w, _) => {
284 if Some(&(w, v)) != self.eparent.get(&v) {
286 let ei = (v, w);
287 self.lowpt.insert(ei, self.height[&w]);
288 self.lowpt_2.insert(ei, self.height[&v]);
289 }
290 }
291 DfsEvent::Finish(v, _) => {
292 for edge in self.graph.edges(v) {
293 let w = edge.target();
294 let ei = (v, w);
295
296 let low = match self.lowpt.get(&ei) {
298 Some(val) => *val,
299 None =>
300 {
304 continue
305 }
306 };
307
308 if self.lowpt_2[&ei] < self.height[&v] {
309 self.nesting_depth.insert(ei, 2 * low + 1);
311 } else {
312 self.nesting_depth.insert(ei, 2 * low);
313 }
314
315 if let Some(e_par) = self.eparent.get(&v) {
317 match self.lowpt[&ei].cmp(&self.lowpt[e_par]) {
318 Ordering::Less => {
319 self.lowpt_2
320 .insert(*e_par, self.lowpt[e_par].min(self.lowpt_2[&ei]));
321 self.lowpt.insert(*e_par, self.lowpt[&ei]);
322 }
323 Ordering::Greater => {
324 modify_if_min(&mut self.lowpt_2, *e_par, self.lowpt[&ei]);
325 }
326 _ => {
327 let val = self.lowpt_2[&ei];
328 modify_if_min(&mut self.lowpt_2, *e_par, val);
329 }
330 }
331 }
332 }
333 }
334 _ => (),
335 }
336 }
337
338 fn lr_testing_visitor(&mut self, event: LRTestDfsEvent<G::NodeId>) -> Result<(), NonPlanar> {
339 match event {
340 LRTestDfsEvent::TreeEdge(v, w) => {
341 let ei = (v, w);
342 if let Some(&last) = self.stack.last() {
343 self.stack_emarker.insert(ei, last);
344 }
345 }
346 LRTestDfsEvent::BackEdge(v, w) => {
347 let ei = (v, w);
348 if let Some(&last) = self.stack.last() {
349 self.stack_emarker.insert(ei, last);
350 }
351 self.lowpt_edge.insert(ei, ei);
352 let c_pair = ConflictPair::new(Interval::default(), Interval::new(ei, ei));
353 self.stack.push(c_pair);
354 }
355 LRTestDfsEvent::FinishEdge(v, w) => {
356 let ei = (v, w);
357 if self.lowpt[&ei] < self.height[&v] {
358 let e_par = self.eparent[&v];
360 let val = self.lowpt_edge[&ei];
361
362 match self.lowpt_edge.entry(e_par) {
363 Entry::Occupied(_) => {
364 self.add_constraints(ei, e_par)?;
365 }
366 Entry::Vacant(o) => {
367 o.insert(val);
368 }
369 }
370 }
371 }
372 LRTestDfsEvent::Finish(v) => {
373 if let Some(&e) = self.eparent.get(&v) {
374 let u = e.0;
375 self.remove_back_edges(u);
376
377 if self.lowpt[&e] < self.height[&u] {
379 if let Some(top) = self.stack.last() {
380 let e_high = match (top.left.high(), top.right.high()) {
381 (Some(hl), Some(hr)) => {
382 if self.lowpt[hl] > self.lowpt[hr] {
383 hl
384 } else {
385 hr
386 }
387 }
388 (Some(hl), None) => hl,
389 (None, Some(hr)) => hr,
390 _ => {
391 unreachable!()
394 }
395 };
396 self.eref.insert(e, *e_high);
397 }
398 }
399 }
400 }
401 }
402
403 Ok(())
404 }
405
406 fn until_top_of_stack_hits_emarker(&mut self, ei: Edge<G>) -> Option<ConflictPair<Edge<G>>> {
407 if let Some(&c_pair) = self.stack.last() {
408 if self.stack_emarker[&ei] != c_pair {
409 return self.stack.pop();
410 }
411 }
412
413 None
414 }
415
416 fn until_top_of_stack_is_conflicting(&mut self, ei: Edge<G>) -> Option<ConflictPair<Edge<G>>> {
417 if let Some(c_pair) = self.stack.last() {
418 if c_pair.left.conflict(self, ei) || c_pair.right.conflict(self, ei) {
419 return self.stack.pop();
420 }
421 }
422
423 None
424 }
425
426 fn union_intervals(&mut self, pi: &mut Interval<Edge<G>>, qi: Interval<Edge<G>>) {
431 match pi.as_mut_low() {
432 Some(p_low) => {
433 let (q_low, q_high) = qi.unwrap();
434 self.eref.insert(*p_low, q_high);
435 *p_low = q_low;
436 }
437 None => {
438 *pi = qi;
439 }
440 }
441 }
442
443 fn add_constraints(&mut self, ei: Edge<G>, e: Edge<G>) -> Result<(), NonPlanar> {
445 let mut c_pair = ConflictPair::<Edge<G>>::default();
446
447 while let Some(mut q_pair) = self.until_top_of_stack_hits_emarker(ei) {
449 if !q_pair.left.is_empty() {
450 q_pair.swap();
451
452 if !q_pair.left.is_empty() {
453 return Err(NonPlanar {});
454 }
455 }
456
457 let qr_low = q_pair.right.low().unwrap();
461 if self.lowpt[qr_low] > self.lowpt[&e] {
462 self.union_intervals(&mut c_pair.right, q_pair.right);
464 } else {
465 self.eref.insert(*qr_low, self.lowpt_edge[&e]);
467 }
468 }
469
470 while let Some(mut q_pair) = self.until_top_of_stack_is_conflicting(ei) {
472 if q_pair.right.conflict(self, ei) {
473 q_pair.swap();
474
475 if q_pair.right.conflict(self, ei) {
476 return Err(NonPlanar {});
477 }
478 }
479
480 if let Some((qr_low, qr_high)) = q_pair.right.as_ref() {
482 if let Some(pr_low) = c_pair.right.as_mut_low() {
483 self.eref.insert(*pr_low, *qr_high);
484 *pr_low = *qr_low;
485 }
486 };
487 self.union_intervals(&mut c_pair.left, q_pair.left);
488 }
489
490 if !c_pair.is_empty() {
491 self.stack.push(c_pair);
492 }
493
494 Ok(())
495 }
496
497 fn until_lowest_top_of_stack_has_height(
498 &mut self,
499 v: G::NodeId,
500 ) -> Option<ConflictPair<Edge<G>>> {
501 if let Some(c_pair) = self.stack.last() {
502 if c_pair.lowest(self) == self.height[&v] {
503 return self.stack.pop();
504 }
505 }
506
507 None
508 }
509
510 fn follow_eref_until_is_target(&self, edge: Edge<G>, v: G::NodeId) -> Option<Edge<G>> {
511 let mut res = Some(&edge);
512 while let Some(b) = is_target::<G>(res, v) {
513 res = self.eref.get(b);
514 }
515
516 res.copied()
517 }
518
519 fn remove_back_edges(&mut self, v: G::NodeId) {
521 while let Some(c_pair) = self.until_lowest_top_of_stack_has_height(v) {
523 if let Some(pl_low) = c_pair.left.low() {
524 self.side.insert(*pl_low, Sign::Minus);
525 }
526 }
527
528 if let Some(mut c_pair) = self.stack.pop() {
530 if let Some((pl_low, pl_high)) = c_pair.left.as_mut() {
532 match self.follow_eref_until_is_target(*pl_high, v) {
533 Some(val) => {
534 *pl_high = val;
535 }
536 None => {
537 let pr_low = c_pair.right.low().unwrap();
541 self.eref.insert(*pl_low, *pr_low);
542 self.side.insert(*pl_low, Sign::Minus);
543 c_pair.left = Interval::default();
544 }
545 }
546 }
547
548 if let Some((pr_low, ref mut pr_high)) = c_pair.right.as_mut() {
550 match self.follow_eref_until_is_target(*pr_high, v) {
551 Some(val) => {
552 *pr_high = val;
553 }
554 None => {
555 let pl_low = c_pair.left.low().unwrap();
559 self.eref.insert(*pr_low, *pl_low);
560 self.side.insert(*pr_low, Sign::Minus);
561 c_pair.right = Interval::default();
562 }
563 };
564 }
565
566 if !c_pair.is_empty() {
567 self.stack.push(c_pair);
568 }
569 }
570 }
571}
572
573fn lr_visit_ordered_dfs_tree<G, F, E>(
578 lr_state: &mut LRState<G>,
579 v: G::NodeId,
580 mut visitor: F,
581) -> Result<(), E>
582where
583 G: GraphBase + IntoEdges,
584 G::NodeId: Hash + Eq,
585 F: FnMut(&mut LRState<G>, LRTestDfsEvent<G::NodeId>) -> Result<(), E>,
586{
587 let mut stack: Vec<(G::NodeId, IntoIter<Edge<G>>)> = vec![(
588 v,
589 edges_filtered_and_sorted_by(
590 lr_state.graph,
591 v,
592 |e| lr_state.lowpt.contains_key(e),
596 |e| lr_state.nesting_depth[e],
598 ),
599 )];
600
601 while let Some(elem) = stack.last_mut() {
602 let v = elem.0;
603 let adjacent_edges = &mut elem.1;
604 let mut next = None;
605
606 for (v, w) in adjacent_edges {
607 if Some(&(v, w)) == lr_state.eparent.get(&w) {
608 visitor(lr_state, LRTestDfsEvent::TreeEdge(v, w))?;
610 next = Some(w);
611 break;
612 } else {
613 visitor(lr_state, LRTestDfsEvent::BackEdge(v, w))?;
615 visitor(lr_state, LRTestDfsEvent::FinishEdge(v, w))?;
616 }
617 }
618
619 match next {
620 Some(w) => stack.push((
621 w,
622 edges_filtered_and_sorted_by(
623 lr_state.graph,
624 w,
625 |e| lr_state.lowpt.contains_key(e),
626 |e| lr_state.nesting_depth[e],
627 ),
628 )),
629 None => {
630 stack.pop();
631 visitor(lr_state, LRTestDfsEvent::Finish(v))?;
632 if let Some(&(u, v)) = lr_state.eparent.get(&v) {
633 visitor(lr_state, LRTestDfsEvent::FinishEdge(u, v))?;
634 }
635 }
636 }
637 }
638
639 Ok(())
640}
641
642pub fn is_planar<G>(graph: G) -> bool
666where
667 G: GraphProp<EdgeType = Undirected>
668 + NodeCount
669 + EdgeCount
670 + IntoEdges
671 + IntoNodeIdentifiers
672 + Visitable,
673 G::NodeId: Hash + Eq,
674{
675 let mut state = LRState::new(graph);
676
677 depth_first_search(graph, graph.node_identifiers(), |event| {
679 state.lr_orientation_visitor(event)
680 });
681
682 for v in state.roots.clone() {
684 let res = lr_visit_ordered_dfs_tree(&mut state, v, |state, event| {
685 state.lr_testing_visitor(event)
686 });
687 if res.is_err() {
688 return false;
689 }
690 }
691
692 true
693}