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.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +2 -2
  3. data/.gitignore +2 -0
  4. data/README.md +12 -12
  5. data/lib/wongi-engine/alpha_index.rb +58 -0
  6. data/lib/wongi-engine/alpha_memory.rb +2 -24
  7. data/lib/wongi-engine/beta/aggregate_node.rb +16 -15
  8. data/lib/wongi-engine/beta/assignment_node.rb +7 -2
  9. data/lib/wongi-engine/beta/beta_node.rb +27 -23
  10. data/lib/wongi-engine/beta/filter_node.rb +8 -13
  11. data/lib/wongi-engine/beta/join_node.rb +15 -28
  12. data/lib/wongi-engine/beta/ncc_node.rb +14 -26
  13. data/lib/wongi-engine/beta/ncc_partner.rb +18 -18
  14. data/lib/wongi-engine/beta/neg_node.rb +23 -55
  15. data/lib/wongi-engine/beta/optional_node.rb +24 -48
  16. data/lib/wongi-engine/beta/or_node.rb +24 -1
  17. data/lib/wongi-engine/beta/production_node.rb +9 -3
  18. data/lib/wongi-engine/beta/root_node.rb +47 -0
  19. data/lib/wongi-engine/beta.rb +1 -1
  20. data/lib/wongi-engine/compiler.rb +6 -34
  21. data/lib/wongi-engine/dsl/action/{base.rb → base_action.rb} +5 -1
  22. data/lib/wongi-engine/dsl/action/error_generator.rb +1 -1
  23. data/lib/wongi-engine/dsl/action/simple_action.rb +1 -1
  24. data/lib/wongi-engine/dsl/action/simple_collector.rb +1 -1
  25. data/lib/wongi-engine/dsl/action/statement_generator.rb +21 -22
  26. data/lib/wongi-engine/dsl/action/trace_action.rb +1 -1
  27. data/lib/wongi-engine/dsl/clause/fact.rb +2 -6
  28. data/lib/wongi-engine/dsl.rb +1 -25
  29. data/lib/wongi-engine/graph.rb +1 -1
  30. data/lib/wongi-engine/network/debug.rb +2 -10
  31. data/lib/wongi-engine/network.rb +44 -105
  32. data/lib/wongi-engine/overlay.rb +589 -0
  33. data/lib/wongi-engine/template.rb +22 -2
  34. data/lib/wongi-engine/token.rb +10 -26
  35. data/lib/wongi-engine/token_assignment.rb +15 -0
  36. data/lib/wongi-engine/version.rb +1 -1
  37. data/lib/wongi-engine/wme.rb +10 -39
  38. data/lib/wongi-engine.rb +3 -1
  39. data/spec/alpha_index_spec.rb +78 -0
  40. data/spec/bug_specs/issue_4_spec.rb +11 -11
  41. data/spec/high_level_spec.rb +8 -101
  42. data/spec/network_spec.rb +8 -6
  43. data/spec/overlay_spec.rb +161 -3
  44. data/spec/rule_specs/any_rule_spec.rb +39 -0
  45. data/spec/rule_specs/assign_spec.rb +1 -1
  46. data/spec/rule_specs/maybe_rule_spec.rb +58 -1
  47. data/spec/rule_specs/ncc_spec.rb +78 -19
  48. data/spec/rule_specs/negative_rule_spec.rb +12 -14
  49. data/spec/spec_helper.rb +4 -0
  50. data/spec/wme_spec.rb +0 -32
  51. metadata +11 -9
  52. data/lib/wongi-engine/beta/beta_memory.rb +0 -60
  53. data/lib/wongi-engine/data_overlay.rb +0 -149
  54. data/spec/rule_specs/or_rule_spec.rb +0 -40
@@ -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.generating_tokens.empty?
43
- wme.generating_tokens.each { |token| io.puts "\t\tTOKEN #{token.object_id}" }
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)
@@ -3,16 +3,14 @@ require 'wongi-engine/network/debug'
3
3
 
4
4
  module Wongi::Engine
5
5
  class Network
6
- attr_reader :alpha_top, :beta_top, :queries, :results, :productions
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
- protected
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
- @timeline = []
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 = BetaMemory.new(nil)
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
- default_overlay.with_child(&block)
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 default_overlay
85
- @default_overlay ||= DataOverlay.new(self)
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, options)
133
- real = find(wme.subject, wme.predicate, wme.object)
134
- return if real.nil?
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
- alpha_top.wmes
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).tap { |wme| wme.overlay = default_overlay })
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 time.zero?
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
- if time.zero?
243
- alpha_hash[hash] = alpha
244
- initial_fill alpha
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
- alpha_top.wmes.each do |wme|
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] = BetaMemory.new(nil)
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
- source = best_alpha(template)
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
- template = Template.new(s, p, o)
313
- source = best_alpha(template)
314
- matching = current_overlay.wmes(source).select { |wme| wme =~ template }
315
- matching.each { |st| yield st.subject, st.predicate, st.object } if block_given?
316
- matching
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
- template = Template.new(s, p, o)
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
- if [BetaMemory, NegNode, NccNode, NccPartner].any? { |klass| node.is_a? klass }
390
- node.tokens.first.destroy while node.tokens.first
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