wongi-engine 0.3.9 → 0.4.0.pre.alpha2

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.
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 +17 -15
  8. data/lib/wongi-engine/beta/assignment_node.rb +7 -2
  9. data/lib/wongi-engine/beta/beta_node.rb +36 -23
  10. data/lib/wongi-engine/beta/filter_node.rb +8 -13
  11. data/lib/wongi-engine/beta/join_node.rb +17 -29
  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 +25 -55
  15. data/lib/wongi-engine/beta/optional_node.rb +26 -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,62 @@ 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 }
45
+
46
+ overlay.add_token(token)
57
47
 
58
- token.overlay.add_token(token, self)
59
- alpha.wmes.each do |wme|
60
- make_join_result(token, wme) if matches?(token, wme)
48
+ template = specialize(alpha.template, tests, token)
49
+ select_wmes(template).each do |wme|
50
+ overlay.add_neg_join_result(NegJoinResult.new(token, wme)) if matches?(token, wme)
61
51
  end
62
- return unless token.neg_join_results.empty?
52
+ return if overlay.neg_join_results_for(token: token).any?
63
53
 
64
54
  children.each do |child|
65
- child.beta_activate Token.new(child, token, nil, {})
55
+ child.beta_activate(Token.new(child, token, nil, {}))
66
56
  end
67
57
  end
68
58
 
69
59
  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
60
+ # p beta_deactivate: {class: self.class, object_id:, token:}
61
+ overlay.remove_token(token)
62
+ beta_deactivate_children(token: token)
87
63
  end
88
64
 
89
65
  def refresh_child(child)
90
66
  tokens.each do |token|
91
- child.beta_activate Token.new(child, token, nil, {}) if token.neg_join_results.empty?
67
+ child.beta_activate(Token.new(child, token, nil, {})) if overlay.neg_join_results_for(token: token).empty?
92
68
  end
93
- alpha.wmes.each do |wme|
94
- alpha_activate wme
69
+ select_wmes(alpha.template).each do |wme|
70
+ alpha_activate wme, children: [child]
95
71
  end
96
72
  end
97
73
 
@@ -104,12 +80,6 @@ module Wongi
104
80
  end
105
81
  true
106
82
  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
83
  end
114
84
  end
115
85
  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,53 @@ 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 }
56
+
57
+ overlay.add_token(token)
67
58
 
68
- token = Token.new(self, t, nil, {})
69
- token.overlay.add_token(token, self)
70
59
  match = false
71
- alpha.wmes.each do |wme|
60
+ template = specialize(alpha.template, tests, token)
61
+ select_wmes(template).each do |wme|
72
62
  assignments = collect_assignments(wme)
73
63
  next unless matches? token, wme
74
64
 
@@ -80,36 +70,24 @@ module Wongi
80
70
  end
81
71
  return if match
82
72
 
83
- token.optional!
84
73
  children.each do |child|
85
74
  child.beta_activate Token.new(child, token, nil, {})
86
75
  end
87
76
  end
88
77
 
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
78
+ def beta_deactivate(token)
79
+ # p beta_deactivate: {class: self.class, object_id:, token:}
80
+ overlay.remove_token(token)
81
+ beta_deactivate_children(token: token)
103
82
  end
104
83
 
105
84
  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
85
+ tokens.each do |token|
86
+ child.beta_activate(Token.new(child, token, nil, {}))
87
+ end
88
+ select_wmes(alpha.template).each do |wme|
89
+ alpha_activate wme, children: [child]
111
90
  end
112
- self.children = tmp
113
91
  end
114
92
 
115
93
  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