rdf-isomorphic 2.0.0.beta1 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/AUTHORS +1 -1
- data/README.md +21 -18
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/lib/rdf/isomorphic.rb +40 -30
- metadata +23 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 195aaafad71d42a7be10bc7d626926d9e65d94a616ca93f3ea8a4e66c47a4dce
|
4
|
+
data.tar.gz: f8e4e24ad820d5de458a970756f830aed9ec87faf05f4ae6c95a33f219d1f3d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 67f8c90aa9656ae7dc9498572d27d084689a1e325083599ec7c02b3e2ced7e09b0d2a19817b31ec0c3038e30f8766bc92da813435fa29408bd93754804861b5e
|
7
|
+
data.tar.gz: 72d1aa0b1d02616ffa4befa055ad5364cc95183d44f2261a231762225a89198e88f83a9144bdba38a81bd5ed912f6a426c24690e7687e2d3491eb5661bb91de6
|
data/AUTHORS
CHANGED
data/README.md
CHANGED
@@ -3,17 +3,18 @@
|
|
3
3
|
This is an [RDF.rb][] extension for RDF Isomorphism functionality for RDF::Enumerables.
|
4
4
|
That includes RDF::Repository, RDF::Graph, query results, and more.
|
5
5
|
|
6
|
-
For more information about [RDF.rb][], see <
|
6
|
+
For more information about [RDF.rb][], see <https://www.rubydoc.info/github/ruby-rdf/rdf/>
|
7
7
|
|
8
|
-
[![Gem Version](https://badge.fury.io/rb/rdf-isomorphic.png)](
|
9
|
-
[![Build Status](https://
|
8
|
+
[![Gem Version](https://badge.fury.io/rb/rdf-isomorphic.png)](https://badge.fury.io/rb/rdf-isomorphic)
|
9
|
+
[![Build Status](https://github.com/ruby-rdf/rdf-isomorphic/workflows/CI/badge.svg?branch=develop)](https://github.com/ruby-rdf/rdf-isomorphic/actions?query=workflow%3ACI)
|
10
|
+
[![Coverage Status](https://coveralls.io/repos/ruby-rdf/rdf-isomorphic/badge.svg?branch=develop)](https://coveralls.io/github/ruby-rdf/rdf-isomorphic?branch=develop)
|
11
|
+
[![Gitter chat](https://badges.gitter.im/ruby-rdf/rdf.png)](https://gitter.im/ruby-rdf/rdf)
|
10
12
|
|
11
13
|
## Synopsis:
|
12
14
|
|
13
15
|
require 'rdf/isomorphic'
|
14
16
|
require 'rdf/ntriples'
|
15
17
|
|
16
|
-
|
17
18
|
a = RDF::Repository.load './tests/isomorphic/test1/test1-1.nt'
|
18
19
|
a.first
|
19
20
|
# < RDF::Statement:0xd344c4(<http://example.org/a> <http://example.org/prop> <_:abc> .) >
|
@@ -32,8 +33,7 @@ For more information about [RDF.rb][], see <http://rdf.rubyforge.org>
|
|
32
33
|
## Algorithm
|
33
34
|
|
34
35
|
The algorithm used here is very similar to the one described by Jeremy Carroll
|
35
|
-
in <
|
36
|
-
<http://blog.datagraph.org/2010/03/rdf-isomorphism>.
|
36
|
+
in <https://www.hpl.hp.com/techreports/2001/HPL-2001-293.pdf>.
|
37
37
|
|
38
38
|
Generally speaking, the Carroll algorithm is a very good fit for RDF graphs. It
|
39
39
|
is a specialization of the naive factorial-time test for graph isomorphism,
|
@@ -64,14 +64,15 @@ specs in RDF libraries. Try this in your tests:
|
|
64
64
|
end
|
65
65
|
|
66
66
|
### Information
|
67
|
-
* Author: Ben Lavender <blavender@gmail.com> - <
|
68
|
-
* Author: Arto Bendiken <arto.bendiken@gmail.com> - <
|
69
|
-
*
|
70
|
-
*
|
67
|
+
* Author: Ben Lavender <blavender@gmail.com> - <https://bhuga.net/>
|
68
|
+
* Author: Arto Bendiken <arto.bendiken@gmail.com> - <https://ar.to/>
|
69
|
+
* Author: Gregg Kellogg <gregg@greggkellogg.net> - <https://greggkellogg.net/>
|
70
|
+
* Source: <https://github.com/ruby-rdf/rdf-isomorphic>
|
71
|
+
* Issues: <https://github.com/ruby-rdf/rdf-isomorphic/issues>
|
71
72
|
|
72
73
|
### See also
|
73
|
-
* RDF.rb: <
|
74
|
-
* RDF.rb source: <
|
74
|
+
* RDF.rb: <https://ruby-rdf.github.com>
|
75
|
+
* RDF.rb source: <https://github.com/ruby-rdf/rdf>
|
75
76
|
|
76
77
|
## Contributing
|
77
78
|
|
@@ -90,14 +91,16 @@ This repository uses [Git Flow](https://github.com/nvie/gitflow) to mange develo
|
|
90
91
|
enough, be assured we will eventually add you in there.
|
91
92
|
* Do note that in order for us to merge any non-trivial changes (as a rule
|
92
93
|
of thumb, additions larger than about 15 lines of code), we need an
|
93
|
-
explicit [public domain dedication][PDD] on record from you
|
94
|
+
explicit [public domain dedication][PDD] on record from you,
|
95
|
+
which you will be asked to agree to on the first commit to a repo within the organization.
|
96
|
+
Note that the agreement applies to all repos in the [Ruby RDF](https://github.com/ruby-rdf/) organization.
|
94
97
|
|
95
98
|
## License
|
96
99
|
|
97
100
|
This is free and unencumbered public domain software. For more information,
|
98
|
-
see <
|
101
|
+
see <https://unlicense.org/> or the accompanying {file:UNLICENSE} file.
|
99
102
|
|
100
|
-
[RDF.rb]:
|
101
|
-
[YARD]:
|
102
|
-
[YARD-GS]:
|
103
|
-
[PDD]:
|
103
|
+
[RDF.rb]: https://ruby-rdf.github.com/
|
104
|
+
[YARD]: https://yardoc.org/
|
105
|
+
[YARD-GS]: https://rubydoc.info/docs/yard/file/docs/GettingStarted.md
|
106
|
+
[PDD]: https://unlicense.org/#unlicensing-contributions
|
data/UNLICENSE
CHANGED
@@ -21,4 +21,4 @@ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
21
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
22
|
OTHER DEALINGS IN THE SOFTWARE.
|
23
23
|
|
24
|
-
For more information, please refer to <
|
24
|
+
For more information, please refer to <https://unlicense.org/>
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
3.1.1
|
data/lib/rdf/isomorphic.rb
CHANGED
@@ -9,25 +9,22 @@ module RDF
|
|
9
9
|
#
|
10
10
|
# RDF::Isomorphic provides the functions isomorphic_with and bijection_to for RDF::Enumerable.
|
11
11
|
#
|
12
|
-
# @see
|
13
|
-
# @see
|
12
|
+
# @see https://www.rubydoc.info/github/ruby-rdf/rdf/
|
13
|
+
# @see https://www.hpl.hp.com/techreports/2001/HPL-2001-293.pdf
|
14
14
|
module Isomorphic
|
15
15
|
autoload :VERSION, 'rdf/isomorphic/version'
|
16
16
|
|
17
17
|
# Returns `true` if this RDF::Enumerable is isomorphic with another.
|
18
18
|
#
|
19
|
-
#
|
20
|
-
# canonicalized while producing a bijection. This results in broader
|
21
|
-
#
|
22
|
-
# representations.
|
23
|
-
#
|
24
|
-
# @param opts [Hash<Symbol => Any>] options
|
19
|
+
# @param canonicalize [Boolean] (false)
|
20
|
+
# If `true`, RDF::Literals will be canonicalized while producing a bijection. This results in broader matches for isomorphism in the case of equivalent literals with different representations.
|
21
|
+
# @param opts [Hash<Symbol => Any>] other options ignored
|
25
22
|
# @param other [RDF::Enumerable]
|
26
23
|
# @return [Boolean]
|
27
24
|
# @example
|
28
25
|
# repository_a.isomorphic_with repository_b #=> true
|
29
|
-
def isomorphic_with?(other,
|
30
|
-
!(bijection_to(other, opts).nil?)
|
26
|
+
def isomorphic_with?(other, canonicalize: false, **opts)
|
27
|
+
!(bijection_to(other, canonicalize: false, **opts).nil?)
|
31
28
|
end
|
32
29
|
|
33
30
|
alias_method :isomorphic?, :isomorphic_with?
|
@@ -45,9 +42,11 @@ module RDF
|
|
45
42
|
# @example
|
46
43
|
# repository_a.bijection_to repository_b
|
47
44
|
# @param other [RDF::Enumerable]
|
48
|
-
# @param
|
45
|
+
# @param canonicalize [Boolean] (false)
|
46
|
+
# If true, RDF::Literals will be canonicalized while producing a bijection. This results in broader matches for isomorphism in the case of equivalent literals with different representations.
|
47
|
+
# @param opts [Hash<Symbol => Any>] other options ignored
|
49
48
|
# @return [Hash, nil]
|
50
|
-
def bijection_to(other,
|
49
|
+
def bijection_to(other, canonicalize: false, **opts)
|
51
50
|
|
52
51
|
grounded_stmts_match = (count == other.count)
|
53
52
|
|
@@ -65,7 +64,10 @@ module RDF
|
|
65
64
|
|
66
65
|
nodes = RDF::Isomorphic.blank_nodes_in(blank_stmts)
|
67
66
|
other_nodes = RDF::Isomorphic.blank_nodes_in(other_blank_stmts)
|
68
|
-
build_bijection_to blank_stmts, nodes, other_blank_stmts, other_nodes,
|
67
|
+
build_bijection_to blank_stmts, nodes, other_blank_stmts, other_nodes,
|
68
|
+
these_grounded_hashes: {},
|
69
|
+
other_grounded_hashes: {},
|
70
|
+
canonicalize: false
|
69
71
|
else
|
70
72
|
nil
|
71
73
|
end
|
@@ -77,7 +79,7 @@ module RDF
|
|
77
79
|
# The main recursive bijection algorithm.
|
78
80
|
#
|
79
81
|
# This algorithm is very similar to the one explained by Jeremy Carroll in
|
80
|
-
#
|
82
|
+
# https://www.hpl.hp.com/techreports/2001/HPL-2001-293.pdf. Page 12 has the
|
81
83
|
# relevant pseudocode.
|
82
84
|
#
|
83
85
|
# Many more comments are in the method itself.
|
@@ -88,10 +90,14 @@ module RDF
|
|
88
90
|
# @param [Array] other_nodes
|
89
91
|
# @param [Hash] these_grounded_hashes
|
90
92
|
# @param [Hash] other_grounded_hashes
|
91
|
-
# @param [
|
93
|
+
# @param canonicalize [Boolean] (false)
|
94
|
+
# If true, RDF::Literals will be canonicalized while producing a bijection. This results in broader matches for isomorphism in the case of equivalent literals with different representations.
|
92
95
|
# @return [nil,Hash]
|
93
96
|
# @private
|
94
|
-
def build_bijection_to(anon_stmts, nodes, other_anon_stmts, other_nodes,
|
97
|
+
def build_bijection_to(anon_stmts, nodes, other_anon_stmts, other_nodes,
|
98
|
+
these_grounded_hashes: {},
|
99
|
+
other_grounded_hashes: {},
|
100
|
+
canonicalize: false)
|
95
101
|
|
96
102
|
# Create a hash signature of every node, based on the signature of
|
97
103
|
# statements it exists in.
|
@@ -99,8 +105,8 @@ module RDF
|
|
99
105
|
# that information to eliminate possible recursion combinations.
|
100
106
|
#
|
101
107
|
# Any mappings given in the method parameters are considered grounded.
|
102
|
-
these_hashes, these_ungrounded_hashes = RDF::Isomorphic.hash_nodes(anon_stmts, nodes, these_grounded_hashes,
|
103
|
-
other_hashes, other_ungrounded_hashes = RDF::Isomorphic.hash_nodes(other_anon_stmts, other_nodes, other_grounded_hashes,
|
108
|
+
these_hashes, these_ungrounded_hashes = RDF::Isomorphic.hash_nodes(anon_stmts, nodes, these_grounded_hashes, canonicalize: canonicalize)
|
109
|
+
other_hashes, other_ungrounded_hashes = RDF::Isomorphic.hash_nodes(other_anon_stmts, other_nodes, other_grounded_hashes, canonicalize: canonicalize)
|
104
110
|
|
105
111
|
# Grounded hashes are built at the same rate between the two graphs (if
|
106
112
|
# they are isomorphic). If there exists a grounded node in one that is
|
@@ -116,7 +122,7 @@ module RDF
|
|
116
122
|
# around for when we recurse later (we only recurse on ungrounded nodes)
|
117
123
|
bijection = {}
|
118
124
|
nodes.each do | node |
|
119
|
-
other_node,
|
125
|
+
other_node, _ = other_ungrounded_hashes.find do | other_node, other_hash |
|
120
126
|
# we need to use eql?, as coincedentally-named bnode identifiers are == in rdf.rb
|
121
127
|
these_ungrounded_hashes[node].eql? other_hash
|
122
128
|
end
|
@@ -148,7 +154,11 @@ module RDF
|
|
148
154
|
next unless these_ungrounded_hashes[node] == other_ungrounded_hashes[other_node]
|
149
155
|
|
150
156
|
hash = Digest::SHA1.hexdigest(node.to_s)
|
151
|
-
bijection = build_bijection_to(anon_stmts, nodes,
|
157
|
+
bijection = build_bijection_to(anon_stmts, nodes,
|
158
|
+
other_anon_stmts, other_nodes,
|
159
|
+
these_grounded_hashes: these_hashes.merge( node => hash),
|
160
|
+
other_grounded_hashes: other_hashes.merge(other_node => hash),
|
161
|
+
canonicalize: canonicalize)
|
152
162
|
end
|
153
163
|
bijection
|
154
164
|
end
|
@@ -162,7 +172,7 @@ module RDF
|
|
162
172
|
# @param [Array<RDF::Statement>] blank_stmt_list
|
163
173
|
# @return [Array<RDF::Node>]
|
164
174
|
def self.blank_nodes_in(blank_stmt_list)
|
165
|
-
blank_stmt_list.map {|statement | statement.
|
175
|
+
blank_stmt_list.map {|statement | statement.terms.select(&:node?)}.flatten.uniq
|
166
176
|
end
|
167
177
|
|
168
178
|
# Given a set of statements, create a mapping of node => SHA1 for a given
|
@@ -180,7 +190,7 @@ module RDF
|
|
180
190
|
# @param [Hash] grounded_hashes
|
181
191
|
# @private
|
182
192
|
# @return [Hash, Hash]
|
183
|
-
def self.hash_nodes(statements, nodes, grounded_hashes, canonicalize
|
193
|
+
def self.hash_nodes(statements, nodes, grounded_hashes, canonicalize: false)
|
184
194
|
hashes = grounded_hashes.dup
|
185
195
|
ungrounded_hashes = {}
|
186
196
|
hash_needed = true
|
@@ -192,7 +202,7 @@ module RDF
|
|
192
202
|
starting_grounded_nodes = hashes.size
|
193
203
|
nodes.each do | node |
|
194
204
|
unless hashes.member? node
|
195
|
-
grounded, hash = node_hash_for(node, statements, hashes, canonicalize)
|
205
|
+
grounded, hash = node_hash_for(node, statements, hashes, canonicalize: canonicalize)
|
196
206
|
if grounded
|
197
207
|
hashes[node] = hash
|
198
208
|
end
|
@@ -231,13 +241,13 @@ module RDF
|
|
231
241
|
# @param [Hash] hashes
|
232
242
|
# @param [Boolean] canonicalize
|
233
243
|
# @return [Boolean, String]
|
234
|
-
def self.node_hash_for(node, statements, hashes, canonicalize)
|
244
|
+
def self.node_hash_for(node, statements, hashes, canonicalize:)
|
235
245
|
statement_signatures = []
|
236
246
|
grounded = true
|
237
247
|
statements.each do | statement |
|
238
|
-
if statement.
|
239
|
-
statement_signatures << hash_string_for(statement, hashes, node, canonicalize)
|
240
|
-
statement.
|
248
|
+
if statement.terms.include?(node)
|
249
|
+
statement_signatures << hash_string_for(statement, hashes, node, canonicalize: canonicalize)
|
250
|
+
statement.terms.each do | resource |
|
241
251
|
grounded = false unless grounded?(resource, hashes) || resource == node
|
242
252
|
end
|
243
253
|
end
|
@@ -251,8 +261,8 @@ module RDF
|
|
251
261
|
# string signatures for grounded node elements.
|
252
262
|
# return [String]
|
253
263
|
# @private
|
254
|
-
def self.hash_string_for(statement, hashes, node, canonicalize)
|
255
|
-
statement.
|
264
|
+
def self.hash_string_for(statement, hashes, node, canonicalize:)
|
265
|
+
statement.terms.map {|r| string_for_node(r, hashes, node, canonicalize: canonicalize)}.join("")
|
256
266
|
end
|
257
267
|
|
258
268
|
# Returns true if a given node is grounded
|
@@ -269,7 +279,7 @@ module RDF
|
|
269
279
|
# nodes will return their hashed form.
|
270
280
|
# @return [String]
|
271
281
|
# @private
|
272
|
-
def self.string_for_node(node, hashes,target, canonicalize)
|
282
|
+
def self.string_for_node(node, hashes,target, canonicalize:)
|
273
283
|
case
|
274
284
|
when node.nil?
|
275
285
|
""
|
metadata
CHANGED
@@ -1,84 +1,73 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rdf-isomorphic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Lavender
|
8
8
|
- Arto Bendiken
|
9
|
-
|
9
|
+
- Gregg Kellogg
|
10
|
+
autorequire:
|
10
11
|
bindir: bin
|
11
12
|
cert_chain: []
|
12
|
-
date:
|
13
|
+
date: 2021-02-02 00:00:00.000000000 Z
|
13
14
|
dependencies:
|
14
15
|
- !ruby/object:Gem::Dependency
|
15
16
|
name: rdf
|
16
17
|
requirement: !ruby/object:Gem::Requirement
|
17
18
|
requirements:
|
18
|
-
- - "
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 2.0.0.beta
|
21
|
-
- - "<"
|
19
|
+
- - "~>"
|
22
20
|
- !ruby/object:Gem::Version
|
23
|
-
version: '3'
|
21
|
+
version: '3.1'
|
24
22
|
type: :runtime
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
25
|
requirements:
|
28
|
-
- - "
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 2.0.0.beta
|
31
|
-
- - "<"
|
26
|
+
- - "~>"
|
32
27
|
- !ruby/object:Gem::Version
|
33
|
-
version: '3'
|
28
|
+
version: '3.1'
|
34
29
|
- !ruby/object:Gem::Dependency
|
35
30
|
name: rdf-spec
|
36
31
|
requirement: !ruby/object:Gem::Requirement
|
37
32
|
requirements:
|
38
|
-
- - "
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 2.0.0.beta
|
41
|
-
- - "<"
|
33
|
+
- - "~>"
|
42
34
|
- !ruby/object:Gem::Version
|
43
|
-
version: '3'
|
35
|
+
version: '3.1'
|
44
36
|
type: :development
|
45
37
|
prerelease: false
|
46
38
|
version_requirements: !ruby/object:Gem::Requirement
|
47
39
|
requirements:
|
48
|
-
- - "
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: 2.0.0.beta
|
51
|
-
- - "<"
|
40
|
+
- - "~>"
|
52
41
|
- !ruby/object:Gem::Version
|
53
|
-
version: '3'
|
42
|
+
version: '3.1'
|
54
43
|
- !ruby/object:Gem::Dependency
|
55
44
|
name: rspec
|
56
45
|
requirement: !ruby/object:Gem::Requirement
|
57
46
|
requirements:
|
58
47
|
- - "~>"
|
59
48
|
- !ruby/object:Gem::Version
|
60
|
-
version: '3.
|
49
|
+
version: '3.10'
|
61
50
|
type: :development
|
62
51
|
prerelease: false
|
63
52
|
version_requirements: !ruby/object:Gem::Requirement
|
64
53
|
requirements:
|
65
54
|
- - "~>"
|
66
55
|
- !ruby/object:Gem::Version
|
67
|
-
version: '3.
|
56
|
+
version: '3.10'
|
68
57
|
- !ruby/object:Gem::Dependency
|
69
58
|
name: yard
|
70
59
|
requirement: !ruby/object:Gem::Requirement
|
71
60
|
requirements:
|
72
61
|
- - "~>"
|
73
62
|
- !ruby/object:Gem::Version
|
74
|
-
version: 0.
|
63
|
+
version: '0.9'
|
75
64
|
type: :development
|
76
65
|
prerelease: false
|
77
66
|
version_requirements: !ruby/object:Gem::Requirement
|
78
67
|
requirements:
|
79
68
|
- - "~>"
|
80
69
|
- !ruby/object:Gem::Version
|
81
|
-
version: 0.
|
70
|
+
version: '0.9'
|
82
71
|
description: RDF.rb extension for graph bijections and isomorphic equivalence.
|
83
72
|
email: public-rdf-ruby@w3.org
|
84
73
|
executables: []
|
@@ -91,11 +80,11 @@ files:
|
|
91
80
|
- VERSION
|
92
81
|
- lib/rdf/isomorphic.rb
|
93
82
|
- lib/rdf/isomorphic/version.rb
|
94
|
-
homepage:
|
83
|
+
homepage: https://ruby-rdf.github.com/rdf-isomorphic
|
95
84
|
licenses:
|
96
85
|
- Unlicense
|
97
86
|
metadata: {}
|
98
|
-
post_install_message:
|
87
|
+
post_install_message:
|
99
88
|
rdoc_options: []
|
100
89
|
require_paths:
|
101
90
|
- lib
|
@@ -103,17 +92,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
92
|
requirements:
|
104
93
|
- - ">="
|
105
94
|
- !ruby/object:Gem::Version
|
106
|
-
version: '2.
|
95
|
+
version: '2.4'
|
107
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
97
|
requirements:
|
109
|
-
- - "
|
98
|
+
- - ">="
|
110
99
|
- !ruby/object:Gem::Version
|
111
|
-
version:
|
100
|
+
version: '0'
|
112
101
|
requirements: []
|
113
|
-
|
114
|
-
|
115
|
-
signing_key:
|
102
|
+
rubygems_version: 3.2.3
|
103
|
+
signing_key:
|
116
104
|
specification_version: 4
|
117
105
|
summary: RDF Graph/Dataset Isomorphism as defined in RDF 1.1 Concepts.
|
118
106
|
test_files: []
|
119
|
-
has_rdoc: false
|