@@ -221,7 +221,7 @@ impl<T, F> SemanticMatcher<T> for F where F: FnMut(&T, &T) -> bool {
221
221
}
222
222
223
223
/// Return Some(bool) if isomorphism is decided, else None.
224
- fn try_match < N , E , Ty , Ix , F , G > ( st : & mut [ Vf2State < Ty , Ix > ; 2 ] ,
224
+ fn try_match < N , E , Ty , Ix , F , G > ( mut st : & mut [ Vf2State < Ty , Ix > ; 2 ] ,
225
225
g0 : & Graph < N , E , Ty , Ix > ,
226
226
g1 : & Graph < N , E , Ty , Ix > ,
227
227
node_match : & mut F ,
@@ -232,15 +232,13 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
232
232
F : SemanticMatcher < N > ,
233
233
G : SemanticMatcher < E > ,
234
234
{
235
+ if st[ 0 ] . is_complete ( ) {
236
+ return Some ( true ) ;
237
+ }
235
238
let g = [ g0, g1] ;
236
239
let graph_indices = 0 ..2 ;
237
240
let end = NodeIndex :: end ( ) ;
238
241
239
- // if all are mapped -- we are done and have an iso
240
- if st[ 0 ] . is_complete ( ) {
241
- return Some ( true )
242
- }
243
-
244
242
// A "depth first" search of a valid mapping from graph 1 to graph 2
245
243
246
244
// F(s, n, m) -- evaluate state s and add mapping n <-> m
@@ -252,67 +250,81 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
252
250
In ,
253
251
Other ,
254
252
}
255
- let mut open_list = OpenList :: Out ;
256
-
257
- let mut to_index;
258
- let mut from_index = None ;
259
- // Try the out list
260
- to_index = st[ 1 ] . next_out_index ( 0 ) ;
261
253
262
- if to_index. is_some ( ) {
263
- from_index = st[ 0 ] . next_out_index ( 0 ) ;
264
- open_list = OpenList :: Out ;
254
+ #[ derive( Clone , PartialEq , Debug ) ]
255
+ enum Frame < N : marker:: Copy > {
256
+ Outer ,
257
+ Inner { nodes : [ N ; 2 ] , open_list : OpenList } ,
258
+ Unwind { nodes : [ N ; 2 ] , open_list : OpenList } ,
265
259
}
266
260
267
- // Try the in list
268
- if to_index. is_none ( ) || from_index. is_none ( ) {
269
- to_index = st[ 1 ] . next_in_index ( 0 ) ;
261
+ let next_candidate = |st : & mut [ Vf2State < Ty , Ix > ; 2 ] |
262
+ -> Option < ( NodeIndex < Ix > , NodeIndex < Ix > , OpenList ) > {
263
+ let mut to_index;
264
+ let mut from_index = None ;
265
+ let mut open_list = OpenList :: Out ;
266
+ // Try the out list
267
+ to_index = st[ 1 ] . next_out_index ( 0 ) ;
270
268
271
269
if to_index. is_some ( ) {
272
- from_index = st[ 0 ] . next_in_index ( 0 ) ;
273
- open_list = OpenList :: In ;
270
+ from_index = st[ 0 ] . next_out_index ( 0 ) ;
271
+ open_list = OpenList :: Out ;
274
272
}
275
- }
273
+ // Try the in list
274
+ if to_index. is_none ( ) || from_index. is_none ( ) {
275
+ to_index = st[ 1 ] . next_in_index ( 0 ) ;
276
276
277
- // Try the other list -- disconnected graph
278
- 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 ;
277
+ if to_index. is_some ( ) {
278
+ from_index = st[ 0 ] . next_in_index ( 0 ) ;
279
+ open_list = OpenList :: In ;
280
+ }
281
+ }
282
+ // Try the other list -- disconnected graph
283
+ if to_index. is_none ( ) || from_index. is_none ( ) {
284
+ to_index = st[ 1 ] . next_rest_index ( 0 ) ;
285
+ if to_index. is_some ( ) {
286
+ from_index = st[ 0 ] . next_rest_index ( 0 ) ;
287
+ open_list = OpenList :: Other ;
288
+ }
289
+ }
290
+ match ( from_index, to_index) {
291
+ ( Some ( n) , Some ( m) ) => Some ( ( NodeIndex :: new ( n) , NodeIndex :: new ( m) , open_list) ) ,
292
+ // No more candidates
293
+ _ => None ,
283
294
}
284
- }
285
-
286
- let ( cand0, cand1) = match ( from_index, to_index) {
287
- ( Some ( n) , Some ( m) ) => ( n, m) ,
288
- // No more candidates
289
- _ => return None ,
290
295
} ;
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
- // Find the next node index to try on the `from` side of the mapping
300
- 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) ; // compensate for start offset.
306
- nx = match cand0 {
307
- None => break , // no more candidates
308
- Some ( ix) => NodeIndex :: new ( ix) ,
309
- } ;
310
- debug_assert ! ( nx. index( ) >= start) ;
296
+ let next_from_ix = |st : & mut [ Vf2State < Ty , Ix > ; 2 ] , nx : NodeIndex < Ix > , open_list : OpenList | -> Option < NodeIndex < Ix > > {
297
+ // Find the next node index to try on the `from` side of the mapping
298
+ let start = nx. index ( ) + 1 ;
299
+ let cand0 = match open_list {
300
+ OpenList :: Out => st[ 0 ] . next_out_index ( start) ,
301
+ OpenList :: In => st[ 0 ] . next_in_index ( start) ,
302
+ OpenList :: Other => st[ 0 ] . next_rest_index ( start) ,
303
+ } . map ( |c| c + start) ; // compensate for start offset.
304
+ match cand0 {
305
+ None => None , // no more candidates
306
+ Some ( ix) => {
307
+ debug_assert ! ( ix >= start) ;
308
+ Some ( NodeIndex :: new ( ix) )
309
+ } ,
311
310
}
312
- first = false ;
313
-
314
- let nodes = [ nx, mx] ;
315
-
311
+ } ;
312
+ //fn pop_state(nodes: [NodeIndex<Ix>; 2]) {
313
+ let pop_state = |st : & mut [ Vf2State < Ty , Ix > ; 2 ] , nodes : [ NodeIndex < Ix > ; 2 ] | {
314
+ // Restore state.
315
+ for j in graph_indices. clone ( ) {
316
+ st[ j] . pop_mapping ( nodes[ j] , g[ j] ) ;
317
+ }
318
+ } ;
319
+ //fn push_state(nodes: [NodeIndex<Ix>; 2]) {
320
+ let push_state = |st : & mut [ Vf2State < Ty , Ix > ; 2 ] , nodes : [ NodeIndex < Ix > ; 2 ] | {
321
+ // Add mapping nx <-> mx to the state
322
+ for j in graph_indices. clone ( ) {
323
+ st[ j] . push_mapping ( nodes[ j] , nodes[ 1 -j] , g[ j] ) ;
324
+ }
325
+ } ;
326
+ //fn is_feasible(nodes: [NodeIndex<Ix>; 2]) -> bool {
327
+ let mut is_feasible = |st : & mut [ Vf2State < Ty , Ix > ; 2 ] , nodes : [ NodeIndex < Ix > ; 2 ] | -> bool {
316
328
// Check syntactic feasibility of mapping by ensuring adjacencies
317
329
// of nx map to adjacencies of mx.
318
330
//
@@ -345,14 +357,13 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
345
357
}
346
358
let has_edge = g[ 1 -j] . is_adjacent ( & st[ 1 -j] . adjacency_matrix , nodes[ 1 -j] , m_neigh) ;
347
359
if !has_edge {
348
- continue ' candidates ;
360
+ return false ;
349
361
}
350
362
}
351
363
}
352
364
if succ_count[ 0 ] != succ_count[ 1 ] {
353
- continue ' candidates ;
365
+ return false ;
354
366
}
355
-
356
367
// R_pred
357
368
if g[ 0 ] . is_directed ( ) {
358
369
let mut pred_count = [ 0 , 0 ] ;
@@ -366,20 +377,18 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
366
377
}
367
378
let has_edge = g[ 1 -j] . is_adjacent ( & st[ 1 -j] . adjacency_matrix , m_neigh, nodes[ 1 -j] ) ;
368
379
if !has_edge {
369
- continue ' candidates ;
380
+ return false ;
370
381
}
371
382
}
372
383
}
373
384
if pred_count[ 0 ] != pred_count[ 1 ] {
374
- continue ' candidates ;
385
+ return false ;
375
386
}
376
387
}
377
-
378
388
// semantic feasibility: compare associated data for nodes
379
389
if F :: enabled ( ) && !node_match. eq ( & g[ 0 ] [ nodes[ 0 ] ] , & g[ 1 ] [ nodes[ 1 ] ] ) {
380
- continue ' candidates ;
390
+ return false ;
381
391
}
382
-
383
392
// semantic feasibility: compare associated data for edges
384
393
if G :: enabled ( ) {
385
394
// outgoing edges
@@ -398,14 +407,13 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
398
407
match g[ 1 -j] . find_edge ( nodes[ 1 - j] , m_neigh) {
399
408
Some ( m_edge) => {
400
409
if !edge_match. eq ( & g[ j] [ n_edge] , & g[ 1 -j] [ m_edge] ) {
401
- continue ' candidates ;
410
+ return false ;
402
411
}
403
412
}
404
413
None => unreachable ! ( ) // covered by syntactic check
405
414
}
406
415
}
407
416
}
408
-
409
417
// incoming edges
410
418
if g[ 0 ] . is_directed ( ) {
411
419
for j in graph_indices. clone ( ) {
@@ -419,7 +427,7 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
419
427
match g[ 1 -j] . find_edge ( m_neigh, nodes[ 1 -j] ) {
420
428
Some ( m_edge) => {
421
429
if !edge_match. eq ( & g[ j] [ n_edge] , & g[ 1 -j] [ m_edge] ) {
422
- continue ' candidates ;
430
+ return false ;
423
431
}
424
432
}
425
433
None => unreachable ! ( ) // covered by syntactic check
@@ -428,29 +436,57 @@ fn try_match<N, E, Ty, Ix, F, G>(st: &mut [Vf2State<Ty, Ix>; 2],
428
436
}
429
437
}
430
438
}
431
-
432
- // Add mapping nx <-> mx to the state
433
- for j in graph_indices. clone ( ) {
434
- st[ j] . push_mapping ( nodes[ j] , nodes[ 1 -j] , g[ j] ) ;
435
- }
436
-
437
- // Check cardinalities of Tin, Tout sets
438
- if st[ 0 ] . out_size == st[ 1 ] . out_size &&
439
- st[ 0 ] . ins_size == st[ 1 ] . ins_size
440
- {
441
-
442
- // Recurse
443
- match try_match ( st, g0, g1, node_match, edge_match) {
444
- None => { }
445
- result => return result,
439
+ true
440
+ } ;
441
+ let mut stack: Vec < Frame < NodeIndex < Ix > > > = vec ! [ Frame :: Outer ] ;
442
+
443
+ while let Some ( frame) = stack. pop ( ) {
444
+ match frame {
445
+ Frame :: Unwind { nodes, open_list : ol} => {
446
+ pop_state ( & mut st, nodes) ;
447
+
448
+ match next_from_ix ( & mut st, nodes[ 0 ] , ol) {
449
+ None => continue ,
450
+ Some ( nx) => {
451
+ let f = Frame :: Inner { nodes : [ nx, nodes[ 1 ] ] , open_list : ol} ;
452
+ stack. push ( f) ;
453
+ }
454
+ }
455
+ }
456
+ Frame :: Outer => {
457
+ match next_candidate ( & mut st) {
458
+ None => continue ,
459
+ Some ( ( nx, mx, ol) ) => {
460
+ let f = Frame :: Inner { nodes : [ nx, mx] , open_list : ol} ;
461
+ stack. push ( f) ;
462
+ }
463
+ }
464
+ }
465
+ Frame :: Inner { nodes, open_list : ol} => {
466
+ if is_feasible ( & mut st, nodes) {
467
+ push_state ( & mut st, nodes) ;
468
+ if st[ 0 ] . is_complete ( ) {
469
+ return Some ( true ) ;
470
+ }
471
+ // Check cardinalities of Tin, Tout sets
472
+ if st[ 0 ] . out_size == st[ 1 ] . out_size &&
473
+ st[ 0 ] . ins_size == st[ 1 ] . ins_size {
474
+ let f0 = Frame :: Unwind { nodes : nodes, open_list : ol} ;
475
+ stack. push ( f0) ;
476
+ stack. push ( Frame :: Outer ) ;
477
+ continue ;
478
+ }
479
+ pop_state ( & mut st, nodes) ;
480
+ }
481
+ match next_from_ix ( & mut st, nodes[ 0 ] , ol) {
482
+ None => continue ,
483
+ Some ( nx) => {
484
+ let f = Frame :: Inner { nodes : [ nx, nodes[ 1 ] ] , open_list : ol} ;
485
+ stack. push ( f) ;
486
+ }
487
+ }
446
488
}
447
- }
448
-
449
- // Restore state.
450
- for j in graph_indices. clone ( ) {
451
- st[ j] . pop_mapping ( nodes[ j] , g[ j] ) ;
452
489
}
453
490
}
454
491
None
455
492
}
456
-
0 commit comments