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
@@ -1,15 +1,8 @@
1
1
  module Wongi
2
2
  module Engine
3
- NegJoinResult = Struct.new :token, :wme, :neg_node do
4
- def unlink
5
- wme.neg_join_results.delete self
6
- token.neg_join_results.delete self
7
- end
8
- end
3
+ NegJoinResult = Struct.new :token, :wme
9
4
 
10
5
  class NegNode < BetaNode
11
- include TokenContainer
12
-
13
6
  attr_reader :alpha, :tests
14
7
 
15
8
  def initialize(parent, tests, alpha, unsafe)
@@ -19,79 +12,60 @@ module Wongi
19
12
  @unsafe = unsafe
20
13
  end
21
14
 
22
- def alpha_activate(wme)
15
+ def alpha_activate(wme, children: self.children)
16
+ # p alpha_activate: {class: self.class, object_id:, wme:}
23
17
  tokens.each do |token|
24
18
  next unless matches?(token, wme) && (@unsafe || !token.generated?(wme)) # feedback loop protection
25
19
 
26
20
  # order matters for proper invalidation
27
- make_join_result(token, wme)
28
- # token.delete_children #if token.neg_join_results.empty? # TODO why was this check here? it seems to break things
29
- children.each do |child|
30
- child.tokens.each do |t|
31
- if t.parent == token
32
- child.beta_deactivate t
33
- # token.destroy
34
- end
35
- end
36
- end
21
+ overlay.add_neg_join_result(NegJoinResult.new(token, wme))
22
+ beta_deactivate_children(token: token, children: children)
37
23
  end
38
24
  end
39
25
 
40
26
  def alpha_deactivate(wme)
41
- wme.neg_join_results.dup.each do |njr|
27
+ # p alpha_deactivate: {class: self.class, object_id:, wme:}
28
+ overlay.neg_join_results_for(wme: wme).each do |njr|
42
29
  tokens.each do |token|
43
30
  next unless token == njr.token
44
31
 
45
- njr.unlink
46
- next unless token.neg_join_results.empty?
32
+ overlay.remove_neg_join_result(njr)
33
+ next unless overlay.neg_join_results_for(token: token).empty?
47
34
 
48
35
  children.each do |child|
49
- child.beta_activate Token.new(child, token, nil, {})
36
+ child.beta_activate(Token.new(child, token, nil))
50
37
  end
51
38
  end
52
39
  end
53
40
  end
54
41
 
55
42
  def beta_activate(token)
56
- return if tokens.find { |et| et.duplicate? token }
43
+ # p beta_activate: {class: self.class, object_id:, token:}
44
+ return if tokens.find { |t| t.duplicate? token }
57
45
 
58
- token.overlay.add_token(token, self)
59
- alpha.wmes.each do |wme|
60
- make_join_result(token, wme) if matches?(token, wme)
46
+ overlay.add_token(token)
47
+ select_wmes(alpha.template).each do |wme|
48
+ overlay.add_neg_join_result(NegJoinResult.new(token, wme)) if matches?(token, wme)
61
49
  end
62
- return unless token.neg_join_results.empty?
50
+ return if overlay.neg_join_results_for(token: token).any?
63
51
 
64
52
  children.each do |child|
65
- child.beta_activate Token.new(child, token, nil, {})
53
+ child.beta_activate(Token.new(child, token, nil, {}))
66
54
  end
67
55
  end
68
56
 
69
57
  def beta_deactivate(token)
70
- return nil unless tokens.find token
71
-
72
- token.overlay.remove_token(token, self)
73
- token.deleted!
74
- if token.parent
75
- token.parent.children.delete token # should this go into Token#destroy?
76
- end
77
- token.neg_join_results.each(&:unlink)
78
- children.each do |child|
79
- child.tokens.each do |t|
80
- if t.parent == token
81
- child.beta_deactivate t
82
- # token.destroy
83
- end
84
- end
85
- end
86
- token
58
+ # p beta_deactivate: {class: self.class, object_id:, token:}
59
+ overlay.remove_token(token)
60
+ beta_deactivate_children(token: token)
87
61
  end
