graphmatcher 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/graphmatcher.rb +2 -1
- data/lib/graphmatcher_vf2pp.rb +49 -3
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ac93435628f298d6ea79c76d0c0f56f21167dc958afd7837636c9de53ad5bfb9
|
|
4
|
+
data.tar.gz: 4d91ff69d4f2c0ddf8eaec29b3ff84d4453ed6d8b47613e1da77a42c1399665d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f60980782fd68a0b41ab83878c3b193d384a85fc780d61910b72a3cc3d41d91fbb657bb2fcccb432f00cd53bfc175b516b061abf6fe4ba809bccb4be2b186552
|
|
7
|
+
data.tar.gz: 3bed6339341e5fc3034d5876288e7b1cbe75a3a09acc108f3c60979ffb1e2c2331c4c9e11a0f4003ea997e6e1bf2162d1cd866d533a59d9891437b772089851b
|
data/lib/graphmatcher.rb
CHANGED
data/lib/graphmatcher_vf2pp.rb
CHANGED
|
@@ -34,7 +34,7 @@ require 'set'
|
|
|
34
34
|
# the original Graphmatcher, but — unlike it — also works on cyclic queries.)
|
|
35
35
|
class GraphmatcherVF2pp
|
|
36
36
|
|
|
37
|
-
VERSION = "0.1
|
|
37
|
+
VERSION = "0.4.1".freeze
|
|
38
38
|
|
|
39
39
|
@@logger = Logger.new(STDOUT)
|
|
40
40
|
@@logger.level = Logger::INFO
|
|
@@ -44,11 +44,15 @@ class GraphmatcherVF2pp
|
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
def initialize(args)
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
# Accept both the native keys (:query/:data) and the schedy worker's
|
|
48
|
+
# keys (:query_graph/:data_graph). :cost_matrix is optional and only
|
|
49
|
+
# consumed by find_matches.
|
|
50
|
+
@query_graph = (args[:query] || args[:query_graph]).to_a
|
|
51
|
+
@data_graph = (args[:data] || args[:data_graph]).to_a
|
|
49
52
|
@limit = args[:limit].to_i
|
|
50
53
|
@max_allowed_time = args[:max_allowed_time].to_f
|
|
51
54
|
@self_loops = args[:self_loops]
|
|
55
|
+
@cost_matrix = args[:cost_matrix]
|
|
52
56
|
validate!
|
|
53
57
|
|
|
54
58
|
@q_adj = @query_graph[0]
|
|
@@ -90,8 +94,50 @@ class GraphmatcherVF2pp
|
|
|
90
94
|
@matches
|
|
91
95
|
end
|
|
92
96
|
|
|
97
|
+
# Cost-aware matching used by the schedy worker's Resource.estimate.
|
|
98
|
+
#
|
|
99
|
+
# Requires a :cost_matrix (passed at construction) laid out as
|
|
100
|
+
# cost_matrix[data_index][query_index] => Numeric
|
|
101
|
+
# i.e. the cost of assigning data vertex `data_index` to query vertex
|
|
102
|
+
# (role) `query_index`. This matches Resource.estimate_costs, which uses a
|
|
103
|
+
# large sentinel (360000) for incompatible pairs.
|
|
104
|
+
#
|
|
105
|
+
# Returns an Array of plans. Each plan has one [data_index, cost] pair per
|
|
106
|
+
# query vertex, in query-vertex order (NOT matching order):
|
|
107
|
+
# [[d0, c0], [d1, c1], ..., [dn, cn]]
|
|
108
|
+
# where ci = cost_matrix[di][i]. The caller computes a plan's cost as the
|
|
109
|
+
# maximum (bottleneck) of the per-node costs and filters/sorts on it, so
|
|
110
|
+
# this method returns every structural match annotated with cost and leaves
|
|
111
|
+
# the cost thresholding to the caller.
|
|
112
|
+
def find_matches
|
|
113
|
+
raise ArgumentError, "find_matches requires :cost_matrix" if @cost_matrix.nil?
|
|
114
|
+
|
|
115
|
+
getMatches.map do |phi|
|
|
116
|
+
phi.each_index.map do |query_index|
|
|
117
|
+
data_index = phi[query_index].first
|
|
118
|
+
[data_index, cost_for(data_index, query_index)]
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
93
123
|
private
|
|
94
124
|
|
|
125
|
+
# Look up cost_matrix[data_index][query_index], tolerating either Hash-of-Hash
|
|
126
|
+
# (as built by Resource.estimate_costs) or Array-of-Array layouts. Missing
|
|
127
|
+
# entries fall back to the incompatibility sentinel so the caller's
|
|
128
|
+
# bottleneck filter discards them.
|
|
129
|
+
INCOMPATIBLE_COST = 360000
|
|
130
|
+
|
|
131
|
+
def cost_for(data_index, query_index)
|
|
132
|
+
return INCOMPATIBLE_COST if data_index.nil?
|
|
133
|
+
row = @cost_matrix[data_index]
|
|
134
|
+
return INCOMPATIBLE_COST if row.nil?
|
|
135
|
+
value = row[query_index]
|
|
136
|
+
value.nil? ? INCOMPATIBLE_COST : value
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
public
|
|
140
|
+
|
|
95
141
|
def timed_out?
|
|
96
142
|
@max_allowed_time > 0 && (Time.now.to_f - @t0) > @max_allowed_time
|
|
97
143
|
end
|