1use std::marker;
2use fixedbitset::FixedBitSet;
3
4use super::{
5 EdgeType,
6 Incoming,
7};
8use super::graph::{
9 Graph,
10 IndexType,
11 NodeIndex,
12};
13
14use super::visit::GetAdjacencyMatrix;
15
16#[derive(Debug)]
17struct Vf2State<Ty, Ix> {
18 mapping: Vec<NodeIndex<Ix>>,
21 out: Vec<usize>,
25 ins: Vec<usize>,
30 out_size: usize,
31 ins_size: usize,
32 adjacency_matrix: FixedBitSet,
33 generation: usize,
34 _etype: marker::PhantomData<Ty>,
35}
36
37impl<Ty, Ix> Vf2State<Ty, Ix>
38 where Ty: EdgeType,
39 Ix: IndexType,
40{
41 pub fn new<N, E>(g: &Graph<N, E, Ty, Ix>) -> Self {
42 let c0 = g.node_count();
43 let mut state = Vf2State {
44 mapping: Vec::with_capacity(c0),
45 out: Vec::with_capacity(c0),
46 ins: Vec::with_capacity(c0 * (g.is_directed() as usize)),
47 out_size: 0,
48 ins_size: 0,
49 adjacency_matrix: g.adjacency_matrix(),
50 generation: 0,
51 _etype: marker::PhantomData,
52 };
53 for _ in 0..c0 {
54 state.mapping.push(NodeIndex::end());
55 state.out.push(0);
56 if Ty::is_directed() {
57 state.ins.push(0);
58 }
59 }
60 state
61 }
62
63 pub fn is_complete(&self) -> bool {
65 self.generation == self.mapping.len()
66 }
67
68 pub fn push_mapping<N, E>(&mut self, from: NodeIndex<Ix>, to: NodeIndex<Ix>,
70 g: &Graph<N, E, Ty, Ix>)
71 {
72 self.generation += 1;
73 let s = self.generation;
74 self.mapping[from.index()] = to;
75 for ix in g.neighbors(from) {
79 if self.out[ix.index()] == 0 {
80 self.out[ix.index()] = s;
81 self.out_size += 1;
82 }
83 }
84 if g.is_directed() {
85 for ix in g.neighbors_directed(from, Incoming) {
86 if self.ins[ix.index()] == 0 {
87 self.ins[ix.index()] = s;
88 self.ins_size += 1;
89 }
90 }
91 }
92 }
93
94 pub fn pop_mapping<N, E>(&mut self, from: NodeIndex<Ix>,
96 g: &Graph<N, E, Ty, Ix>)
97 {
98 let s = self.generation;
99 self.generation -= 1;
100
101 self.mapping[from.index()] = NodeIndex::end();
103
104 for ix in g.neighbors(from) {
106 if self.out[ix.index()] == s {
107 self.out[ix.index()] = 0;
108 self.out_size -= 1;
109 }
110 }
111 if g.is_directed() {
112 for ix in g.neighbors_directed(from, Incoming) {
113 if self.ins[ix.index()] == s {
114 self.ins[ix.index()] = 0;
115 self.ins_size -= 1;
116 }
117 }
118 }
119 }
120
121 pub fn next_out_index(&self, from_index: usize) -> Option<usize>
123 {
124 self.out[from_index..].iter()
125 .enumerate()
126 .find(move |&(index, elt)| *elt > 0 &&
127 self.mapping[from_index + index] == NodeIndex::end())
128 .map(|(index, _)| index)
129 }
130
131 pub fn next_in_index(&self, from_index: usize) -> Option<usize>
133 {
134 if !Ty::is_directed() {
135 return None
136 }
137 self.ins[from_index..].iter()
138 .enumerate()
139 .find(move |&(index, elt)| *elt > 0
140 && self.mapping[from_index + index] == NodeIndex::end())
141 .map(|(index, _)| index)
142 }
143
144 pub fn next_rest_index(&self, from_index: usize) -> Option<usize>
146 {
147 self.mapping[from_index..].iter()
148 .enumerate()
149 .find(|&(_, elt)| *elt == NodeIndex::end())
150 .map(|(index, _)| index)
151 }
152}
153
154
155pub fn is_isomorphic<N, E, Ty, Ix>(g0: &Graph<N, E, Ty, Ix>,
167 g1: &Graph<N, E, Ty, Ix>) -> bool
168 where Ty: EdgeType,
169 Ix: IndexType,
170{
171 if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
172 return false
173 }
174
175 let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
176 try_match(&mut st, g0, g1, &mut NoSemanticMatch, &mut NoSemanticMatch).unwrap_or(false)
177}
178
179pub fn is_isomorphic_matching<N, E, Ty, Ix, F, G>(g0: &Graph<N, E, Ty, Ix>,
186 g1: &Graph<N, E, Ty, Ix>,
187 mut node_match: F,
188 mut edge_match: G) -> bool
189 where Ty: EdgeType,
190 Ix: IndexType,
191 F: FnMut(&N, &N) -> bool,
192 G: FnMut(&E, &E) -> bool,
193{
194 if g0.node_count() != g1.node_count() || g0.edge_count() != g1.edge_count() {
195 return false
196 }
197
198 let mut st = [Vf2State::new(g0), Vf2State::new(g1)];
199 try_match(&mut st, g0, g1, &mut node_match, &mut edge_match).unwrap_or(false)
200}
201
202trait SemanticMatcher<T> {
203 fn enabled() -> bool;
204 fn eq(&mut self, &T, &T) -> bool;
205}
206
207struct NoSemanticMatch;
208
209impl<T> SemanticMatcher<T> for NoSemanticMatch {
210 #[inline]
211 fn enabled() -> bool { false }
212 #[inline]
213 fn eq(&mut self, _: &T, _: &T) -> bool { true }
214}
215
216impl<T, F> SemanticMatcher<T> for F where F: FnMut(&T, &T) -> bool {
217 #[inline]
218 fn enabled() -> bool { true }
219 #[inline]
220 fn eq(&mut self, a: &T, b: &T) -> bool { self(a, b) }
221}
222
223fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
225 g0: &Graph<N, E, Ty, Ix>,
226 g1: &Graph<N, E, Ty, Ix>,
227 node_match: &mut F,
228 edge_match: &mut G)
229 -> Option<bool>
230 where Ty: EdgeType,
231 Ix: IndexType,
232 F: SemanticMatcher<N>,
233 G: SemanticMatcher<E>,
234{
235 let g = [g0, g1];
236 let graph_indices = 0..2;
237 let end = NodeIndex::end();
238
239 if st[0].is_complete() {
241 return Some(true)
242 }
243
244 #[derive(Copy, Clone, PartialEq, Debug)]
250 enum OpenList {
251 Out,
252 In,
253 Other,
254 }
255 let mut open_list = OpenList::Out;
256
257 let mut to_index;
258 let mut from_index = None;
259 to_index = st[1].next_out_index(0);
261
262 if to_index.is_some() {
263 from_index = st[0].next_out_index(0);
264 open_list = OpenList::Out;
265 }
266
267 if to_index.is_none() || from_index.is_none() {
269 to_index = st[1].next_in_index(0);
270
271 if to_index.is_some() {
272 from_index = st[0].next_in_index(0);
273 open_list = OpenList::In;
274 }
275 }
276
277 if to_index.is_none() || from_index.is_none() {
279 to_index = st[1].next_rest_index(0);
280 if to_index.is_some() {
281 from_index = st[0].next_rest_index(0);
282 open_list = OpenList::Other;
283 }
284 }
285
286 let (cand0, cand1) = match (from_index, to_index) {
287 (Some(n), Some(m)) => (n, m),
288 _ => return None,
290 };
291
292 let mut nx = NodeIndex::new(cand0);
293 let mx = NodeIndex::new(cand1);
294
295 let mut first = true;
296
297 'candidates: loop {
298 if !first {
299 let start = nx.index() + 1;
301 let cand0 = match open_list {
302 OpenList::Out => st[0].next_out_index(start),
303 OpenList::In => st[0].next_in_index(start),
304 OpenList::Other => st[0].next_rest_index(start),
305 }.map(|c| c + start); nx = match cand0 {
307 None => break, Some(ix) => NodeIndex::new(ix),
309 };
310 debug_assert!(nx.index() >= start);
311 }
312 first = false;
313
314 let nodes = [nx, mx];
315
316 let mut succ_count = [0, 0];
334 for j in graph_indices.clone() {
335 for n_neigh in g[j].neighbors(nodes[j]) {
336 succ_count[j] += 1;
337 let m_neigh = if nodes[j] != n_neigh {
339 st[j].mapping[n_neigh.index()]
340 } else {
341 nodes[1 - j]
342 };
343 if m_neigh == end {
344 continue;
345 }
346 let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, nodes[1-j], m_neigh);
347 if !has_edge {
348 continue 'candidates;
349 }
350 }
351 }
352 if succ_count[0] != succ_count[1] {
353 continue 'candidates;
354 }
355
356 if g[0].is_directed() {
358 let mut pred_count = [0, 0];
359 for j in graph_indices.clone() {
360 for n_neigh in g[j].neighbors_directed(nodes[j], Incoming) {
361 pred_count[j] += 1;
362 let m_neigh = st[j].mapping[n_neigh.index()];
364 if m_neigh == end {
365 continue;
366 }
367 let has_edge = g[1-j].is_adjacent(&st[1-j].adjacency_matrix, m_neigh, nodes[1-j]);
368 if !has_edge {
369 continue 'candidates;
370 }
371 }
372 }
373 if pred_count[0] != pred_count[1] {
374 continue 'candidates;
375 }
376 }
377
378 if F::enabled() && !node_match.eq(&g[0][nodes[0]], &g[1][nodes[1]]) {
380 continue 'candidates;
381 }
382
383 if G::enabled() {
385 for j in graph_indices.clone() {
387 let mut edges = g[j].neighbors(nodes[j]).detach();
388 while let Some((n_edge, n_neigh)) = edges.next(g[j]) {
389 let m_neigh = if nodes[j] != n_neigh {
391 st[j].mapping[n_neigh.index()]
392 } else {
393 nodes[1 - j]
394 };
395 if m_neigh == end {
396 continue;
397 }
398 match g[1-j].find_edge(nodes[1 - j], m_neigh) {
399 Some(m_edge) => {
400 if !edge_match.eq(&g[j][n_edge], &g[1-j][m_edge]) {
401 continue 'candidates;
402 }
403 }
404 None => unreachable!() }
406 }
407 }
408
409 if g[0].is_directed() {
411 for j in graph_indices.clone() {
412 let mut edges = g[j].neighbors_directed(nodes[j], Incoming).detach();
413 while let Some((n_edge, n_neigh)) = edges.next(g[j]) {
414 let m_neigh = st[j].mapping[n_neigh.index()];
416 if m_neigh == end {
417 continue;
418 }
419 match g[1-j].find_edge(m_neigh, nodes[1-j]) {
420 Some(m_edge) => {
421 if !edge_match.eq(&g[j][n_edge], &g[1-j][m_edge]) {
422 continue 'candidates;
423 }
424 }
425 None => unreachable!() }
427 }
428 }
429 }
430 }
431
432 for j in graph_indices.clone() {
434 st[j].push_mapping(nodes[j], nodes[1-j], g[j]);
435 }
436
437 if st[0].out_size == st[1].out_size &&
439 st[0].ins_size == st[1].ins_size
440 {
441
442 match try_match(st, g0, g1, node_match, edge_match) {
444 None => {}
445 result => return result,
446 }
447 }
448
449 for j in graph_indices.clone() {
451 st[j].pop_mapping(nodes[j], g[j]);
452 }
453 }
454 None
455}
456