Class: KBS::Engine
- Inherits:
-
Object
- Object
- KBS::Engine
- Defined in:
- lib/kbs/engine.rb
Direct Known Subclasses
Instance Attribute Summary collapse
-
#alpha_memories ⇒ Object
readonly
Returns the value of attribute alpha_memories.
-
#production_nodes ⇒ Object
readonly
Returns the value of attribute production_nodes.
-
#rules ⇒ Object
readonly
Returns the value of attribute rules.
-
#working_memory ⇒ Object
readonly
Returns the value of attribute working_memory.
Instance Method Summary collapse
- #add_fact(type, attributes = {}) ⇒ Object
- #add_rule(rule) ⇒ Object
-
#initialize ⇒ Engine
constructor
A new instance of Engine.
- #remove_fact(fact) ⇒ Object
-
#reset ⇒ Object
Clear all transient RETE state while preserving the compiled rule network.
- #run ⇒ Object
- #update(action, fact) ⇒ Object
Constructor Details
#initialize ⇒ Engine
Returns a new instance of Engine.
7 8 9 10 11 12 13 14 15 16 17 18 19 |
# File 'lib/kbs/engine.rb', line 7 def initialize @working_memory = WorkingMemory.new @rules = [] @alpha_memories = {} @production_nodes = {} @root_beta_memory = BetaMemory.new # Add initial dummy token to root beta memory # This represents "no conditions matched yet" and allows the first condition to match @root_beta_memory.add_token(Token.new(nil, nil, nil)) @working_memory.add_observer(self) end |
Instance Attribute Details
#alpha_memories ⇒ Object (readonly)
Returns the value of attribute alpha_memories.
5 6 7 |
# File 'lib/kbs/engine.rb', line 5 def alpha_memories @alpha_memories end |
#production_nodes ⇒ Object (readonly)
Returns the value of attribute production_nodes.
5 6 7 |
# File 'lib/kbs/engine.rb', line 5 def production_nodes @production_nodes end |
#rules ⇒ Object (readonly)
Returns the value of attribute rules.
5 6 7 |
# File 'lib/kbs/engine.rb', line 5 def rules @rules end |
#working_memory ⇒ Object (readonly)
Returns the value of attribute working_memory.
5 6 7 |
# File 'lib/kbs/engine.rb', line 5 def working_memory @working_memory end |
Instance Method Details
#add_fact(type, attributes = {}) ⇒ Object
26 27 28 29 30 |
# File 'lib/kbs/engine.rb', line 26 def add_fact(type, attributes = {}) fact = Fact.new(type, attributes) @working_memory.add_fact(fact) fact end |
#add_rule(rule) ⇒ Object
21 22 23 24 |
# File 'lib/kbs/engine.rb', line 21 def add_rule(rule) @rules << rule build_network_for_rule(rule) end |
#remove_fact(fact) ⇒ Object
32 33 34 |
# File 'lib/kbs/engine.rb', line 32 def remove_fact(fact) @working_memory.remove_fact(fact) end |
#reset ⇒ Object
Clear all transient RETE state while preserving the compiled rule network.
The RETE network has four levels of transient state:
1. WorkingMemory — holds all asserted facts
2. AlphaMemory — holds facts matching each pattern
3. BetaMemory — holds tokens from condition joins
4. ProductionNode — holds tokens ready to fire
Simply clearing working memory facts doesn't cascade reliably through intermediate beta memories. Stale tokens in beta memories cause false matches when new facts are asserted on the next cycle.
This method clears all four levels directly while preserving the root beta memory's dummy token (needed for first-condition joins).
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/kbs/engine.rb', line 70 def reset # 1. Clear working memory directly (bypass observer — we clear everything) @working_memory.facts.clear # 2. Clear alpha memories and their downstream beta memories @alpha_memories.each_value do |alpha_mem| alpha_mem.items.clear # Each alpha memory successor is a JoinNode or NegationNode. # Their successors are intermediate BetaMemory nodes. # The root beta memory is never a join node successor, so # its dummy token is preserved. alpha_mem.successors.each do |join_node| next unless join_node.respond_to?(:successors) join_node.successors.each do |beta_or_prod| beta_or_prod.tokens.clear if beta_or_prod.respond_to?(:tokens) end end end # 3. Clear production node tokens @production_nodes.each_value { |node| node.tokens.clear } # 4. Clear stale child references from the root dummy token @root_beta_memory.tokens.each { |t| t.children.clear } end |
#run ⇒ Object
48 49 50 51 52 53 54 |
# File 'lib/kbs/engine.rb', line 48 def run @production_nodes.values.each do |node| node.tokens.each do |token| node.fire_rule(token) end end end |
#update(action, fact) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/kbs/engine.rb', line 36 def update(action, fact) if action == :add @alpha_memories.each do |pattern, memory| memory.activate(fact) if fact.matches?(pattern) end elsif action == :remove @alpha_memories.each do |pattern, memory| memory.deactivate(fact) if fact.matches?(pattern) end end end |