fix bug in matcher
This commit is contained in:
parent
a0ccb3f35d
commit
f9049be167
1 changed files with 56 additions and 37 deletions
|
|
@ -105,12 +105,14 @@ class MatcherVF2:
|
|||
def _match(self, state, already_visited, indent=0):
|
||||
# print(" "*indent, "match")
|
||||
|
||||
def visit_for_first_time(state):
|
||||
hashable_state = state.make_hashable()
|
||||
if hashable_state in already_visited:
|
||||
return False
|
||||
already_visited.add(hashable_state)
|
||||
return True
|
||||
hashable_state = state.make_hashable()
|
||||
if hashable_state in already_visited:
|
||||
# print(" "*indent, " SKIP - ALREADY VISITED")
|
||||
# print(" "*indent, " ", hashable_state)
|
||||
return
|
||||
# print(" "*indent, " ADD STATE")
|
||||
# print(" "*indent, " ", hashable_state)
|
||||
already_visited.add(hashable_state)
|
||||
|
||||
|
||||
if len(state.mapping_edges) == len(self.guest.edges):
|
||||
|
|
@ -120,49 +122,63 @@ class MatcherVF2:
|
|||
yield state
|
||||
return
|
||||
|
||||
def read_edge(edge, direction):
|
||||
if direction == "outgoing":
|
||||
return edge.tgt
|
||||
elif direction == "incoming":
|
||||
return edge.src
|
||||
else:
|
||||
raise Exception("wtf!")
|
||||
|
||||
def attempt_grow(direction, indent):
|
||||
# print(" "*indent, 'attempt_grow', direction)
|
||||
if state.boundary != None:
|
||||
g_vtx, h_vtx = state.boundary
|
||||
for g_candidate_edge in getattr(g_vtx, direction):
|
||||
# print(" "*indent, g_candidate_edge)
|
||||
# print(" "*indent, 'g_candidate_edge:', g_candidate_edge)
|
||||
if g_candidate_edge in state.mapping_edges:
|
||||
# print(" "*indent, " skip, guest edge already matched")
|
||||
continue # skip already matched guest edge
|
||||
g_candidate_vtx = g_candidate_edge.tgt
|
||||
g_candidate_vtx = read_edge(g_candidate_edge, direction)
|
||||
for h_candidate_edge in getattr(h_vtx, direction):
|
||||
# print(" "*indent, 'h_candidate_edge:', h_candidate_edge)
|
||||
if h_candidate_edge in state.r_mapping_edges:
|
||||
# print(" "*indent, " skip, host edge already matched")
|
||||
continue # skip already matched host edge
|
||||
h_candidate_vtx = h_candidate_edge.tgt
|
||||
h_candidate_vtx = read_edge(h_candidate_edge, direction)
|
||||
# print(" "*indent, 'grow edge', g_candidate_edge, ':', h_candidate_edge)
|
||||
new_state = state.grow_edge(h_candidate_edge, g_candidate_edge)
|
||||
if visit_for_first_time(new_state):
|
||||
# print(" "*indent, 'grow edge', g_candidate_edge, ':', h_candidate_edge)
|
||||
yield from attempt_match_vtxs(
|
||||
new_state,
|
||||
g_candidate_vtx,
|
||||
h_candidate_vtx,
|
||||
indent+1)
|
||||
yield from attempt_match_vtxs(
|
||||
new_state,
|
||||
g_candidate_vtx,
|
||||
h_candidate_vtx,
|
||||
indent+1)
|
||||
|
||||
def attempt_match_vtxs(state, g_candidate_vtx, h_candidate_vtx, indent):
|
||||
# print(" "*indent, 'attempt_match_vtxs')
|
||||
if g_candidate_vtx in state.mapping_vtxs:
|
||||
if state.mapping_vtxs[g_candidate_vtx] != h_candidate_vtx:
|
||||
# print(" "*indent, " nope, guest already mapped (mismatch)")
|
||||
return # guest vtx is already mapped but doesn't match host vtx
|
||||
if h_candidate_vtx in state.r_mapping_vtxs:
|
||||
if state.r_mapping_vtxs[h_candidate_vtx] != g_candidate_vtx:
|
||||
# print(" "*indent, " nope, host already mapped (mismatch)")
|
||||
return # host vtx is already mapped but doesn't match guest vtx
|
||||
g_outdegree = len(g_candidate_vtx.outgoing)
|
||||
h_outdegree = len(h_candidate_vtx.outgoing)
|
||||
if g_outdegree > h_outdegree:
|
||||
return
|
||||
g_indegree = len(g_candidate_vtx.incoming)
|
||||
h_indegree = len(h_candidate_vtx.incoming)
|
||||
if g_indegree > h_indegree:
|
||||
return
|
||||
if not self.compare_fn(h_candidate_vtx.value, g_candidate_vtx.value):
|
||||
return
|
||||
new_state = state.grow_vtx(
|
||||
h_candidate_vtx,
|
||||
g_candidate_vtx)
|
||||
if visit_for_first_time(new_state):
|
||||
# print(" "*indent, 'attempt_match_vtxs')
|
||||
if h_candidate_vtx in state.r_mapping_vtxs:
|
||||
if state.r_mapping_vtxs[h_candidate_vtx] != g_candidate_vtx:
|
||||
return # host vtx is already mapped but doesn't match guest vtx
|
||||
g_outdegree = len(g_candidate_vtx.outgoing)
|
||||
h_outdegree = len(h_candidate_vtx.outgoing)
|
||||
if g_outdegree > h_outdegree:
|
||||
return
|
||||
g_indegree = len(g_candidate_vtx.incoming)
|
||||
h_indegree = len(h_candidate_vtx.incoming)
|
||||
if g_indegree > h_indegree:
|
||||
return
|
||||
if not self.compare_fn(h_candidate_vtx.value, g_candidate_vtx.value):
|
||||
return
|
||||
# print(" "*indent, 'grow vtx', g_candidate_vtx, ':', h_candidate_vtx)
|
||||
yield from self._match(new_state, already_visited, indent+1)
|
||||
# print(" "*indent, 'grow vtx', g_candidate_vtx, ':', h_candidate_vtx)
|
||||
yield from self._match(new_state, already_visited, indent+1)
|
||||
|
||||
# print(" "*indent, 'preferred...')
|
||||
yield from attempt_grow('outgoing', indent+1)
|
||||
|
|
@ -176,36 +192,39 @@ class MatcherVF2:
|
|||
# if indent == 0:
|
||||
# print('visited', len(already_visited), 'states total')
|
||||
|
||||
|
||||
# demo time...
|
||||
if __name__ == "__main__":
|
||||
host = Graph()
|
||||
host.vtxs = [Vertex(0), Vertex(1), Vertex(2)]
|
||||
host.vtxs = [Vertex(0), Vertex(1), Vertex(2), Vertex(3)]
|
||||
host.edges = [
|
||||
Edge(host.vtxs[0], host.vtxs[1]),
|
||||
Edge(host.vtxs[1], host.vtxs[2]),
|
||||
Edge(host.vtxs[2], host.vtxs[0]),
|
||||
Edge(host.vtxs[2], host.vtxs[3]),
|
||||
Edge(host.vtxs[3], host.vtxs[2]),
|
||||
]
|
||||
|
||||
guest = Graph()
|
||||
guest.vtxs = [Vertex('src'), Vertex('tgt')]
|
||||
guest.edges = [
|
||||
Edge(guest.vtxs[0], guest.vtxs[1]),
|
||||
Edge(guest.vtxs[1], guest.vtxs[0]),
|
||||
]
|
||||
|
||||
m = MatcherVF2(host, guest, lambda hv, gv: True)
|
||||
import time
|
||||
durations = 0
|
||||
iterations = 2000
|
||||
iterations = 100
|
||||
print("Patience...")
|
||||
for n in range(iterations):
|
||||
time_start = time.perf_counter_ns()
|
||||
matches = [mm for mm in m.match()]
|
||||
# print("found", len(matches), "matches")
|
||||
time_end = time.perf_counter_ns()
|
||||
time_duration = time_end - time_start
|
||||
durations += time_duration
|
||||
|
||||
print(f'{iterations} iterations, took {durations/1000000:.3f} ms, {durations/iterations/1000000:.3f} ms per iteration')
|
||||
print("found", len(matches), "matches")
|
||||
for mm in matches:
|
||||
print("match:")
|
||||
print(" ", mm.mapping_vtxs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue