wongi-engine 0.0.2 → 0.0.3

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,6 +1,7 @@
1
1
  require 'wongi-engine/beta/beta_node'
2
2
  require 'wongi-engine/beta/beta_memory'
3
3
  require 'wongi-engine/beta/filter_node'
4
+ require 'wongi-engine/beta/assignment_node'
4
5
  require 'wongi-engine/beta/join_node'
5
6
  require 'wongi-engine/beta/ncc_partner'
6
7
  require 'wongi-engine/beta/ncc_node'
@@ -55,7 +55,7 @@ dsl {
55
55
  accept Wongi::Engine::NccProductionRule
56
56
 
57
57
  clause :any
58
- action Wongi::Engine::AnyRule
58
+ accept Wongi::Engine::AnyRule
59
59
 
60
60
  clause :maybe, :optional
61
61
  accept Wongi::Engine::OptionalTemplate
@@ -66,6 +66,12 @@ dsl {
66
66
  clause :diff, :ne
67
67
  accept Wongi::Engine::InequalityTest
68
68
 
69
+ clause :assert, :dynamic
70
+ accept Wongi::Engine::AssertingTest
71
+
72
+ clause :assign, :introduce
73
+ accept Wongi::Engine::Assignment
74
+
69
75
  clause :asserted, :added
70
76
  body { |s, p, o|
71
77
  missing s, p, o, -1
@@ -0,0 +1,20 @@
1
+ module Wongi::Engine
2
+
3
+ class AssertingTest < FilterTest
4
+
5
+ def initialize *vars, &body
6
+ @vars = vars
7
+ @body = body
8
+ end
9
+
10
+ def passes? token
11
+ if @vars.empty?
12
+ @body.call token
13
+ else
14
+ @body.call *( @vars.map { |var| token[var] } )
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ end
@@ -0,0 +1,36 @@
1
+ module Wongi::Engine
2
+
3
+ class EqualityTest < FilterTest
4
+
5
+ attr_reader :x, :y
6
+
7
+ def initialize x, y
8
+ @x, @y = x, y
9
+ end
10
+
11
+ def passes? token
12
+
13
+ x = if Template.variable? @x
14
+ token[@x]
15
+ else
16
+ @x
17
+ end
18
+
19
+ y = if Template.variable? @y
20
+ token[@y]
21
+ else
22
+ @y
23
+ end
24
+
25
+ return false if x == :_ || y == :_
26
+ return x == y
27
+
28
+ end
29
+
30
+ def == other
31
+ super && x == other.x && y == other.y
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,21 @@
1
+ module Wongi::Engine
2
+
3
+ class FilterTest
4
+
5
+ def passes? token
6
+ raise "#{self.class} must implement #passes?"
7
+ end
8
+
9
+ def compile context
10
+ context.node = context.node.beta_memory.filter_node( self )
11
+ context.earlier << self
12
+ context
13
+ end
14
+
15
+ def == other
16
+ self.class == other.class
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,36 @@
1
+ module Wongi::Engine
2
+
3
+ class InequalityTest < FilterTest
4
+
5
+ attr_reader :x, :y
6
+
7
+ def initialize x, y
8
+ @x, @y = x, y
9
+ end
10
+
11
+ def passes? token
12
+
13
+ x = if Template.variable? @x
14
+ token[@x]
15
+ else
16
+ @x
17
+ end
18
+
19
+ y = if Template.variable? @y
20
+ token[@y]
21
+ else
22
+ @y
23
+ end
24
+
25
+ return false if x == :_ || y == :_
26
+ return x != y
27
+
28
+ end
29
+
30
+ def == other
31
+ super && x == other.x && y == other.y
32
+ end
33
+
34
+ end
35
+
36
+ end
@@ -0,0 +1,4 @@
1
+ require 'wongi-engine/filter/filter_test'
2
+ require 'wongi-engine/filter/equality_test'
3
+ require 'wongi-engine/filter/inequality_test'
4
+ require 'wongi-engine/filter/asserting_test'
@@ -18,6 +18,66 @@ module Wongi::Engine
18
18
  end
19
19
  end
20
20
 
21
+ def full_dump io = $stdout
22
+
23
+ alpha_hash.each_value do |alpha|
24
+ io.puts "ALPHA #{alpha.template}"
25
+ alpha.wmes.each do |wme|
26
+ dump_wme wme, io
27
+ end
28
+ end
29
+ dump_beta beta_top, io
30
+
31
+ end
32
+
33
+ private
34
+
35
+ def token_lineage token
36
+ result = []
37
+ while token.parent
38
+ result << token.parent
39
+ token = token.parent
40
+ end
41
+ result
42
+ end
43
+
44
+ def dump_wme wme, io
45
+ io.puts "\tWME: #{wme.object_id} #{wme}"
46
+ wme.tokens.each { |token| io.puts "\t\tTOKEN #{token.object_id}" }
47
+ io.puts "\tGENERATING:" unless wme.generating_tokens.empty?
48
+ wme.generating_tokens.each { |token| io.puts "\t\tTOKEN #{token.object_id}" }
49
+ end
50
+
51
+ def dump_beta beta, io
52
+ case beta
53
+ when BetaMemory
54
+ dump_beta_memory beta, io
55
+ when NccNode
56
+ dump_ncc beta, io
57
+ else
58
+ io.puts "BETA #{beta.object_id} #{beta.class} : TODO"
59
+
60
+ end
61
+ io.puts "\tCHILDREN: #{beta.children.map(&:object_id).join ", "}"
62
+ beta.children.each { |child| dump_beta child, io } unless beta.children.empty?
63
+ end
64
+
65
+ def dump_beta_memory beta, io
66
+ io.puts "BETA MEMORY #{beta.object_id}"
67
+ beta.tokens.each { |token|
68
+ io.puts "\tTOKEN #{token.object_id} [#{token_lineage(token).map(&:object_id).map(&:to_s).join(" - ")}]"
69
+ token.wmes.each { |wme| io.puts "\t\tWME " + wme.object_id.to_s }
70
+ }
71
+ end
72
+
73
+ def dump_ncc beta, io
74
+ io.puts "NCC #{beta.object_id}"
75
+ beta.tokens.each { |token|
76
+ io.puts "\tTOKEN #{token.object_id} [#{token_lineage(token).map(&:object_id).map(&:to_s).join(" - ")}]"
77
+ token.wmes.each { |wme| io.puts "\t\tWME " + wme.object_id.to_s }
78
+ }
79
+ end
80
+
21
81
  end
22
82
 
23
83
  end
@@ -169,6 +169,10 @@ module Wongi::Engine
169
169
 
170
170
  def retract wme, is_real = false
171
171
 
172
+ if wme.is_a? Array
173
+ return retract( WME.new(*wme), is_real )
174
+ end
175
+
172
176
  if ! is_real
173
177
  if @current_context
174
178
  @current_context.retracted_wmes << wme
@@ -386,7 +390,7 @@ module Wongi::Engine
386
390
  beta = root.network conditions, [], parameters, alpha_deaf
387
391
 
388
392
  production = ProductionNode.new( beta, actions )
389
- production.update_above
393
+ production.refresh
390
394
  production
391
395
  end
392
396
 
@@ -19,7 +19,6 @@ module Wongi::Engine
19
19
  @opt_join_results = []
20
20
  @ncc_results = []
21
21
  @generated_wmes = []
22
- @deexecutors = []
23
22
  token.children << self if token
24
23
  wme.tokens << self if wme
25
24
  end
@@ -48,51 +47,21 @@ module Wongi::Engine
48
47
 
49
48
  def wmes
50
49
  if parent
51
- parent.wmes + [wme]
50
+ parent.wmes + (wme ? [wme] : [])
52
51
  else
53
- [wme]
52
+ wme ? [wme] : []
54
53
  end
55
54
  end
56
55
 
57
- def delete preserve_self = false
56
+ def delete
58
57
  delete_children
59
- # => TODO: why was this last check needed? consult the Rete PhD
60
- @node.tokens.delete self unless preserve_self# or @node.kind_of?( NccPartner )
58
+ @node.tokens.delete self unless @node.kind_of?( NccPartner )
61
59
  @wme.tokens.delete self if @wme
62
60
  @parent.children.delete self if @parent
63
61
 
64
62
  retract_generated
65
- deexecute
66
-
67
- case @node
68
- when NegNode
69
- @neg_join_results.each do |njr|
70
- njr.wme.neg_join_results.delete njr if njr.wme
71
- end
72
- @neg_join_results = []
73
-
74
- when OptionalNode
75
- @opt_join_results.each do |ojr|
76
- ojr.wme.opt_join_results.delete ojr
77
- end
78
- @opt_join_results = []
79
-
80
- when NccNode
81
- @ncc_results.each do |nccr|
82
- nccr.wme.tokens.delete nccr
83
- nccr.parent.children.delete nccr
84
- end
85
- @ncc_results = []
86
-
87
- when NccPartner
88
- @owner.ncc_results.delete self
89
- if @owner.ncc_results.empty?
90
- @node.ncc.children.each do |node|
91
- node.left_activate @owner, nil, {}
92
- end
93
- end
94
- end
95
63
 
64
+ @node.delete_token self
96
65
  end
97
66
 
98
67
  def delete_children
@@ -118,11 +87,6 @@ module Wongi::Engine
118
87
 
119
88
  end
120
89
 
121
- def deexecute
122
- @deexecutors.each { |deexec| deexec.deexecute self }
123
- @deexecutors = []
124
- end
125
-
126
90
  def all_assignments
127
91
  raise "Assignments is not a hash" unless @assignments.kind_of?( Hash )
128
92
  if @parent
@@ -1,5 +1,5 @@
1
1
  module Wongi
2
2
  module Engine
3
- VERSION = "0.0.2"
3
+ VERSION = "0.0.3"
4
4
  end
5
5
  end
@@ -57,7 +57,7 @@ module Wongi::Engine
57
57
 
58
58
  alphas.each { |alpha| alpha.remove self }.clear
59
59
  while tokens.first
60
- tokens.first.delete self # => will remove itself from the array
60
+ tokens.first.delete # => will remove itself from the array
61
61
  end
62
62
 
63
63
  destroy_neg_join_results
@@ -90,9 +90,9 @@ module Wongi::Engine
90
90
  results = token.neg_join_results
91
91
  results.delete njr
92
92
 
93
- if results.empty? && !rete.in_snapshot?
93
+ if results.empty? #&& !rete.in_snapshot?
94
94
  token.node.children.each { |beta|
95
- beta.left_activate token, nil, { }
95
+ beta.beta_activate token, nil, { }
96
96
  }
97
97
  end
98
98
 
@@ -109,7 +109,7 @@ module Wongi::Engine
109
109
  if results.empty?
110
110
  token.delete_children
111
111
  token.node.children.each { |beta|
112
- beta.left_activate token
112
+ beta.beta_activate token
113
113
  }
114
114
  end
115
115
 
data/lib/wongi-engine.rb CHANGED
@@ -14,6 +14,7 @@ require 'wongi-engine/template'
14
14
  require 'wongi-engine/wme'
15
15
  require 'wongi-engine/wme_match_data'
16
16
  require 'wongi-engine/token'
17
+ require 'wongi-engine/filter'
17
18
  require 'wongi-engine/alpha_memory'
18
19
  require 'wongi-engine/beta'
19
20
  require 'wongi-engine/dsl'
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ASSERT test" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ def production
14
+ @production
15
+ end
16
+
17
+ def test_rule &block
18
+ @production = ( engine << rule( 'test-rule', &block ) )
19
+ end
20
+
21
+ it "should pass with a constant 'true'" do
22
+
23
+ test_rule {
24
+ forall {
25
+ assert { |token|
26
+ true
27
+ }
28
+ }
29
+ }
30
+
31
+ production.should have(1).tokens
32
+
33
+ end
34
+
35
+ it "should fail with a constant 'false'" do
36
+
37
+ test_rule {
38
+ forall {
39
+ assert { |token|
40
+ false
41
+ }
42
+ }
43
+ }
44
+
45
+ production.should have(0).tokens
46
+
47
+ end
48
+
49
+ it "should use the token with no arguments" do
50
+
51
+ test_rule {
52
+ forall {
53
+ has :X, "is", :Y
54
+ assert { |token|
55
+ token[:X] == "resistance"
56
+ }
57
+ }
58
+ }
59
+
60
+ engine << ["resistance", "is", "futile"]
61
+
62
+ production.should have(1).tokens
63
+ production.tokens.first[:X].should == "resistance"
64
+
65
+ end
66
+
67
+ it "should use individual variables with arguments" do
68
+
69
+ test_rule {
70
+ forall {
71
+ has :X, "is", :Y
72
+ assert :X, :Y do |x, y|
73
+ y == "futile"
74
+ end
75
+ }
76
+ }
77
+
78
+ engine << ["resistance", "is", "futile"]
79
+
80
+ production.should have(1).tokens
81
+ production.tokens.first[:X].should == "resistance"
82
+
83
+ end
84
+
85
+ end
@@ -178,63 +178,7 @@ describe 'the engine' do
178
178
  rete.results["test-query"].tokens.first[:Y].should == 42
179
179
 
180
180
  end
181
-
182
- it 'should support negative subnets' do
183
-
184
- production = (rete << rule('ncc') {
185
- forall {
186
- has "base", "is", :Base
187
- none {
188
- has :Base, 2, :X
189
- has :X, 4, 5
190
- }
191
- }
192
- })
193
-
194
- rete << ["base", "is", 1]
195
-
196
- production.should have(1).tokens
197
-
198
- rete << [1, 2, 3]
199
-
200
- production.should have(1).tokens
201
-
202
- rete << [3, 4, 5]
203
-
204
- production.should have(0).tokens
205
-
206
- rete << ["base", "is", 2]
207
-
208
- production.should have(1).tokens
209
-
210
- end
211
-
212
- it 'should support optional matches' do
213
-
214
- production = (rete << rule('optional') {
215
- forall {
216
- has "answer", "is", :Answer
217
- maybe :Answer, "is", :Kind
218
- }
219
- })
220
-
221
- rete << ["answer", "is", 42]
222
- rete << ["answer", "is", 43]
223
- rete << [42, "is", "canonical"]
224
-
225
- production.should have(2).tokens
226
-
227
- canon = production.tokens.select { |token| not token[:Kind].nil? }
228
- canon.should have(1).items
229
- canon.first[:Answer].should == 42
230
- canon.first[:Kind].should == "canonical"
231
-
232
- non_canon = production.tokens.select { |token| token[:Kind].nil? }
233
- non_canon.should have(1).items
234
- non_canon.first[:Answer].should == 43
235
-
236
- end
237
-
181
+
238
182
  context 'with timelines' do
239
183
 
240
184
  it 'should not match with no past point' do
@@ -282,7 +226,7 @@ describe 'the engine' do
282
226
  rete.snapshot!
283
227
  rete << [1, 2, 3]
284
228
  production.should have(1).tokens
285
- puts count
229
+ #puts count
286
230
  end
287
231
 
288
232
  it 'should not match kept items' do
@@ -297,7 +241,7 @@ describe 'the engine' do
297
241
  production.should have(1).tokens
298
242
  rete.snapshot!
299
243
  production.should have(0).tokens
300
- puts count
244
+ #puts count
301
245
  end
302
246
 
303
247
  end
@@ -316,7 +260,7 @@ describe 'the engine' do
316
260
  production.should have(0).tokens
317
261
  rete.snapshot!
318
262
  production.should have(1).tokens
319
- puts count
263
+ #puts count
320
264
  end
321
265
 
322
266
  it 'should not match asserted wmes' do
@@ -331,7 +275,7 @@ describe 'the engine' do
331
275
  rete.snapshot!
332
276
  rete << [1, 2, 3]
333
277
  production.should have(0).tokens
334
- puts count
278
+ #puts count
335
279
  end
336
280
 
337
281
  end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ANY rule" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ context "with just one option" do
14
+
15
+ it "should act like a positive matcher" do
16
+
17
+ engine << rule('one-option') {
18
+ forall {
19
+ any {
20
+ option {
21
+ has 1, 2, :X
22
+ has :X, 4, 5
23
+ }
24
+ }
25
+ }
26
+ }
27
+
28
+ production = engine.productions['one-option']
29
+
30
+ engine << [1, 2, 3]
31
+ engine << [3, 4, 5]
32
+
33
+ production.should have(1).tokens
34
+
35
+ end
36
+
37
+ end
38
+
39
+ context "with several options" do
40
+
41
+ specify "all matching branches must pass" do
42
+
43
+ engine << rule('two-options') {
44
+ forall {
45
+ has 1, 2, :X
46
+ any {
47
+ option {
48
+ has :X, 4, 5
49
+ }
50
+ option {
51
+ has :X, "four", "five"
52
+ }
53
+ }
54
+ }
55
+ make {
56
+ collect :X, :threes
57
+ }
58
+ }
59
+
60
+ production = engine.productions['two-options']
61
+
62
+ engine << [1, 2, 3]
63
+ engine << [3, 4, 5]
64
+ engine << [1, 2, "three"]
65
+ engine << ["three", "four", "five"]
66
+
67
+ production.should have(2).tokens
68
+ engine.collection(:threes).should include(3)
69
+ engine.collection(:threes).should include("three")
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe "ASSIGN rule" do
4
+
5
+ before :each do
6
+ @engine = Wongi::Engine.create
7
+ end
8
+
9
+ def engine
10
+ @engine
11
+ end
12
+
13
+ def production
14
+ @production
15
+ end
16
+
17
+ def test_rule &block
18
+ @production = ( engine << rule( 'test-rule', &block ) )
19
+ end
20
+
21
+ it "should assign simple expressions" do
22
+
23
+ test_rule {
24
+ forall {
25
+ assign :X do
26
+ 42
27
+ end
28
+ }
29
+ }
30
+
31
+ production.should have(1).tokens
32
+ production.tokens.first[:X].should == 42
33
+
34
+ end
35
+
36
+ it "should be able to access previous assignments" do
37
+
38
+ test_rule {
39
+ forall {
40
+ has 1, 2, :X
41
+ assign :Y do |token|
42
+ token[:X] * 2
43
+ end
44
+ }
45
+ }
46
+
47
+ engine << [1, 2, 5]
48
+ production.tokens.first[:Y].should == 10
49
+
50
+ end
51
+
52
+ end