88
62
 
89
63
  def refresh_child(child)
90
64
  tokens.each do |token|
91
- child.beta_activate Token.new(child, token, nil, {}) if token.neg_join_results.empty?
65
+ child.beta_activate(Token.new(child, token, nil, {})) if overlay.neg_join_results_for(token: token).empty?
92
66
  end
93
- alpha.wmes.each do |wme|
94
- alpha_activate wme
67
+ select_wmes(alpha.template).each do |wme|
68
+ alpha_activate wme, children: [child]
95
69
  end
96
70
  end
97
71
 
@@ -104,12 +78,6 @@ module Wongi
104
78
  end
105
79
  true
106
80
  end
107
-
108
- def make_join_result(token, wme)
109
- njr = NegJoinResult.new token, wme, self
110
- token.neg_join_results << njr
111
- wme.neg_join_results << njr
112
- end
113
81
  end
114
82
  end
115
83
  end
@@ -1,15 +1,8 @@
1
1
  module Wongi
2
2
  module Engine
3
- OptionalJoinResult = Struct.new :token, :wme do
4
- def unlink
5
- wme.opt_join_results.delete self
6
- token.opt_join_results.delete self
7
- end
8
- end
3
+ OptionalJoinResult = Struct.new :token, :wme
9
4
 
10
5
  class OptionalNode < BetaNode
11
- include TokenContainer
12
-
13
6
  attr_reader :alpha, :tests, :assignment_pattern
14
7
 
15
8
  def initialize(parent, alpha, tests, assignments)
@@ -19,56 +12,51 @@ module Wongi
19
12
  @assignment_pattern = assignments
20
13
  end
21
14
 
22
- def make_opt_result(token, wme)
23
- jr = OptionalJoinResult.new token, wme
24
- token.opt_join_results << jr
25
- wme.opt_join_results << jr
26
- end
27
-
28
- def alpha_activate(wme)
15
+ def alpha_activate(wme, children: self.children)
29
16
  assignments = collect_assignments(wme)
30
17
  tokens.each do |token|
31
18
  next unless matches? token, wme
32
19
 
20
+ optional = overlay.opt_join_results_for(token: token).empty?
21
+
33
22
  children.each do |child|
34
- if token.optional?
35
- token.no_optional!
23
+ if optional
24
+ # we're going to change the optional state so the old ones need to be removed
36
25
  child.tokens.each do |ct|
37
26
  child.beta_deactivate(ct) if ct.parent == token
38
27
  end
39
28
  end
40
29
  child.beta_activate Token.new(child, token, wme, assignments)
41
30
  end
42
- make_opt_result token, wme
31
+ overlay.add_opt_join_result(OptionalJoinResult.new(token, wme))
43
32
  end
44
33
  end
45
34
 
46
35
  def alpha_deactivate(wme)
47
- wme.opt_join_results.dup.each do |ojr|
36
+ # p alpha_deactivate: {wme:}
37
+ overlay.opt_join_results_for(wme: wme).each do |ojr|
48
38
  tokens.each do |token|
49
39
  next unless token == ojr.token
50
40
 
51
- ojr.unlink
52
- next unless token.opt_join_results.empty?
41
+ overlay.remove_opt_join_result(ojr)
42
+ next unless overlay.opt_join_results_for(token: token).empty?
53
43
 
54
44
  children.each do |child|
55
45
  child.tokens.each do |ct|
56
46
  child.beta_deactivate(ct) if ct.parent == token
57
47
  end
58
- token.optional!
59
48
  child.beta_activate Token.new(child, token, nil, {})
60
49
  end
61
50
  end
62
51
  end
63
52
  end
64
53
 
65
- def beta_activate(t)
66
- return if tokens.find { |token| token.parent == t }
54
+ def beta_activate(token)
55
+ return if tokens.find { |t| t.duplicate? token }
67
56
 
68
- token = Token.new(self, t, nil, {})
69
- token.overlay.add_token(token, self)
57
+ overlay.add_token(token)
70
58
  match = false
