wongi-engine 0.0.17 → 0.1.0.alpha1

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,45 +1,107 @@
1
1
  module Wongi
2
2
  module Engine
3
3
 
4
- OptionalJoinResult = Struct.new :owner, :wme
4
+ OptionalJoinResult = Struct.new :token, :wme do
5
+ def unlink
6
+ wme.opt_join_results.delete self
7
+ token.opt_join_results.delete self
8
+ end
9
+ end
10
+
11
+ class OptionalNode < BetaNode
12
+
13
+ attr_reader :alpha, :tests, :assignments, :tokens
5
14
 
6
- class OptionalNode < JoinNode
15
+ def initialize parent, alpha, tests, assignments
16
+ super( parent )
17
+ @alpha = alpha
18
+ @tests = tests
19
+ @assignments = assignments
20
+ @tokens = []
21
+ end
7
22
 
8
- def initialize parent, tests, assignment
9
- super parent, tests, assignment, []
23
+ def make_opt_result token, wme
24
+ jr = OptionalJoinResult.new token, wme
25
+ token.opt_join_results << jr
26
+ wme.opt_join_results << jr
10
27
  end
11
28
 
12
29
  def alpha_activate wme
13
- parent.tokens.each do |token|
30
+ assignments = collect_assignments( wme )
31
+ self.tokens.each do |token|
14
32
  if matches? token, wme
15
- if token.has_optional?
16
- token.has_optional = false
17
- token.delete_children
33
+ children.each do |child|
34
+ if token.optional?
35
+ token.no_optional!
36
+ child.tokens.select { |ct| ct.parent == token }.each do |ct|
37
+ child.beta_deactivate ct
38
+ end
39
+ end
40
+ child.beta_activate Token.new( child, token, wme, assignments )
18
41
  end
19
- propagate_activation(token, wme, collect_assignments(wme))
20
- jr = OptionalJoinResult.new token, wme
21
- token.opt_join_results << jr
22
- wme.opt_join_results << jr
42
+ make_opt_result token, wme
23
43
  end
24
44
  end
25
45
  end
26
46
 
27
- def beta_activate token
47
+ def alpha_deactivate wme
48
+ wme.opt_join_results.dup.each do |ojr|
49
+ safe_tokens.select { |token| token == ojr.token }.each do |token|
50
+ ojr.unlink
51
+ if token.opt_join_results.empty?
52
+ children.each do |child|
53
+ child.tokens.select { |ct| ct.parent == token }.each do |ct|
54
+ child.beta_deactivate ct
55
+ end
56
+ token.optional!
57
+ child.beta_activate Token.new( child, token, nil, { } )
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def beta_activate t
65
+ return if @tokens.find { |token| token.parent == t }
66
+ token = Token.new( self, t, nil, { } )
67
+ @tokens << token
28
68
  match = false
29
69
  alpha.wmes.each do |wme|
30
70
  assignments = collect_assignments(wme)
31
71
  if matches? token, wme
32
72
  match = true
33
- propagate_activation(token, wme, assignments)
34
- jr = OptionalJoinResult.new token, wme
35
- token.opt_join_results << jr
36
- wme.opt_join_results << jr
73
+ children.each do |child|
74
+ child.beta_activate Token.new( child, token, wme, assignments )
75
+ end
76
+ make_opt_result token, wme
37
77
  end
38
78
  end
39
79
  unless match
40
- token.has_optional = true
41
- propagate_activation(token, nil, {})
80
+ token.optional!
81
+ children.each do |child|
82
+ child.beta_activate Token.new( child, token, nil, { } )
83
+ end
84
+ end
85
+ end
86
+
87
+ def beta_deactivate t
88
+ token = @tokens.find { |token| token.parent == t }
89
+ return unless token
90
+ return unless @tokens.delete token
91
+ token.deleted!
92
+ if token.parent
93
+ token.parent.children.delete token
42
94
  end
95
+ token.opt_join_results.each &:unlink
96
+ children.each do |child|
97
+ child.tokens.each do |t|
98
+ if t.parent == token
99
+ child.beta_deactivate t
100
+ #token.destroy
101
+ end
102
+ end
103
+ end
104
+ token
43
105
  end
44
106
 
45
107
  def refresh_child child
@@ -60,6 +122,36 @@ module Wongi
60
122
  token.opt_join_results.clear
61
123
  end
62
124
 
