wongi-engine 0.0.14 → 0.0.16

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.
@@ -1,443 +1,442 @@
1
- require 'wongi-engine/network/collectable'
2
- require 'wongi-engine/network/debug'
3
-
4
- module Wongi::Engine
5
- class Network
6
-
7
- attr_reader :alpha_top, :beta_top
8
- attr_reader :queries, :results
9
- attr_reader :productions
10
-
11
- include NetworkParts::Collectable
12
-
13
- protected
14
- attr_accessor :alpha_hash
15
- attr_writer :alpha_top, :beta_top
16
- attr_writer :queries, :results
17
-
18
- public
19
-
20
- def debug!
21
- extend NetworkParts::Debug
22
- end
23
-
24
- def rdf!
25
- if ! defined? Wongi::RDF::DocumentSupport
26
- begin
27
- require 'wongi-rdf'
28
- rescue LoadError => e
29
- raise "'wongi-rdf' is required for RDF support"
30
- end
31
- end
32
-
33
- extend Wongi::RDF::DocumentSupport
34
- class << self
35
- def statements
36
- alpha_top.wmes
37
- end
38
- end
39
-
40
- @namespaces = { }
41
- @blank_counter = 1
42
- @ns_counter = 0
43
- @used_blanks = { }
44
- end
45
-
46
- def initialize
47
- @timeline = []
48
- self.alpha_top = AlphaMemory.new( Template.new( :_, :_, :_ ), self )
49
- self.alpha_hash = { Template.hash_for( :_, :_, :_ ) => self.alpha_top }
50
- self.beta_top = BetaMemory.new(nil)
51
- self.beta_top.rete = self
52
- self.beta_top.seed
53
- self.queries = {}
54
- self.results = {}
55
- @cache = {}
56
- @revns = {}
57
- @contexts = {}
58
-
59
- @productions = { }
60
-
61
- @collectors = {}
62
- @collectors[:error] = []
63
-
64
- end
65
-
66
- def dump
67
- beta_top.dump
68
- end
69
-
70
- def alphas
71
- alpha_hash.values
72
- end
73
-
74
- def import thing
75
- case thing
76
- when String, Numeric, TrueClass, FalseClass, NilClass, Wongi::RDF::Node
77
- thing
78
- when Symbol
79
- thing
80
- else
81
- thing
82
- end
83
- end
84
-
85
- def assert wme
86
-
87
- unless wme.rete == self
88
- wme = wme.import_into self
89
- end
90
-
91
- if @current_context
92
- @current_context.asserted_wmes << wme
93
- wme.context = @current_context
94
- end
95
-
96
- return if @cache.has_key?(wme)
97
-
98
- # puts "ASSERTING #{wme}"
99
- @cache[wme] = wme
100
-
101
- s = wme.subject
102
- p = wme.predicate
103
- o = wme.object
104
-
105
- alpha_activate(lookup( s, p, o), wme)
106
- alpha_activate(lookup( s, p, :_), wme)
107
- alpha_activate(lookup( s, :_, o), wme)
108
- alpha_activate(lookup(:_, p, o), wme)
109
- alpha_activate(lookup( s, :_, :_), wme)
110
- alpha_activate(lookup(:_, p, :_), wme)
111
- alpha_activate(lookup(:_, :_, o), wme)
112
- alpha_activate(lookup(:_, :_, :_), wme)
113
-
114
- wme
115
- end
116
-
117
- def wmes
118
- alpha_top.wmes
119
- end
120
- alias_method :statements, :wmes
121
- alias_method :facts, :wmes
122
-
123
- def in_snapshot?
124
- @in_snapshot
125
- end
126
-
127
- def snapshot!
128
- @timeline.each_with_index do |slice, index|
129
- source = if index == @timeline.size - 1
130
- alpha_hash
131
- else
132
- @timeline[index+1]
133
- end
134
- # puts "source = #{source}"
135
- wmes = {}
136
- slice.each { |key, alpha| wmes[key] = alpha.wmes }
137
- slice.each do |key, alpha|
138
- in_snapshot {
139
- wmes[key].dup.each { |wme| wme.destroy }
140
- }
141
- alpha.snapshot! source[key]
142
- end
143
- end
144
- end
145
-
146
- def rule name = nil, &block
147
- r = ProductionRule.new( name || generate_rule_name )
148
- r.instance_eval &block
149
- self << r
150
- end
151
-
152
- def query name, &block
153
- q = Query.new name
154
- q.instance_eval &block
155
- self << q
156
- end
157
-
158
- def << something
159
- case something
160
- when Array
161
- if something.length == 3
162
- assert WME.new( *something )
163
- else
164
- raise "Arrays must have 3 elements"
165
- end
166
- when ProductionRule
167
- derived = something.import_into self
168
- production = add_production derived.conditions, derived.actions
169
- if something.name
170
- productions[ something.name ] = production
171
- end
172
- when Query
173
- derived = something.import_into self
174
- prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
175
- when Ruleset
176
- something.install self
177
- when WME
178
- assert something
179
- when Wongi::RDF::Statement
180
- assert WME.new( something.subject, something.predicate, something.object, self )
181
- #when Wongi::RDF::Document
182
- # something.statements.each do |st|
183
- # assert WME.new( st.subject, st.predicate, st.object, self )
184
- # end
185
- when Network
186
- something.each do |st|
187
- assert st.import_into( self )
188
- end
189
- else
190
- raise "I don't know how to accept a #{something.class}"
191
- end
192
- end
193
-
194
- def retract wme, is_real = false
195
-
196
- if wme.is_a? Array
197
- return retract( WME.new(*wme), is_real )
198
- end
199
-
200
- if ! is_real
201
- if @current_context
202
- @current_context.retracted_wmes << wme
203
- end
204
- end
205
-
206
- real = if is_real
207
- wme
208
- else
209
- #find(wme.subject, wme.predicate, wme.object)
210
- @cache[wme]
211
- end
212
-
213
- return false if real.nil?
214
- @cache.delete(real)
215
- raise "Cannot retract inferred statements" unless real.manual?
216
-
217
- real.destroy
218
-
219
- true
220
-
221
- end
222
-
223
- def compile_alpha condition
224
- template = Template.new :_, :_, :_
225
- time = condition.time
226
-
227
- template.subject = condition.subject unless Template.variable?( condition.subject )
228
- template.predicate = condition.predicate unless Template.variable?( condition.predicate )
229
- template.object = condition.object unless Template.variable?( condition.object )
230
-
231
- hash = template.hash
232
- # puts "COMPILED CONDITION #{condition} WITH KEY #{key}"
233
- if time == 0
234
- return self.alpha_hash[ hash ] if self.alpha_hash.has_key?( hash )
235
- else
236
- return @timeline[time+1][ hash ] if @timeline[time+1] && @timeline[time+1].has_key?( hash )
237
- end
238
-
239
- alpha = AlphaMemory.new( template, self )
240
-
241
- if time == 0
242
- self.alpha_hash[ hash ] = alpha
243
- initial_fill alpha
244
- else
245
- if @timeline[time+1].nil?
246
- # => ensure lineage from 0 to time
247
- compile_alpha condition.class.new(condition.subject, condition.predicate, condition.object, time: time + 1)
248
- @timeline.unshift Hash.new
249
- end
250
- @timeline[time+1][ hash ] = alpha
251
- end
252
- alpha
253
- end
254
-
255
- def cache s, p, o
256
- compile_alpha Template.new(s, p, o).import_into( self )
257
- end
258
-
259
- def initial_fill alpha
260
- tpl = alpha.template
261
- source = more_generic_alpha(tpl)
262
- # puts "more efficient by #{alpha_top.wmes.size - source.wmes.size}" unless source ==
263
- # alpha_top
264
- source.wmes.each do |wme|
265
- alpha.activate wme if wme =~ tpl
266
- end
267
- end
268
-
269
- def add_production conditions, actions = []
270
- real_add_production self.beta_top, conditions, [], actions, false
271
- end
272
-
273
- def remove_production pnode
274
- delete_node_with_ancestors pnode
275
- end
276
-
277
- def prepare_query name, conditions, parameters, actions = []
278
- query = self.queries[ name ] = BetaMemory.new( nil )
279
- query.rete = self
280
- transformed = {}
281
- parameters.each { |param| transformed[param] = nil }
282
- query.seed transformed
283
- self.results[ name ] = real_add_production query, conditions, parameters, actions, true
284
- end
285
-
286
- def execute name, valuations
287
- beta = self.queries[name]
288
- raise "Undefined query #{name}; known queries are #{queries.keys}" unless beta
289
- beta.subst valuations
290
- end
291
-
292
- def inspect
293
- "<Rete>"
294
- end
295
-
296
- def context= name
297
- if name && !@contexts.has_key?(name)
298
- @current_context = (@contexts[name] ||= ModelContext.new name)
299
- end
300
- end
301
-
302
- def retract_context name
303
- return unless @contexts.has_key?(name)
304
-
305
- if @current_context && @current_context.name == name
306
- @current_context = nil
307
- end
308
- ctx = @contexts[name]
309
- ctx.asserted_wmes.select { |wme| wme.generating_tokens.empty? }.each { |wme| retract(wme, true) }
310
- ctx.retracted_wmes.each { |wme| assert(wme) }
311
- @contexts.delete name
312
- end
313
-
314
- def exists? wme
315
- @cache[ wme ]
316
- end
317
-
318
- def each *args
319
- return unless block_given?
320
- unless args.length == 0 || args.length == 3
321
- raise "Document#each expects a pattern or nothing at all"
322
- end
323
- s, p, o = if args.empty?
324
- [:_, :_, :_]
325
- else
326
- args
327
- end
328
- no_check = s == :_ && p == :_ && o == :_
329
- template = Template.new(s, p, o).import_into self
330
- alpha_top.wmes.each do |wme|
331
- yield wme if (no_check || wme =~ template)
332
- end
333
- end
334
-
335
- def select s, p, o
336
- template = Template.new(s, p, o).import_into self
337
- matching = alpha_top.wmes.select { |wme| wme =~ template }
338
- if block_given?
339
- matching.each { |st| yield st.subject, st.predicate, st.object }
340
- end
341
- matching
342
- end
343
-
344
- def find s, p, o
345
- template = Template.new(s, p, o).import_into self
346
- source = best_alpha(template)
347
- # puts "looking for #{template} among #{source.wmes.size} triples of #{source.template}"
348
- source.wmes.detect { |wme| wme =~ template }
349
- end
350
-
351
- protected
352
-
353
- def in_snapshot
354
- @in_snapshot = true
355
- yield
356
- ensure
357
- @in_snapshot = false
358
- end
359
-
360
- def generate_rule_name
361
- "rule_#{productions.length}"
362
- end
363
-
364
- def lookup s, p, o
365
- key = Template.hash_for(s, p, o)
366
- # puts "Lookup for #{key}"
367
- self.alpha_hash[ key ]
368
- end
369
-
370
- def alpha_activate alpha, wme
371
- alpha.activate(wme) if alpha
372
- end
373
-
374
- def more_generic_alpha template
375
- return alpha_top # OPTIMISE => temporary; may use later or not use at all
376
- return alpha_top if template.root?
377
- more_generic_templates(template).reduce alpha_top do |best, template|
378
- alpha = alpha_hash[template.hash]
379
- if alpha && alpha.wmes.size < best.wmes.size
380
- alpha
381
- else
382
- best
383
- end
384
- end
385
- end
386
-
387
- def more_generic_templates template
388
- set = []
389
- set << template.with_subject( :_ ) unless template.subject == :_
390
- set << template.with_predicate( :_ ) unless template.predicate == :_
391
- set << template.with_object( :_ ) unless template.object == :_
392
- set.select { |item| not item.root? }
393
- end
394
-
395
- def best_alpha template
396
- candidates = alpha_hash.values.select do |alpha|
397
- template =~ alpha.template
398
- end
399
- result = candidates.inject do |best, alpha|
400
- if best.nil?
401
- alpha
402
- elsif alpha.wmes.to_a.length < best.wmes.to_a.length
403
- alpha
404
- else
405
- best
406
- end
407
- end
408
- puts "Best alpha for #{template} is #{result}"
409
- result
410
- end
411
-
412
- def real_add_production root, conditions, parameters, actions, alpha_deaf
413
- beta = root.network conditions, [], parameters, alpha_deaf
414
-
415
- production = ProductionNode.new( beta, actions )
416
- production.refresh
417
- production
418
- end
419
-
420
- def delete_node_with_ancestors node
421
-
422
- if node.kind_of?( NccNode )
423
- delete_node_with_ancestors node.partner
424
- end
425
-
426
- if [BetaMemory, NegNode, NccNode, NccPartner].any? { | klass| node.kind_of? klass }
427
- while node.tokens.first
428
- node.tokens.first.delete
429
- end
430
- end
431
-
432
- if node.parent
433
- node.parent.children.delete node
434
- if node.parent.children.empty?
435
- delete_node_with_ancestors(node.parent)
436
- end
437
- end
438
-
439
- end
440
-
441
- end
442
-
443
- end
1
+ require 'wongi-engine/network/collectable'
2
+ require 'wongi-engine/network/debug'
3
+
4
+ module Wongi::Engine
5
+ class Network
6
+
7
+ attr_reader :alpha_top, :beta_top
8
+ attr_reader :queries, :results
9
+ attr_reader :productions
10
+
11
+ include NetworkParts::Collectable
12
+
13
+ protected
14
+ attr_accessor :alpha_hash
15
+ attr_writer :alpha_top, :beta_top
16
+ attr_writer :queries, :results
17
+
18
+ public
19
+
20
+ def debug!
21
+ extend NetworkParts::Debug
22
+ end
23
+
24
+ def rdf!
25
+ if ! defined? Wongi::RDF::DocumentSupport
26
+ begin
27
+ require 'wongi-rdf'
28
+ rescue LoadError => e
29
+ raise "'wongi-rdf' is required for RDF support"
30
+ end
31
+ end
32
+
33
+ extend Wongi::RDF::DocumentSupport
34
+ class << self
35
+ def statements
36
+ alpha_top.wmes
37
+ end
38
+ end
39
+
40
+ @namespaces = { }
41
+ @blank_counter = 1
42
+ @ns_counter = 0
43
+ @used_blanks = { }
44
+ end
45
+
46
+ def initialize
47
+ @timeline = []
48
+ self.alpha_top = AlphaMemory.new( Template.new( :_, :_, :_ ), self )
49
+ self.alpha_hash = { Template.hash_for( :_, :_, :_ ) => self.alpha_top }
50
+ self.beta_top = BetaMemory.new(nil)
51
+ self.beta_top.rete = self
52
+ self.beta_top.seed
53
+ self.queries = {}
54
+ self.results = {}
55
+ @cache = {}
56
+ @revns = {}
57
+ @contexts = {}
58
+
59
+ @productions = { }
60
+
61
+ @collectors = {}
62
+ @collectors[:error] = []
63
+
64
+ end
65
+
66
+ def dump
67
+ beta_top.dump
68
+ end
69
+
70
+ def alphas
71
+ alpha_hash.values
72
+ end
73
+
74
+ def import thing
75
+ case thing
76
+ when String, Numeric, TrueClass, FalseClass, NilClass, Wongi::RDF::Node
77
+ thing
78
+ when Symbol
79
+ thing
80
+ else
81
+ thing
82
+ end
83
+ end
84
+
85
+ def assert wme
86
+
87
+ unless wme.rete == self
88
+ wme = wme.import_into self
89
+ end
90
+
91
+ if @current_context
92
+ @current_context.asserted_wmes << wme
93
+ wme.context = @current_context
94
+ end
95
+
96
+ return if @cache.has_key?(wme)
97
+
98
+ # puts "ASSERTING #{wme}"
99
+ @cache[wme] = wme
100
+
101
+ s = wme.subject
102
+ p = wme.predicate
103
+ o = wme.object
104
+
105
+ alpha_activate(lookup( s, p, o), wme)
106
+ alpha_activate(lookup( s, p, :_), wme)
107
+ alpha_activate(lookup( s, :_, o), wme)
108
+ alpha_activate(lookup(:_, p, o), wme)
109
+ alpha_activate(lookup( s, :_, :_), wme)
110
+ alpha_activate(lookup(:_, p, :_), wme)
111
+ alpha_activate(lookup(:_, :_, o), wme)
112
+ alpha_activate(lookup(:_, :_, :_), wme)
113
+
114
+ wme
115
+ end
116
+
117
+ def wmes
118
+ alpha_top.wmes
119
+ end
120
+ alias_method :statements, :wmes
121
+ alias_method :facts, :wmes
122
+
123
+ def in_snapshot?
124
+ @in_snapshot
125
+ end
126
+
127
+ def snapshot!
128
+ @timeline.each_with_index do |slice, index|
129
+ source = if index == @timeline.size - 1
130
+ alpha_hash
131
+ else
132
+ @timeline[index+1]
133
+ end
134
+ # puts "source = #{source}"
135
+ wmes = {}
136
+ slice.each { |key, alpha| wmes[key] = alpha.wmes }
137
+ slice.each do |key, alpha|
138
+ in_snapshot {
139
+ wmes[key].dup.each { |wme| wme.destroy }
140
+ }
141
+ alpha.snapshot! source[key]
142
+ end
143
+ end
144
+ end
145
+
146
+ def rule name = nil, &block
147
+ r = ProductionRule.new( name || generate_rule_name )
148
+ r.instance_eval &block
149
+ self << r
150
+ end
151
+
152
+ def query name, &block
153
+ q = Query.new name
154
+ q.instance_eval &block
155
+ self << q
156
+ end
157
+
158
+ def << something
159
+ case something
160
+ when Array
161
+ if something.length == 3
162
+ assert WME.new( *something )
163
+ else
164
+ raise "Arrays must have 3 elements"
165
+ end
166
+ when ProductionRule
167
+ derived = something.import_into self
168
+ production = add_production derived.conditions, derived.actions
169
+ if something.name
170
+ productions[ something.name ] = production
171
+ end
172
+ when Query
173
+ derived = something.import_into self
174
+ prepare_query derived.name, derived.conditions, derived.parameters, derived.actions
175
+ when Ruleset
176
+ something.install self
177
+ when WME
178
+ assert something
179
+ when Wongi::RDF::Statement
180
+ assert WME.new( something.subject, something.predicate, something.object, self )
181
+ #when Wongi::RDF::Document
182
+ # something.statements.each do |st|
183
+ # assert WME.new( st.subject, st.predicate, st.object, self )
184
+ # end
185
+ when Network
186
+ something.each do |st|
187
+ assert st.import_into( self )
188
+ end
189
+ else
190
+ raise "I don't know how to accept a #{something.class}"
191
+ end
192
+ end
193
+
194
+ def retract wme, is_real = false
195
+
196
+ if wme.is_a? Array
197
+ return retract( WME.new(*wme), is_real )
198
+ end
199
+
200
+ if ! is_real
201
+ if @current_context
202
+ @current_context.retracted_wmes << wme
203
+ end
204
+ end
205
+
206
+ real = if is_real
207
+ wme
208
+ else
209
+ #find(wme.subject, wme.predicate, wme.object)
210
+ @cache[wme]
211
+ end
212
+
213
+ return false if real.nil?
214
+ @cache.delete(real)
215
+ raise "Cannot retract inferred statements" unless real.manual?
216
+
217
+ real.destroy
218
+
219
+ true
220
+
221
+ end
222
+
223
+ def compile_alpha condition
224
+ template = Template.new :_, :_, :_
225
+ time = condition.time
226
+
227
+ template.subject = condition.subject unless Template.variable?( condition.subject )
228
+ template.predicate = condition.predicate unless Template.variable?( condition.predicate )
229
+ template.object = condition.object unless Template.variable?( condition.object )
230
+
231
+ hash = template.hash
232
+ # puts "COMPILED CONDITION #{condition} WITH KEY #{key}"
233
+ if time == 0
234
+ return self.alpha_hash[ hash ] if self.alpha_hash.has_key?( hash )
235
+ else
236
+ return @timeline[time+1][ hash ] if @timeline[time+1] && @timeline[time+1].has_key?( hash )
237
+ end
238
+
239
+ alpha = AlphaMemory.new( template, self )
240
+
241
+ if time == 0
242
+ self.alpha_hash[ hash ] = alpha
243
+ initial_fill alpha
244
+ else
245
+ if @timeline[time+1].nil?
246
+ # => ensure lineage from 0 to time
247
+ compile_alpha condition.class.new(condition.subject, condition.predicate, condition.object, time: time + 1)
248
+ @timeline.unshift Hash.new
249
+ end
250
+ @timeline[time+1][ hash ] = alpha
251
+ end
252
+ alpha
253
+ end
254
+
255
+ def cache s, p, o
256
+ compile_alpha Template.new(s, p, o).import_into( self )
257
+ end
258
+
259
+ def initial_fill alpha
260
+ tpl = alpha.template
261
+ source = more_generic_alpha(tpl)
262
+ # puts "more efficient by #{alpha_top.wmes.size - source.wmes.size}" unless source ==
263
+ # alpha_top
264
+ source.wmes.each do |wme|
265
+ alpha.activate wme if wme =~ tpl
266
+ end
267
+ end
268
+
269
+ def add_production conditions, actions = []
270
+ real_add_production self.beta_top, conditions, [], actions, false
271
+ end
272
+
273
+ def remove_production pnode
274
+ delete_node_with_ancestors pnode
275
+ end
276
+
277
+ def prepare_query name, conditions, parameters, actions = []
278
+ query = self.queries[ name ] = BetaMemory.new( nil )
279
+ query.rete = self
280
+ transformed = {}
281
+ parameters.each { |param| transformed[param] = nil }
282
+ query.seed transformed
283
+ self.results[ name ] = real_add_production query, conditions, parameters, actions, true
284
+ end
285
+
286
+ def execute name, valuations
287
+ beta = self.queries[name]
288
+ raise "Undefined query #{name}; known queries are #{queries.keys}" unless beta
289
+ beta.subst valuations
290
+ end
291
+
292
+ def inspect
293
+ "<Rete>"
294
+ end
295
+
296
+ def context= name
297
+ if name && !@contexts.has_key?(name)
298
+ @current_context = (@contexts[name] ||= ModelContext.new name)
299
+ end
300
+ end
301
+
302
+ def retract_context name
303
+ return unless @contexts.has_key?(name)
304
+
305
+ if @current_context && @current_context.name == name
306
+ @current_context = nil
307
+ end
308
+ ctx = @contexts[name]
309
+ ctx.asserted_wmes.select { |wme| wme.generating_tokens.empty? }.each { |wme| retract(wme, true) }
310
+ ctx.retracted_wmes.each { |wme| assert(wme) }
311
+ @contexts.delete name
312
+ end
313
+
314
+ def exists? wme
315
+ @cache[ wme ]
316
+ end
317
+
318
+ def each *args
319
+ return unless block_given?
320
+ unless args.length == 0 || args.length == 3
321
+ raise "Document#each expects a pattern or nothing at all"
322
+ end
323
+ s, p, o = if args.empty?
324
+ [:_, :_, :_]
325
+ else
326
+ args
327
+ end
328
+ no_check = s == :_ && p == :_ && o == :_
329
+ template = Template.new(s, p, o).import_into self
330
+ alpha_top.wmes.each do |wme|
331
+ yield wme if (no_check || wme =~ template)
332
+ end
333
+ end
334
+
335
+ def select s, p, o
336
+ template = Template.new(s, p, o).import_into self
337
+ matching = alpha_top.wmes.select { |wme| wme =~ template }
338
+ if block_given?
339
+ matching.each { |st| yield st.subject, st.predicate, st.object }
340
+ end
341
+ matching
342
+ end
343
+
344
+ def find s, p, o
345
+ template = Template.new(s, p, o).import_into self
346
+ source = best_alpha(template)
347
+ # puts "looking for #{template} among #{source.wmes.size} triples of #{source.template}"
348
+ source.wmes.detect { |wme| wme =~ template }
349
+ end
350
+
351
+ protected
352
+
353
+ def in_snapshot
354
+ @in_snapshot = true
355
+ yield
356
+ ensure
357
+ @in_snapshot = false
358
+ end
359
+
360
+ def generate_rule_name
361
+ "rule_#{productions.length}"
362
+ end
363
+
364
+ def lookup s, p, o
365
+ key = Template.hash_for(s, p, o)
366
+ # puts "Lookup for #{key}"
367
+ self.alpha_hash[ key ]
368
+ end
369
+
370
+ def alpha_activate alpha, wme
371
+ alpha.activate(wme) if alpha
372
+ end
373
+
374
+ def more_generic_alpha template
375
+ return alpha_top # OPTIMISE => temporary; may use later or not use at all
376
+ return alpha_top if template.root?
377
+ more_generic_templates(template).reduce alpha_top do |best, template|
378
+ alpha = alpha_hash[template.hash]
379
+ if alpha && alpha.wmes.size < best.wmes.size
380
+ alpha
381
+ else
382
+ best
383
+ end
384
+ end
385
+ end
386
+
387
+ def more_generic_templates template
388
+ set = []
389
+ set << template.with_subject( :_ ) unless template.subject == :_
390
+ set << template.with_predicate( :_ ) unless template.predicate == :_
391
+ set << template.with_object( :_ ) unless template.object == :_
392
+ set.select { |item| not item.root? }
393
+ end
394
+
395
+ def best_alpha template
396
+ candidates = alpha_hash.values.select do |alpha|
397
+ template =~ alpha.template
398
+ end
399
+ result = candidates.inject do |best, alpha|
400
+ if best.nil?
401
+ alpha
402
+ elsif alpha.wmes.to_a.length < best.wmes.to_a.length
403
+ alpha
404
+ else
405
+ best
406
+ end
407
+ end
408
+ result
409
+ end
410
+
411
+ def real_add_production root, conditions, parameters, actions, alpha_deaf
412
+ beta = root.network conditions, [], parameters, alpha_deaf
413
+
414
+ production = ProductionNode.new( beta, actions )
415
+ production.refresh
416
+ production
417
+ end
418
+
419
+ def delete_node_with_ancestors node
420
+
421
+ if node.kind_of?( NccNode )
422
+ delete_node_with_ancestors node.partner
423
+ end
424
+
425
+ if [BetaMemory, NegNode, NccNode, NccPartner].any? { | klass| node.kind_of? klass }
426
+ while node.tokens.first
427
+ node.tokens.first.delete
428
+ end
429
+ end
430
+
431
+ if node.parent
432
+ node.parent.children.delete node
433
+ if node.parent.children.empty?
434
+ delete_node_with_ancestors(node.parent)
435
+ end
436
+ end
437
+
438
+ end
439
+
440
+ end
441
+
442
+ end