wongi-engine 0.0.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +349 -0
- data/Rakefile +2 -0
- data/examples/ex01.rb +23 -0
- data/examples/ex02.rb +36 -0
- data/examples/graphviz.rb +15 -0
- data/examples/timeline.rb +48 -0
- data/lib/wongi-engine.rb +22 -0
- data/lib/wongi-engine/alpha_memory.rb +46 -0
- data/lib/wongi-engine/beta.rb +10 -0
- data/lib/wongi-engine/beta/beta_memory.rb +48 -0
- data/lib/wongi-engine/beta/beta_node.rb +164 -0
- data/lib/wongi-engine/beta/filter_node.rb +109 -0
- data/lib/wongi-engine/beta/join_node.rb +127 -0
- data/lib/wongi-engine/beta/ncc_node.rb +46 -0
- data/lib/wongi-engine/beta/ncc_partner.rb +43 -0
- data/lib/wongi-engine/beta/neg_node.rb +58 -0
- data/lib/wongi-engine/beta/optional_node.rb +43 -0
- data/lib/wongi-engine/beta/or_node.rb +76 -0
- data/lib/wongi-engine/beta/production_node.rb +31 -0
- data/lib/wongi-engine/core_ext.rb +57 -0
- data/lib/wongi-engine/dsl.rb +112 -0
- data/lib/wongi-engine/dsl/action.rb +12 -0
- data/lib/wongi-engine/dsl/actions/error_generator.rb +42 -0
- data/lib/wongi-engine/dsl/actions/simple_action.rb +23 -0
- data/lib/wongi-engine/dsl/actions/simple_collector.rb +51 -0
- data/lib/wongi-engine/dsl/actions/statement_generator.rb +52 -0
- data/lib/wongi-engine/dsl/actions/trace_action.rb +52 -0
- data/lib/wongi-engine/dsl/any_rule.rb +48 -0
- data/lib/wongi-engine/dsl/dsl_builder.rb +44 -0
- data/lib/wongi-engine/dsl/dsl_extensions.rb +43 -0
- data/lib/wongi-engine/dsl/extension_clause.rb +36 -0
- data/lib/wongi-engine/dsl/generation_clause.rb +15 -0
- data/lib/wongi-engine/dsl/generic_production_rule.rb +78 -0
- data/lib/wongi-engine/dsl/ncc_production_rule.rb +21 -0
- data/lib/wongi-engine/dsl/production_rule.rb +4 -0
- data/lib/wongi-engine/dsl/query.rb +24 -0
- data/lib/wongi-engine/graph.rb +71 -0
- data/lib/wongi-engine/model_context.rb +13 -0
- data/lib/wongi-engine/network.rb +416 -0
- data/lib/wongi-engine/network/collectable.rb +42 -0
- data/lib/wongi-engine/network/debug.rb +25 -0
- data/lib/wongi-engine/ruleset.rb +74 -0
- data/lib/wongi-engine/template.rb +111 -0
- data/lib/wongi-engine/token.rb +137 -0
- data/lib/wongi-engine/version.rb +5 -0
- data/lib/wongi-engine/wme.rb +134 -0
- data/lib/wongi-engine/wme_match_data.rb +34 -0
- data/spec/dataset_spec.rb +26 -0
- data/spec/dsl_spec.rb +9 -0
- data/spec/high_level_spec.rb +341 -0
- data/spec/ruleset_spec.rb +54 -0
- data/spec/simple_action_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- data/spec/wme_spec.rb +83 -0
- data/wongi-engine.gemspec +19 -0
- metadata +110 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'wongi-engine'
|
2
|
+
|
3
|
+
def sep
|
4
|
+
puts "---------------------------"
|
5
|
+
end
|
6
|
+
|
7
|
+
engine = Wongi::Engine.create
|
8
|
+
|
9
|
+
engine.debug!
|
10
|
+
|
11
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, 0 )
|
12
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, -1 )
|
13
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, -2 )
|
14
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, -3 )
|
15
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, -4 )
|
16
|
+
engine.compile_alpha Wongi::Engine::Template.new( :_, :_, :_, -5 )
|
17
|
+
|
18
|
+
engine.full_wme_dump
|
19
|
+
|
20
|
+
sep
|
21
|
+
|
22
|
+
engine << [1, 1, 1]
|
23
|
+
engine.full_wme_dump
|
24
|
+
engine.snapshot!
|
25
|
+
|
26
|
+
sep
|
27
|
+
|
28
|
+
engine << [2, 2, 2]
|
29
|
+
engine.full_wme_dump
|
30
|
+
engine.snapshot!
|
31
|
+
|
32
|
+
sep
|
33
|
+
|
34
|
+
engine << [3, 3, 3]
|
35
|
+
engine.full_wme_dump
|
36
|
+
engine.snapshot!
|
37
|
+
|
38
|
+
sep
|
39
|
+
|
40
|
+
engine << [4, 4, 4]
|
41
|
+
engine.full_wme_dump
|
42
|
+
engine.snapshot!
|
43
|
+
|
44
|
+
sep
|
45
|
+
|
46
|
+
engine << [5, 5, 5]
|
47
|
+
engine.full_wme_dump
|
48
|
+
engine.snapshot!
|
data/lib/wongi-engine.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module Wongi
|
2
|
+
module Engine
|
3
|
+
|
4
|
+
def self.create
|
5
|
+
Network.new
|
6
|
+
end
|
7
|
+
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'wongi-engine/version'
|
12
|
+
require 'wongi-engine/core_ext'
|
13
|
+
require 'wongi-engine/template'
|
14
|
+
require 'wongi-engine/wme'
|
15
|
+
require 'wongi-engine/wme_match_data'
|
16
|
+
require 'wongi-engine/token'
|
17
|
+
require 'wongi-engine/alpha_memory'
|
18
|
+
require 'wongi-engine/beta'
|
19
|
+
require 'wongi-engine/dsl'
|
20
|
+
require 'wongi-engine/ruleset'
|
21
|
+
require 'wongi-engine/network'
|
22
|
+
require 'wongi-engine/graph'
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
|
3
|
+
class AlphaMemory
|
4
|
+
|
5
|
+
attr_reader :betas, :template, :rete, :wmes
|
6
|
+
|
7
|
+
def initialize template, rete = nil
|
8
|
+
@template = template
|
9
|
+
@rete = rete
|
10
|
+
@betas = []
|
11
|
+
@wmes = []
|
12
|
+
@frozen = false
|
13
|
+
end
|
14
|
+
|
15
|
+
def activate wme
|
16
|
+
betas.each do |beta|
|
17
|
+
beta.right_activate wme
|
18
|
+
end
|
19
|
+
@wmes << wme
|
20
|
+
wme.alphas << self
|
21
|
+
end
|
22
|
+
|
23
|
+
def remove wme
|
24
|
+
@wmes.delete wme
|
25
|
+
# we don't need to unlink ourselves from the wme
|
26
|
+
# because this is only called from WME#destroy
|
27
|
+
# so the wme will take care of it itself
|
28
|
+
end
|
29
|
+
|
30
|
+
def snapshot! alpha
|
31
|
+
alpha.wmes.map( &:dup ).each do |wme|
|
32
|
+
activate wme
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
"<Alpha #{__id__} template=#{template} wmes=#{wmes}>"
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_s
|
41
|
+
inspect
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'wongi-engine/beta/beta_node'
|
2
|
+
require 'wongi-engine/beta/beta_memory'
|
3
|
+
require 'wongi-engine/beta/filter_node'
|
4
|
+
require 'wongi-engine/beta/join_node'
|
5
|
+
require 'wongi-engine/beta/ncc_partner'
|
6
|
+
require 'wongi-engine/beta/ncc_node'
|
7
|
+
require 'wongi-engine/beta/neg_node'
|
8
|
+
require 'wongi-engine/beta/optional_node'
|
9
|
+
require 'wongi-engine/beta/or_node'
|
10
|
+
require 'wongi-engine/beta/production_node'
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
|
3
|
+
class BetaMemory < BetaNode
|
4
|
+
attr_reader :tokens, :last_token
|
5
|
+
|
6
|
+
def initialize parent
|
7
|
+
super
|
8
|
+
@tokens = []
|
9
|
+
end
|
10
|
+
|
11
|
+
def seed assignments = {}
|
12
|
+
t = Token.new( nil, nil, assignments )
|
13
|
+
t.node = self
|
14
|
+
@tokens << t
|
15
|
+
end
|
16
|
+
|
17
|
+
def subst valuations
|
18
|
+
token = @tokens.first
|
19
|
+
token.delete true
|
20
|
+
valuations.each { |variable, value| token.subst variable, value }
|
21
|
+
self.children.each do |child|
|
22
|
+
child.left_activate token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def left_activate token, wme, assignments
|
27
|
+
# puts "MEMORY #{@id} left-activated with #{wme}"
|
28
|
+
t = Token.new( token, wme, assignments)
|
29
|
+
t.node = self
|
30
|
+
@last_token = t
|
31
|
+
@tokens << t
|
32
|
+
self.children.each do |child|
|
33
|
+
if child.kind_of? BetaMemory
|
34
|
+
child.left_activate t, nil, {}
|
35
|
+
else
|
36
|
+
child.left_activate t
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# => TODO: investigate if we really need this
|
42
|
+
#def beta_memory
|
43
|
+
# self
|
44
|
+
#end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
module Wongi::Engine
|
2
|
+
|
3
|
+
class BetaNode
|
4
|
+
|
5
|
+
include CoreExt
|
6
|
+
|
7
|
+
attr_writer :rete
|
8
|
+
attr_reader :parent
|
9
|
+
attr_accessor :children
|
10
|
+
attr_predicate :debug
|
11
|
+
|
12
|
+
def initialize parent = nil
|
13
|
+
@parent = parent
|
14
|
+
@children = []
|
15
|
+
if parent
|
16
|
+
parent.children << self
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def depth
|
21
|
+
@depth ||= if parent.nil?
|
22
|
+
0
|
23
|
+
else
|
24
|
+
parent.depth + 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def rete
|
30
|
+
if parent
|
31
|
+
parent.rete
|
32
|
+
else
|
33
|
+
@rete
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def beta_memory
|
38
|
+
return self if BetaMemory === self # the easiest way to do this at the top
|
39
|
+
beta = children.find { |node| BetaMemory === node }
|
40
|
+
if beta.nil?
|
41
|
+
beta = BetaMemory.new self
|
42
|
+
beta.update_above
|
43
|
+
end
|
44
|
+
beta
|
45
|
+
end
|
46
|
+
|
47
|
+
def join_node alpha, tests, assignment, alpha_deaf
|
48
|
+
existing = children.find{ |node| JoinNode === node && node.equivalent?( alpha, tests, assignment ) }
|
49
|
+
return existing if existing
|
50
|
+
|
51
|
+
node = JoinNode.new self, tests, assignment
|
52
|
+
node.alpha = alpha
|
53
|
+
alpha.betas << node unless alpha_deaf
|
54
|
+
|
55
|
+
node
|
56
|
+
end
|
57
|
+
|
58
|
+
def optional_node alpha, tests, assignment, alpha_deaf
|
59
|
+
node = OptionalNode.new self, tests, assignment
|
60
|
+
node.alpha = alpha
|
61
|
+
alpha.betas << node unless alpha_deaf
|
62
|
+
node
|
63
|
+
end
|
64
|
+
|
65
|
+
def filter_node test
|
66
|
+
existing = children.find{ |node| FilterNode === node && node.equivalent?( test ) }
|
67
|
+
return existing if existing
|
68
|
+
|
69
|
+
node = FilterNode.new self, test
|
70
|
+
node.update_above
|
71
|
+
node
|
72
|
+
end
|
73
|
+
|
74
|
+
def neg_node alpha, tests, alpha_deaf
|
75
|
+
node = NegNode.new self, tests, alpha
|
76
|
+
alpha.betas << node unless alpha_deaf
|
77
|
+
node.update_above
|
78
|
+
node
|
79
|
+
end
|
80
|
+
|
81
|
+
def ncc_node condition, earlier, parameters, alpha_deaf
|
82
|
+
bottom = network condition.children, earlier, parameters, alpha_deaf
|
83
|
+
self.children.each do |node|
|
84
|
+
if node.kind_of?( NccNode ) and node.partner.parent == bottom
|
85
|
+
return node
|
86
|
+
end
|
87
|
+
end
|
88
|
+
ncc = NccNode.new self
|
89
|
+
partner = NccPartner.new bottom.beta_memory
|
90
|
+
ncc.partner = partner
|
91
|
+
partner.ncc = ncc
|
92
|
+
partner.divergent = self
|
93
|
+
# partner.conjuncts = condition.children.size
|
94
|
+
ncc.update_above
|
95
|
+
partner.update_above
|
96
|
+
ncc
|
97
|
+
end
|
98
|
+
|
99
|
+
CompilationContext = Struct.new :node, :rete, :earlier, :parameters, :alpha_deaf
|
100
|
+
def network conditions, earlier, parameters, alpha_deaf
|
101
|
+
# puts "Getting beta subnetwork"
|
102
|
+
conditions.inject(CompilationContext.new self, self.rete, earlier, parameters, alpha_deaf) do |context, condition|
|
103
|
+
condition.compile context
|
104
|
+
end.node
|
105
|
+
end
|
106
|
+
|
107
|
+
def update_above
|
108
|
+
update_from self.parent
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
|
113
|
+
def propagate_activation token, wme, assignments
|
114
|
+
self.children.each do |child|
|
115
|
+
child.left_activate token, wme, assignments
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def update_from parent
|
120
|
+
case parent
|
121
|
+
|
122
|
+
when BetaMemory
|
123
|
+
parent.tokens.each do |token|
|
124
|
+
self.left_activate token, nil, {}
|
125
|
+
end
|
126
|
+
|
127
|
+
when JoinNode, OptionalNode
|
128
|
+
tmp = parent.children
|
129
|
+
parent.children = [ self ]
|
130
|
+
parent.alpha.wmes.each do |wme|
|
131
|
+
parent.right_activate wme
|
132
|
+
end
|
133
|
+
parent.children = tmp
|
134
|
+
|
135
|
+
when FilterNode
|
136
|
+
tmp = parent.children
|
137
|
+
parent.children = [ self ]
|
138
|
+
parent.parent.tokens.each do |token|
|
139
|
+
parent.left_activate token
|
140
|
+
end
|
141
|
+
parent.children = tmp
|
142
|
+
|
143
|
+
when NegNode
|
144
|
+
parent.tokens.each do |token|
|
145
|
+
if token.neg_join_results.empty?
|
146
|
+
left_activate token, nil, {}
|
147
|
+
end
|
148
|
+
end
|
149
|
+
parent.alpha.wmes.each do |wme|
|
150
|
+
parent.right_activate wme
|
151
|
+
end
|
152
|
+
|
153
|
+
when NccNode
|
154
|
+
parent.tokens.each do |token|
|
155
|
+
if token.ncc_results.empty?
|
156
|
+
left_activate token, nil, {}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
end # => case
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Wongi
|
2
|
+
module Engine
|
3
|
+
|
4
|
+
|
5
|
+
class FilterTest
|
6
|
+
|
7
|
+
def passes? token
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def compile context
|
12
|
+
context.node = context.node.beta_memory.filter_node( self )
|
13
|
+
context.earlier << self
|
14
|
+
context
|
15
|
+
end
|
16
|
+
|
17
|
+
def == other
|
18
|
+
self.class == other.class
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
class EqualityTest < FilterTest
|
24
|
+
|
25
|
+
attr_reader :x, :y
|
26
|
+
|
27
|
+
def initialize x, y
|
28
|
+
@x, @y = x, y
|
29
|
+
end
|
30
|
+
|
31
|
+
def passes? token
|
32
|
+
|
33
|
+
x = if Template.variable? @x
|
34
|
+
token[@x]
|
35
|
+
else
|
36
|
+
@x
|
37
|
+
end
|
38
|
+
|
39
|
+
y = if Template.variable? @y
|
40
|
+
token[@y]
|
41
|
+
else
|
42
|
+
@y
|
43
|
+
end
|
44
|
+
|
45
|
+
return false if x == :_ || y == :_
|
46
|
+
return x == y
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
def == other
|
51
|
+
super && x == other.x && y == other.y
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
class InequalityTest < FilterTest
|
57
|
+
|
58
|
+
attr_reader :x, :y
|
59
|
+
|
60
|
+
def initialize x, y
|
61
|
+
@x, @y = x, y
|
62
|
+
end
|
63
|
+
|
64
|
+
def passes? token
|
65
|
+
|
66
|
+
x = if Template.variable? @x
|
67
|
+
token[@x]
|
68
|
+
else
|
69
|
+
@x
|
70
|
+
end
|
71
|
+
|
72
|
+
y = if Template.variable? @y
|
73
|
+
token[@y]
|
74
|
+
else
|
75
|
+
@y
|
76
|
+
end
|
77
|
+
|
78
|
+
return false if x == :_ || y == :_
|
79
|
+
return x != y
|
80
|
+
|
81
|
+
end
|
82
|
+
|
83
|
+
def == other
|
84
|
+
super && x == other.x && y == other.y
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
class FilterNode < BetaNode
|
90
|
+
|
91
|
+
attr_accessor :test
|
92
|
+
|
93
|
+
def initialize parent, test
|
94
|
+
super parent
|
95
|
+
self.test = test
|
96
|
+
end
|
97
|
+
|
98
|
+
def left_activate token
|
99
|
+
if test.passes? token
|
100
|
+
propagate_activation token, nil, {}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def equivalent? test
|
105
|
+
test == self.test
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|