71
- alpha.wmes.each do |wme|
59
+ select_wmes(alpha.template).each do |wme|
72
60
  assignments = collect_assignments(wme)
73
61
  next unless matches? token, wme
74
62
 
@@ -80,36 +68,24 @@ module Wongi
80
68
  end
81
69
  return if match
82
70
 
83
- token.optional!
84
71
  children.each do |child|
85
72
  child.beta_activate Token.new(child, token, nil, {})
86
73
  end
87
74
  end
88
75
 
89
- def beta_deactivate(t)
90
- token = tokens.find { |own_token| own_token.parent == t }
91
- return unless token
92
-
93
- token.overlay.remove_token(token, self)
94
- token.deleted!
95
- token.parent.children.delete token if token.parent
96
- token.opt_join_results.each(&:unlink)
97
- children.each do |child|
98
- child.tokens.each do |child_token|
99
- child.beta_deactivate(child_token) if child_token.parent == token
100
- end
101
- end
102
- token
76
+ def beta_deactivate(token)
77
+ # p beta_deactivate: {class: self.class, object_id:, token:}
78
+ overlay.remove_token(token)
79
+ beta_deactivate_children(token: token)
103
80
  end
104
81
 
105
82
  def refresh_child(child)
106
- tmp = children
107
- self.children = [child]
108
- refresh # do the beta part
109
- alpha.wmes.each do |wme|
110
- alpha_activate wme
83
+ tokens.each do |token|
84
+ child.beta_activate(Token.new(child, token, nil, {}))
85
+ end
86
+ select_wmes(alpha.template).each do |wme|
87
+ alpha_activate wme, children: [child]
111
88
  end
112
- self.children = tmp
113
89
  end
114
90
 
115
91
  private
@@ -1,6 +1,6 @@
1
1
  module Wongi
2
2
  module Engine
3
- class OrNode < BetaMemory
3
+ class OrNode < BetaNode
4
4
  attr_reader :parents, :rete
5
5
 
6
6
  def initialize(parents)
@@ -24,11 +24,34 @@ module Wongi
24
24
  parents.map(&:depth).max + 1
25
25
  end
26
26
 
27
+ def beta_activate(token)
28
+ # p beta_activate: {class: self.class, object_id:, token:}
29
+ return if tokens.find { token.duplicate?(_1) }
30
+
31
+ overlay.add_token(token)
32
+
33
+ children.each do |child|
34
+ child.beta_activate(Token.new(child, token, nil))
35
+ end
36
+ end
37
+
38
+ def beta_deactivate(token)
39
+ # p beta_deactivate: {class: self.class, object_id:, token:}
40
+ overlay.remove_token(token)
41
+ beta_deactivate_children(token: token)
42
+ end
43
+
27
44
  def refresh
28
45
  parents.each do |parent|
29
46
  parent.refresh_child self
30
47
  end
31
48
  end
49
+
50
+ def refresh_child(child)
51
+ tokens.each do |token|
52
+ child.beta_activate(Token.new(child, token, nil))
53
+ end
54
+ end
32
55
  end
33
56
  end
34
57
  end
@@ -1,6 +1,6 @@
1
1
  module Wongi
2
2
  module Engine
3
- class ProductionNode < BetaMemory
3
+ class ProductionNode < BetaNode
4
4
  attr_accessor :tracer, :compilation_context
5
5
 
6
6
  def initialize(parent, actions)
@@ -9,7 +9,10 @@ module Wongi
9
9
  end
10
10
 
11
11
  def beta_activate(token)
12
- return unless super
12
+ # p beta_activate: {class: self.class, object_id:, token:}
13
+ return if tokens.find { |t| t.duplicate? token }
14
+
15
+ overlay.add_token(token)
13
16
 
14
17
  @actions.each do |action|
15
18
  action.execute token if action.respond_to? :execute
@@ -17,7 +20,10 @@ module Wongi
17
20
  end
18
21
 
19
22
  def beta_deactivate(token)
20
- return unless super
23
+ # p beta_deactivate: {class: self.class, object_id:, token:}
24
+
25
+ # we should remove before the actions because otherwise the longer rule chains (like the infinite neg-gen cycle) don't work as expected
26
+ overlay.remove_token(token)
21
27
 
