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,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