wongi-engine 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,112 @@
1
+ def ruleset name = nil, &definition
2
+ rs = Wongi::Engine::Ruleset.new
3
+ if ! name.nil?
4
+ rs.name name
5
+ end
6
+ rs.instance_eval &definition if block_given?
7
+ rs
8
+ end
9
+
10
+ def rule name, &definition
11
+ r = Wongi::Engine::ProductionRule.new name
12
+ r.instance_eval &definition
13
+ r
14
+ end
15
+
16
+ def query name, &definition
17
+ q = Wongi::Engine::Query.new name
18
+ q.instance_eval &definition
19
+ q
20
+ end
21
+
22
+ def dsl &definition
23
+ Wongi::Engine::DSLBuilder.new.build &definition
24
+ end
25
+
26
+ require 'wongi-engine/dsl/dsl_extensions'
27
+ require 'wongi-engine/dsl/dsl_builder'
28
+ require 'wongi-engine/dsl/action'
29
+ require 'wongi-engine/dsl/generation_clause'
30
+ require 'wongi-engine/dsl/extension_clause'
31
+ require 'wongi-engine/dsl/generic_production_rule'
32
+ require 'wongi-engine/dsl/production_rule'
33
+ require 'wongi-engine/dsl/ncc_production_rule'
34
+ require 'wongi-engine/dsl/any_rule'
35
+ require 'wongi-engine/dsl/query'
36
+ require 'wongi-engine/dsl/actions/simple_action'
37
+ require 'wongi-engine/dsl/actions/statement_generator'
38
+ require 'wongi-engine/dsl/actions/simple_collector'
39
+ require 'wongi-engine/dsl/actions/trace_action'
40
+ require 'wongi-engine/dsl/actions/error_generator'
41
+
42
+
43
+
44
+ dsl {
45
+
46
+ section :forall
47
+
48
+ clause :has, :fact
49
+ action Wongi::Engine::Template
50
+
51
+ clause :missing, :neg
52
+ action Wongi::Engine::NegTemplate
53
+
54
+ clause :none, :ncc
55
+ accept Wongi::Engine::NccProductionRule
56
+
57
+ clause :any
58
+ action Wongi::Engine::AnyRule
59
+
60
+ clause :maybe, :optional
61
+ accept Wongi::Engine::OptionalTemplate
62
+
63
+ clause :same, :eq, :equal
64
+ accept Wongi::Engine::EqualityTest
65
+
66
+ clause :diff, :ne
67
+ accept Wongi::Engine::InequalityTest
68
+
69
+ clause :asserted, :added
70
+ body { |s, p, o|
71
+ missing s, p, o, -1
72
+ has s, p, o, 0
73
+ }
74
+
75
+ clause :retracted, :removed
76
+ body { |s, p, o|
77
+ has s, p, o, -1
78
+ missing s, p, o, 0
79
+ }
80
+
81
+ clause :kept, :still_has
82
+ body { |s, p, o|
83
+ has s, p, o, -1
84
+ has s, p, o, 0
85
+ }
86
+
87
+ clause :kept_missing, :still_missing
88
+ body { |s, p, o|
89
+ missing s, p, o, -1
90
+ missing s, p, o, 0
91
+ }
92
+
93
+
94
+ section :make
95
+
96
+ clause :gen
97
+ accept Wongi::Engine::GenerationClause
98
+
99
+ clause :trace
100
+ action Wongi::Engine::TraceAction
101
+
102
+ clause :error
103
+ action Wongi::Engine::ErrorGenerator
104
+
105
+ clause :collect
106
+ action Wongi::Engine::SimpleCollector
107
+
108
+ clause :action
109
+ action Wongi::Engine::SimpleAction
110
+
111
+ }
112
+
@@ -0,0 +1,12 @@
1
+ module Wongi::Engine
2
+ class Action
3
+
4
+ include CoreExt
5
+
6
+ attr_accessor :production
7
+ attr_accessor :rule
8
+ attr_accessor :name
9
+ attr_accessor :rete
10
+
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ module Wongi
2
+ module Engine
3
+ class ReteError
4
+
5
+ attr_reader :token, :message
6
+ def initialize token, message, literate
7
+ @token, @message, @literate = token, message, literate
8
+ end
9
+ def literate?
10
+ @literate
11
+ end
12
+ end
13
+
14
+ class ErrorGenerator < Wongi::Engine::Action
15
+
16
+ def initialize message = nil, &messenger
17
+ @message, @messenger = message, messenger
18
+ end
19
+
20
+ def rete=
21
+ super
22
+ rete.add_collector :error, self
23
+ end
24
+
25
+ def errors
26
+ production.tokens.map do |token|
27
+ message = if @messenger
28
+ @messenger.call token.assignments
29
+ else
30
+ @message
31
+ end
32
+ ReteError.new token, message, literate?
33
+ end
34
+ end
35
+
36
+ def literate?
37
+ not @messenger.nil?
38
+ end
39
+
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,23 @@
1
+ module Wongi::Engine
2
+
3
+ class SimpleAction < Action
4
+
5
+ def initialize action = nil, *args, &block
6
+ @action = if action.is_a? Class
7
+ action.new *args, &block
8
+ else
9
+ action || block
10
+ end
11
+ end
12
+
13
+ def execute token
14
+ if @action.respond_to? :call
15
+ @action.call token
16
+ elsif @action.respond_to? :execute
17
+ @action.execute token
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,51 @@
1
+ module Wongi::Engine
2
+
3
+ class SimpleCollector < Action
4
+
5
+ def self.collector
6
+ Class.new self
7
+ end
8
+
9
+ def initialize variable, name = nil
10
+ @variable = variable
11
+ @name = name if name
12
+ #(class << self; self; end).instance_eval do
13
+ # define_method method do
14
+ # collect variable
15
+ # end
16
+ # alias_method method, :default_collect
17
+ # end
18
+ end
19
+
20
+ def default_collect
21
+ collect @variable
22
+ end
23
+
24
+ def name= n
25
+ @name = n unless @name
26
+ end
27
+
28
+ def rete= rete
29
+ rete.add_collector self, name
30
+ end
31
+
32
+ def collect var
33
+ production.tokens.map { |token| token[var] }
34
+ end
35
+
36
+ end
37
+
38
+ class GenericCollectClause
39
+
40
+ def initialize name, variable
41
+
42
+ end
43
+
44
+ def import_into rete
45
+ collector = SimpleCollector.new @variable
46
+
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,52 @@
1
+ module Wongi::Engine
2
+ class StatementGenerator < Action
3
+
4
+ def initialize template
5
+ @template = template
6
+ end
7
+
8
+ def execute token
9
+
10
+ subject = if Template.variable?( @template.subject )
11
+ v = token[ @template.subject ]
12
+ raise "Unbound variable #{@template.subject} in token #{token}" if v.nil?
13
+ v
14
+ else
15
+ @template.subject
16
+ end
17
+
18
+ predicate = if Template.variable?( @template.predicate )
19
+ v = token[ @template.predicate ]
20
+ raise "Unbound variable #{@template.predicate} in token #{token}" if v.nil?
21
+ v
22
+ else
23
+ @template.predicate
24
+ end
25
+
26
+ object = if Template.variable?( @template.object )
27
+ v = token[ @template.object ]
28
+ raise "Unbound variable #{@template.object} in token #{token}" if v.nil?
29
+ v
30
+ else
31
+ @template.object
32
+ end
33
+
34
+ wme = WME.new subject, predicate, object
35
+
36
+ production.tracer.trace( action: self, wme: wme ) if production.tracer
37
+ if existing = rete.exists?( wme )
38
+ generated = existing.generating_tokens.size
39
+ if generated > 0 && ! token.generated_wmes.include?( existing )
40
+ token.generated_wmes << existing
41
+ existing.generating_tokens << token
42
+ end
43
+ else
44
+ added = rete << wme
45
+ token.generated_wmes << added
46
+ added.generating_tokens << token
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ module Wongi::Engine
2
+ class TraceAction < Action
3
+
4
+ class DefaultTracer
5
+
6
+ attr_accessor :action
7
+
8
+ def trace args
9
+ case args[:action]
10
+ when TraceAction
11
+ if args[:token]
12
+ action.io.puts "EXECUTED RULE #{args[:action].rule.name} WITH #{args[:token]}"
13
+ else
14
+ action.io.puts "EXECUTED RULE #{args[:action].rule.name}"
15
+ end
16
+ when StatementGenerator
17
+ action.io.puts "GENERATED #{args[:wme]}" if action.generation?
18
+ end
19
+ end
20
+
21
+ end
22
+
23
+ attr_reader :io
24
+ attr_predicate :generation, :values
25
+
26
+ def initialize opts = { }
27
+ [:generation, :values, :tracer, :tracer_class, :io].each do |option|
28
+ if opts.has_key? option
29
+ instance_variable_set "@#{option}", opts[option]
30
+ end
31
+ end
32
+ @io ||= $stdout
33
+ @tracer ||= (@tracer_class || DefaultTracer).new
34
+ @tracer.action = self
35
+ end
36
+
37
+ def trace args
38
+ @tracer.trace args
39
+ end
40
+
41
+ def execute token
42
+ production.tracer = self
43
+ if values?
44
+ trace action: self, token: token
45
+ else
46
+ trace action: self
47
+ end
48
+ end
49
+ end
50
+
51
+
52
+ end
@@ -0,0 +1,48 @@
1
+ module Wongi::Engine
2
+ class AnyRule
3
+
4
+ attr_reader :variants
5
+
6
+ def initialize &block
7
+ @variants = []
8
+ if block
9
+ instance_eval &block
10
+ end
11
+ end
12
+
13
+ def variant &block
14
+ var = VariantRule.new
15
+ var.instance_eval &block
16
+ variants << var
17
+ end
18
+
19
+ def import_into rete
20
+ AnySet.new variants.map { |variant|
21
+ if variant.respond_to? :import_into
22
+ variant.import_into(rete)
23
+ else
24
+ variant
25
+ end
26
+ }
27
+ end
28
+
29
+ end
30
+
31
+ class VariantRule < GenericProductionRule
32
+
33
+ def initialize name = nil
34
+ super
35
+ @current_section = :forall
36
+ end
37
+
38
+ def import_into rete
39
+ VariantSet.new @acceptors[:forall].map { |condition|
40
+ if condition.respond_to? :import_into
41
+ condition.import_into(rete)
42
+ else
43
+ condition
44
+ end
45
+ }
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,44 @@
1
+ module Wongi::Engine
2
+ class DSLBuilder
3
+
4
+ def initialize
5
+ @current_section = nil
6
+ @current_clause = nil
7
+ @clauses = []
8
+ end
9
+
10
+ def build &definition
11
+ instance_eval &definition
12
+ @clauses.each do |c|
13
+ DSLExtensions.create_extension c
14
+ end
15
+ end
16
+
17
+ def section s
18
+ @current_section = s
19
+ end
20
+
21
+ def clause *c
22
+ @current_clause = c
23
+ end
24
+
25
+ def action klass = nil, &block
26
+ raise "Cannot create an action without a clause" if @current_clause.nil?
27
+ @clauses << { :section => @current_section, :clause => @current_clause, :action => klass || block }
28
+ @current_clause = nil
29
+ end
30
+
31
+ def body klass = nil, &block
32
+ raise "Cannot create a body without a clause" if @current_clause.nil?
33
+ @clauses << { :section => @current_section, :clause => @current_clause, :body => klass || block }
34
+ @current_clause = nil
35
+ end
36
+
37
+ def accept klass
38
+ raise "Cannot create an acceptor without a clause" if @current_clause.nil?
39
+ @clauses << { :section => @current_section, :clause => @current_clause, :accept => klass }
40
+ @current_clause = nil
41
+ end
42
+
43
+ end
44
+ end