wongi-engine 0.1.4 → 0.2.0
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/.hgignore +6 -0
- data/.hgtags +2 -4
- data/.travis.yml +19 -6
- data/README.md +18 -442
- data/examples/ex02.rb +3 -2
- data/examples/graphviz.rb +1 -0
- data/lib/wongi-engine/alpha_memory.rb +11 -6
- data/lib/wongi-engine/beta/assignment_node.rb +0 -15
- data/lib/wongi-engine/beta/beta_memory.rb +7 -31
- data/lib/wongi-engine/beta/beta_node.rb +25 -95
- data/lib/wongi-engine/beta/join_node.rb +14 -46
- data/lib/wongi-engine/beta/ncc_node.rb +8 -34
- data/lib/wongi-engine/beta/ncc_partner.rb +3 -19
- data/lib/wongi-engine/beta/neg_node.rb +7 -16
- data/lib/wongi-engine/beta/optional_node.rb +23 -30
- data/lib/wongi-engine/beta/or_node.rb +0 -51
- data/lib/wongi-engine/beta/production_node.rb +1 -0
- data/lib/wongi-engine/compiler.rb +115 -0
- data/lib/wongi-engine/data_overlay.rb +140 -0
- data/lib/wongi-engine/dsl/action/base.rb +11 -0
- data/lib/wongi-engine/dsl/{actions → action}/error_generator.rb +3 -14
- data/lib/wongi-engine/dsl/action/simple_action.rb +60 -0
- data/lib/wongi-engine/dsl/action/simple_collector.rb +52 -0
- data/lib/wongi-engine/dsl/action/statement_generator.rb +45 -0
- data/lib/wongi-engine/dsl/action/trace_action.rb +49 -0
- data/lib/wongi-engine/dsl/any_rule.rb +4 -21
- data/lib/wongi-engine/dsl/assuming.rb +6 -12
- data/lib/wongi-engine/dsl/builder.rb +44 -0
- data/lib/wongi-engine/dsl/clause/assign.rb +15 -0
- data/lib/wongi-engine/dsl/clause/fact.rb +71 -0
- data/lib/wongi-engine/dsl/clause/gen.rb +17 -0
- data/lib/wongi-engine/dsl/clause/generic.rb +38 -0
- data/lib/wongi-engine/dsl/{dsl_extensions.rb → generated.rb} +5 -5
- data/lib/wongi-engine/dsl/ncc_subrule.rb +15 -0
- data/lib/wongi-engine/dsl/query.rb +10 -11
- data/lib/wongi-engine/dsl/rule.rb +84 -0
- data/lib/wongi-engine/dsl.rb +102 -97
- data/lib/wongi-engine/enumerators.rb +21 -0
- data/lib/wongi-engine/error.rb +13 -2
- data/lib/wongi-engine/filter/filter_test.rb +1 -13
- data/lib/wongi-engine/graph.rb +7 -7
- data/lib/wongi-engine/network.rb +108 -181
- data/lib/wongi-engine/ruleset.rb +6 -6
- data/lib/wongi-engine/template.rb +30 -84
- data/lib/wongi-engine/token.rb +3 -34
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine/wme.rb +9 -60
- data/lib/wongi-engine.rb +3 -0
- data/spec/beta_node_spec.rb +2 -0
- data/spec/generation_spec.rb +1 -1
- data/spec/high_level_spec.rb +29 -11
- data/spec/overlay_spec.rb +22 -0
- data/spec/simple_action_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/wme_spec.rb +22 -22
- data/wongi-engine.gemspec +1 -1
- metadata +37 -17
- data/lib/wongi-engine/dsl/action.rb +0 -12
- data/lib/wongi-engine/dsl/actions/simple_action.rb +0 -62
- data/lib/wongi-engine/dsl/actions/simple_collector.rb +0 -51
- data/lib/wongi-engine/dsl/actions/statement_generator.rb +0 -67
- data/lib/wongi-engine/dsl/actions/trace_action.rb +0 -52
- data/lib/wongi-engine/dsl/dsl_builder.rb +0 -44
- data/lib/wongi-engine/dsl/extension_clause.rb +0 -36
- data/lib/wongi-engine/dsl/generation_clause.rb +0 -15
- data/lib/wongi-engine/dsl/generic_production_rule.rb +0 -82
- data/lib/wongi-engine/dsl/ncc_production_rule.rb +0 -21
- data/lib/wongi-engine/dsl/production_rule.rb +0 -4
- data/lib/wongi-engine/model_context.rb +0 -13
data/lib/wongi-engine/network.rb
CHANGED
|
@@ -7,6 +7,7 @@ module Wongi::Engine
|
|
|
7
7
|
attr_reader :alpha_top, :beta_top
|
|
8
8
|
attr_reader :queries, :results
|
|
9
9
|
attr_reader :productions
|
|
10
|
+
attr_reader :overlays
|
|
10
11
|
|
|
11
12
|
include NetworkParts::Collectable
|
|
12
13
|
|
|
@@ -46,7 +47,7 @@ module Wongi::Engine
|
|
|
46
47
|
def initialize
|
|
47
48
|
@timeline = []
|
|
48
49
|
self.alpha_top = AlphaMemory.new( Template.new( :_, :_, :_ ), self )
|
|
49
|
-
self.alpha_hash = {
|
|
50
|
+
self.alpha_hash = { alpha_top.template.hash => alpha_top }
|
|
50
51
|
self.beta_top = BetaMemory.new(nil)
|
|
51
52
|
self.beta_top.rete = self
|
|
52
53
|
self.beta_top.seed
|
|
@@ -54,7 +55,6 @@ module Wongi::Engine
|
|
|
54
55
|
self.results = {}
|
|
55
56
|
@cache = {}
|
|
56
57
|
@revns = {}
|
|
57
|
-
@contexts = {}
|
|
58
58
|
|
|
59
59
|
@productions = { }
|
|
60
60
|
|
|
@@ -67,69 +67,58 @@ module Wongi::Engine
|
|
|
67
67
|
beta_top.dump
|
|
68
68
|
end
|
|
69
69
|
|
|
70
|
+
def with_overlay(&block)
|
|
71
|
+
default_overlay.with_child(&block)
|
|
72
|
+
end
|
|
73
|
+
|
|
70
74
|
def alphas
|
|
71
75
|
alpha_hash.values
|
|
72
76
|
end
|
|
73
77
|
|
|
74
|
-
def import thing
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
# def import thing
|
|
79
|
+
# case thing
|
|
80
|
+
# when String, Numeric, TrueClass, FalseClass, NilClass, Wongi::RDF::Node
|
|
81
|
+
# thing
|
|
82
|
+
# when Symbol
|
|
83
|
+
# thing
|
|
84
|
+
# else
|
|
85
|
+
# thing
|
|
86
|
+
# end
|
|
87
|
+
# end
|
|
88
|
+
|
|
89
|
+
def default_overlay
|
|
90
|
+
@default_overlay ||= DataOverlay.new(self)
|
|
83
91
|
end
|
|
84
92
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
if @current_cascade.nil?
|
|
89
|
-
@current_cascade = @next_cascade
|
|
90
|
-
@next_cascade = nil
|
|
91
|
-
process_cascade
|
|
92
|
-
end
|
|
93
|
+
# @private
|
|
94
|
+
def add_overlay(o)
|
|
95
|
+
overlays << o
|
|
93
96
|
end
|
|
94
97
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
if @current_cascade.nil?
|
|
99
|
-
@current_cascade = @next_cascade
|
|
100
|
-
@next_cascade = nil
|
|
101
|
-
process_cascade
|
|
102
|
-
end
|
|
98
|
+
# @private
|
|
99
|
+
def remove_overlay(o)
|
|
100
|
+
overlays.delete(o) unless o == default_overlay
|
|
103
101
|
end
|
|
104
102
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
when :retract
|
|
113
|
-
real_retract wme, options
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
@current_cascade = @next_cascade
|
|
117
|
-
@next_cascade = nil
|
|
118
|
-
iterations += 1
|
|
119
|
-
end
|
|
103
|
+
# @private
|
|
104
|
+
def overlays
|
|
105
|
+
@overlays ||= []
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def assert(wme)
|
|
109
|
+
default_overlay.assert(wme)
|
|
120
110
|
end
|
|
121
111
|
|
|
122
|
-
def
|
|
112
|
+
def retract(wme, options = {})
|
|
113
|
+
default_overlay.retract(wme, options)
|
|
114
|
+
end
|
|
123
115
|
|
|
116
|
+
# @private
|
|
117
|
+
def real_assert( wme )
|
|
124
118
|
unless wme.rete == self
|
|
125
119
|
wme = wme.import_into self
|
|
126
120
|
end
|
|
127
121
|
|
|
128
|
-
if @current_context
|
|
129
|
-
@current_context.asserted_wmes << wme
|
|
130
|
-
wme.context = @current_context
|
|
131
|
-
end
|
|
132
|
-
|
|
133
122
|
if existing = @cache[wme]
|
|
134
123
|
existing.manual! if wme.manual?
|
|
135
124
|
return
|
|
@@ -143,6 +132,28 @@ module Wongi::Engine
|
|
|
143
132
|
wme
|
|
144
133
|
end
|
|
145
134
|
|
|
135
|
+
# @private
|
|
136
|
+
def real_retract wme, options
|
|
137
|
+
real = @cache[wme]
|
|
138
|
+
|
|
139
|
+
return if real.nil?
|
|
140
|
+
if real.generated? # still some generator tokens left
|
|
141
|
+
if real.manual?
|
|
142
|
+
real.manual = false
|
|
143
|
+
else
|
|
144
|
+
raise Error, "cannot retract automatic facts"
|
|
145
|
+
end
|
|
146
|
+
else
|
|
147
|
+
if options[:automatic] && real.manual? # auto-retracting a fact that has been added manually
|
|
148
|
+
return
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
@cache.delete(real)
|
|
153
|
+
|
|
154
|
+
alphas_for( real ).each { |a| a.deactivate real }
|
|
155
|
+
end
|
|
156
|
+
|
|
146
157
|
def wmes
|
|
147
158
|
alpha_top.wmes
|
|
148
159
|
end
|
|
@@ -173,82 +184,52 @@ module Wongi::Engine
|
|
|
173
184
|
end
|
|
174
185
|
|
|
175
186
|
def rule name = nil, &block
|
|
176
|
-
r =
|
|
187
|
+
r = DSL::Rule.new( name || generate_rule_name )
|
|
177
188
|
r.instance_eval &block
|
|
178
189
|
self << r
|
|
179
190
|
end
|
|
180
191
|
|
|
181
192
|
def query name, &block
|
|
182
|
-
q = Query.new name
|
|
193
|
+
q = DSL::Query.new name
|
|
183
194
|
q.instance_eval &block
|
|
184
195
|
self << q
|
|
185
196
|
end
|
|
186
197
|
|
|
187
198
|
def << something
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
199
|
+
if something.respond_to?( :install )
|
|
200
|
+
something.install( self )
|
|
201
|
+
else
|
|
202
|
+
case something
|
|
203
|
+
when Array
|
|
191
204
|
assert WME.new( *something )
|
|
205
|
+
when WME
|
|
206
|
+
assert something
|
|
207
|
+
# when Wongi::RDF::Statement
|
|
208
|
+
# assert WME.new( something.subject, something.predicate, something.object, self )
|
|
209
|
+
#when Wongi::RDF::Document
|
|
210
|
+
# something.statements.each do |st|
|
|
211
|
+
# assert WME.new( st.subject, st.predicate, st.object, self )
|
|
212
|
+
# end
|
|
213
|
+
when Network
|
|
214
|
+
something.wmes.each { |wme| assert( wme ) }
|
|
192
215
|
else
|
|
193
|
-
raise "
|
|
194
|
-
end
|
|
195
|
-
when ProductionRule
|
|
196
|
-
derived = something.import_into self
|
|
197
|
-
production = add_production derived.conditions, derived.actions
|
|
198
|
-
if something.name
|
|
199
|
-
productions[ something.name ] = production
|
|
216
|
+
raise Error, "I don't know how to accept a #{something.class}"
|
|
200
217
|
end
|
|
201
|
-
production
|
|
202
|
-
when Query
|
|
203
|
-
derived = something.import_into self
|
|
204
|
-
prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
|
|
205
|
-
when Ruleset
|
|
206
|
-
something.install self
|
|
207
|
-
when WME
|
|
208
|
-
assert something
|
|
209
|
-
when Wongi::RDF::Statement
|
|
210
|
-
assert WME.new( something.subject, something.predicate, something.object, self )
|
|
211
|
-
#when Wongi::RDF::Document
|
|
212
|
-
# something.statements.each do |st|
|
|
213
|
-
# assert WME.new( st.subject, st.predicate, st.object, self )
|
|
214
|
-
# end
|
|
215
|
-
when Network
|
|
216
|
-
something.each do |st|
|
|
217
|
-
assert st.import_into( self )
|
|
218
|
-
end
|
|
219
|
-
else
|
|
220
|
-
raise "I don't know how to accept a #{something.class}"
|
|
221
218
|
end
|
|
222
219
|
end
|
|
223
220
|
|
|
224
|
-
def
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
real = @cache[wme]
|
|
231
|
-
|
|
232
|
-
return if real.nil?
|
|
233
|
-
if real.generated? # still some generator tokens left
|
|
234
|
-
if real.manual?
|
|
235
|
-
real.manual = false
|
|
236
|
-
else
|
|
237
|
-
raise "cannot retract automatic facts"
|
|
238
|
-
end
|
|
239
|
-
else
|
|
240
|
-
if options[:automatic] && real.manual? # auto-retracting a fact that has been added manually
|
|
241
|
-
return
|
|
242
|
-
end
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
if @current_context
|
|
246
|
-
@current_context.retracted_wmes << wme
|
|
221
|
+
def install_rule( rule )
|
|
222
|
+
derived = rule.import_into self
|
|
223
|
+
production = build_production beta_top, derived.conditions, [], derived.actions, false
|
|
224
|
+
if rule.name
|
|
225
|
+
productions[ rule.name ] = production
|
|
247
226
|
end
|
|
227
|
+
production
|
|
228
|
+
end
|
|
248
229
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
230
|
+
def install_query( query )
|
|
231
|
+
derived = query.import_into self
|
|
232
|
+
prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
|
|
252
233
|
end
|
|
253
234
|
|
|
254
235
|
def compile_alpha condition
|
|
@@ -284,23 +265,16 @@ module Wongi::Engine
|
|
|
284
265
|
end
|
|
285
266
|
|
|
286
267
|
def cache s, p, o
|
|
287
|
-
compile_alpha Template.new(s, p, o)
|
|
268
|
+
compile_alpha Template.new(s, p, o)
|
|
288
269
|
end
|
|
289
270
|
|
|
271
|
+
# TODO: pick an alpha with fewer candidates to go through
|
|
290
272
|
def initial_fill alpha
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
# puts "more efficient by #{alpha_top.wmes.size - source.wmes.size}" unless source ==
|
|
294
|
-
# alpha_top
|
|
295
|
-
source.wmes.each do |wme|
|
|
296
|
-
alpha.activate wme if wme =~ tpl
|
|
273
|
+
alpha_top.wmes.each do |wme|
|
|
274
|
+
alpha.activate wme if wme =~ alpha.template
|
|
297
275
|
end
|
|
298
276
|
end
|
|
299
277
|
|
|
300
|
-
def add_production conditions, actions = []
|
|
301
|
-
real_add_production self.beta_top, conditions, [], actions, false
|
|
302
|
-
end
|
|
303
|
-
|
|
304
278
|
def remove_production pnode
|
|
305
279
|
delete_node_with_ancestors pnode
|
|
306
280
|
end
|
|
@@ -308,15 +282,13 @@ module Wongi::Engine
|
|
|
308
282
|
def prepare_query name, conditions, parameters, actions = []
|
|
309
283
|
query = self.queries[ name ] = BetaMemory.new( nil )
|
|
310
284
|
query.rete = self
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
query.seed transformed
|
|
314
|
-
self.results[ name ] = real_add_production query, conditions, parameters, actions, true
|
|
285
|
+
query.seed(Hash[parameters.map{ |param| [param, nil]}])
|
|
286
|
+
self.results[ name ] = build_production query, conditions, parameters, actions, true
|
|
315
287
|
end
|
|
316
288
|
|
|
317
289
|
def execute name, valuations
|
|
318
290
|
beta = self.queries[name]
|
|
319
|
-
raise "Undefined query #{name}; known queries are #{queries.keys}" unless beta
|
|
291
|
+
raise Error, "Undefined query #{name}; known queries are #{queries.keys}" unless beta
|
|
320
292
|
beta.subst valuations
|
|
321
293
|
end
|
|
322
294
|
|
|
@@ -324,25 +296,6 @@ module Wongi::Engine
|
|
|
324
296
|
"<Rete>"
|
|
325
297
|
end
|
|
326
298
|
|
|
327
|
-
def context= name
|
|
328
|
-
if name && !@contexts.has_key?(name)
|
|
329
|
-
@current_context = (@contexts[name] ||= ModelContext.new name)
|
|
330
|
-
end
|
|
331
|
-
end
|
|
332
|
-
|
|
333
|
-
# TODO: contexts are probably broken with the new improved handling of manual & generated
|
|
334
|
-
def retract_context name
|
|
335
|
-
return unless @contexts.has_key?(name)
|
|
336
|
-
|
|
337
|
-
if @current_context && @current_context.name == name
|
|
338
|
-
@current_context = nil
|
|
339
|
-
end
|
|
340
|
-
ctx = @contexts[name]
|
|
341
|
-
ctx.asserted_wmes.select { |wme| wme.generating_tokens.empty? }.each { |wme| retract(wme, true) }
|
|
342
|
-
ctx.retracted_wmes.each { |wme| assert(wme) }
|
|
343
|
-
@contexts.delete name
|
|
344
|
-
end
|
|
345
|
-
|
|
346
299
|
def exists? wme
|
|
347
300
|
@cache[ wme ]
|
|
348
301
|
end
|
|
@@ -350,7 +303,7 @@ module Wongi::Engine
|
|
|
350
303
|
def each *args
|
|
351
304
|
return unless block_given?
|
|
352
305
|
unless args.length == 0 || args.length == 3
|
|
353
|
-
raise "
|
|
306
|
+
raise Error, "Network#each expects a pattern or nothing at all"
|
|
354
307
|
end
|
|
355
308
|
s, p, o = if args.empty?
|
|
356
309
|
[:_, :_, :_]
|
|
@@ -365,7 +318,7 @@ module Wongi::Engine
|
|
|
365
318
|
end
|
|
366
319
|
|
|
367
320
|
def select s, p, o
|
|
368
|
-
template = Template.new(s, p, o)
|
|
321
|
+
template = Template.new(s, p, o)
|
|
369
322
|
matching = alpha_top.wmes.select { |wme| wme =~ template }
|
|
370
323
|
if block_given?
|
|
371
324
|
matching.each { |st| yield st.subject, st.predicate, st.object }
|
|
@@ -374,7 +327,7 @@ module Wongi::Engine
|
|
|
374
327
|
end
|
|
375
328
|
|
|
376
329
|
def find s, p, o
|
|
377
|
-
template = Template.new(s, p, o)
|
|
330
|
+
template = Template.new(s, p, o)
|
|
378
331
|
source = best_alpha(template)
|
|
379
332
|
# puts "looking for #{template} among #{source.wmes.size} triples of #{source.template}"
|
|
380
333
|
source.wmes.detect { |wme| wme =~ template }
|
|
@@ -382,6 +335,7 @@ module Wongi::Engine
|
|
|
382
335
|
|
|
383
336
|
protected
|
|
384
337
|
|
|
338
|
+
|
|
385
339
|
def in_snapshot
|
|
386
340
|
@in_snapshot = true
|
|
387
341
|
yield
|
|
@@ -404,7 +358,7 @@ module Wongi::Engine
|
|
|
404
358
|
lookup(:_, p, :_),
|
|
405
359
|
lookup(:_, :_, o),
|
|
406
360
|
lookup(:_, :_, :_),
|
|
407
|
-
].compact
|
|
361
|
+
].compact!.tap(&:uniq!)
|
|
408
362
|
end
|
|
409
363
|
|
|
410
364
|
def lookup s, p, o
|
|
@@ -414,52 +368,25 @@ module Wongi::Engine
|
|
|
414
368
|
end
|
|
415
369
|
|
|
416
370
|
def alpha_activate alpha, wme
|
|
417
|
-
alpha.activate(wme)
|
|
418
|
-
end
|
|
419
|
-
|
|
420
|
-
def more_generic_alpha template
|
|
421
|
-
return alpha_top # OPTIMISE => temporary; may use later or not use at all
|
|
422
|
-
return alpha_top if template.root?
|
|
423
|
-
more_generic_templates(template).reduce alpha_top do |best, template|
|
|
424
|
-
alpha = alpha_hash[template.hash]
|
|
425
|
-
if alpha && alpha.wmes.size < best.wmes.size
|
|
426
|
-
alpha
|
|
427
|
-
else
|
|
428
|
-
best
|
|
429
|
-
end
|
|
430
|
-
end
|
|
431
|
-
end
|
|
432
|
-
|
|
433
|
-
def more_generic_templates template
|
|
434
|
-
set = []
|
|
435
|
-
set << template.with_subject( :_ ) unless template.subject == :_
|
|
436
|
-
set << template.with_predicate( :_ ) unless template.predicate == :_
|
|
437
|
-
set << template.with_object( :_ ) unless template.object == :_
|
|
438
|
-
set.select { |item| not item.root? }
|
|
371
|
+
alpha.activate(wme)
|
|
439
372
|
end
|
|
440
373
|
|
|
441
374
|
def best_alpha template
|
|
442
|
-
|
|
443
|
-
template =~ alpha.template
|
|
444
|
-
end
|
|
445
|
-
result = candidates.inject do |best, alpha|
|
|
446
|
-
if best.nil?
|
|
447
|
-
alpha
|
|
448
|
-
elsif alpha.wmes.to_a.length < best.wmes.to_a.length
|
|
375
|
+
alpha_hash.inject(nil) do |best, (_, alpha)|
|
|
376
|
+
if template =~ alpha.template && (best.nil? || alpha.size < best.size)
|
|
449
377
|
alpha
|
|
450
378
|
else
|
|
451
379
|
best
|
|
452
380
|
end
|
|
453
381
|
end
|
|
454
|
-
result
|
|
455
382
|
end
|
|
456
383
|
|
|
457
|
-
def
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
384
|
+
def build_production root, conditions, parameters, actions, alpha_deaf
|
|
385
|
+
compiler = Compiler.new(self, root, conditions, parameters, alpha_deaf)
|
|
386
|
+
ProductionNode.new(compiler.compile, actions).tap do |production|
|
|
387
|
+
production.compilation_context = compiler
|
|
388
|
+
production.refresh
|
|
389
|
+
end
|
|
463
390
|
end
|
|
464
391
|
|
|
465
392
|
def delete_node_with_ancestors node
|
data/lib/wongi-engine/ruleset.rb
CHANGED
|
@@ -5,12 +5,12 @@ module Wongi
|
|
|
5
5
|
class << self
|
|
6
6
|
|
|
7
7
|
def [] name
|
|
8
|
-
raise "undefined ruleset #{name}" unless rulesets.has_key?( name )
|
|
8
|
+
raise Error, "undefined ruleset #{name}" unless rulesets.has_key?( name )
|
|
9
9
|
rulesets[ name ]
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def register name, ruleset
|
|
13
|
-
raise "ruleset #{name} already exists" if rulesets.has_key?( name )
|
|
13
|
+
raise Error, "ruleset #{name} already exists" if rulesets.has_key?( name )
|
|
14
14
|
rulesets[ name ] = ruleset
|
|
15
15
|
end
|
|
16
16
|
|
|
@@ -36,8 +36,8 @@ module Wongi
|
|
|
36
36
|
def install rete
|
|
37
37
|
# puts "Installing ruleset #{name}"
|
|
38
38
|
@rules.each { |rule| rete << rule }
|
|
39
|
-
rescue
|
|
40
|
-
e1 =
|
|
39
|
+
rescue StandardError => e
|
|
40
|
+
e1 = Error.new "error installing ruleset '#{name||'<unnamed>'}': #{e}"
|
|
41
41
|
e1.set_backtrace e.backtrace
|
|
42
42
|
raise e1
|
|
43
43
|
end
|
|
@@ -56,14 +56,14 @@ module Wongi
|
|
|
56
56
|
# end
|
|
57
57
|
|
|
58
58
|
def rule name, &definition
|
|
59
|
-
r =
|
|
59
|
+
r = DSL::Rule.new name
|
|
60
60
|
r.instance_eval &definition
|
|
61
61
|
@rules << r
|
|
62
62
|
r
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def query name, &definition
|
|
66
|
-
r = Query.new name
|
|
66
|
+
r = DSL::Query.new name
|
|
67
67
|
r.instance_eval &definition
|
|
68
68
|
@rules << r
|
|
69
69
|
r
|
|
@@ -1,60 +1,36 @@
|
|
|
1
1
|
module Wongi::Engine
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
include CoreExt
|
|
6
|
-
|
|
7
|
-
attr_reader :unsafe
|
|
8
|
-
attr_predicate debug: false
|
|
3
|
+
Template = Struct.new( :subject, :predicate, :object ) do
|
|
9
4
|
|
|
10
5
|
def self.variable? thing
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def initialize s, p, o, options = { }
|
|
15
|
-
time = options[:time] || 0
|
|
16
|
-
unsafe = options[:unsafe] || false
|
|
17
|
-
debug! if options[:debug]
|
|
18
|
-
raise "Cannot work with continuous time" unless time.integer?
|
|
19
|
-
raise "Cannot look into the future" if time > 0
|
|
20
|
-
super( s, p, o, time )
|
|
21
|
-
@filters = []
|
|
22
|
-
@unsafe = unsafe
|
|
6
|
+
return false unless thing.is_a?(Symbol)
|
|
7
|
+
thing[0] >= 'A' && thing[0] <= 'Z'
|
|
23
8
|
end
|
|
24
9
|
|
|
25
|
-
|
|
26
|
-
copy = self.class.new r.import( subject ), r.import( predicate ), r.import( object ), time: time, unsafe: unsafe, debug: debug?
|
|
27
|
-
@filters.each { |f| copy.filters << f }
|
|
28
|
-
copy
|
|
29
|
-
end
|
|
10
|
+
# TODO: reintroduce Network#import when bringing back RDF support
|
|
30
11
|
|
|
31
12
|
def root?
|
|
32
13
|
subject == :_ && predicate == :_ && object == :_
|
|
33
14
|
end
|
|
34
15
|
|
|
35
16
|
def variables
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
17
|
+
[].tap do |a|
|
|
18
|
+
a << subject if Template.variable?( subject )
|
|
19
|
+
a << predicate if Template.variable?( predicate )
|
|
20
|
+
a << object if Template.variable?( object )
|
|
21
|
+
end
|
|
41
22
|
end
|
|
42
23
|
|
|
43
24
|
def hash
|
|
44
|
-
@hash ||=
|
|
25
|
+
@hash ||= [subject.hash, predicate.hash, object.hash].hash
|
|
45
26
|
end
|
|
46
27
|
|
|
47
28
|
def self.hash_for *args
|
|
48
29
|
args.map( &:hash ).hash
|
|
49
30
|
end
|
|
50
31
|
|
|
51
|
-
def === wme
|
|
52
|
-
wme =~ self if WME === wme
|
|
53
|
-
end
|
|
54
|
-
|
|
55
32
|
def == other
|
|
56
|
-
|
|
57
|
-
subject == other.subject && predicate == other.predicate && object == other.object
|
|
33
|
+
other.is_a?(Template) && subject == other.subject && predicate == other.predicate && object == other.object
|
|
58
34
|
end
|
|
59
35
|
|
|
60
36
|
def =~ template
|
|
@@ -64,66 +40,36 @@ module Wongi::Engine
|
|
|
64
40
|
( template.predicate == :_ || template.predicate == predicate ) &&
|
|
65
41
|
( template.object == :_ || template.object == object )
|
|
66
42
|
else
|
|
67
|
-
raise "
|
|
43
|
+
raise Error, "templates can only match other templates"
|
|
68
44
|
end
|
|
69
45
|
end
|
|
70
46
|
|
|
71
|
-
|
|
72
|
-
def compile context
|
|
73
|
-
tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
|
|
74
|
-
alpha = context.rete.compile_alpha( self )
|
|
75
|
-
context.node = context.node.beta_memory.join_node( alpha, tests, assignment, context.alpha_deaf )
|
|
76
|
-
context.node.context = context
|
|
77
|
-
context.node.debug = debug?
|
|
78
|
-
context.earlier << self
|
|
79
|
-
context
|
|
80
|
-
end
|
|
81
|
-
|
|
82
47
|
def inspect
|
|
83
|
-
"
|
|
48
|
+
"<~#{subject.inspect} #{predicate.inspect} #{object.inspect}>"
|
|
84
49
|
end
|
|
85
50
|
|
|
86
51
|
def to_s
|
|
87
52
|
inspect
|
|
88
53
|
end
|
|
89
54
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
context.node.debug = debug?
|
|
108
|
-
context.earlier << self
|
|
109
|
-
context
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
class OptionalTemplate < Template
|
|
114
|
-
|
|
115
|
-
def compile context
|
|
116
|
-
tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
|
|
117
|
-
alpha = context.rete.compile_alpha( self )
|
|
118
|
-
context.node = context.node.beta_memory.optional_node( alpha, tests, assignment, context.alpha_deaf )
|
|
119
|
-
context.node.context = context
|
|
120
|
-
context.node.debug = debug?
|
|
121
|
-
context.earlier << self
|
|
122
|
-
context
|
|
55
|
+
def resolve!(token)
|
|
56
|
+
s = if Template.variable?(subject)
|
|
57
|
+
token[subject].tap { |x| raise DefinitionError, "unbound variable #{subject} in token #{token}" unless x}
|
|
58
|
+
else
|
|
59
|
+
subject
|
|
60
|
+
end
|
|
61
|
+
p = if Template.variable?(predicate)
|
|
62
|
+
token[predicate].tap { |x| raise DefinitionError, "unbound variable #{predicate} in token #{token}" unless x}
|
|
63
|
+
else
|
|
64
|
+
predicate
|
|
65
|
+
end
|
|
66
|
+
o = if Template.variable?(object)
|
|
67
|
+
token[object].tap { |x| raise DefinitionError, "unbound variable #{object} in token #{token}" unless x}
|
|
68
|
+
else
|
|
69
|
+
object
|
|
70
|
+
end
|
|
71
|
+
[s, p, o]
|
|
123
72
|
end
|
|
124
73
|
|
|
125
74
|
end
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
75
|
end
|