22
28
  @actions.each do |action|
23
29
  action.deexecute token if action.respond_to? :deexecute
@@ -0,0 +1,47 @@
1
+ module Wongi::Engine
2
+ class RootNode < BetaNode
3
+ def seed(assignments = {})
4
+ @seed = assignments
5
+ t = Token.new(self, nil, nil, assignments)
6
+ rete.default_overlay.add_token(t)
7
+ end
8
+
9
+ def subst(valuations)
10
+ beta_deactivate(tokens.first)
11
+ token = Token.new(self, nil, nil, @seed)
12
+ valuations.each { |variable, value| token.subst variable, value }
13
+ beta_activate(token)
14
+ end
15
+
16
+ def beta_activate(token)
17
+ # existing = tokens.find { |et| et.duplicate? token }
18
+ # return if existing # TODO: really?
19
+
20
+ overlay.add_token(token)
21
+
22
+ children.each do |child|
23
+ child.beta_activate(Token.new(child, token, nil))
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ def beta_deactivate(token)
30
+ return nil unless tokens.find token
31
+
32
+ overlay.remove_token(token)
33
+
34
+ children.each do |child|
35
+ child.tokens.select { _1.parent == token }.each { child.beta_deactivate(_1) }
36
+ end
37
+
38
+ nil
39
+ end
40
+
41
+ def refresh_child(child)
42
+ tokens.each do |token|
43
+ child.beta_activate(Token.new(child, token, nil))
44
+ end
45
+ end
46
+ end
47
+ end
@@ -1,5 +1,5 @@
1
1
  require 'wongi-engine/beta/beta_node'
2
- require 'wongi-engine/beta/beta_memory'
2
+ require 'wongi-engine/beta/root_node'
3
3
  require 'wongi-engine/beta/filter_node'
4
4
  require 'wongi-engine/beta/assignment_node'
5
5
  require 'wongi-engine/beta/join_node'
@@ -24,37 +24,13 @@ module Wongi::Engine
24
24
  end
25
25
  end
26
26
 
27
- # TODO: should the following be the responsibility of Compiler or of each individual DSL clause?
28
-
29
- def beta_memory
30
- return if node.is_a?(BetaMemory)
31
-
32
- self.node = if (existing = node.children.find { |n| n.is_a?(BetaMemory) })
33
- existing
34
- else
35
- BetaMemory.new(node).tap(&:refresh)
36
- end
37
- end
38
-
39
- def singleton_beta_memory
40
- return if node.is_a?(SingletonBetaMemory)
41
-
42
- self.node = if (existing = node.children.find { |n| n.is_a?(SingletonBetaMemory) })
43
- existing
44
- else
45
- SingletonBetaMemory.new(node).tap(&:refresh)
46
- end
47
- end
48
-
49
27
  def assignment_node(variable, body)
50
- beta_memory
51
28
  self.node = AssignmentNode.new(node, variable, body).tap(&:refresh)
52
29
  declare(variable)
53
30
  end
54
31
 
55
32
  def join_node(condition, tests, assignment)
56
33
  alpha = rete.compile_alpha(condition)
57
- beta_memory
58
34
  self.node = if (existing = node.children.find { |n| n.is_a?(JoinNode) && n.equivalent?(alpha, tests, assignment) && !n.children.map(&:class).include?(Wongi::Engine::OrNode) })
59
35
  existing
60
36
  else
@@ -63,6 +39,7 @@ module Wongi::Engine
63
39
  alpha.betas << join unless alpha_deaf
64
40
  end
65
41
  end
42
+ node.tap(&:refresh)
66
43
  end
67
44
 
68
45
  def neg_node(condition, tests, unsafe)
@@ -75,24 +52,21 @@ module Wongi::Engine
75
52
 
76
53
  def opt_node(condition, tests, assignment)
77
54
  alpha = rete.compile_alpha(condition)
78
- beta_memory
79
55
  self.node = OptionalNode.new(node, alpha, tests, assignment).tap do |node|
