wongi-engine 0.3.9 → 0.4.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +2 -2
- data/.gitignore +2 -0
- data/README.md +12 -12
- data/lib/wongi-engine/alpha_index.rb +58 -0
- data/lib/wongi-engine/alpha_memory.rb +2 -24
- data/lib/wongi-engine/beta/aggregate_node.rb +16 -15
- data/lib/wongi-engine/beta/assignment_node.rb +7 -2
- data/lib/wongi-engine/beta/beta_node.rb +27 -23
- data/lib/wongi-engine/beta/filter_node.rb +8 -13
- data/lib/wongi-engine/beta/join_node.rb +15 -28
- data/lib/wongi-engine/beta/ncc_node.rb +14 -26
- data/lib/wongi-engine/beta/ncc_partner.rb +18 -18
- data/lib/wongi-engine/beta/neg_node.rb +23 -55
- data/lib/wongi-engine/beta/optional_node.rb +24 -48
- data/lib/wongi-engine/beta/or_node.rb +24 -1
- data/lib/wongi-engine/beta/production_node.rb +9 -3
- data/lib/wongi-engine/beta/root_node.rb +47 -0
- data/lib/wongi-engine/beta.rb +1 -1
- data/lib/wongi-engine/compiler.rb +6 -34
- data/lib/wongi-engine/dsl/action/{base.rb → base_action.rb} +5 -1
- data/lib/wongi-engine/dsl/action/error_generator.rb +1 -1
- data/lib/wongi-engine/dsl/action/simple_action.rb +1 -1
- data/lib/wongi-engine/dsl/action/simple_collector.rb +1 -1
- data/lib/wongi-engine/dsl/action/statement_generator.rb +21 -22
- data/lib/wongi-engine/dsl/action/trace_action.rb +1 -1
- data/lib/wongi-engine/dsl/clause/fact.rb +2 -6
- data/lib/wongi-engine/dsl.rb +1 -25
- data/lib/wongi-engine/graph.rb +1 -1
- data/lib/wongi-engine/network/debug.rb +2 -10
- data/lib/wongi-engine/network.rb +44 -105
- data/lib/wongi-engine/overlay.rb +589 -0
- data/lib/wongi-engine/template.rb +22 -2
- data/lib/wongi-engine/token.rb +10 -26
- data/lib/wongi-engine/token_assignment.rb +15 -0
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine/wme.rb +10 -39
- data/lib/wongi-engine.rb +3 -1
- data/spec/alpha_index_spec.rb +78 -0
- data/spec/bug_specs/issue_4_spec.rb +11 -11
- data/spec/high_level_spec.rb +8 -101
- data/spec/network_spec.rb +8 -6
- data/spec/overlay_spec.rb +161 -3
- data/spec/rule_specs/any_rule_spec.rb +39 -0
- data/spec/rule_specs/assign_spec.rb +1 -1
- data/spec/rule_specs/maybe_rule_spec.rb +58 -1
- data/spec/rule_specs/ncc_spec.rb +78 -19
- data/spec/rule_specs/negative_rule_spec.rb +12 -14
- data/spec/spec_helper.rb +4 -0
- data/spec/wme_spec.rb +0 -32
- metadata +11 -9
- data/lib/wongi-engine/beta/beta_memory.rb +0 -60
- data/lib/wongi-engine/data_overlay.rb +0 -149
- data/spec/rule_specs/or_rule_spec.rb +0 -40
data/lib/wongi-engine/graph.rb
CHANGED
@@ -44,7 +44,7 @@ module Wongi::Engine
|
|
44
44
|
return if @seen_betas.include? beta
|
45
45
|
|
46
46
|
@seen_betas << beta
|
47
|
-
io.puts "node#{print_hash beta.object_id} [label=\"#{beta.class.name.split('::').last}\"];"
|
47
|
+
io.puts "node#{print_hash beta.object_id} [label=\"#{beta.class.name.split('::').last}\\nid=#{beta.object_id}\"];"
|
48
48
|
if beta.is_a? NccNode
|
49
49
|
io.puts "node#{print_hash beta.partner.object_id} -> node#{print_hash beta.object_id};"
|
50
50
|
io.puts "{ rank=same; node#{print_hash beta.partner.object_id} node#{print_hash beta.object_id} }"
|
@@ -2,14 +2,6 @@ module Wongi::Engine
|
|
2
2
|
module NetworkParts
|
3
3
|
module Debug
|
4
4
|
def full_wme_dump
|
5
|
-
@timeline.each_with_index do |slice, index|
|
6
|
-
puts "time #{index - @timeline.length}"
|
7
|
-
slice.each do |_key, alpha|
|
8
|
-
puts "\t#{alpha.template} -> [#{alpha.wmes.map(&:to_s).join ', '}]"
|
9
|
-
end
|
10
|
-
puts ""
|
11
|
-
end
|
12
|
-
puts "time 0"
|
13
5
|
alpha_hash.each do |_key, alpha|
|
14
6
|
puts "\t#{alpha.template} -> [#{alpha.wmes.map(&:to_s).join ', '}]"
|
15
7
|
end
|
@@ -39,8 +31,8 @@ module Wongi::Engine
|
|
39
31
|
def dump_wme(wme, io)
|
40
32
|
io.puts "\tWME: #{wme.object_id} #{wme}"
|
41
33
|
wme.tokens.each { |token| io.puts "\t\tTOKEN #{token.object_id}" }
|
42
|
-
io.puts "\tGENERATING:" unless wme.
|
43
|
-
wme.
|
34
|
+
io.puts "\tGENERATING:" unless wme.generators.empty?
|
35
|
+
wme.generators.each { |token| io.puts "\t\tTOKEN #{token.object_id}" }
|
44
36
|
end
|
45
37
|
|
46
38
|
def dump_beta(beta, io)
|
data/lib/wongi-engine/network.rb
CHANGED
@@ -3,16 +3,14 @@ require 'wongi-engine/network/debug'
|
|
3
3
|
|
4
4
|
module Wongi::Engine
|
5
5
|
class Network
|
6
|
-
|
6
|
+
attr_accessor :alpha_top, :beta_top, :queries, :results, :alpha_hash
|
7
|
+
attr_reader :productions, :overlays
|
7
8
|
|
8
9
|
include NetworkParts::Collectable
|
10
|
+
private :overlays
|
11
|
+
private :alpha_hash, :alpha_hash=
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
attr_accessor :alpha_hash
|
13
|
-
attr_writer :alpha_top, :beta_top, :queries, :results
|
14
|
-
|
15
|
-
public
|
13
|
+
private :alpha_top=, :beta_top=, :queries=, :results=
|
16
14
|
|
17
15
|
def debug!
|
18
16
|
extend NetworkParts::Debug
|
@@ -42,10 +40,11 @@ module Wongi::Engine
|
|
42
40
|
end
|
43
41
|
|
44
42
|
def initialize
|
45
|
-
@
|
43
|
+
@overlays = [base_overlay]
|
44
|
+
|
46
45
|
self.alpha_top = AlphaMemory.new(Template.new(:_, :_, :_), self)
|
47
46
|
self.alpha_hash = { alpha_top.template.hash => alpha_top }
|
48
|
-
self.beta_top =
|
47
|
+
self.beta_top = RootNode.new(nil)
|
49
48
|
beta_top.rete = self
|
50
49
|
beta_top.seed
|
51
50
|
self.queries = {}
|
@@ -63,7 +62,12 @@ module Wongi::Engine
|
|
63
62
|
end
|
64
63
|
|
65
64
|
def with_overlay(&block)
|
66
|
-
|
65
|
+
child = current_overlay.new_child
|
66
|
+
add_overlay(child)
|
67
|
+
block.call(child)
|
68
|
+
ensure
|
69
|
+
remove_overlay(child)
|
70
|
+
child.dispose!
|
67
71
|
end
|
68
72
|
|
69
73
|
def alphas
|
@@ -81,17 +85,20 @@ module Wongi::Engine
|
|
81
85
|
# end
|
82
86
|
# end
|
83
87
|
|
84
|
-
def
|
85
|
-
@
|
88
|
+
def base_overlay
|
89
|
+
@base_overlay ||= Overlay.new(self)
|
86
90
|
end
|
87
91
|
|
92
|
+
# TODO: deprecate this
|
93
|
+
alias default_overlay base_overlay
|
94
|
+
|
88
95
|
# @private
|
89
|
-
def add_overlay(o)
|
96
|
+
private def add_overlay(o)
|
90
97
|
overlays << o
|
91
98
|
end
|
92
99
|
|
93
100
|
# @private
|
94
|
-
def remove_overlay(o)
|
101
|
+
private def remove_overlay(o)
|
95
102
|
overlays.delete(o) unless o == default_overlay
|
96
103
|
end
|
97
104
|
|
@@ -100,11 +107,6 @@ module Wongi::Engine
|
|
100
107
|
overlays.last
|
101
108
|
end
|
102
109
|
|
103
|
-
# @private
|
104
|
-
def overlays
|
105
|
-
@overlays ||= []
|
106
|
-
end
|
107
|
-
|
108
110
|
def assert(wme)
|
109
111
|
default_overlay.assert(wme)
|
110
112
|
end
|
@@ -115,65 +117,23 @@ module Wongi::Engine
|
|
115
117
|
|
116
118
|
# @private
|
117
119
|
def real_assert(wme)
|
118
|
-
wme = wme.import_into self unless wme.rete == self
|
119
|
-
|
120
|
-
# source = best_alpha(wme)
|
121
|
-
if (existing = find(wme.subject, wme.predicate, wme.object))
|
122
|
-
existing.manual! if wme.manual?
|
123
|
-
return
|
124
|
-
end
|
125
|
-
|
126
120
|
alphas_for(wme).each { |a| a.activate wme }
|
127
|
-
|
128
121
|
wme
|
129
122
|
end
|
130
123
|
|
131
124
|
# @private
|
132
|
-
def real_retract(wme
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
if real.generated? # still some generator tokens left
|
137
|
-
raise Error, "cannot retract automatic facts" unless real.manual?
|
138
|
-
|
139
|
-
real.manual = false
|
140
|
-
elsif options[:automatic] && real.manual?
|
141
|
-
return
|
142
|
-
end
|
143
|
-
|
144
|
-
alphas_for(real).each { |a| a.deactivate real }
|
125
|
+
def real_retract(wme)
|
126
|
+
# p real_retract: {wme:}
|
127
|
+
alphas_for(wme).each { |a| a.deactivate wme }
|
145
128
|
end
|
146
129
|
|
147
130
|
def wmes
|
148
|
-
|
131
|
+
current_overlay.select(:_, :_, :_)
|
149
132
|
end
|
150
133
|
|
151
134
|
alias statements wmes
|
152
135
|
alias facts wmes
|
153
136
|
|
154
|
-
def in_snapshot?
|
155
|
-
@in_snapshot
|
156
|
-
end
|
157
|
-
|
158
|
-
def snapshot!
|
159
|
-
@timeline.each_with_index do |slice, index|
|
160
|
-
source = if index == @timeline.size - 1
|
161
|
-
alpha_hash
|
162
|
-
else
|
163
|
-
@timeline[index + 1]
|
164
|
-
end
|
165
|
-
# puts "source = #{source}"
|
166
|
-
wmes = {}
|
167
|
-
slice.each do |key, alpha|
|
168
|
-
wmes[key] = alpha.wmes
|
169
|
-
in_snapshot {
|
170
|
-
wmes[key].dup.each(&:destroy)
|
171
|
-
}
|
172
|
-
alpha.snapshot! source[key]
|
173
|
-
end
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
137
|
def rule(name = nil, &block)
|
178
138
|
r = DSL::Rule.new(name || generate_rule_name)
|
179
139
|
r.instance_eval(&block)
|
@@ -192,7 +152,7 @@ module Wongi::Engine
|
|
192
152
|
else
|
193
153
|
case something
|
194
154
|
when Array
|
195
|
-
assert(WME.new(*something)
|
155
|
+
assert(WME.new(*something))
|
196
156
|
when WME
|
197
157
|
assert something
|
198
158
|
# when Wongi::RDF::Statement
|
@@ -223,7 +183,6 @@ module Wongi::Engine
|
|
223
183
|
|
224
184
|
def compile_alpha(condition)
|
225
185
|
template = Template.new :_, :_, :_
|
226
|
-
time = condition.time
|
227
186
|
|
228
187
|
template.subject = condition.subject unless Template.variable?(condition.subject)
|
229
188
|
template.predicate = condition.predicate unless Template.variable?(condition.predicate)
|
@@ -231,25 +190,13 @@ module Wongi::Engine
|
|
231
190
|
|
232
191
|
hash = template.hash
|
233
192
|
# puts "COMPILED CONDITION #{condition} WITH KEY #{key}"
|
234
|
-
if
|
235
|
-
return alpha_hash[hash] if alpha_hash.key?(hash)
|
236
|
-
elsif @timeline[time + 1] && @timeline[time + 1].key?(hash)
|
237
|
-
return @timeline[time + 1][hash]
|
238
|
-
end
|
193
|
+
return alpha_hash[hash] if alpha_hash.key?(hash)
|
239
194
|
|
240
195
|
alpha = AlphaMemory.new(template, self)
|
241
196
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
else
|
246
|
-
if @timeline[time + 1].nil?
|
247
|
-
# => ensure lineage from 0 to time
|
248
|
-
compile_alpha condition.class.new(condition.subject, condition.predicate, condition.object, time: time + 1)
|
249
|
-
@timeline.unshift({})
|
250
|
-
end
|
251
|
-
@timeline[time + 1][hash] = alpha
|
252
|
-
end
|
197
|
+
alpha_hash[hash] = alpha
|
198
|
+
initial_fill alpha
|
199
|
+
|
253
200
|
alpha
|
254
201
|
end
|
255
202
|
|
@@ -259,7 +206,7 @@ module Wongi::Engine
|
|
259
206
|
|
260
207
|
# TODO: pick an alpha with fewer candidates to go through
|
261
208
|
def initial_fill(alpha)
|
262
|
-
|
209
|
+
default_overlay.select(:_, :_, :_).each do |wme|
|
263
210
|
alpha.activate wme if wme =~ alpha.template
|
264
211
|
end
|
265
212
|
end
|
@@ -269,7 +216,7 @@ module Wongi::Engine
|
|
269
216
|
end
|
270
217
|
|
271
218
|
def prepare_query(name, conditions, parameters, actions = [])
|
272
|
-
query = queries[name] =
|
219
|
+
query = queries[name] = RootNode.new(nil)
|
273
220
|
query.rete = self
|
274
221
|
query.seed(parameters.to_h { |param| [param, nil] })
|
275
222
|
results[name] = build_production query, conditions, parameters, actions, true
|
@@ -299,8 +246,7 @@ module Wongi::Engine
|
|
299
246
|
else
|
300
247
|
raise Error, "Network#each expect a template or nothing at all"
|
301
248
|
end
|
302
|
-
|
303
|
-
matching = current_overlay.wmes(source).select { |wme| wme =~ template }
|
249
|
+
matching = current_overlay.select(template)
|
304
250
|
if block_given?
|
305
251
|
matching.each(&block)
|
306
252
|
else
|
@@ -309,29 +255,20 @@ module Wongi::Engine
|
|
309
255
|
end
|
310
256
|
|
311
257
|
def select(s, p, o)
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
258
|
+
matching = current_overlay.select(s, p, o)
|
259
|
+
if block_given?
|
260
|
+
matching.each(&block)
|
261
|
+
else
|
262
|
+
matching.each
|
263
|
+
end
|
317
264
|
end
|
318
265
|
|
319
266
|
def find(s, p, o)
|
320
|
-
|
321
|
-
source = best_alpha(template)
|
322
|
-
# puts "looking for #{template} among #{source.wmes.size} triples of #{source.template}"
|
323
|
-
current_overlay.wmes(source).find { |wme| wme =~ template }
|
267
|
+
current_overlay.select(s, p, o).first
|
324
268
|
end
|
325
269
|
|
326
270
|
protected
|
327
271
|
|
328
|
-
def in_snapshot
|
329
|
-
@in_snapshot = true
|
330
|
-
yield
|
331
|
-
ensure
|
332
|
-
@in_snapshot = false
|
333
|
-
end
|
334
|
-
|
335
272
|
def generate_rule_name
|
336
273
|
"rule_#{productions.length}"
|
337
274
|
end
|
@@ -386,8 +323,10 @@ module Wongi::Engine
|
|
386
323
|
# the root node should not be deleted
|
387
324
|
return unless node.parent
|
388
325
|
|
389
|
-
|
390
|
-
|
326
|
+
node.tokens.dup.each do |token|
|
327
|
+
overlays.each do |overlay|
|
328
|
+
overlay.remove_own_token(token)
|
329
|
+
end
|
391
330
|
end
|
392
331
|
|
393
332
|
node.parent.children.delete node
|