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.
Files changed (59) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE +22 -0
  4. data/README.md +349 -0
  5. data/Rakefile +2 -0
  6. data/examples/ex01.rb +23 -0
  7. data/examples/ex02.rb +36 -0
  8. data/examples/graphviz.rb +15 -0
  9. data/examples/timeline.rb +48 -0
  10. data/lib/wongi-engine.rb +22 -0
  11. data/lib/wongi-engine/alpha_memory.rb +46 -0
  12. data/lib/wongi-engine/beta.rb +10 -0
  13. data/lib/wongi-engine/beta/beta_memory.rb +48 -0
  14. data/lib/wongi-engine/beta/beta_node.rb +164 -0
  15. data/lib/wongi-engine/beta/filter_node.rb +109 -0
  16. data/lib/wongi-engine/beta/join_node.rb +127 -0
  17. data/lib/wongi-engine/beta/ncc_node.rb +46 -0
  18. data/lib/wongi-engine/beta/ncc_partner.rb +43 -0
  19. data/lib/wongi-engine/beta/neg_node.rb +58 -0
  20. data/lib/wongi-engine/beta/optional_node.rb +43 -0
  21. data/lib/wongi-engine/beta/or_node.rb +76 -0
  22. data/lib/wongi-engine/beta/production_node.rb +31 -0
  23. data/lib/wongi-engine/core_ext.rb +57 -0
  24. data/lib/wongi-engine/dsl.rb +112 -0
  25. data/lib/wongi-engine/dsl/action.rb +12 -0
  26. data/lib/wongi-engine/dsl/actions/error_generator.rb +42 -0
  27. data/lib/wongi-engine/dsl/actions/simple_action.rb +23 -0
  28. data/lib/wongi-engine/dsl/actions/simple_collector.rb +51 -0
  29. data/lib/wongi-engine/dsl/actions/statement_generator.rb +52 -0
  30. data/lib/wongi-engine/dsl/actions/trace_action.rb +52 -0
  31. data/lib/wongi-engine/dsl/any_rule.rb +48 -0
  32. data/lib/wongi-engine/dsl/dsl_builder.rb +44 -0
  33. data/lib/wongi-engine/dsl/dsl_extensions.rb +43 -0
  34. data/lib/wongi-engine/dsl/extension_clause.rb +36 -0
  35. data/lib/wongi-engine/dsl/generation_clause.rb +15 -0
  36. data/lib/wongi-engine/dsl/generic_production_rule.rb +78 -0
  37. data/lib/wongi-engine/dsl/ncc_production_rule.rb +21 -0
  38. data/lib/wongi-engine/dsl/production_rule.rb +4 -0
  39. data/lib/wongi-engine/dsl/query.rb +24 -0
  40. data/lib/wongi-engine/graph.rb +71 -0
  41. data/lib/wongi-engine/model_context.rb +13 -0
  42. data/lib/wongi-engine/network.rb +416 -0
  43. data/lib/wongi-engine/network/collectable.rb +42 -0
  44. data/lib/wongi-engine/network/debug.rb +25 -0
  45. data/lib/wongi-engine/ruleset.rb +74 -0
  46. data/lib/wongi-engine/template.rb +111 -0
  47. data/lib/wongi-engine/token.rb +137 -0
  48. data/lib/wongi-engine/version.rb +5 -0
  49. data/lib/wongi-engine/wme.rb +134 -0
  50. data/lib/wongi-engine/wme_match_data.rb +34 -0
  51. data/spec/dataset_spec.rb +26 -0
  52. data/spec/dsl_spec.rb +9 -0
  53. data/spec/high_level_spec.rb +341 -0
  54. data/spec/ruleset_spec.rb +54 -0
  55. data/spec/simple_action_spec.rb +40 -0
  56. data/spec/spec_helper.rb +1 -0
  57. data/spec/wme_spec.rb +83 -0
  58. data/wongi-engine.gemspec +19 -0
  59. metadata +110 -0
@@ -0,0 +1,15 @@
1
+ require 'wongi-engine'
2
+
3
+ include Wongi::Engine
4
+
5
+ ds = Network.new
6
+ ds << rule('demo') {
7
+ forall {
8
+ has 1, 2, 3
9
+ maybe 4, 5, 6
10
+ }
11
+ }
12
+
13
+ File.open "rete.dot", "w" do |io|
14
+ Graph.new( ds ).dot( io )
15
+ end
@@ -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!
@@ -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