omf_rete 0.5
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.
- data/.gitignore +4 -0
- data/README.md +182 -0
- data/Rakefile +14 -0
- data/lib/omf_rete/abstract_tuple_set.rb +68 -0
- data/lib/omf_rete/indexed_tuple_set.rb +129 -0
- data/lib/omf_rete/join_op.rb +113 -0
- data/lib/omf_rete/planner/abstract_plan.rb +57 -0
- data/lib/omf_rete/planner/filter_plan.rb +49 -0
- data/lib/omf_rete/planner/join_plan.rb +94 -0
- data/lib/omf_rete/planner/plan_builder.rb +302 -0
- data/lib/omf_rete/planner/plan_level_builder.rb +94 -0
- data/lib/omf_rete/planner/plan_set.rb +82 -0
- data/lib/omf_rete/planner/source_plan.rb +81 -0
- data/lib/omf_rete/store/alpha/alpha_element.rb +95 -0
- data/lib/omf_rete/store/alpha/alpha_inner_element.rb +96 -0
- data/lib/omf_rete/store/alpha/alpha_leaf_element.rb +41 -0
- data/lib/omf_rete/store/alpha/alpha_store.rb +197 -0
- data/lib/omf_rete/store.rb +57 -0
- data/lib/omf_rete/tuple_stream.rb +241 -0
- data/lib/omf_rete/version.rb +9 -0
- data/lib/omf_rete.rb +35 -0
- data/omf_rete.gemspec +24 -0
- data/tests/test.rb +8 -0
- data/tests/test_backtracking.rb +42 -0
- data/tests/test_filter.rb +77 -0
- data/tests/test_indexed_tuple_set.rb +58 -0
- data/tests/test_join_op.rb +50 -0
- data/tests/test_planner.rb +232 -0
- data/tests/test_store.rb +157 -0
- metadata +74 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
|
2
|
+
module OMF::Rete::Store::Alpha
|
3
|
+
|
4
|
+
# Module internal class, will only be instantiated by +Store+
|
5
|
+
#
|
6
|
+
class AlphaElement
|
7
|
+
|
8
|
+
def self.create(level, length)
|
9
|
+
rem = length - level
|
10
|
+
if (rem > 1)
|
11
|
+
AlphaInnerElement.new(level, length)
|
12
|
+
else
|
13
|
+
AlphaLeafElement.new(level)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(level)
|
18
|
+
@level = level
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class AlphaInnerElement < AlphaElement
|
24
|
+
|
25
|
+
def initialize(level, length)
|
26
|
+
super(level)
|
27
|
+
@length = length
|
28
|
+
@children = {}
|
29
|
+
if (level < length)
|
30
|
+
@wildChild = AlphaElement.create(level + 1, length)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# see Store
|
35
|
+
#
|
36
|
+
def registerTSet(tset, pattern)
|
37
|
+
pitem = pattern[@level]
|
38
|
+
if (pitem) # not nil
|
39
|
+
child = (@children[pitem] ||= AlphaElement.create(@level + 1, @length))
|
40
|
+
child.registerTSet(tset, pattern)
|
41
|
+
else # wildcard
|
42
|
+
@wildChild.registerTSet(tset, pattern)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
def addTuple(tarray)
|
48
|
+
el = tarray[@level]
|
49
|
+
if (child = @children[el])
|
50
|
+
child.addTuple(tarray)
|
51
|
+
end
|
52
|
+
@wildChild.addTuple(tarray) if (@wildChild)
|
53
|
+
end
|
54
|
+
end # AlphaInnerElement
|
55
|
+
|
56
|
+
# Module internal class, will only be instantiated by +Store+
|
57
|
+
#
|
58
|
+
class AlphaLeafElement < AlphaElement
|
59
|
+
|
60
|
+
def initialize(level)
|
61
|
+
super
|
62
|
+
@tsetIndex = {}
|
63
|
+
@tsetWildcards = []
|
64
|
+
end
|
65
|
+
|
66
|
+
# see Store
|
67
|
+
#
|
68
|
+
def registerTSet(tset, pattern)
|
69
|
+
pitem = pattern[@level]
|
70
|
+
leaf = (@level == @length)
|
71
|
+
if (pitem) # not nil
|
72
|
+
(@tsetIndex[pitem] ||= []) << tset
|
73
|
+
else # wildcard
|
74
|
+
@tsetWildcards << tset
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def addTuple(tarray)
|
79
|
+
# check if we have any matching tsets
|
80
|
+
item = tarray[@level]
|
81
|
+
if (arr = @tsetIndex[item])
|
82
|
+
arr.each do |s|
|
83
|
+
s.addTuple(tarray)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
@tsetWildcards.each do |s|
|
87
|
+
s.addTuple(tarray)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
end # AlphaLeafElement
|
94
|
+
|
95
|
+
end # Moana::Filter::Store::Alpha
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'omf_rete/store/alpha/alpha_element'
|
2
|
+
|
3
|
+
module OMF::Rete::Store::Alpha
|
4
|
+
|
5
|
+
# Module internal class, will only be instantiated by +Store+
|
6
|
+
#
|
7
|
+
class AlphaElement
|
8
|
+
|
9
|
+
def self.create(level, length)
|
10
|
+
rem = length - level
|
11
|
+
if (rem > 1)
|
12
|
+
AlphaInnerElement.new(level, length)
|
13
|
+
else
|
14
|
+
AlphaLeafElement.new(level)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def initialize(level)
|
19
|
+
@level = level
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
class AlphaInnerElement < AlphaElement
|
25
|
+
|
26
|
+
def initialize(level, length)
|
27
|
+
super(level)
|
28
|
+
@length = length
|
29
|
+
@children = {}
|
30
|
+
if (level < length)
|
31
|
+
@wildChild = AlphaElement.create(level + 1, length)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# see Store
|
36
|
+
#
|
37
|
+
def registerTSet(tset, pattern)
|
38
|
+
pitem = pattern[@level]
|
39
|
+
if (pitem) # not nil
|
40
|
+
child = (@children[pitem] ||= AlphaElement.create(@level + 1, @length))
|
41
|
+
child.registerTSet(tset, pattern)
|
42
|
+
else # wildcard
|
43
|
+
@wildChild.registerTSet(tset, pattern)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
def addTuple(tarray)
|
49
|
+
el = tarray[@level]
|
50
|
+
if (child = @children[el])
|
51
|
+
child.addTuple(tarray)
|
52
|
+
end
|
53
|
+
@wildChild.addTuple(tarray) if (@wildChild)
|
54
|
+
end
|
55
|
+
end # AlphaInnerElement
|
56
|
+
|
57
|
+
# Module internal class, will only be instantiated by +Store+
|
58
|
+
#
|
59
|
+
class AlphaLeafElement < AlphaElement
|
60
|
+
|
61
|
+
def initialize(level)
|
62
|
+
super
|
63
|
+
@tsetIndex = {}
|
64
|
+
@tsetWildcards = []
|
65
|
+
end
|
66
|
+
|
67
|
+
# see Store
|
68
|
+
#
|
69
|
+
def registerTSet(tset, pattern)
|
70
|
+
pitem = pattern[@level]
|
71
|
+
leaf = (@level == @length)
|
72
|
+
if (pitem) # not nil
|
73
|
+
(@tsetIndex[pitem] ||= []) << tset
|
74
|
+
else # wildcard
|
75
|
+
@tsetWildcards << tset
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def addTuple(tarray)
|
80
|
+
# check if we have any matching tsets
|
81
|
+
item = tarray[@level]
|
82
|
+
if (arr = @tsetIndex[item])
|
83
|
+
arr.each do |s|
|
84
|
+
s.addTuple(tarray)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
@tsetWildcards.each do |s|
|
88
|
+
s.addTuple(tarray)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
end # AlphaLeafElement
|
95
|
+
|
96
|
+
end # Moana::Filter::Store::Alpha
|
@@ -0,0 +1,41 @@
|
|
1
|
+
|
2
|
+
require 'omf_rete/store/alpha/alpha_element'
|
3
|
+
|
4
|
+
module OMF::Rete::Store::Alpha
|
5
|
+
|
6
|
+
# Module internal class, will only be instantiated by +Store+
|
7
|
+
#
|
8
|
+
class AlphaLeafElement < AlphaElement
|
9
|
+
|
10
|
+
def initialize(level)
|
11
|
+
super
|
12
|
+
@tsetIndex = {}
|
13
|
+
@tsetWildcards = []
|
14
|
+
end
|
15
|
+
|
16
|
+
# see Store
|
17
|
+
#
|
18
|
+
def registerTSet(tset, pattern)
|
19
|
+
pitem = pattern[@level]
|
20
|
+
leaf = (@level == @length)
|
21
|
+
if (pitem) # not nil
|
22
|
+
(@tsetIndex[pitem] ||= []) << tset
|
23
|
+
else # wildcard
|
24
|
+
@tsetWildcards << tset
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def addTuple(tarray)
|
29
|
+
# check if we have any matching tsets
|
30
|
+
item = tarray[@level]
|
31
|
+
if (arr = @tsetIndex[item])
|
32
|
+
arr.each do |s|
|
33
|
+
s.addTuple(tarray)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@tsetWildcards.each do |s|
|
37
|
+
s.addTuple(tarray)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end # AlphaLeafElement
|
41
|
+
end # Moana::Filter::Store::Alpha
|
@@ -0,0 +1,197 @@
|
|
1
|
+
require 'set'
|
2
|
+
require 'omf_rete/store/alpha/alpha_inner_element'
|
3
|
+
require 'omf_rete/store/alpha/alpha_leaf_element'
|
4
|
+
|
5
|
+
module OMF::Rete::Store::Alpha
|
6
|
+
|
7
|
+
# Module internal class, will only be instantiated by +Store+
|
8
|
+
#
|
9
|
+
class AlphaElement
|
10
|
+
|
11
|
+
def self.create(level, length)
|
12
|
+
rem = length - level
|
13
|
+
if (rem > 1)
|
14
|
+
AlphaInnerElement.new(level, length)
|
15
|
+
else
|
16
|
+
AlphaLeafElement.new(level)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(level)
|
21
|
+
@level = level
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class AlphaInnerElement < AlphaElement
|
27
|
+
|
28
|
+
def initialize(level, length)
|
29
|
+
super(level)
|
30
|
+
@length = length
|
31
|
+
@children = {}
|
32
|
+
if (level < length)
|
33
|
+
@wildChild = AlphaElement.create(level + 1, length)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# see Store
|
38
|
+
#
|
39
|
+
def registerTSet(tset, pattern)
|
40
|
+
pitem = pattern[@level]
|
41
|
+
if (pitem) # not nil
|
42
|
+
child = (@children[pitem] ||= AlphaElement.create(@level + 1, @length))
|
43
|
+
child.registerTSet(tset, pattern)
|
44
|
+
else # wildcard
|
45
|
+
@wildChild.registerTSet(tset, pattern)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def addTuple(tarray)
|
51
|
+
el = tarray[@level]
|
52
|
+
if (child = @children[el])
|
53
|
+
child.addTuple(tarray)
|
54
|
+
end
|
55
|
+
@wildChild.addTuple(tarray) if (@wildChild)
|
56
|
+
end
|
57
|
+
end # AlphaInnerElement
|
58
|
+
|
59
|
+
# Module internal class, will only be instantiated by +Store+
|
60
|
+
#
|
61
|
+
class AlphaLeafElement < AlphaElement
|
62
|
+
|
63
|
+
def initialize(level)
|
64
|
+
super
|
65
|
+
@tsetIndex = {}
|
66
|
+
@tsetWildcards = []
|
67
|
+
end
|
68
|
+
|
69
|
+
# see Store
|
70
|
+
#
|
71
|
+
def registerTSet(tset, pattern)
|
72
|
+
pitem = pattern[@level]
|
73
|
+
leaf = (@level == @length)
|
74
|
+
if (pitem) # not nil
|
75
|
+
(@tsetIndex[pitem] ||= []) << tset
|
76
|
+
else # wildcard
|
77
|
+
@tsetWildcards << tset
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def addTuple(tarray)
|
82
|
+
# check if we have any matching tsets
|
83
|
+
item = tarray[@level]
|
84
|
+
if (arr = @tsetIndex[item])
|
85
|
+
arr.each do |s|
|
86
|
+
s.addTuple(tarray)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
@tsetWildcards.each do |s|
|
90
|
+
s.addTuple(tarray)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
|
96
|
+
end # AlphaLeafElement
|
97
|
+
|
98
|
+
#
|
99
|
+
# Class to store tuples for use in MoanaFilter
|
100
|
+
#
|
101
|
+
class Store #< MObject
|
102
|
+
include OMF::Rete::Store
|
103
|
+
|
104
|
+
attr_reader :length
|
105
|
+
|
106
|
+
# Initialize a tuple store for tuples of
|
107
|
+
# fixed length +length+.
|
108
|
+
#
|
109
|
+
def initialize(length, opts = {})
|
110
|
+
@length = length
|
111
|
+
@root = AlphaInnerElement.new(0, length)
|
112
|
+
@index = []
|
113
|
+
length.times do @index << {} end
|
114
|
+
end
|
115
|
+
|
116
|
+
def query(queryPattern, projectPattern = nil, &block)
|
117
|
+
pb = PlanBuilder.new(queryPattern, self)
|
118
|
+
pb.build
|
119
|
+
pb.materialize(projectPattern, &block)
|
120
|
+
end
|
121
|
+
|
122
|
+
# Register a +TSet+ and add all tuples currently
|
123
|
+
# and in the future matching +pattern+
|
124
|
+
#
|
125
|
+
def registerTSet(tset, pattern)
|
126
|
+
pat = pattern.collect do |el|
|
127
|
+
(el.is_a?(Symbol) && el.to_s.end_with?('?')) ? nil : el
|
128
|
+
end
|
129
|
+
@root.registerTSet(tset, pat)
|
130
|
+
# seed tset which already stored data
|
131
|
+
find(pattern).each do |t|
|
132
|
+
tset.addTuple(t)
|
133
|
+
end
|
134
|
+
tset
|
135
|
+
end
|
136
|
+
|
137
|
+
def createTSet(description, indexPattern)
|
138
|
+
tset = Moana::Filter::IndexedTupleSet.new(description, indexPattern)
|
139
|
+
registerTSet(tset, description)
|
140
|
+
tset
|
141
|
+
end
|
142
|
+
|
143
|
+
def addTuple(tarray)
|
144
|
+
@length.times do |i|
|
145
|
+
item = tarray[i]
|
146
|
+
ia = @index[i][item] ||= Set.new
|
147
|
+
unless ia.add?(tarray)
|
148
|
+
return # this is a duplicate
|
149
|
+
end
|
150
|
+
end
|
151
|
+
@root.addTuple(tarray)
|
152
|
+
end
|
153
|
+
|
154
|
+
# Return a set of tuples which match +pattern+. Pattern is
|
155
|
+
# a tuples of the same length this store is configured for
|
156
|
+
# where any non-nil element is matched directly and any
|
157
|
+
# nil element is considered a wildcard.
|
158
|
+
#
|
159
|
+
def find(pattern)
|
160
|
+
seta = []
|
161
|
+
allWildcards = true
|
162
|
+
@length.times do |i|
|
163
|
+
if (item = pattern[i])
|
164
|
+
allWildcards = false
|
165
|
+
res = @index[i][item]
|
166
|
+
#puts "res: index #{i}, res: #{res.inspect}"
|
167
|
+
seta << res if res # only add if non-nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
if (allWildcards)
|
171
|
+
res = Set.new
|
172
|
+
@index[0].each_value do |s|
|
173
|
+
res.merge(s)
|
174
|
+
end
|
175
|
+
return res
|
176
|
+
end
|
177
|
+
# get intersection of all returned sets
|
178
|
+
if (seta.empty?)
|
179
|
+
return Set.new
|
180
|
+
end
|
181
|
+
res = nil
|
182
|
+
seta.each do |s|
|
183
|
+
if res
|
184
|
+
res = res.intersection(s)
|
185
|
+
else
|
186
|
+
res = s
|
187
|
+
end
|
188
|
+
#puts "merge: in: #{s.inspect}, res: #{res.inspect}"
|
189
|
+
end
|
190
|
+
return res
|
191
|
+
end
|
192
|
+
|
193
|
+
def to_s()
|
194
|
+
"Store"
|
195
|
+
end
|
196
|
+
end # Store
|
197
|
+
end # Moana
|
@@ -0,0 +1,57 @@
|
|
1
|
+
|
2
|
+
require 'omf_rete'
|
3
|
+
|
4
|
+
|
5
|
+
module OMF::Rete::Store
|
6
|
+
DEF_TYPE = :alpha
|
7
|
+
|
8
|
+
def self.create(length, opts = {})
|
9
|
+
case (type = opts[:type] || DEF_TYPE)
|
10
|
+
when :alpha
|
11
|
+
require 'omf_rete/store/alpha/alpha_store'
|
12
|
+
return OMF::Rete::Store::Alpha::Store.new(length, opts)
|
13
|
+
else
|
14
|
+
raise "Unknown store type '#{type}'"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
#--- INTERFACE ---
|
19
|
+
|
20
|
+
def query(queryPattern, projectPattern = nil, &block)
|
21
|
+
raise "'query' - Not implemented."
|
22
|
+
end
|
23
|
+
|
24
|
+
def subscribe(name, query, out_pattern = nil, &block)
|
25
|
+
require 'omf_rete/planner/plan_builder'
|
26
|
+
|
27
|
+
pb = OMF::Rete::Planner::PlanBuilder.new(query, self)
|
28
|
+
pb.build
|
29
|
+
pb.materialize(out_pattern, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
def addTuple(tarray)
|
33
|
+
end
|
34
|
+
|
35
|
+
# alias
|
36
|
+
def add(*els)
|
37
|
+
addTuple(els)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Return a set of tuples which match +pattern+. Pattern is
|
41
|
+
# a tuples of the same length this store is configured for
|
42
|
+
# where any non-nil element is matched directly and any
|
43
|
+
# nil element is considered a wildcard.
|
44
|
+
#
|
45
|
+
def find(pattern)
|
46
|
+
end
|
47
|
+
|
48
|
+
# Register a function to be called whenever a query is performed
|
49
|
+
# on the store. The arguments to the proc are identical to that
|
50
|
+
# of +query+. The returned tuple set is added to the store and
|
51
|
+
# returned with any other tuples stored which match the query
|
52
|
+
# pattern.
|
53
|
+
#
|
54
|
+
def on_query(&requestProc)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|