wongi-engine 0.0.14 → 0.0.16
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/.travis.yml +8 -0
- data/README.md +3 -11
- data/lib/wongi-engine/beta/beta_memory.rb +3 -4
- data/lib/wongi-engine/beta/beta_node.rb +5 -0
- data/lib/wongi-engine/beta/neg_node.rb +92 -94
- data/lib/wongi-engine/beta/production_node.rb +1 -2
- data/lib/wongi-engine/dsl/actions/statement_generator.rb +55 -55
- data/lib/wongi-engine/network.rb +442 -443
- data/lib/wongi-engine/token.rb +138 -133
- data/lib/wongi-engine/version.rb +1 -1
- data/lib/wongi-engine/wme.rb +138 -140
- data/spec/bug_specs/issue_4_spec.rb +9 -9
- data/spec/dataset_spec.rb +3 -3
- data/spec/filter_specs/assert_test_spec.rb +6 -6
- data/spec/filter_specs/less_test_spec.rb +1 -1
- data/spec/high_level_spec.rb +34 -34
- data/spec/rule_specs/any_rule_spec.rb +4 -4
- data/spec/rule_specs/assign_spec.rb +3 -4
- data/spec/rule_specs/maybe_rule_spec.rb +12 -12
- data/spec/rule_specs/ncc_spec.rb +6 -6
- data/spec/rule_specs/negative_rule_spec.rb +70 -70
- data/spec/ruleset_spec.rb +8 -8
- data/spec/simple_action_spec.rb +3 -3
- data/spec/spec_helper.rb +2 -0
- data/spec/wme_spec.rb +21 -21
- data/wongi-engine.gemspec +6 -2
- metadata +53 -9
data/lib/wongi-engine/token.rb
CHANGED
@@ -1,133 +1,138 @@
|
|
1
|
-
module Wongi::Engine
|
2
|
-
|
3
|
-
class Token
|
4
|
-
|
5
|
-
include CoreExt
|
6
|
-
|
7
|
-
attr_reader :
|
8
|
-
attr_accessor :node, :owner
|
9
|
-
attr_reader :neg_join_results
|
10
|
-
attr_reader :opt_join_results
|
11
|
-
attr_reader :ncc_results
|
12
|
-
attr_reader :generated_wmes
|
13
|
-
attr_predicate :has_optional
|
14
|
-
|
15
|
-
def initialize token, wme, assignments
|
16
|
-
@parent, @wme, @assignments = token, wme, assignments
|
17
|
-
@children = []
|
18
|
-
@deleted = false
|
19
|
-
@neg_join_results = []
|
20
|
-
@opt_join_results = []
|
21
|
-
@ncc_results = []
|
22
|
-
@generated_wmes = []
|
23
|
-
token.children << self if token
|
24
|
-
wme.tokens << self if wme
|
25
|
-
end
|
26
|
-
|
27
|
-
def ancestors
|
28
|
-
if parent
|
29
|
-
parent.ancestors.unshift parent
|
30
|
-
else
|
31
|
-
[]
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def subst variable, value
|
36
|
-
@cached_assignments = nil
|
37
|
-
if @assignments.has_key? variable
|
38
|
-
@assignments[ variable ] = value
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def assignments
|
43
|
-
@cached_assignments ||= all_assignments
|
44
|
-
end
|
45
|
-
|
46
|
-
def [] var
|
47
|
-
assignments[ var ]
|
48
|
-
end
|
49
|
-
|
50
|
-
def duplicate?
|
51
|
-
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_s
|
55
|
-
str = "TOKEN [ parent=#{parent ? parent.object_id : 'nil'} "
|
56
|
-
all_assignments.each_pair { |key, value| str << "#{key} => #{value} " }
|
57
|
-
str << "]"
|
58
|
-
str
|
59
|
-
end
|
60
|
-
|
61
|
-
def wmes
|
62
|
-
if parent
|
63
|
-
parent.wmes + (wme ? [wme] : [])
|
64
|
-
else
|
65
|
-
wme ? [wme] : []
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
def delete
|
70
|
-
delete_children
|
71
|
-
#@node.tokens.delete self unless @node.kind_of?( NccPartner )
|
72
|
-
@wme.tokens.delete self if @wme
|
73
|
-
@parent.children.delete self if @parent
|
74
|
-
|
75
|
-
retract_generated
|
76
|
-
@deleted = true
|
77
|
-
@node.delete_token self
|
78
|
-
end
|
79
|
-
|
80
|
-
def deleted?
|
81
|
-
@deleted
|
82
|
-
end
|
83
|
-
|
84
|
-
def delete_children
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
@
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
1
|
+
module Wongi::Engine
|
2
|
+
|
3
|
+
class Token
|
4
|
+
|
5
|
+
include CoreExt
|
6
|
+
|
7
|
+
attr_reader :wme, :children
|
8
|
+
attr_accessor :node, :owner, :parent
|
9
|
+
attr_reader :neg_join_results
|
10
|
+
attr_reader :opt_join_results
|
11
|
+
attr_reader :ncc_results
|
12
|
+
attr_reader :generated_wmes
|
13
|
+
attr_predicate :has_optional
|
14
|
+
|
15
|
+
def initialize token, wme, assignments
|
16
|
+
@parent, @wme, @assignments = token, wme, assignments
|
17
|
+
@children = []
|
18
|
+
@deleted = false
|
19
|
+
@neg_join_results = []
|
20
|
+
@opt_join_results = []
|
21
|
+
@ncc_results = []
|
22
|
+
@generated_wmes = []
|
23
|
+
token.children << self if token
|
24
|
+
wme.tokens << self if wme
|
25
|
+
end
|
26
|
+
|
27
|
+
def ancestors
|
28
|
+
if parent
|
29
|
+
parent.ancestors.unshift parent
|
30
|
+
else
|
31
|
+
[]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def subst variable, value
|
36
|
+
@cached_assignments = nil
|
37
|
+
if @assignments.has_key? variable
|
38
|
+
@assignments[ variable ] = value
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def assignments
|
43
|
+
@cached_assignments ||= all_assignments
|
44
|
+
end
|
45
|
+
|
46
|
+
def [] var
|
47
|
+
assignments[ var ]
|
48
|
+
end
|
49
|
+
|
50
|
+
def duplicate? node, parent, wme, assignments
|
51
|
+
self.node.equal?(node) && self.parent.equal?(parent) && self.wme.equal?(wme) && self.assignments == assignments
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
str = "TOKEN [ parent=#{parent ? parent.object_id : 'nil'} "
|
56
|
+
all_assignments.each_pair { |key, value| str << "#{key} => #{value} " }
|
57
|
+
str << "]"
|
58
|
+
str
|
59
|
+
end
|
60
|
+
|
61
|
+
def wmes
|
62
|
+
if parent
|
63
|
+
parent.wmes + (wme ? [wme] : [])
|
64
|
+
else
|
65
|
+
wme ? [wme] : []
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def delete
|
70
|
+
delete_children
|
71
|
+
#@node.tokens.delete self unless @node.kind_of?( NccPartner )
|
72
|
+
@wme.tokens.delete self if @wme
|
73
|
+
@parent.children.delete self if @parent
|
74
|
+
|
75
|
+
retract_generated
|
76
|
+
@deleted = true
|
77
|
+
@node.delete_token self
|
78
|
+
end
|
79
|
+
|
80
|
+
def deleted?
|
81
|
+
@deleted
|
82
|
+
end
|
83
|
+
|
84
|
+
def delete_children
|
85
|
+
children = @children
|
86
|
+
@children = []
|
87
|
+
children.each do |token|
|
88
|
+
token.parent = nil
|
89
|
+
token.delete
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def generated? wme
|
94
|
+
return true if generated_wmes.any? { |w| w == wme }
|
95
|
+
return children.any? { |t| t.generated? wme }
|
96
|
+
end
|
97
|
+
|
98
|
+
protected
|
99
|
+
|
100
|
+
def retract_generated
|
101
|
+
for_retraction = []
|
102
|
+
|
103
|
+
@generated_wmes.dup.each do |wme|
|
104
|
+
unless wme.manual? # => TODO: does this ever fail at all?
|
105
|
+
wme.generating_tokens.delete self
|
106
|
+
if wme.generating_tokens.empty?
|
107
|
+
for_retraction << wme
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
@generated_wmes = []
|
112
|
+
for_retraction.each { |wme| wme.rete.retract wme, true }
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def all_assignments
|
117
|
+
raise "Assignments is not a hash" unless @assignments.kind_of?( Hash )
|
118
|
+
if @parent
|
119
|
+
@parent.assignments.merge @assignments
|
120
|
+
else
|
121
|
+
@assignments
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
126
|
+
|
127
|
+
class FakeToken < Token
|
128
|
+
def initialize token, wme, assignments
|
129
|
+
@parent, @wme, @assignments = token, wme, assignments
|
130
|
+
@children = []
|
131
|
+
@neg_join_results = []
|
132
|
+
@opt_join_results = []
|
133
|
+
@ncc_results = []
|
134
|
+
@generated_wmes = []
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
data/lib/wongi-engine/version.rb
CHANGED
data/lib/wongi-engine/wme.rb
CHANGED
@@ -1,140 +1,138 @@
|
|
1
|
-
module Wongi::Engine
|
2
|
-
|
3
|
-
class WME < Struct.new( :subject, :predicate, :object )
|
4
|
-
|
5
|
-
attr_reader :rete
|
6
|
-
|
7
|
-
attr_reader :alphas, :tokens, :generating_tokens
|
8
|
-
attr_reader :neg_join_results, :opt_join_results
|
9
|
-
|
10
|
-
def initialize s, p, o, r = nil
|
11
|
-
|
12
|
-
@deleted = false
|
13
|
-
@alphas = []
|
14
|
-
@tokens = []
|
15
|
-
@generating_tokens = []
|
16
|
-
@neg_join_results = []
|
17
|
-
@opt_join_results = []
|
18
|
-
|
19
|
-
@rete = r
|
20
|
-
|
21
|
-
if r
|
22
|
-
super( r.import(s), r.import(p), r.import(o) )
|
23
|
-
else
|
24
|
-
super( s, p, o )
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
def import_into r
|
30
|
-
self.class.new subject, predicate, object, r
|
31
|
-
end
|
32
|
-
|
33
|
-
def dup
|
34
|
-
self.class.new subject, predicate, object, rete
|
35
|
-
end
|
36
|
-
|
37
|
-
def == other
|
38
|
-
subject == other.subject && predicate == other.predicate && object == other.object
|
39
|
-
end
|
40
|
-
|
41
|
-
def =~ template
|
42
|
-
raise "Cannot match a WME against a #{template.class}" unless Template === template
|
43
|
-
result = match_member(
|
44
|
-
if result.match?
|
45
|
-
result
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def manual?
|
50
|
-
generating_tokens.empty?
|
51
|
-
end
|
52
|
-
|
53
|
-
def generated?
|
54
|
-
!manual?
|
55
|
-
end
|
56
|
-
|
57
|
-
def deleted?
|
58
|
-
@deleted
|
59
|
-
end
|
60
|
-
|
61
|
-
def destroy
|
62
|
-
return if deleted?
|
63
|
-
@deleted = true
|
64
|
-
alphas.each { |alpha| alpha.remove self }.clear
|
65
|
-
while tokens.first
|
66
|
-
tokens.first.delete # => will remove itself from the array
|
67
|
-
end
|
68
|
-
|
69
|
-
destroy_neg_join_results
|
70
|
-
destroy_opt_join_results
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
|
-
def inspect
|
75
|
-
"<WME #{subject.inspect} #{predicate.inspect} #{object.inspect}>"
|
76
|
-
end
|
77
|
-
|
78
|
-
def to_s
|
79
|
-
inspect
|
80
|
-
end
|
81
|
-
|
82
|
-
def hash
|
83
|
-
@hash ||= array_form.map( &:hash ).hash
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def array_form
|
89
|
-
@array_form ||= [ subject, predicate, object ]
|
90
|
-
end
|
91
|
-
|
92
|
-
def destroy_neg_join_results
|
93
|
-
neg_join_results.each do |njr|
|
94
|
-
|
95
|
-
token = njr.owner
|
96
|
-
results = token.neg_join_results
|
97
|
-
results.delete njr
|
98
|
-
|
99
|
-
if results.empty? #&& !rete.in_snapshot?
|
100
|
-
token.node.children.each { |beta|
|
101
|
-
beta.beta_activate token, nil, { }
|
102
|
-
}
|
103
|
-
end
|
104
|
-
|
105
|
-
end.clear
|
106
|
-
end
|
107
|
-
|
108
|
-
def destroy_opt_join_results
|
109
|
-
opt_join_results.each do |ojr|
|
110
|
-
|
111
|
-
token = ojr.owner
|
112
|
-
results = token.opt_join_results
|
113
|
-
results.delete ojr
|
114
|
-
|
115
|
-
if results.empty?
|
116
|
-
token.delete_children
|
117
|
-
token.node.children.each { |beta|
|
118
|
-
beta.beta_activate token
|
119
|
-
}
|
120
|
-
end
|
121
|
-
|
122
|
-
end.clear
|
123
|
-
end
|
124
|
-
|
125
|
-
def match_member
|
126
|
-
result = WMEMatchData.new
|
127
|
-
mine
|
128
|
-
|
129
|
-
|
130
|
-
result.match!
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
1
|
+
module Wongi::Engine
|
2
|
+
|
3
|
+
class WME < Struct.new( :subject, :predicate, :object )
|
4
|
+
|
5
|
+
attr_reader :rete
|
6
|
+
|
7
|
+
attr_reader :alphas, :tokens, :generating_tokens
|
8
|
+
attr_reader :neg_join_results, :opt_join_results
|
9
|
+
|
10
|
+
def initialize s, p, o, r = nil
|
11
|
+
|
12
|
+
@deleted = false
|
13
|
+
@alphas = []
|
14
|
+
@tokens = []
|
15
|
+
@generating_tokens = []
|
16
|
+
@neg_join_results = []
|
17
|
+
@opt_join_results = []
|
18
|
+
|
19
|
+
@rete = r
|
20
|
+
|
21
|
+
if r
|
22
|
+
super( r.import(s), r.import(p), r.import(o) )
|
23
|
+
else
|
24
|
+
super( s, p, o )
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def import_into r
|
30
|
+
self.class.new subject, predicate, object, r
|
31
|
+
end
|
32
|
+
|
33
|
+
def dup
|
34
|
+
self.class.new subject, predicate, object, rete
|
35
|
+
end
|
36
|
+
|
37
|
+
def == other
|
38
|
+
subject == other.subject && predicate == other.predicate && object == other.object
|
39
|
+
end
|
40
|
+
|
41
|
+
def =~ template
|
42
|
+
raise "Cannot match a WME against a #{template.class}" unless Template === template
|
43
|
+
result = match_member( self.subject, template.subject ) & match_member( self.predicate, template.predicate ) & match_member( self.object, template.object )
|
44
|
+
if result.match?
|
45
|
+
result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def manual?
|
50
|
+
generating_tokens.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
def generated?
|
54
|
+
!manual?
|
55
|
+
end
|
56
|
+
|
57
|
+
def deleted?
|
58
|
+
@deleted
|
59
|
+
end
|
60
|
+
|
61
|
+
def destroy
|
62
|
+
return if deleted?
|
63
|
+
@deleted = true
|
64
|
+
alphas.each { |alpha| alpha.remove self }.clear
|
65
|
+
while tokens.first
|
66
|
+
tokens.first.delete # => will remove itself from the array
|
67
|
+
end
|
68
|
+
|
69
|
+
destroy_neg_join_results
|
70
|
+
destroy_opt_join_results
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
def inspect
|
75
|
+
"<WME #{subject.inspect} #{predicate.inspect} #{object.inspect}>"
|
76
|
+
end
|
77
|
+
|
78
|
+
def to_s
|
79
|
+
inspect
|
80
|
+
end
|
81
|
+
|
82
|
+
def hash
|
83
|
+
@hash ||= array_form.map( &:hash ).hash
|
84
|
+
end
|
85
|
+
|
86
|
+
protected
|
87
|
+
|
88
|
+
def array_form
|
89
|
+
@array_form ||= [ subject, predicate, object ]
|
90
|
+
end
|
91
|
+
|
92
|
+
def destroy_neg_join_results
|
93
|
+
neg_join_results.each do |njr|
|
94
|
+
|
95
|
+
token = njr.owner
|
96
|
+
results = token.neg_join_results
|
97
|
+
results.delete njr
|
98
|
+
|
99
|
+
if results.empty? #&& !rete.in_snapshot?
|
100
|
+
token.node.children.each { |beta|
|
101
|
+
beta.beta_activate token, nil, { }
|
102
|
+
}
|
103
|
+
end
|
104
|
+
|
105
|
+
end.clear
|
106
|
+
end
|
107
|
+
|
108
|
+
def destroy_opt_join_results
|
109
|
+
opt_join_results.each do |ojr|
|
110
|
+
|
111
|
+
token = ojr.owner
|
112
|
+
results = token.opt_join_results
|
113
|
+
results.delete ojr
|
114
|
+
|
115
|
+
if results.empty?
|
116
|
+
token.delete_children
|
117
|
+
token.node.children.each { |beta|
|
118
|
+
beta.beta_activate token
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
end.clear
|
123
|
+
end
|
124
|
+
|
125
|
+
def match_member mine, theirs
|
126
|
+
result = WMEMatchData.new
|
127
|
+
if theirs == :_ || mine == theirs
|
128
|
+
result.match!
|
129
|
+
elsif Template.variable? theirs
|
130
|
+
result.match!
|
131
|
+
result[theirs] = mine
|
132
|
+
end
|
133
|
+
result
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
@@ -24,8 +24,8 @@ describe "issue 4" do
|
|
24
24
|
numbers = engine.select :_, :is_number, true
|
25
25
|
evens = engine.select :_, :is_even, true
|
26
26
|
|
27
|
-
numbers.
|
28
|
-
evens.
|
27
|
+
expect(numbers).to be_empty
|
28
|
+
expect(evens.length).to eq(10)
|
29
29
|
|
30
30
|
end
|
31
31
|
|
@@ -51,8 +51,8 @@ describe "issue 4" do
|
|
51
51
|
numbers = engine.select :_, :is_number, true
|
52
52
|
evens = engine.select :_, :is_even, true
|
53
53
|
|
54
|
-
numbers.
|
55
|
-
evens.
|
54
|
+
expect(numbers).to be_empty
|
55
|
+
expect(evens.length).to eq(10)
|
56
56
|
|
57
57
|
end
|
58
58
|
|
@@ -85,9 +85,9 @@ describe "issue 4" do
|
|
85
85
|
evens = engine.select :_, :is_even, true
|
86
86
|
odds = engine.select :_, :is_odd, true
|
87
87
|
|
88
|
-
numbers.
|
89
|
-
evens.
|
90
|
-
odds.
|
88
|
+
expect(numbers).to be_empty
|
89
|
+
expect(evens.length).to eq(5)
|
90
|
+
expect(odds).to be_empty
|
91
91
|
|
92
92
|
end
|
93
93
|
|
@@ -134,7 +134,7 @@ describe "issue 4" do
|
|
134
134
|
odds = engine.select :_, :is_odd, true
|
135
135
|
|
136
136
|
# numbers.should be_empty
|
137
|
-
evens.
|
138
|
-
odds.
|
137
|
+
expect(evens.length).to eq(5)
|
138
|
+
expect(odds.length).to eq(5)
|
139
139
|
end
|
140
140
|
end
|
data/spec/dataset_spec.rb
CHANGED
@@ -13,13 +13,13 @@ describe Wongi::Engine::Network do
|
|
13
13
|
}
|
14
14
|
|
15
15
|
production = ds.productions['test-rule']
|
16
|
-
production.
|
16
|
+
expect(production).not_to be_nil
|
17
17
|
|
18
|
-
production.
|
18
|
+
expect(production).to be_empty
|
19
19
|
|
20
20
|
ds << [1, 2, 3]
|
21
21
|
|
22
|
-
production.
|
22
|
+
expect(production.size).to eq(1)
|
23
23
|
|
24
24
|
end
|
25
25
|
|
@@ -28,7 +28,7 @@ describe "ASSERT test" do
|
|
28
28
|
}
|
29
29
|
}
|
30
30
|
|
31
|
-
production.
|
31
|
+
expect(production.size).to eq(1)
|
32
32
|
|
33
33
|
end
|
34
34
|
|
@@ -42,7 +42,7 @@ describe "ASSERT test" do
|
|
42
42
|
}
|
43
43
|
}
|
44
44
|
|
45
|
-
production.
|
45
|
+
expect(production.size).to eq(0)
|
46
46
|
|
47
47
|
end
|
48
48
|
|
@@ -59,8 +59,8 @@ describe "ASSERT test" do
|
|
59
59
|
|
60
60
|
engine << ["resistance", "is", "futile"]
|
61
61
|
|
62
|
-
production.
|
63
|
-
production.tokens.first[:X].
|
62
|
+
expect(production.size).to eq(1)
|
63
|
+
expect(production.tokens.first[:X]).to eq("resistance")
|
64
64
|
|
65
65
|
end
|
66
66
|
|
@@ -77,8 +77,8 @@ describe "ASSERT test" do
|
|
77
77
|
|
78
78
|
engine << ["resistance", "is", "futile"]
|
79
79
|
|
80
|
-
production.
|
81
|
-
production.tokens.first[:X].
|
80
|
+
expect(production.size).to eq(1)
|
81
|
+
expect(production.tokens.first[:X]).to eq("resistance")
|
82
82
|
|
83
83
|
end
|
84
84
|
|