125
+ private
126
+
127
+ def matches? token, wme
128
+ @tests.each do |test|
129
+ return false unless test.matches?( token, wme )
130
+ end
131
+ true
132
+ end
133
+
134
+ def collect_assignments wme
135
+ assignments = {}
136
+ return assignments if self.assignments.nil?
137
+ # puts "more assignments"
138
+ [:subject, :predicate, :object].each do |field|
139
+ if self.assignments.send(field) != :_
140
+ #puts "#{self.assignments.send(field)} = #{wme.send(field)}"
141
+ assignments[ self.assignments.send(field) ] = TokenAssignment.new( wme, field )
142
+ end
143
+ end
144
+ assignments
145
+ end
146
+
147
+ def safe_tokens
148
+ Enumerator.new do |y|
149
+ @tokens.dup.each do |token|
150
+ y << token unless token.deleted?
151
+ end
152
+ end
153
+ end
154
+
63
155
  end
64
156
  end
65
157
  end
@@ -7,17 +7,20 @@ module Wongi
7
7
 
8
8
  def initialize parent, actions
9
9
  super(parent)
10
- @actions = actions
11
- @actions.each { |action| action.production = self }
10
+ @actions = actions.each { |action| action.production = self }
12
11
  end
13
12
 
14
- def beta_activate token, wme, assignments
15
- generated = super
13
+ def beta_activate token
14
+ return unless super
16
15
  @actions.each do |action|
17
- # @tokens.each do |t|
18
- # action.execute t
19
- # end
20
- action.execute generated if action.respond_to? :execute
16
+ action.execute token if action.respond_to? :execute
17
+ end
18
+ end
19
+
20
+ def beta_deactivate token
21
+ return unless super
22
+ @actions.each do |action|
23
+ action.deexecute token if action.respond_to? :deexecute
21
24
  end
22
25
  end
23
26
 
@@ -46,6 +46,12 @@ module Wongi::Engine
46
46
  end
47
47
  end
48
48
 
49
+ def abstract name
50
+ define_method name do |*args|
51
+ raise NoMethodError.new "#{name} is not implemented for #{self.class.name}", name
52
+ end
53
+ end
54
+
49
55
  end
50
56
 
51
57
  def self.included mod
@@ -3,14 +3,20 @@ module Wongi::Engine
3
3
  class SimpleAction < Action
4
4
 
5
5
  def initialize action = nil, *args, &block
6
- @action = if action.is_a? Class
7
- action.new *args, &block
8
- else
9
- action || block
6
+ @args = args
7
+ case action
8
+ when Class
9
+ @action = @deaction = @reaction = action.new *args, &block
10
+ when Hash
11
+ @action = instance_or_proc action[:activate]
12
+ @deaction = instance_or_proc action[:deactivate]
13
+ @reaction = instance_or_proc action[:reactivate]
10
14
  end
15
+ @action ||= block
11
16
  end
12
17
 
13
18
  def execute token
19
+ return unless @action
14
20
  if @action.is_a?( Proc ) || @action.respond_to?( :to_proc )
15
21
  rete.instance_exec token, &@action
16
22
  elsif @action.respond_to? :call
@@ -20,6 +26,37 @@ module Wongi::Engine
20
26
  end
21
27
  end
22
28
 
29
+ def deexecute token
30
+ return unless @deaction
31
+ if @deaction.is_a?( Proc ) || @deaction.respond_to?( :to_proc )
32
+ rete.instance_exec token, &@deaction
33
+ elsif @deaction.respond_to? :call
34
+ @deaction.call token
35
+ elsif @deaction.respond_to? :deexecute
36
+ @deaction.execute token
37
+ end
38
+ end
39
+
40
+ def reexecute token, newtoken
41
+ return unless @reaction
42
+ if @reaction.is_a?( Proc ) || @reaction.respond_to?( :to_proc )
43
+ rete.instance_exec token, newtoken, &@reaction
44
+ elsif @reaction.respond_to? :call
45
+ @reaction.call token, newtoken
46
+ elsif @reaction.respond_to? :reexecute
47
+ @reaction.execute token, newtoken
48
+ end
49
+ end
50
+
51
+ def instance_or_proc thing
52
+ case thing
53
+ when Class
54
+ thing.new
55
+ when Proc
56
+ thing
57
+ end
58
+ end
59
+
23
60
  end
24
61
 
25
62
  end
@@ -51,5 +51,16 @@ module Wongi::Engine
51
51
 