80
56
  alpha.betas << node unless alpha_deaf
57
+ node.refresh
81
58
  end
82
59
  end
83
60
 
84
61
  def aggregate_node(condition, tests, assignment, map, function, assign)
85
62
  declare(assign)
86
63
  alpha = rete.compile_alpha(condition)
87
- beta_memory
88
64
  self.node = AggregateNode.new(node, alpha, tests, assignment, map, function, assign).tap do |node|
89
65
  alpha.betas << node unless alpha_deaf
90
- end
91
- beta_memory
66
+ end.tap(&:refresh)
92
67
  end
93
68
 
94
69
  def or_node(variants)
95
- beta_memory
96
70
  subvariables = []
97
71
  branches = variants.map do |variant|
98
72
  subcompiler = Compiler.new(rete, node, variant.conditions, parameters, false)
@@ -110,7 +84,6 @@ module Wongi::Engine
110
84
  end
111
85
 
112
86
  def ncc_node(subrule, alpha_deaf)
113
- beta_memory
114
87
  subcompiler = Compiler.new(rete, node, subrule.conditions, parameters, alpha_deaf)
115
88
  declared_variables.each { |v| subcompiler.declare(v) }
116
89
  bottom = subcompiler.compile
@@ -118,8 +91,8 @@ module Wongi::Engine
118
91
  self.node = existing
119
92
  return
120
93
  end
121
- ncc = NccNode.new node
122
- partner = NccPartner.new subcompiler.tap(&:beta_memory).node
94
+ ncc = NccNode.new(node)
95
+ partner = NccPartner.new(subcompiler.node)
123
96
  ncc.partner = partner
124
97
  partner.ncc = ncc
125
98
  partner.divergent = node
@@ -130,8 +103,7 @@ module Wongi::Engine
130
103
  end
131
104
 
132
105
  def filter_node(filter)
133
- beta_memory
134
- self.node = FilterNode.new(node, filter)
106
+ self.node = FilterNode.new(node, filter).tap(&:refresh)
135
107
  end
136
108
  end
137
109
  end
@@ -1,8 +1,12 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class Base
3
+ class BaseAction
4
4
  include CoreExt
5
5
  attr_accessor :production, :rule, :name, :rete
6
+
7
+ def overlay
8
+ rete.current_overlay
9
+ end
6
10
  end
7
11
  end
8
12
  end
@@ -1,6 +1,6 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class ErrorGenerator < Base
3
+ class ErrorGenerator < BaseAction
4
4
  def initialize(message = nil, &messenger)
5
5
  super()
6
6
  @message = message
@@ -1,6 +1,6 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class SimpleAction < Base
3
+ class SimpleAction < BaseAction
4
4
  def initialize(action = nil, *args, &block)
5
5
  super()
6
6
  @args = args
@@ -1,6 +1,6 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class SimpleCollector < Base
3
+ class SimpleCollector < BaseAction
4
4
  def self.collector
5
5
  Class.new self
6
6
  end
@@ -1,45 +1,44 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class StatementGenerator < Base
3
+ class StatementGenerator < BaseAction
4
+ GeneratorOrigin = Struct.new(:token, :action)
5
+
6
+ attr_reader :template
7
+ private :template
8
+
4
9
  def initialize(template)
5
10
  super()
6
11
  @template = template
7
12
  end
8
13
 
9
14
  def execute(token)
10
- subject, predicate, object = @template.resolve!(token)
15
+ # p execute: {token:}
16
+ subject, predicate, object = template.resolve!(token)
17
+
18
+ wme = WME.new(subject, predicate, object)
11
19
 
12
- # link to rete here to ensure proper linking with token
13
- wme = WME.new subject, predicate, object, rete
14
- wme.manual = false
15
- wme.overlay = token.overlay
20
+ origin = GeneratorOrigin.new(token, self)
16
21
 
17
22
  production.tracer.trace(action: self, wme: wme) if production.tracer
