1use alloc::{vec, vec::Vec};
2use core::convert::TryFrom;
3
4use crate::data::DataMap;
5use crate::visit::EdgeCount;
6use crate::visit::EdgeRef;
7use crate::visit::GetAdjacencyMatrix;
8use crate::visit::GraphBase;
9use crate::visit::GraphProp;
10use crate::visit::IntoEdgesDirected;
11use crate::visit::IntoNeighborsDirected;
12use crate::visit::NodeCompactIndexable;
13use crate::{Incoming, Outgoing};
14
15use self::semantic::EdgeMatcher;
16use self::semantic::NoSemanticMatch;
17use self::semantic::NodeMatcher;
18use self::state::Vf2State;
19
20mod state {
21 use super::*;
22
23 #[derive(Debug)]
24 pub struct Vf2State<'a, G: GetAdjacencyMatrix> {
26 pub graph: &'a G,
28 pub mapping: Vec<usize>,
31 out: Vec<usize>,
35 ins: Vec<usize>,
40 pub out_size: usize,
41 pub ins_size: usize,
42 pub adjacency_matrix: G::AdjMatrix,
43 generation: usize,
44 }
45
46 impl<'a, G> Vf2State<'a, G>
47 where
48 G: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
49 {
50 pub fn new(g: &'a G) -> Self {
51 let c0 = g.node_count();
52 Vf2State {
53 graph: g,
54 mapping: vec![usize::MAX; c0],
55 out: vec![0; c0],
56 ins: vec![0; c0 * (g.is_directed() as usize)],
57 out_size: 0,
58 ins_size: 0,
59 adjacency_matrix: g.adjacency_matrix(),
60 generation: 0,
61 }
62 }
63
64 pub fn is_complete(&self) -> bool {
66 self.generation == self.mapping.len()
67 }
68
69 pub fn push_mapping(&mut self, from: G::NodeId, to: usize) {
71 self.generation += 1;
72 self.mapping[self.graph.to_index(from)] = to;
73 for ix in self.graph.neighbors_directed(from, Outgoing) {
77 if self.out[self.graph.to_index(ix)] == 0 {
78 self.out[self.graph.to_index(ix)] = self.generation;
79 self.out_size += 1;
80 }
81 }
82 if self.graph.is_directed() {
83 for ix in self.graph.neighbors_directed(from, Incoming) {
84 if self.ins[self.graph.to_index(ix)] == 0 {
85 self.ins[self.graph.to_index(ix)] = self.generation;
86 self.ins_size += 1;
87 }
88 }
89 }
90 }
91
92 pub fn pop_mapping(&mut self, from: G::NodeId) {
94 self.mapping[self.graph.to_index(from)] = usize::MAX;
96
97 for ix in self.graph.neighbors_directed(from, Outgoing) {
99 if self.out[self.graph.to_index(ix)] == self.generation {
100 self.out[self.graph.to_index(ix)] = 0;
101 self.out_size -= 1;
102 }
103 }
104 if self.graph.is_directed() {
105 for ix in self.graph.neighbors_directed(from, Incoming) {
106 if self.ins[self.graph.to_index(ix)] == self.generation {
107 self.ins[self.graph.to_index(ix)] = 0;
108 self.ins_size -= 1;
109 }
110 }
111 }
112
113 self.generation -= 1;
114 }
115
116 pub fn next_out_index(&self, from_index: usize) -> Option<usize> {
118 self.out[from_index..]
119 .iter()
120 .enumerate()
121 .find(move |&(index, &elt)| {
122 elt > 0 && self.mapping[from_index + index] == usize::MAX
123 })
124 .map(|(index, _)| index)
125 }
126
127 pub fn next_in_index(&self, from_index: usize) -> Option<usize> {
129 if !self.graph.is_directed() {
130 return None;
131 }
132 self.ins[from_index..]
133 .iter()
134 .enumerate()
135 .find(move |&(index, &elt)| {
136 elt > 0 && self.mapping[from_index + index] == usize::MAX
137 })
138 .map(|(index, _)| index)
139 }
140
141 pub fn next_rest_index(&self, from_index: usize) -> Option<usize> {
143 self.mapping[from_index..]
144 .iter()
145 .enumerate()
146 .find(|&(_, &elt)| elt == usize::MAX)
147 .map(|(index, _)| index)
148 }
149 }
150}
151
152mod semantic {
153 use super::*;
154
155 pub struct NoSemanticMatch;
156
157 pub trait NodeMatcher<G0: GraphBase, G1: GraphBase> {
158 fn enabled() -> bool;
159 fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool;
160 }
161
162 impl<G0: GraphBase, G1: GraphBase> NodeMatcher<G0, G1> for NoSemanticMatch {
163 #[inline]
164 fn enabled() -> bool {
165 false
166 }
167 #[inline]
168 fn eq(&mut self, _g0: &G0, _g1: &G1, _n0: G0::NodeId, _n1: G1::NodeId) -> bool {
169 true
170 }
171 }
172
173 impl<G0, G1, F> NodeMatcher<G0, G1> for F
174 where
175 G0: GraphBase + DataMap,
176 G1: GraphBase + DataMap,
177 F: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
178 {
179 #[inline]
180 fn enabled() -> bool {
181 true
182 }
183 #[inline]
184 fn eq(&mut self, g0: &G0, g1: &G1, n0: G0::NodeId, n1: G1::NodeId) -> bool {
185 if let (Some(x), Some(y)) = (g0.node_weight(n0), g1.node_weight(n1)) {
186 self(x, y)
187 } else {
188 false
189 }
190 }
191 }
192
193 pub trait EdgeMatcher<G0: GraphBase, G1: GraphBase> {
194 fn enabled() -> bool;
195 fn eq(
196 &mut self,
197 _g0: &G0,
198 _g1: &G1,
199 e0: (G0::NodeId, G0::NodeId),
200 e1: (G1::NodeId, G1::NodeId),
201 ) -> bool;
202 }
203
204 impl<G0: GraphBase, G1: GraphBase> EdgeMatcher<G0, G1> for NoSemanticMatch {
205 #[inline]
206 fn enabled() -> bool {
207 false
208 }
209 #[inline]
210 fn eq(
211 &mut self,
212 _g0: &G0,
213 _g1: &G1,
214 _e0: (G0::NodeId, G0::NodeId),
215 _e1: (G1::NodeId, G1::NodeId),
216 ) -> bool {
217 true
218 }
219 }
220
221 impl<G0, G1, F> EdgeMatcher<G0, G1> for F
222 where
223 G0: GraphBase + DataMap + IntoEdgesDirected,
224 G1: GraphBase + DataMap + IntoEdgesDirected,
225 F: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
226 {
227 #[inline]
228 fn enabled() -> bool {
229 true
230 }
231 #[inline]
232 fn eq(
233 &mut self,
234 g0: &G0,
235 g1: &G1,
236 e0: (G0::NodeId, G0::NodeId),
237 e1: (G1::NodeId, G1::NodeId),
238 ) -> bool {
239 let w0 = g0
240 .edges_directed(e0.0, Outgoing)
241 .find(|edge| edge.target() == e0.1)
242 .and_then(|edge| g0.edge_weight(edge.id()));
243 let w1 = g1
244 .edges_directed(e1.0, Outgoing)
245 .find(|edge| edge.target() == e1.1)
246 .and_then(|edge| g1.edge_weight(edge.id()));
247 if let (Some(x), Some(y)) = (w0, w1) {
248 self(x, y)
249 } else {
250 false
251 }
252 }
253 }
254}
255
256mod matching {
257 use super::*;
258
259 #[derive(Copy, Clone, PartialEq, Debug)]
260 enum OpenList {
261 Out,
262 In,
263 Other,
264 }
265
266 #[derive(Clone, PartialEq, Debug)]
267 enum Frame<G0, G1>
268 where
269 G0: GraphBase,
270 G1: GraphBase,
271 {
272 Outer,
273 Inner {
274 nodes: (G0::NodeId, G1::NodeId),
275 open_list: OpenList,
276 },
277 Unwind {
278 nodes: (G0::NodeId, G1::NodeId),
279 open_list: OpenList,
280 },
281 }
282
283 fn is_feasible<G0, G1, NM, EM>(
284 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
285 nodes: (G0::NodeId, G1::NodeId),
286 node_match: &mut NM,
287 edge_match: &mut EM,
288 ) -> bool
289 where
290 G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
291 G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
292 NM: NodeMatcher<G0, G1>,
293 EM: EdgeMatcher<G0, G1>,
294 {
295 macro_rules! field {
296 ($x:ident, 0) => {
297 $x.0
298 };
299 ($x:ident, 1) => {
300 $x.1
301 };
302 ($x:ident, 1 - 0) => {
303 $x.1
304 };
305 ($x:ident, 1 - 1) => {
306 $x.0
307 };
308 }
309
310 macro_rules! r_succ {
311 ($j:tt) => {{
312 let mut succ_count = 0;
313 for n_neigh in field!(st, $j)
314 .graph
315 .neighbors_directed(field!(nodes, $j), Outgoing)
316 {
317 succ_count += 1;
318 let m_neigh = if field!(nodes, $j) != n_neigh {
320 field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
321 } else {
322 field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
323 };
324 if m_neigh == usize::MAX {
325 continue;
326 }
327 let has_edge = field!(st, 1 - $j).graph.is_adjacent(
328 &field!(st, 1 - $j).adjacency_matrix,
329 field!(nodes, 1 - $j),
330 field!(st, 1 - $j).graph.from_index(m_neigh),
331 );
332 if !has_edge {
333 return false;
334 }
335 }
336 succ_count
337 }};
338 }
339
340 macro_rules! r_pred {
341 ($j:tt) => {{
342 let mut pred_count = 0;
343 for n_neigh in field!(st, $j)
344 .graph
345 .neighbors_directed(field!(nodes, $j), Incoming)
346 {
347 pred_count += 1;
348 let m_neigh = field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
350 if m_neigh == usize::MAX {
351 continue;
352 }
353 let has_edge = field!(st, 1 - $j).graph.is_adjacent(
354 &field!(st, 1 - $j).adjacency_matrix,
355 field!(st, 1 - $j).graph.from_index(m_neigh),
356 field!(nodes, 1 - $j),
357 );
358 if !has_edge {
359 return false;
360 }
361 }
362 pred_count
363 }};
364 }
365
366 if r_succ!(0) > r_succ!(1) {
384 return false;
385 }
386 if st.0.graph.is_directed() && r_pred!(0) > r_pred!(1) {
388 return false;
389 }
390
391 if NM::enabled() && !node_match.eq(st.0.graph, st.1.graph, nodes.0, nodes.1) {
393 return false;
394 }
395 if EM::enabled() {
397 macro_rules! edge_feasibility {
398 ($j:tt) => {{
399 for n_neigh in field!(st, $j)
400 .graph
401 .neighbors_directed(field!(nodes, $j), Outgoing)
402 {
403 let m_neigh = if field!(nodes, $j) != n_neigh {
404 field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)]
405 } else {
406 field!(st, 1 - $j).graph.to_index(field!(nodes, 1 - $j))
407 };
408 if m_neigh == usize::MAX {
409 continue;
410 }
411
412 let e0 = (field!(nodes, $j), n_neigh);
413 let e1 = (
414 field!(nodes, 1 - $j),
415 field!(st, 1 - $j).graph.from_index(m_neigh),
416 );
417 let edges = (e0, e1);
418 if !edge_match.eq(
419 st.0.graph,
420 st.1.graph,
421 field!(edges, $j),
422 field!(edges, 1 - $j),
423 ) {
424 return false;
425 }
426 }
427 if field!(st, $j).graph.is_directed() {
428 for n_neigh in field!(st, $j)
429 .graph
430 .neighbors_directed(field!(nodes, $j), Incoming)
431 {
432 let m_neigh =
434 field!(st, $j).mapping[field!(st, $j).graph.to_index(n_neigh)];
435 if m_neigh == usize::MAX {
436 continue;
437 }
438
439 let e0 = (n_neigh, field!(nodes, $j));
440 let e1 = (
441 field!(st, 1 - $j).graph.from_index(m_neigh),
442 field!(nodes, 1 - $j),
443 );
444 let edges = (e0, e1);
445 if !edge_match.eq(
446 st.0.graph,
447 st.1.graph,
448 field!(edges, $j),
449 field!(edges, 1 - $j),
450 ) {
451 return false;
452 }
453 }
454 }
455 }};
456 }
457
458 edge_feasibility!(0);
459 edge_feasibility!(1);
460 }
461 true
462 }
463
464 fn next_candidate<G0, G1>(
465 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
466 ) -> Option<(G0::NodeId, G1::NodeId, OpenList)>
467 where
468 G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
469 G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
470 {
471 let mut from_index = None;
472 let mut open_list = OpenList::Out;
473 let mut to_index = st.1.next_out_index(0);
474
475 if to_index.is_some() {
477 from_index = st.0.next_out_index(0);
478 open_list = OpenList::Out;
479 }
480 if to_index.is_none() || from_index.is_none() {
482 to_index = st.1.next_in_index(0);
483
484 if to_index.is_some() {
485 from_index = st.0.next_in_index(0);
486 open_list = OpenList::In;
487 }
488 }
489 if to_index.is_none() || from_index.is_none() {
491 to_index = st.1.next_rest_index(0);
492 if to_index.is_some() {
493 from_index = st.0.next_rest_index(0);
494 open_list = OpenList::Other;
495 }
496 }
497 match (from_index, to_index) {
498 (Some(n), Some(m)) => Some((
499 st.0.graph.from_index(n),
500 st.1.graph.from_index(m),
501 open_list,
502 )),
503 _ => None,
505 }
506 }
507
508 fn next_from_ix<G0, G1>(
509 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
510 nx: G1::NodeId,
511 open_list: OpenList,
512 ) -> Option<G1::NodeId>
513 where
514 G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
515 G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
516 {
517 let start = st.1.graph.to_index(nx) + 1;
519 let cand1 = match open_list {
520 OpenList::Out => st.1.next_out_index(start),
521 OpenList::In => st.1.next_in_index(start),
522 OpenList::Other => st.1.next_rest_index(start),
523 }
524 .map(|c| c + start); match cand1 {
526 None => None, Some(ix) => {
528 debug_assert!(ix >= start);
529 Some(st.1.graph.from_index(ix))
530 }
531 }
532 }
533
534 fn pop_state<G0, G1>(
535 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
536 nodes: (G0::NodeId, G1::NodeId),
537 ) where
538 G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
539 G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
540 {
541 st.0.pop_mapping(nodes.0);
542 st.1.pop_mapping(nodes.1);
543 }
544
545 fn push_state<G0, G1>(
546 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
547 nodes: (G0::NodeId, G1::NodeId),
548 ) where
549 G0: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
550 G1: GetAdjacencyMatrix + GraphProp + NodeCompactIndexable + IntoNeighborsDirected,
551 {
552 st.0.push_mapping(nodes.0, st.1.graph.to_index(nodes.1));
553 st.1.push_mapping(nodes.1, st.0.graph.to_index(nodes.0));
554 }
555
556 pub fn try_match<G0, G1, NM, EM>(
558 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
559 node_match: &mut NM,
560 edge_match: &mut EM,
561 match_subgraph: bool,
562 ) -> Option<bool>
563 where
564 G0: NodeCompactIndexable
565 + EdgeCount
566 + GetAdjacencyMatrix
567 + GraphProp
568 + IntoNeighborsDirected,
569 G1: NodeCompactIndexable
570 + EdgeCount
571 + GetAdjacencyMatrix
572 + GraphProp
573 + IntoNeighborsDirected,
574 NM: NodeMatcher<G0, G1>,
575 EM: EdgeMatcher<G0, G1>,
576 {
577 let mut stack = vec![Frame::Outer];
578 if isomorphisms(st, node_match, edge_match, match_subgraph, &mut stack).is_some() {
579 Some(true)
580 } else {
581 None
582 }
583 }
584
585 fn isomorphisms<G0, G1, NM, EM>(
586 st: &mut (Vf2State<'_, G0>, Vf2State<'_, G1>),
587 node_match: &mut NM,
588 edge_match: &mut EM,
589 match_subgraph: bool,
590 stack: &mut Vec<Frame<G0, G1>>,
591 ) -> Option<Vec<usize>>
592 where
593 G0: NodeCompactIndexable
594 + EdgeCount
595 + GetAdjacencyMatrix
596 + GraphProp
597 + IntoNeighborsDirected,
598 G1: NodeCompactIndexable
599 + EdgeCount
600 + GetAdjacencyMatrix
601 + GraphProp
602 + IntoNeighborsDirected,
603 NM: NodeMatcher<G0, G1>,
604 EM: EdgeMatcher<G0, G1>,
605 {
606 if st.0.is_complete() {
607 return Some(st.0.mapping.clone());
608 }
609
610 let mut result = None;
614 while let Some(frame) = stack.pop() {
615 match frame {
616 Frame::Unwind { nodes, open_list } => {
617 pop_state(st, nodes);
618
619 match next_from_ix(st, nodes.1, open_list) {
620 None => continue,
621 Some(nx) => {
622 let f = Frame::Inner {
623 nodes: (nodes.0, nx),
624 open_list,
625 };
626 stack.push(f);
627 }
628 }
629 }
630 Frame::Outer => match next_candidate(st) {
631 None => continue,
632 Some((nx, mx, open_list)) => {
633 let f = Frame::Inner {
634 nodes: (nx, mx),
635 open_list,
636 };
637 stack.push(f);
638 }
639 },
640 Frame::Inner { nodes, open_list } => {
641 if is_feasible(st, nodes, node_match, edge_match) {
642 push_state(st, nodes);
643 if st.0.is_complete() {
644 result = Some(st.0.mapping.clone());
645 }
646 if (!match_subgraph
648 && st.0.out_size == st.1.out_size
649 && st.0.ins_size == st.1.ins_size)
650 || (match_subgraph
651 && st.0.out_size <= st.1.out_size
652 && st.0.ins_size <= st.1.ins_size)
653 {
654 let f0 = Frame::Unwind { nodes, open_list };
655 stack.push(f0);
656 stack.push(Frame::Outer);
657 continue;
658 }
659 pop_state(st, nodes);
660 }
661 match next_from_ix(st, nodes.1, open_list) {
662 None => continue,
663 Some(nx) => {
664 let f = Frame::Inner {
665 nodes: (nodes.0, nx),
666 open_list,
667 };
668 stack.push(f);
669 }
670 }
671 }
672 }
673 if result.is_some() {
674 return result;
675 }
676 }
677 result
678 }
679
680 pub struct GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
681 where
682 G0: NodeCompactIndexable
683 + EdgeCount
684 + GetAdjacencyMatrix
685 + GraphProp
686 + IntoNeighborsDirected,
687 G1: NodeCompactIndexable
688 + EdgeCount
689 + GetAdjacencyMatrix
690 + GraphProp
691 + IntoNeighborsDirected,
692 NM: NodeMatcher<G0, G1>,
693 EM: EdgeMatcher<G0, G1>,
694 {
695 st: (Vf2State<'a, G0>, Vf2State<'b, G1>),
696 node_match: &'c mut NM,
697 edge_match: &'c mut EM,
698 match_subgraph: bool,
699 stack: Vec<Frame<G0, G1>>,
700 }
701
702 impl<'a, 'b, 'c, G0, G1, NM, EM> GraphMatcher<'a, 'b, 'c, G0, G1, NM, EM>
703 where
704 G0: NodeCompactIndexable
705 + EdgeCount
706 + GetAdjacencyMatrix
707 + GraphProp
708 + IntoNeighborsDirected,
709 G1: NodeCompactIndexable
710 + EdgeCount
711 + GetAdjacencyMatrix
712 + GraphProp
713 + IntoNeighborsDirected,
714 NM: NodeMatcher<G0, G1>,
715 EM: EdgeMatcher<G0, G1>,
716 {
717 pub fn new(
718 g0: &'a G0,
719 g1: &'b G1,
720 node_match: &'c mut NM,
721 edge_match: &'c mut EM,
722 match_subgraph: bool,
723 ) -> Self {
724 let stack = vec![Frame::Outer];
725 Self {
726 st: (Vf2State::new(g0), Vf2State::new(g1)),
727 node_match,
728 edge_match,
729 match_subgraph,
730 stack,
731 }
732 }
733 }
734
735 impl<G0, G1, NM, EM> Iterator for GraphMatcher<'_, '_, '_, G0, G1, NM, EM>
736 where
737 G0: NodeCompactIndexable
738 + EdgeCount
739 + GetAdjacencyMatrix
740 + GraphProp
741 + IntoNeighborsDirected,
742 G1: NodeCompactIndexable
743 + EdgeCount
744 + GetAdjacencyMatrix
745 + GraphProp
746 + IntoNeighborsDirected,
747 NM: NodeMatcher<G0, G1>,
748 EM: EdgeMatcher<G0, G1>,
749 {
750 type Item = Vec<usize>;
751
752 fn next(&mut self) -> Option<Self::Item> {
753 isomorphisms(
754 &mut self.st,
755 self.node_match,
756 self.edge_match,
757 self.match_subgraph,
758 &mut self.stack,
759 )
760 }
761
762 fn size_hint(&self) -> (usize, Option<usize>) {
763 let n = self.st.0.graph.node_count();
767
768 let upper_bounds: Vec<Option<usize>> = [
771 1u64,
772 1,
773 2,
774 6,
775 24,
776 120,
777 720,
778 5040,
779 40320,
780 362880,
781 3628800,
782 39916800,
783 479001600,
784 6227020800,
785 87178291200,
786 1307674368000,
787 20922789888000,
788 355687428096000,
789 6402373705728000,
790 121645100408832000,
791 2432902008176640000,
792 ]
793 .iter()
794 .map(|n| usize::try_from(*n).ok())
795 .collect();
796
797 if n > upper_bounds.len() {
798 return (0, None);
799 }
800
801 (0, upper_bounds[n])
802 }
803 }
804}
805
806pub fn is_isomorphic<G0, G1>(g0: G0, g1: G1) -> bool
818where
819 G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
820 G1: NodeCompactIndexable
821 + EdgeCount
822 + GetAdjacencyMatrix
823 + GraphProp<EdgeType = G0::EdgeType>
824 + IntoNeighborsDirected,
825{
826 if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
827 return false;
828 }
829
830 let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
831 self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, false)
832 .unwrap_or(false)
833}
834
835pub fn is_isomorphic_matching<G0, G1, NM, EM>(
842 g0: G0,
843 g1: G1,
844 mut node_match: NM,
845 mut edge_match: EM,
846) -> bool
847where
848 G0: NodeCompactIndexable
849 + EdgeCount
850 + DataMap
851 + GetAdjacencyMatrix
852 + GraphProp
853 + IntoEdgesDirected,
854 G1: NodeCompactIndexable
855 + EdgeCount
856 + DataMap
857 + GetAdjacencyMatrix
858 + GraphProp<EdgeType = G0::EdgeType>
859 + IntoEdgesDirected,
860 NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
861 EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
862{
863 if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
864 return false;
865 }
866
867 let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
868 self::matching::try_match(&mut st, &mut node_match, &mut edge_match, false).unwrap_or(false)
869}
870
871pub fn is_isomorphic_subgraph<G0, G1>(g0: G0, g1: G1) -> bool
905where
906 G0: NodeCompactIndexable + EdgeCount + GetAdjacencyMatrix + GraphProp + IntoNeighborsDirected,
907 G1: NodeCompactIndexable
908 + EdgeCount
909 + GetAdjacencyMatrix
910 + GraphProp<EdgeType = G0::EdgeType>
911 + IntoNeighborsDirected,
912{
913 if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
914 return false;
915 }
916
917 let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
918 self::matching::try_match(&mut st, &mut NoSemanticMatch, &mut NoSemanticMatch, true)
919 .unwrap_or(false)
920}
921
922pub fn is_isomorphic_subgraph_matching<G0, G1, NM, EM>(
929 g0: G0,
930 g1: G1,
931 mut node_match: NM,
932 mut edge_match: EM,
933) -> bool
934where
935 G0: NodeCompactIndexable
936 + EdgeCount
937 + DataMap
938 + GetAdjacencyMatrix
939 + GraphProp
940 + IntoEdgesDirected,
941 G1: NodeCompactIndexable
942 + EdgeCount
943 + DataMap
944 + GetAdjacencyMatrix
945 + GraphProp<EdgeType = G0::EdgeType>
946 + IntoEdgesDirected,
947 NM: FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
948 EM: FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
949{
950 if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
951 return false;
952 }
953
954 let mut st = (Vf2State::new(&g0), Vf2State::new(&g1));
955 self::matching::try_match(&mut st, &mut node_match, &mut edge_match, true).unwrap_or(false)
956}
957
958pub fn subgraph_isomorphisms_iter<'a, G0, G1, NM, EM>(
965 g0: &'a G0,
966 g1: &'a G1,
967 node_match: &'a mut NM,
968 edge_match: &'a mut EM,
969) -> Option<impl Iterator<Item = Vec<usize>> + 'a>
970where
971 G0: 'a
972 + NodeCompactIndexable
973 + EdgeCount
974 + DataMap
975 + GetAdjacencyMatrix
976 + GraphProp
977 + IntoEdgesDirected,
978 G1: 'a
979 + NodeCompactIndexable
980 + EdgeCount
981 + DataMap
982 + GetAdjacencyMatrix
983 + GraphProp<EdgeType = G0::EdgeType>
984 + IntoEdgesDirected,
985 NM: 'a + FnMut(&G0::NodeWeight, &G1::NodeWeight) -> bool,
986 EM: 'a + FnMut(&G0::EdgeWeight, &G1::EdgeWeight) -> bool,
987{
988 if g0.node_count() > g1.node_count() || g0.edge_count() > g1.edge_count() {
989 return None;
990 }
991
992 Some(self::matching::GraphMatcher::new(
993 g0, g1, node_match, edge_match, true,
994 ))
995}