52
52
  end
53
53
 
54
+ def deexecute token
55
+ token.generated_wmes.reject( &:manual? ).inject( [] ) do |list, wme|
56
+ list.tap do |l|
57
+ wme.generating_tokens.delete token
58
+ l << wme if wme.generating_tokens.empty?
59
+ end
60
+ end.each do |wme|
61
+ rete.retract wme
62
+ end
63
+ end
64
+
54
65
  end
55
66
  end
@@ -83,6 +83,43 @@ module Wongi::Engine
83
83
  end
84
84
 
85
85
  def assert wme
86
+ @next_cascade ||= []
87
+ @next_cascade << [:assert, wme]
88
+ if @current_cascade.nil?
89
+ @current_cascade = @next_cascade
90
+ @next_cascade = nil
91
+ process_cascade
92
+ end
93
+ end
94
+
95
+ def retract wme
96
+ @next_cascade ||= []
97
+ @next_cascade << [:retract, wme]
98
+ if @current_cascade.nil?
99
+ @current_cascade = @next_cascade
100
+ @next_cascade = nil
101
+ process_cascade
102
+ end
103
+ end
104
+
105
+ def process_cascade
106
+ iterations = 0
107
+ while @current_cascade
108
+ @current_cascade.each do |(operation, wme)|
109
+ case operation
110
+ when :assert
111
+ real_assert wme
112
+ when :retract
113
+ real_retract wme
114
+ end
115
+ end
116
+ @current_cascade = @next_cascade
117
+ @next_cascade = nil
118
+ iterations += 1
119
+ end
120
+ end
121
+
122
+ def real_assert wme
86
123
 
87
124
  unless wme.rete == self
88
125
  wme = wme.import_into self
@@ -98,18 +135,7 @@ module Wongi::Engine
98
135
  # puts "ASSERTING #{wme}"
99
136
  @cache[wme] = wme
100
137
 
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)
138
+ alphas_for( wme ).each { |a| a.activate wme }
113
139
 
114
140
  wme
115
141
  end
@@ -192,10 +218,10 @@ module Wongi::Engine
192
218
  end
193
219
  end
194
220
 
195
- def retract wme, is_real = false
221
+ def real_retract wme, is_real = false
196
222
 
197
223
  if wme.is_a? Array
198
- return retract( WME.new(*wme), is_real )
224
+ return real_retract( WME.new(*wme), is_real )
199
225
  end
200
226
 
201
227
  if ! is_real
@@ -211,14 +237,11 @@ module Wongi::Engine
211
237
  @cache[wme]
212
238
  end
213
239
 
214
- return false if real.nil?
240
+ return if real.nil?
215
241
  raise "Cannot retract inferred statements" unless real.manual?
216
242
  @cache.delete(real)
217
243
 
218
- real.destroy
219
-
220
- true
221
-
244
+ alphas_for( real ).each { |a| a.deactivate real }
222
245
  end
223
246
 
224
247
  def compile_alpha condition
@@ -362,6 +385,20 @@ module Wongi::Engine
362
385
  "rule_#{productions.length}"
363
386
  end
364
387
 
388
+ def alphas_for wme
389
+ s, p, o = wme.subject, wme.predicate, wme.object
390
+ [
391
+ lookup( s, p, o),
392
+ lookup( s, p, :_),
393
+ lookup( s, :_, o),
394
+ lookup(:_, p, o),
395
+ lookup( s, :_, :_),
396
+ lookup(:_, p, :_),
397
+ lookup(:_, :_, o),
398
+ lookup(:_, :_, :_),
399
+ ].compact.uniq
400
+ end
401
+
365
402
  def lookup s, p, o
366
403
  key = Template.hash_for(s, p, o)
367
404
  # puts "Lookup for #{key}"
@@ -4,7 +4,7 @@ module Wongi::Engine
4
4
 
5
5
  include CoreExt
6
6
 
7
- attr_reader :filters, :unsafe
7
+ attr_reader :unsafe
8
8
  attr_predicate debug: false
9
9
 
10
10
  def self.variable? thing
@@ -72,7 +72,7 @@ module Wongi::Engine
72
72
  def compile context
73
73
  tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
74
74
  alpha = context.rete.compile_alpha( self )
75
- context.node = context.node.beta_memory.join_node( alpha, tests, assignment, @filters, context.alpha_deaf )
75
+ context.node = context.node.beta_memory.join_node( alpha, tests, assignment, context.alpha_deaf )
76
76
  context.node.context = context