18
- if (existing = rete.exists?(wme))
19
- generated = existing.generating_tokens.size
20
- if generated.positive? && !token.generated_wmes.include?(existing)
23
+ if (existing = overlay.find(wme))
24
+ # do not mark purely manual tokens as generated, because a circular rule such as the symmetric friend generator this would cause both sides to become self-sustaining
25
+ # TODO: but this may have to be smarter, because there may be more indirect ways of creating such a situation
26
+ if overlay.generated?(wme)
21
27
  token.generated_wmes << existing
22
- existing.generating_tokens << token
28
+ overlay.assert(existing, generator: origin)
23
29
  end
24
30
  else
25
31
  token.generated_wmes << wme
26
- wme.generating_tokens << token
27
- # this MUST be done after we link the wme and the token
28
- # in order for neg rule invalidation to work
29
- wme.overlay.assert wme
32
+ overlay.assert(wme, generator: origin)
30
33
  end
31
34
  end
32
35
 
33
36
  def deexecute(token)
34
- generated = token.generated_wmes.reject(&:manual?)
35
-
36
- wmes_for_deletion = generated.each_with_object([]) do |wme, acc|
37
- wme.generating_tokens.delete token
38
- acc << wme if wme.generating_tokens.empty?
39
- end
37
+ origin = GeneratorOrigin.new(token, self)
40
38
 
41
- wmes_for_deletion.each do |wme|
42
- wme.overlay.retract wme, automatic: true
39
+ generated = token.generated_wmes.select { overlay.generators(_1).include?(origin) }
40
+ generated.each do |wme|
41
+ overlay.retract wme, generator: origin
43
42
  end
44
43
  end
45
44
  end
@@ -1,6 +1,6 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Action
3
- class TraceAction < Base
3
+ class TraceAction < BaseAction
4
4
  class DefaultTracer
5
5
  attr_accessor :action
6
6
 
@@ -1,17 +1,13 @@
1
1
  module Wongi::Engine
2
2
  module DSL::Clause
3
- Has = Struct.new(:subject, :predicate, :object, :time) do
3
+ Has = Struct.new(:subject, :predicate, :object) do
4
4
  include CoreExt
5
5
  attr_predicate :debug
6
6
 
7
7
  def initialize(s, p, o, options = {})
8
- time = options[:time] || 0
9
8
  @unsafe = options[:unsafe] || false
10
9
  debug! if options[:debug]
11
- raise "Cannot work with continuous time" unless time.integer?
12
- raise "Cannot look into the future" if time.positive?
13
-
14
- super(s, p, o, time)
10
+ super(s, p, o)
15
11
  end
16
12
 
17
13
  def compile(context)
@@ -36,7 +36,7 @@ require 'wongi-engine/dsl/clause/fact'
36
36
  require 'wongi-engine/dsl/clause/aggregate'
37
37
  require 'wongi-engine/dsl/clause/assign'
38
38
  require 'wongi-engine/dsl/clause/gen'
39
- require 'wongi-engine/dsl/action/base'
39
+ require 'wongi-engine/dsl/action/base_action'
40
40
  require 'wongi-engine/dsl/rule'
41
41
  require 'wongi-engine/dsl/ncc_subrule'
42
42
  require 'wongi-engine/dsl/any_rule'
@@ -110,30 +110,6 @@ module Wongi::Engine::DSL
110
110
  clause :assign, :introduce, :let
111
111
  accept Clause::Assign
112
112
 
113
- clause :asserted, :added
114
- body { |s, p, o|
115
- has s, p, o, time: 0
116
- missing s, p, o, time: -1
117
- }
118
-
119
- clause :retracted, :removed
120
- body { |s, p, o|
121
- has s, p, o, time: -1
122
- missing s, p, o, time: 0
123
- }
124
-
125
- clause :kept, :still_has
126
- body { |s, p, o|
127
- has s, p, o, time: -1
128
- has s, p, o, time: 0
129
- }
130
-
131
- clause :kept_missing, :still_missing
132
- body { |s, p, o|
133
- missing s, p, o, time: -1
134
- missing s, p, o, time: 0
135
- }
136
-
137
113
  clause :assuming
138
114
  accept Wongi::Engine::AssumingClause
139
115