wongi-engine 0.4.0.pre.alpha9 → 0.4.0.pre.alpha11
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.
- checksums.yaml +4 -4
- data/lib/wongi-engine/beta/aggregate_node.rb +7 -7
- data/lib/wongi-engine/beta/beta_node.rb +2 -1
- data/lib/wongi-engine/dsl/action/statement_generator.rb +13 -19
- data/lib/wongi-engine/generator_tracker.rb +32 -0
- data/lib/wongi-engine/join_results.rb +80 -0
- data/lib/wongi-engine/network.rb +6 -10
- data/lib/wongi-engine/overlay.rb +79 -185
- data/lib/wongi-engine/token.rb +27 -47
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine.rb +2 -0
- data/spec/bug_specs/issue_4_spec.rb +12 -12
- data/spec/high_level_spec.rb +2 -2
- data/spec/overlay_spec.rb +0 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c6618cdaae22d90fec75bb11bbfeb27477d9aca0661d0de91ab04ce3b434ce6e
|
4
|
+
data.tar.gz: c9973d3a202faa0882653e99a3db546af9b02f6d1e09af075e4749681903743b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ec734eba8278f9ed3b8571b67a5e7449c4d172143673953d568bc4299383dc60579c295457010a3e9160de5698ecd529713dad80940751fce6c8b599d05dc91
|
7
|
+
data.tar.gz: ead1a3405786c7be13882c24ce8457ff31efa003bd9a84722073ff543ddff028b201c5d769756a2fadadfa84bbf0d5289db810f4e06d574c6b5960cb3a55302e
|
@@ -57,17 +57,17 @@ module Wongi::Engine
|
|
57
57
|
[tokens]
|
58
58
|
end
|
59
59
|
|
60
|
-
|
61
60
|
groups.each do |tokens|
|
62
|
-
aggregated =
|
61
|
+
aggregated = aggregate.call(tokens.map(&map))
|
63
62
|
assignment = { var => aggregated }
|
64
63
|
children = child ? [child] : self.children
|
65
|
-
tokens.each do |token|
|
66
|
-
# TODO: optimize this to work with a diff of actual changes
|
67
|
-
beta_deactivate_children(token: token, children: children)
|
68
|
-
end
|
69
64
|
children.each do |beta|
|
70
|
-
|
65
|
+
new_token = Token.new(beta, tokens, nil, assignment)
|
66
|
+
# nothing changed, skip useless traversal
|
67
|
+
next if beta.tokens.find { _1.duplicate?(new_token) }
|
68
|
+
|
69
|
+
beta.tokens.select { |child| tokens.any? { child.child_of?(_1) } }.each { beta.beta_deactivate(_1) }
|
70
|
+
beta.beta_activate(new_token)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
@@ -3,8 +3,6 @@ require "set"
|
|
3
3
|
module Wongi::Engine
|
4
4
|
module DSL::Action
|
5
5
|
class StatementGenerator < BaseAction
|
6
|
-
GeneratorOrigin = Struct.new(:token, :action)
|
7
|
-
|
8
6
|
attr_reader :template
|
9
7
|
private :template
|
10
8
|
|
@@ -23,13 +21,13 @@ module Wongi::Engine
|
|
23
21
|
production.tracer.trace(action: self, wme: wme) if production.tracer
|
24
22
|
|
25
23
|
if should_assert?(wme, token)
|
26
|
-
|
27
|
-
token.generated_wmes << wme
|
28
|
-
overlay.assert(wme, generator: origin)
|
24
|
+
overlay.assert(wme, generator: token)
|
29
25
|
end
|
30
26
|
end
|
31
27
|
|
32
28
|
private def should_assert?(wme, token)
|
29
|
+
return true if rete.bypass_consistency_checks?
|
30
|
+
|
33
31
|
considered_tokens = Set.new
|
34
32
|
tokens_to_consider = [token]
|
35
33
|
until tokens_to_consider.empty?
|
@@ -37,34 +35,30 @@ module Wongi::Engine
|
|
37
35
|
considered_tokens.add(token)
|
38
36
|
|
39
37
|
# self-affirming reasoning
|
40
|
-
|
38
|
+
if token.wme == wme
|
39
|
+
# puts "detected self-affirming"
|
40
|
+
return false
|
41
|
+
end
|
41
42
|
|
42
43
|
# asserting this WME would invalidate the match
|
43
44
|
# TODO: clean up
|
44
|
-
|
45
|
+
if token.node.is_a?(NegNode) && wme =~ token.node.alpha.template && token.node.matches?(token, wme) # how much is actually necessary?
|
46
|
+
# puts "detected self-negating"
|
47
|
+
return false
|
48
|
+
end
|
45
49
|
|
46
50
|
token.parents.each { |parent| tokens_to_consider.push(parent) unless considered_tokens.include?(parent) }
|
47
51
|
|
48
52
|
next unless token.wme
|
49
53
|
|
50
|
-
overlay.generators(token.wme).each do |
|
51
|
-
tokens_to_consider.push(
|
54
|
+
overlay.generators(token.wme).each do |generating_token|
|
55
|
+
tokens_to_consider.push(generating_token) unless considered_tokens.include?(generating_token)
|
52
56
|
end
|
53
57
|
end
|
54
58
|
|
55
59
|
# we could not prove that the new WME should not be asserted
|
56
60
|
true
|
57
61
|
end
|
58
|
-
|
59
|
-
def deexecute(token)
|
60
|
-
# p deexecute: {token:}
|
61
|
-
origin = GeneratorOrigin.new(token, self)
|
62
|
-
|
63
|
-
generated = token.generated_wmes.dup # select { overlay.generators(_1).include?(origin) }
|
64
|
-
generated.each do |wme|
|
65
|
-
overlay.retract wme, generator: origin
|
66
|
-
end
|
67
|
-
end
|
68
62
|
end
|
69
63
|
end
|
70
64
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
class GeneratorTracker
|
3
|
+
def initialize
|
4
|
+
@by_wme = Hash.new { |h, k| h[k] = Set.new }
|
5
|
+
@by_token = Hash.new { |h, k| h[k] = Set.new }
|
6
|
+
end
|
7
|
+
|
8
|
+
def add(wme, token)
|
9
|
+
@by_wme[wme].add(token)
|
10
|
+
@by_token[token.object_id].add(wme)
|
11
|
+
end
|
12
|
+
|
13
|
+
def for_wme(wme)
|
14
|
+
@by_wme.has_key?(wme) ? @by_wme[wme] : Set.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def for_token(token)
|
18
|
+
@by_token.has_key?(token.object_id) ? @by_token[token.object_id] : Set.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def remove_token(token)
|
22
|
+
wmes = for_token(token)
|
23
|
+
@by_token.delete(token.object_id)
|
24
|
+
wmes.each do |wme|
|
25
|
+
next unless @by_wme.key?(wme)
|
26
|
+
|
27
|
+
@by_wme[wme].delete(token)
|
28
|
+
@by_wme.delete(wme) if @by_wme[wme].empty?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
class JoinResults
|
3
|
+
attr_reader :by_wme, :by_token, :hidden
|
4
|
+
private :by_wme, :by_token
|
5
|
+
private :hidden
|
6
|
+
def initialize
|
7
|
+
@by_wme = Hash.new { |h, k| h[k] = {} }
|
8
|
+
@by_token = Hash.new { |h, k| h[k] = {} }
|
9
|
+
@hidden = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def for(wme: nil, token: nil)
|
13
|
+
if wme
|
14
|
+
by_wme.key?(wme) ? by_wme[wme].keys : []
|
15
|
+
elsif token
|
16
|
+
by_token.key?(token.object_id) ? by_token[token.object_id].keys : []
|
17
|
+
else
|
18
|
+
[]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def has?(jr)
|
23
|
+
by_wme.key?(jr.wme) && by_wme[jr.wme].key?(jr)
|
24
|
+
end
|
25
|
+
|
26
|
+
def hidden?(jr)
|
27
|
+
hidden.key?(jr)
|
28
|
+
end
|
29
|
+
|
30
|
+
def add(jr)
|
31
|
+
if hidden.key?(jr)
|
32
|
+
hidden.delete(jr)
|
33
|
+
else
|
34
|
+
by_wme[jr.wme][jr] = true
|
35
|
+
by_token[jr.token.object_id][jr] = true
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def remove(jr)
|
40
|
+
unless has?(jr)
|
41
|
+
hide(jr)
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
if by_wme.key?(jr.wme)
|
46
|
+
by_wme[jr.wme].delete(jr)
|
47
|
+
if by_wme[jr.wme].empty?
|
48
|
+
by_wme.delete(jr.wme)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
if by_token.key?(jr.token.object_id)
|
53
|
+
by_token[jr.token.object_id].delete(jr)
|
54
|
+
if by_token[jr.token.object_id].empty?
|
55
|
+
by_token.delete(jr.token.object_id)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def hide(jr)
|
61
|
+
hidden[jr] = true
|
62
|
+
end
|
63
|
+
|
64
|
+
def remove_token(token)
|
65
|
+
return unless by_token.key?(token.object_id)
|
66
|
+
|
67
|
+
by_token[token.object_id].keys.each do |jr|
|
68
|
+
remove(jr)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def remove_wme(wme)
|
73
|
+
return unless by_wme.key?(wme)
|
74
|
+
|
75
|
+
by_wme[wme].keys do |jr|
|
76
|
+
remove(jr)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/wongi-engine/network.rb
CHANGED
@@ -3,9 +3,12 @@ require 'wongi-engine/network/debug'
|
|
3
3
|
|
4
4
|
module Wongi::Engine
|
5
5
|
class Network
|
6
|
+
include CoreExt
|
6
7
|
attr_accessor :alpha_top, :beta_top, :queries, :results, :alpha_hash
|
7
8
|
attr_reader :productions, :overlays
|
8
9
|
|
10
|
+
attr_predicate :bypass_consistency_checks
|
11
|
+
|
9
12
|
include NetworkParts::Collectable
|
10
13
|
private :overlays
|
11
14
|
private :alpha_hash, :alpha_hash=
|
@@ -67,7 +70,6 @@ module Wongi::Engine
|
|
67
70
|
block.call(child)
|
68
71
|
ensure
|
69
72
|
remove_overlay(child)
|
70
|
-
child.dispose!
|
71
73
|
end
|
72
74
|
|
73
75
|
def alphas
|
@@ -203,9 +205,8 @@ module Wongi::Engine
|
|
203
205
|
compile_alpha Template.new(s, p, o)
|
204
206
|
end
|
205
207
|
|
206
|
-
# TODO: pick an alpha with fewer candidates to go through
|
207
208
|
def initial_fill(alpha)
|
208
|
-
default_overlay.select(:_, :_, :_).each do |wme|
|
209
|
+
default_overlay.select(:_, :_, :_).to_a.each do |wme|
|
209
210
|
alpha.activate wme if wme =~ alpha.template
|
210
211
|
end
|
211
212
|
end
|
@@ -254,16 +255,11 @@ module Wongi::Engine
|
|
254
255
|
end
|
255
256
|
|
256
257
|
def select(s, p, o, &block)
|
257
|
-
|
258
|
-
if block_given?
|
259
|
-
matching.each(&block)
|
260
|
-
else
|
261
|
-
matching.each
|
262
|
-
end
|
258
|
+
current_overlay.select(s, p, o, &block)
|
263
259
|
end
|
264
260
|
|
265
261
|
def find(s, p, o)
|
266
|
-
|
262
|
+
select(s, p, o).first
|
267
263
|
end
|
268
264
|
|
269
265
|
protected
|
data/lib/wongi-engine/overlay.rb
CHANGED
@@ -1,92 +1,13 @@
|
|
1
1
|
module Wongi::Engine
|
2
2
|
class Overlay
|
3
|
-
class JoinResults
|
4
|
-
attr_reader :by_wme, :by_token, :hidden
|
5
|
-
private :by_wme, :by_token
|
6
|
-
private :hidden
|
7
|
-
def initialize
|
8
|
-
@by_wme = Hash.new { |h, k| h[k] = {} }
|
9
|
-
@by_token = Hash.new { |h, k| h[k] = {} }
|
10
|
-
@hidden = {}
|
11
|
-
end
|
12
|
-
|
13
|
-
def for(wme: nil, token: nil)
|
14
|
-
if wme
|
15
|
-
by_wme.key?(wme) ? by_wme[wme].keys : []
|
16
|
-
elsif token
|
17
|
-
by_token.key?(token.object_id) ? by_token[token.object_id].keys : []
|
18
|
-
else
|
19
|
-
[]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def has?(jr)
|
24
|
-
by_wme.key?(jr.wme) && by_wme[jr.wme].key?(jr)
|
25
|
-
end
|
26
|
-
|
27
|
-
def hidden?(jr)
|
28
|
-
hidden.key?(jr)
|
29
|
-
end
|
30
3
|
|
31
|
-
|
32
|
-
if hidden.key?(jr)
|
33
|
-
hidden.delete(jr)
|
34
|
-
else
|
35
|
-
by_wme[jr.wme][jr] = true
|
36
|
-
by_token[jr.token.object_id][jr] = true
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def remove(jr)
|
41
|
-
unless has?(jr)
|
42
|
-
hide(jr)
|
43
|
-
return
|
44
|
-
end
|
45
|
-
|
46
|
-
if by_wme.key?(jr.wme)
|
47
|
-
by_wme[jr.wme].delete(jr)
|
48
|
-
if by_wme[jr.wme].empty?
|
49
|
-
by_wme.delete(jr.wme)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
if by_token.key?(jr.token.object_id)
|
54
|
-
by_token[jr.token.object_id].delete(jr)
|
55
|
-
if by_token[jr.token.object_id].empty?
|
56
|
-
by_token.delete(jr.token.object_id)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def hide(jr)
|
62
|
-
hidden[jr] = true
|
63
|
-
end
|
64
|
-
|
65
|
-
def remove_token(token)
|
66
|
-
return unless by_token.key?(token.object_id)
|
67
|
-
|
68
|
-
by_token[token.object_id].keys.each do |jr|
|
69
|
-
remove(jr)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def remove_wme(wme)
|
74
|
-
return unless by_wme.key?(wme)
|
75
|
-
|
76
|
-
by_wme[wme].keys do |jr|
|
77
|
-
remove(jr)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
attr_reader :rete, :parent, :wmes, :tokens, :indexes, :queue, :hidden_parent_wmes, :hidden_parent_tokens, :wme_generators, :hidden_parent_wme_generators, :wme_manual, :hidden_parent_wme_manual, :neg_join_results, :opt_join_results, :ncc_tokens, :ncc_tokens_owner, :hidden_ncc_tokens
|
4
|
+
attr_reader :rete, :parent, :wmes, :tokens, :indexes, :queue, :hidden_parent_wmes, :hidden_parent_tokens, :generator_tracker, :wme_manual, :hidden_parent_wme_manual, :neg_join_results, :opt_join_results, :ncc_tokens, :ncc_tokens_owner, :hidden_ncc_tokens
|
83
5
|
private :wmes, :tokens
|
84
6
|
private :indexes
|
85
7
|
private :queue
|
86
8
|
private :hidden_parent_wmes
|
87
9
|
private :hidden_parent_tokens
|
88
|
-
private :
|
89
|
-
private :hidden_parent_wme_generators
|
10
|
+
private :generator_tracker
|
90
11
|
private :wme_manual
|
91
12
|
private :hidden_parent_wme_manual
|
92
13
|
private :neg_join_results
|
@@ -111,10 +32,9 @@ module Wongi::Engine
|
|
111
32
|
@hidden_parent_wmes = {}
|
112
33
|
|
113
34
|
@tokens = Hash.new { |h, k| h[k] = [] }
|
114
|
-
@hidden_parent_tokens =
|
35
|
+
@hidden_parent_tokens = Set.new
|
115
36
|
|
116
|
-
@
|
117
|
-
@hidden_parent_wme_generators = {}
|
37
|
+
@generator_tracker = GeneratorTracker.new
|
118
38
|
|
119
39
|
@wme_manual = {}
|
120
40
|
@hidden_parent_wme_manual = {}
|
@@ -140,14 +60,6 @@ module Wongi::Engine
|
|
140
60
|
parent.ancestor?(other)
|
141
61
|
end
|
142
62
|
|
143
|
-
def dispose!
|
144
|
-
return if default?
|
145
|
-
|
146
|
-
tokens.each do |_node, tokens|
|
147
|
-
tokens.each(&:dispose!)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
63
|
def <<(thing)
|
152
64
|
case thing
|
153
65
|
when Array
|
@@ -180,19 +92,23 @@ module Wongi::Engine
|
|
180
92
|
def run_queue
|
181
93
|
until queue.empty?
|
182
94
|
operation, wme, options = queue.shift
|
95
|
+
|
183
96
|
case operation
|
184
97
|
when :assert
|
185
|
-
|
98
|
+
existing_wme = find_ignoring_hidden(wme)
|
99
|
+
wme = existing_wme || wme
|
186
100
|
visible = !find(wme).nil?
|
187
101
|
add_wme(wme, **options)
|
188
102
|
rete.real_assert(wme) unless visible
|
103
|
+
|
189
104
|
when :retract
|
190
105
|
wme = find_ignoring_hidden(wme)
|
191
|
-
|
106
|
+
if wme # it's perhaps better to return quietly, because complicated cascades may delete a WME while we're going through the queue
|
107
|
+
visible = !find(wme).nil?
|
108
|
+
remove_wme(wme, **options)
|
109
|
+
rete.real_retract(wme) if visible
|
110
|
+
end
|
192
111
|
|
193
|
-
visible = !find(wme).nil?
|
194
|
-
remove_wme(wme, **options)
|
195
|
-
rete.real_retract(wme) if visible
|
196
112
|
end
|
197
113
|
end
|
198
114
|
end
|
@@ -226,12 +142,12 @@ module Wongi::Engine
|
|
226
142
|
when 1
|
227
143
|
case args.first
|
228
144
|
when Template
|
229
|
-
|
145
|
+
each_by_template(args.first)
|
230
146
|
else
|
231
147
|
raise ArgumentError
|
232
148
|
end
|
233
149
|
when 3
|
234
|
-
|
150
|
+
each_by_template(Template.new(*args))
|
235
151
|
else
|
236
152
|
raise ArgumentError
|
237
153
|
end
|
@@ -248,28 +164,22 @@ module Wongi::Engine
|
|
248
164
|
generators(wme).any?
|
249
165
|
end
|
250
166
|
|
251
|
-
def
|
252
|
-
|
167
|
+
def generators(wme)
|
168
|
+
Enumerator.new do |y|
|
169
|
+
generator_tracker.for_wme(wme).each { y << _1 }
|
253
170
|
if parent
|
254
|
-
parent.
|
255
|
-
else
|
256
|
-
false
|
171
|
+
parent.generators(wme).reject { hidden_token?(_1) }.each { y << _1 }
|
257
172
|
end
|
173
|
+
end
|
258
174
|
end
|
259
175
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
own_generators = wme_generators.key?(wme) ? wme_generators[wme] : []
|
266
|
-
parent_generators =
|
267
|
-
if parent
|
268
|
-
parent.generators(wme).reject { |g| hidden_parent_wme_generators.key?(g) }
|
269
|
-
else
|
270
|
-
[]
|
176
|
+
def generated_wmes(token)
|
177
|
+
Enumerator.new do |y|
|
178
|
+
generator_tracker.for_token(token).each { y << _1 }
|
179
|
+
if parent && !hidden_token?(token)
|
180
|
+
parent.generated_wmes(token).reject { hidden_wme?(_1) }.each { y << _1 }
|
271
181
|
end
|
272
|
-
|
182
|
+
end
|
273
183
|
end
|
274
184
|
|
275
185
|
private def own_manual?(wme)
|
@@ -277,7 +187,7 @@ module Wongi::Engine
|
|
277
187
|
end
|
278
188
|
|
279
189
|
private def own_generated?(wme)
|
280
|
-
|
190
|
+
generator_tracker.for_wme(wme).any?
|
281
191
|
end
|
282
192
|
|
283
193
|
private def find_wme(wme)
|
@@ -285,7 +195,11 @@ module Wongi::Engine
|
|
285
195
|
end
|
286
196
|
|
287
197
|
private def find_own_wme(wme)
|
288
|
-
|
198
|
+
has_own_wme?(wme) ? wme : nil
|
199
|
+
end
|
200
|
+
|
201
|
+
private def has_own_wme?(wme)
|
202
|
+
wmes.include?(wme)
|
289
203
|
end
|
290
204
|
|
291
205
|
private def find_parents_wme(wme)
|
@@ -302,28 +216,29 @@ module Wongi::Engine
|
|
302
216
|
end
|
303
217
|
end
|
304
218
|
|
305
|
-
|
306
|
-
|
219
|
+
def each_by_template(template)
|
220
|
+
Enumerator.new do |y|
|
221
|
+
each_own_wme_by_template(template, y)
|
222
|
+
each_parent_wme_by_template(template, y)
|
223
|
+
end
|
307
224
|
end
|
308
225
|
|
309
|
-
private def
|
226
|
+
private def each_own_wme_by_template(template, y)
|
310
227
|
if template.concrete?
|
311
228
|
wme = find_own_wme(WME.from_concrete_template(template))
|
312
|
-
|
229
|
+
y << wme if wme
|
313
230
|
elsif template.root?
|
314
|
-
wmes
|
231
|
+
wmes.each { y << _1 }
|
315
232
|
else
|
316
233
|
indexes.map { |index|
|
317
234
|
index.collections_for_template(template)
|
318
|
-
}.compact.first
|
235
|
+
}.compact.first.each { y << _1 }
|
319
236
|
end
|
320
237
|
end
|
321
238
|
|
322
|
-
private def
|
239
|
+
private def each_parent_wme_by_template(template, y)
|
323
240
|
if parent
|
324
|
-
parent.
|
325
|
-
else
|
326
|
-
Set.new
|
241
|
+
parent.each_by_template(template).reject { hidden_wme?(_1) }.each { y << _1 }
|
327
242
|
end
|
328
243
|
end
|
329
244
|
|
@@ -332,32 +247,17 @@ module Wongi::Engine
|
|
332
247
|
|
333
248
|
# if we previously hid this locally, unhide it
|
334
249
|
hidden_parent_wmes.delete(wme)
|
335
|
-
if generator
|
336
|
-
hidden_parent_wme_generators.delete(generator)
|
337
|
-
else
|
338
|
-
hidden_parent_wme_manual.delete(wme)
|
339
|
-
end
|
340
250
|
|
341
|
-
|
342
|
-
if generator
|
343
|
-
wme_generators[wme] << generator unless own_generated_by?(wme, generator)
|
344
|
-
else
|
345
|
-
wme_manual[wme] = true
|
346
|
-
end
|
347
|
-
elsif find_parents_wme(wme)
|
348
|
-
if generator
|
349
|
-
wme_generators[wme] << generator unless generated_by?(wme, generator)
|
350
|
-
else
|
351
|
-
wme_manual[wme] = true unless manual?(wme)
|
352
|
-
end
|
353
|
-
else
|
251
|
+
unless has_own_wme?(wme)
|
354
252
|
wmes.add(wme)
|
355
253
|
indexes.each { _1.add(wme) }
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
254
|
+
end
|
255
|
+
|
256
|
+
if generator
|
257
|
+
generator_tracker.add(wme, generator)
|
258
|
+
else
|
259
|
+
hidden_parent_wme_manual.delete(wme)
|
260
|
+
wme_manual[wme] = true
|
361
261
|
end
|
362
262
|
end
|
363
263
|
|
@@ -365,15 +265,9 @@ module Wongi::Engine
|
|
365
265
|
# p remove_wme: { wme:, generator: !!generator }
|
366
266
|
|
367
267
|
if find_own_wme(wme)
|
368
|
-
if generator
|
369
|
-
if own_generated_by?(wme, generator)
|
370
|
-
wme_generators[wme].delete(generator)
|
371
|
-
wme_generators.delete(wme) if wme_generators[wme].empty?
|
372
|
-
end
|
373
|
-
elsif own_manual?(wme)
|
374
|
-
wme_manual.delete(wme)
|
375
|
-
end
|
268
|
+
wme_manual.delete(wme) if generator.nil?
|
376
269
|
|
270
|
+
# no remaining reasons to keep this WME around
|
377
271
|
if !own_generated?(wme) && !own_manual?(wme)
|
378
272
|
wmes.delete(wme)
|
379
273
|
indexes.each { _1.remove(wme) }
|
@@ -388,23 +282,10 @@ module Wongi::Engine
|
|
388
282
|
|
389
283
|
# must be parents' then
|
390
284
|
|
391
|
-
if generator
|
392
|
-
|
393
|
-
if
|
394
|
-
|
395
|
-
wme_generators.delete(wme) if wme_generators[wme].empty?
|
396
|
-
end
|
397
|
-
# if we're still generated, hide parents'
|
398
|
-
if generated_by?(wme, generator)
|
399
|
-
hidden_parent_wme_generators[generator] = true
|
400
|
-
end
|
401
|
-
else
|
402
|
-
if own_manual?(wme)
|
403
|
-
wme_manual.delete(wme)
|
404
|
-
end
|
405
|
-
if manual?(wme)
|
406
|
-
hidden_parent_wme_manual[wme] = true
|
407
|
-
end
|
285
|
+
if generator.nil?
|
286
|
+
wme_manual.delete(wme)
|
287
|
+
# if still manual, it must be from the parent
|
288
|
+
hidden_parent_wme_manual[wme] = true if manual?(wme)
|
408
289
|
end
|
409
290
|
|
410
291
|
if !manual?(wme) && !generated?(wme)
|
@@ -416,7 +297,8 @@ module Wongi::Engine
|
|
416
297
|
# p add_token: {token:}
|
417
298
|
# TODO: is this really likely to happen? we don't normally restore deleted tokens but rather create new ones in the activation
|
418
299
|
if hidden_token?(token)
|
419
|
-
|
300
|
+
puts "odd case"
|
301
|
+
unhide_token(token)
|
420
302
|
return
|
421
303
|
end
|
422
304
|
|
@@ -425,9 +307,13 @@ module Wongi::Engine
|
|
425
307
|
|
426
308
|
def remove_token(token)
|
427
309
|
# p remove_token: {token:}
|
310
|
+
|
311
|
+
# capture the entire enumerated state
|
312
|
+
wmes = generated_wmes(token).to_a
|
313
|
+
|
428
314
|
if own_node_tokens(token.node).find { _1.equal?(token) }.nil?
|
429
315
|
if parents_node_tokens(token.node).find { _1.equal?(token) }
|
430
|
-
|
316
|
+
hide_token(token)
|
431
317
|
|
432
318
|
# do not hide JRs from the WME side: it will be done in the alpha deactivation and the JRs have to stay visible until then
|
433
319
|
parent_neg_join_results_for(token: token).each { neg_join_results.hide(_1) }
|
@@ -437,10 +323,12 @@ module Wongi::Engine
|
|
437
323
|
hidden_ncc_tokens[token][ncc] = true
|
438
324
|
end
|
439
325
|
end
|
440
|
-
|
326
|
+
else
|
327
|
+
remove_own_token(token)
|
441
328
|
end
|
442
329
|
|
443
|
-
|
330
|
+
wmes.each { retract(_1, generator: token) }
|
331
|
+
|
444
332
|
end
|
445
333
|
|
446
334
|
def remove_own_token(token)
|
@@ -448,6 +336,7 @@ module Wongi::Engine
|
|
448
336
|
tokens[token.node.object_id].delete(token)
|
449
337
|
neg_join_results.remove_token(token)
|
450
338
|
opt_join_results.remove_token(token)
|
339
|
+
generator_tracker.remove_token(token)
|
451
340
|
|
452
341
|
# if this is an NCC partner token
|
453
342
|
if (owner = ncc_tokens_owner[token])
|
@@ -465,9 +354,6 @@ module Wongi::Engine
|
|
465
354
|
end
|
466
355
|
ncc_tokens.delete(token)
|
467
356
|
hidden_ncc_tokens.delete(token)
|
468
|
-
|
469
|
-
# we know we are the owner, and nobody wants it anymore, so this is the safe place to do it
|
470
|
-
token.dispose!
|
471
357
|
end
|
472
358
|
|
473
359
|
def node_tokens(beta)
|
@@ -482,7 +368,7 @@ module Wongi::Engine
|
|
482
368
|
|
483
369
|
private def parents_node_tokens(beta)
|
484
370
|
if parent
|
485
|
-
parent.node_tokens(beta).reject {
|
371
|
+
parent.node_tokens(beta).reject { hidden_token?(_1) }
|
486
372
|
else
|
487
373
|
[]
|
488
374
|
end
|
@@ -581,7 +467,15 @@ module Wongi::Engine
|
|
581
467
|
end
|
582
468
|
|
583
469
|
private def hidden_token?(token)
|
584
|
-
hidden_parent_tokens.
|
470
|
+
hidden_parent_tokens.include?(token.object_id)
|
471
|
+
end
|
472
|
+
|
473
|
+
private def hide_token(token)
|
474
|
+
hidden_parent_tokens.add(token.object_id)
|
475
|
+
end
|
476
|
+
|
477
|
+
private def unhide_token(token)
|
478
|
+
hidden_parent_tokens.delete(token.object_id)
|
585
479
|
end
|
586
480
|
end
|
587
481
|
end
|
data/lib/wongi-engine/token.rb
CHANGED
@@ -2,16 +2,13 @@ require 'set'
|
|
2
2
|
|
3
3
|
module Wongi::Engine
|
4
4
|
class Token
|
5
|
-
attr_reader :wme, :node, :
|
5
|
+
attr_reader :wme, :node, :parents
|
6
6
|
|
7
7
|
def initialize(node, parents, wme, assignments = {})
|
8
8
|
@node = node
|
9
9
|
@parents = Set.new(Array(parents))
|
10
10
|
@wme = wme
|
11
11
|
@assignments = assignments
|
12
|
-
@deleted = false
|
13
|
-
@ncc_results = []
|
14
|
-
@generated_wmes = []
|
15
12
|
end
|
16
13
|
|
17
14
|
def ancestors
|
@@ -30,12 +27,18 @@ module Wongi::Engine
|
|
30
27
|
@assignments[variable] = value
|
31
28
|
end
|
32
29
|
|
30
|
+
def own_assignments
|
31
|
+
@assignments
|
32
|
+
end
|
33
|
+
|
33
34
|
def assignments
|
34
|
-
|
35
|
+
parents.each_with_object({}) do |parent, acc|
|
36
|
+
acc.merge!(parent.assignments)
|
37
|
+
end.merge(own_assignments)
|
35
38
|
end
|
36
39
|
|
37
40
|
def [](var)
|
38
|
-
a =
|
41
|
+
a = assignment(var)
|
39
42
|
a.respond_to?(:call) ? a.call(self) : a
|
40
43
|
end
|
41
44
|
|
@@ -43,8 +46,23 @@ module Wongi::Engine
|
|
43
46
|
vars.map { self[_1] }
|
44
47
|
end
|
45
48
|
|
49
|
+
def assignment(x)
|
50
|
+
return @assignments[x] if has_own_var?(x)
|
51
|
+
|
52
|
+
parents.each do |parent|
|
53
|
+
a = parent.assignment(x)
|
54
|
+
return a if a
|
55
|
+
end
|
56
|
+
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
46
60
|
def has_var?(x)
|
47
|
-
|
61
|
+
has_own_var?(x) || parents.any? { _1.has_var?(x) }
|
62
|
+
end
|
63
|
+
|
64
|
+
def has_own_var?(x)
|
65
|
+
@assignments.key?(x)
|
48
66
|
end
|
49
67
|
|
50
68
|
# TODO: ignore assignments?
|
@@ -52,12 +70,12 @@ module Wongi::Engine
|
|
52
70
|
instance_of?(other.class) &&
|
53
71
|
parents == other.parents &&
|
54
72
|
wme == other.wme &&
|
55
|
-
|
73
|
+
own_assignments == other.own_assignments
|
56
74
|
end
|
57
75
|
|
58
76
|
def to_s
|
59
77
|
str = "TOKEN [ #{object_id} ancestors=#{ancestors.map(&:object_id).map(&:to_s).join('.')} "
|
60
|
-
|
78
|
+
assignments.each_pair { |key, value| str << "#{key}=#{value.is_a?(TokenAssignment) ? "#{value.call} (#{value})" : value} " }
|
61
79
|
str << "]"
|
62
80
|
str
|
63
81
|
end
|
@@ -65,43 +83,5 @@ module Wongi::Engine
|
|
65
83
|
def inspect
|
66
84
|
to_s
|
67
85
|
end
|
68
|
-
|
69
|
-
# def destroy
|
70
|
-
# deleted!
|
71
|
-
# end
|
72
|
-
|
73
|
-
def dispose!
|
74
|
-
# parent.children.delete(self) if parent
|
75
|
-
# @parent = nil
|
76
|
-
@wme = nil
|
77
|
-
end
|
78
|
-
|
79
|
-
# for neg feedback loop protection
|
80
|
-
# def generated?(wme)
|
81
|
-
# return true if generated_wmes.any? { |w| w == wme }
|
82
|
-
#
|
83
|
-
# children.any? { |t| t.generated? wme }
|
84
|
-
# end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def all_assignments
|
89
|
-
parents.each_with_object({}) do |parent, acc|
|
90
|
-
acc.merge!(parent.assignments)
|
91
|
-
end.merge(@assignments)
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
class FakeToken < Token
|
96
|
-
def initialize(token, wme, assignments) # rubocop:disable Lint/MissingSuper
|
97
|
-
@parent = token
|
98
|
-
@wme = wme
|
99
|
-
@assignments = assignments
|
100
|
-
# @children = []
|
101
|
-
@neg_join_results = []
|
102
|
-
@opt_join_results = []
|
103
|
-
@ncc_results = []
|
104
|
-
@generated_wmes = []
|
105
|
-
end
|
106
86
|
end
|
107
87
|
end
|
data/lib/wongi-engine/version.rb
CHANGED
data/lib/wongi-engine.rb
CHANGED
@@ -28,6 +28,8 @@ require 'wongi-engine/beta'
|
|
28
28
|
require 'wongi-engine/dsl'
|
29
29
|
require 'wongi-engine/ruleset'
|
30
30
|
require 'wongi-engine/compiler'
|
31
|
+
require 'wongi-engine/join_results'
|
32
|
+
require 'wongi-engine/generator_tracker'
|
31
33
|
require 'wongi-engine/overlay'
|
32
34
|
require 'wongi-engine/enumerators'
|
33
35
|
require 'wongi-engine/network'
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "issue 4" do
|
4
|
-
it "
|
4
|
+
it "correctly retracts pre-added items from within a rule" do
|
5
5
|
engine = Wongi::Engine.create
|
6
6
|
|
7
7
|
10.times { |i| engine << [i, :is_number, true] }
|
@@ -22,11 +22,11 @@ describe "issue 4" do
|
|
22
22
|
numbers = engine.select :_, :is_number, true
|
23
23
|
evens = engine.select :_, :is_even, true
|
24
24
|
|
25
|
-
expect(numbers.
|
26
|
-
expect(evens.
|
25
|
+
expect(numbers.count).to eq(0)
|
26
|
+
expect(evens.count).to eq(10)
|
27
27
|
end
|
28
28
|
|
29
|
-
it "
|
29
|
+
it "correctly retracts post-added items from within a rule" do
|
30
30
|
engine = Wongi::Engine.create
|
31
31
|
|
32
32
|
engine.rule 'segregate' do
|
@@ -47,8 +47,8 @@ describe "issue 4" do
|
|
47
47
|
numbers = engine.select :_, :is_number, true
|
48
48
|
evens = engine.select :_, :is_even, true
|
49
49
|
|
50
|
-
expect(numbers.
|
51
|
-
expect(evens.
|
50
|
+
expect(numbers.count).to eq(0)
|
51
|
+
expect(evens.count).to eq(5)
|
52
52
|
end
|
53
53
|
|
54
54
|
# cascaded processing affects this
|
@@ -80,9 +80,9 @@ describe "issue 4" do
|
|
80
80
|
evens = engine.select :_, :is_even, true
|
81
81
|
odds = engine.select :_, :is_odd, true
|
82
82
|
|
83
|
-
expect(numbers.
|
84
|
-
expect(evens.
|
85
|
-
expect(odds.
|
83
|
+
expect(numbers.count).to eq(0)
|
84
|
+
expect(evens.count).to eq(5)
|
85
|
+
expect(odds.count).to eq(5)
|
86
86
|
end
|
87
87
|
|
88
88
|
it "does not lose track when another rule affects a set" do
|
@@ -126,8 +126,8 @@ describe "issue 4" do
|
|
126
126
|
evens = engine.select :_, :is_even, true
|
127
127
|
odds = engine.select :_, :is_odd, true
|
128
128
|
|
129
|
-
expect(numbers.
|
130
|
-
expect(evens.
|
131
|
-
expect(odds.
|
129
|
+
expect(numbers.count).to eq(5)
|
130
|
+
expect(evens.count).to eq(5)
|
131
|
+
expect(odds.count).to eq(5)
|
132
132
|
end
|
133
133
|
end
|
data/spec/high_level_spec.rb
CHANGED
@@ -115,10 +115,10 @@ describe Wongi::Engine::Network do
|
|
115
115
|
engine << ["Bob", :age, 43]
|
116
116
|
|
117
117
|
items = engine.select "Alice", :younger, "Bob"
|
118
|
-
expect(items.
|
118
|
+
expect(items.count).to eq(1)
|
119
119
|
|
120
120
|
items = engine.select "Bob", :older, "Alice"
|
121
|
-
expect(items.
|
121
|
+
expect(items.count).to eq(1)
|
122
122
|
end
|
123
123
|
|
124
124
|
it 'uses collectors' do
|
data/spec/overlay_spec.rb
CHANGED
@@ -136,11 +136,6 @@ describe Wongi::Engine::Overlay do
|
|
136
136
|
|
137
137
|
overlay.retract(wme)
|
138
138
|
expect(overlay.find(wme)).to be_nil
|
139
|
-
expect(child1.find(wme)).to be_nil
|
140
|
-
expect(child2.find(wme)).to be_nil
|
141
|
-
|
142
|
-
child1.assert(wme)
|
143
|
-
expect(overlay.find(wme)).to be_nil
|
144
139
|
expect(child1.find(wme)).to eq(wme)
|
145
140
|
expect(child2.find(wme)).to eq(wme)
|
146
141
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wongi-engine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.0.pre.
|
4
|
+
version: 0.4.0.pre.alpha11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valeri Sokolov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-11-
|
11
|
+
date: 2022-11-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -139,7 +139,9 @@ files:
|
|
139
139
|
- lib/wongi-engine/filter/inequality_test.rb
|
140
140
|
- lib/wongi-engine/filter/less_than_or_equal_test.rb
|
141
141
|
- lib/wongi-engine/filter/less_than_test.rb
|
142
|
+
- lib/wongi-engine/generator_tracker.rb
|
142
143
|
- lib/wongi-engine/graph.rb
|
144
|
+
- lib/wongi-engine/join_results.rb
|
143
145
|
- lib/wongi-engine/network.rb
|
144
146
|
- lib/wongi-engine/network/collectable.rb
|
145
147
|
- lib/wongi-engine/network/debug.rb
|