77
77
  context.node.debug = debug?
78
78
  context.earlier << self
@@ -97,8 +97,6 @@ module Wongi::Engine
97
97
 
98
98
  class NegTemplate < Template
99
99
 
100
- undef_method :filters
101
-
102
100
  # :arg: context => Wongi::Rete::BetaNode::CompilationContext
103
101
  def compile context
104
102
  tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
@@ -114,8 +112,6 @@ module Wongi::Engine
114
112
 
115
113
  class OptionalTemplate < Template
116
114
 
117
- undef_method :filters
118
-
119
115
  def compile context
120
116
  tests, assignment = *JoinNode.compile( self, context.earlier, context.parameters )
121
117
  alpha = context.rete.compile_alpha( self )
@@ -5,15 +5,18 @@ module Wongi::Engine
5
5
  include CoreExt
6
6
 
7
7
  attr_reader :children
8
- attr_accessor :node, :owner, :parent
8
+ attr_reader :wme
9
+ attr_reader :node
10
+ attr_accessor :owner, :parent
9
11
  attr_reader :neg_join_results
10
12
  attr_reader :opt_join_results
11
13
  attr_reader :ncc_results
12
14
  attr_reader :generated_wmes
13
- attr_predicate :has_optional
15
+ attr_predicate :optional
16
+ attr_predicate :deleted
14
17
 
15
- def initialize token, wme, assignments
16
- @parent, @wme, @assignments = token, wme, assignments
18
+ def initialize node, token, wme, assignments
19
+ @node, @parent, @wme, @assignments = node, token, wme, assignments
17
20
  @children = []
18
21
  @deleted = false
19
22
  @neg_join_results = []
@@ -49,8 +52,9 @@ module Wongi::Engine
49
52
  end
50
53
  end
51
54
 
52
- def duplicate? parent, wme, assignments
53
- self.parent.equal?(parent) && @wme.equal?(wme) && self.assignments == assignments
55
+ # TODO ignore assignments?
56
+ def duplicate? other
57
+ self.parent.equal?(other.parent) && @wme.equal?(other.wme) && self.assignments == other.assignments
54
58
  end
55
59
 
56
60
  def to_s
@@ -61,29 +65,26 @@ module Wongi::Engine
61
65
  end
62
66
 
63
67
  def destroy
64
- delete_children
65
- #@node.tokens.delete self unless @node.kind_of?( NccPartner )
66
- @wme.tokens.delete self if @wme
67
- @parent.children.delete self if @parent
68
-
69
- retract_generated
70
- @deleted = true
71
- @node.delete_token self
72
- end
73
-
74
- def deleted?
75
- @deleted
68
+ # delete_children
69
+ # #@node.tokens.delete self unless @node.kind_of?( NccPartner )
70
+ # @wme.tokens.delete self if @wme
71
+ # @parent.children.delete self if @parent
72
+
73
+ # retract_generated
74
+ deleted!
75
+ # @node.delete_token self
76
76
  end
77
77
 
78
- def delete_children
79
- children = @children
80
- @children = []
81
- children.each do |token|
82
- token.parent = nil
83
- token.destroy
84
- end
85
- end
78
+ # def delete_children
79
+ # children = @children
80
+ # @children = []
81
+ # children.each do |token|
82
+ # token.parent = nil
83
+ # token.destroy
84
+ # end
85
+ # end
86
86
 
87
+ # for neg feedback loop protection
87
88
  def generated? wme
88
89
  return true if generated_wmes.any? { |w| w == wme }
89
90
  return children.any? { |t| t.generated? wme }
@@ -91,21 +92,21 @@ module Wongi::Engine
91
92
 
92
93
  protected
93
94
 
94
- def retract_generated
95
- for_retraction = []
96
-
97
- @generated_wmes.dup.each do |wme|
98
- unless wme.manual? # => TODO: does this ever fail at all?
99
- wme.generating_tokens.delete self
100
- if wme.generating_tokens.empty?
101
- for_retraction << wme
102
- end
103
- end
104
- end
105
- @generated_wmes = []
106
- for_retraction.each { |wme| wme.rete.retract wme, true }
107
-
108
- end
95
+ # def retract_generated
96
+ # for_retraction = []
97
+
98
+ # @generated_wmes.dup.each do |wme|
99
+ # unless wme.manual? # => TODO: does this ever fail at all?
100
+ # wme.generating_tokens.delete self
101
+ # if wme.generating_tokens.empty?
102
+ # for_retraction << wme
103
+ # end
104
+ # end
105
+ # end
106
+ # @generated_wmes = []
107
+ # for_retraction.each { |wme| wme.rete.retract wme, true }
108
+
109
+ # end
109
110
 
