wongi-engine 0.3.8 → 0.4.0.pre.alpha1
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/.github/workflows/test.yml +2 -2
- data/.gitignore +2 -0
- data/README.md +13 -13
- 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 +177 -1
- 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 +27 -13
- 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 -141
- 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
|