110
111
  def all_assignments
111
112
  raise "Assignments is not a hash" unless @assignments.kind_of?( Hash )
@@ -1,5 +1,5 @@
1
1
  module Wongi
2
2
  module Engine
3
- VERSION = "0.0.17"
3
+ VERSION = "0.1.0.alpha1"
4
4
  end
5
5
  end
@@ -2,10 +2,13 @@ module Wongi::Engine
2
2
 
3
3
  class WME < Struct.new( :subject, :predicate, :object )
4
4
 
5
+ include CoreExt
6
+
5
7
  attr_reader :rete
6
8
 
7
9
  attr_reader :alphas, :tokens, :generating_tokens
8
10
  attr_reader :neg_join_results, :opt_join_results
11
+ attr_predicate :deleted
9
12
 
10
13
  def initialize s, p, o, r = nil
11
14
 
@@ -54,25 +57,21 @@ module Wongi::Engine
54
57
  !manual?
55
58
  end
56
59
 
57
- def deleted?
58
- @deleted
59
- end
60
+ # def destroy
61
+ # return if deleted?
62
+ # @deleted = true
63
+ # alphas.each { |alpha| alpha.remove self }.clear
64
+ # tokens = @tokens
65
+ # @tokens = []
66
+ # tokens.each &:destroy
60
67
 
61
- def destroy
62
- return if deleted?
63
- @deleted = true
64
- alphas.each { |alpha| alpha.remove self }.clear
65
- tokens = @tokens
66
- @tokens = []
67
- tokens.each &:destroy
68
+ # destroy_neg_join_results
69
+ # destroy_opt_join_results
68
70
 
69
- destroy_neg_join_results
70
- destroy_opt_join_results
71
-
72
- end
71
+ # end
73
72
 
74
73
  def inspect
75
- "<WME #{subject.inspect} #{predicate.inspect} #{object.inspect}>"
74
+ "{#{subject.inspect} #{predicate.inspect} #{object.inspect}}"
76
75
  end
77
76
 
78
77
  def to_s
@@ -89,38 +88,38 @@ module Wongi::Engine
89
88
  @array_form ||= [ subject, predicate, object ]
90
89
  end
91
90
 
92
- def destroy_neg_join_results
93
- neg_join_results.each do |njr|
91
+ # def destroy_neg_join_results
92
+ # neg_join_results.each do |njr|
94
93
 
95
- token = njr.owner
96
- results = token.neg_join_results
97
- results.delete njr
94
+ # token = njr.owner
95
+ # results = token.neg_join_results
96
+ # results.delete njr
98
97
 
99
- if results.empty? #&& !rete.in_snapshot?
100
- token.node.children.each { |beta|
101
- beta.beta_activate token, nil, { }
102
- }
103
- end
98
+ # if results.empty? #&& !rete.in_snapshot?
99
+ # token.node.children.each { |beta|
100
+ # beta.beta_activate token, nil, { }
101
+ # }
102
+ # end
104
103
 
105
- end.clear
106
- end
104
+ # end.clear
105
+ # end
107
106
 
108
- def destroy_opt_join_results
109
- opt_join_results.each do |ojr|
107
+ # def destroy_opt_join_results
108
+ # opt_join_results.each do |ojr|
110
109
 
111
- token = ojr.owner
112
- results = token.opt_join_results
113
- results.delete ojr
110
+ # token = ojr.owner
111
+ # results = token.opt_join_results
112
+ # results.delete ojr
114
113
 
115
- if results.empty?
116
- token.delete_children
117
- token.node.children.each { |beta|
118
- beta.beta_activate token
119
- }
120
- end
114
+ # if results.empty?
115
+ # token.delete_children
116
+ # token.node.children.each { |beta|
117
+ # beta.beta_activate token
118
+ # }
119
+ # end
121
120
 
122
- end.clear
123
- end
121
+ # end.clear
122
+ # end
124
123
 
125
124
  def match_member mine, theirs
126
125
  result = WMEMatchData.new