kbs 0.0.1 → 0.1.0

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 (86) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/deploy-github-pages.yml +52 -0
  3. data/CHANGELOG.md +68 -2
  4. data/README.md +235 -334
  5. data/docs/DOCUMENTATION_STATUS.md +158 -0
  6. data/docs/advanced/custom-persistence.md +775 -0
  7. data/docs/advanced/debugging.md +726 -0
  8. data/docs/advanced/index.md +8 -0
  9. data/docs/advanced/performance.md +832 -0
  10. data/docs/advanced/testing.md +691 -0
  11. data/docs/api/blackboard.md +1157 -0
  12. data/docs/api/engine.md +978 -0
  13. data/docs/api/facts.md +1212 -0
  14. data/docs/api/index.md +12 -0
  15. data/docs/api/rules.md +1034 -0
  16. data/docs/architecture/blackboard.md +553 -0
  17. data/docs/architecture/index.md +277 -0
  18. data/docs/architecture/network-structure.md +343 -0
  19. data/docs/architecture/rete-algorithm.md +737 -0
  20. data/docs/assets/css/custom.css +83 -0
  21. data/docs/assets/images/blackboard-architecture.svg +136 -0
  22. data/docs/assets/images/compiled-network.svg +101 -0
  23. data/docs/assets/images/fact-assertion-flow.svg +117 -0
  24. data/docs/assets/images/kbs.jpg +0 -0
  25. data/docs/assets/images/pattern-matching-trace.svg +136 -0
  26. data/docs/assets/images/rete-network-layers.svg +96 -0
  27. data/docs/assets/images/system-layers.svg +69 -0
  28. data/docs/assets/images/trading-signal-network.svg +139 -0
  29. data/docs/assets/js/mathjax.js +17 -0
  30. data/docs/examples/expert-systems.md +1031 -0
  31. data/docs/examples/index.md +9 -0
  32. data/docs/examples/multi-agent.md +1335 -0
  33. data/docs/examples/stock-trading.md +488 -0
  34. data/docs/guides/blackboard-memory.md +558 -0
  35. data/docs/guides/dsl.md +1321 -0
  36. data/docs/guides/facts.md +652 -0
  37. data/docs/guides/getting-started.md +383 -0
  38. data/docs/guides/index.md +23 -0
  39. data/docs/guides/negation.md +529 -0
  40. data/docs/guides/pattern-matching.md +561 -0
  41. data/docs/guides/persistence.md +451 -0
  42. data/docs/guides/variable-binding.md +491 -0
  43. data/docs/guides/writing-rules.md +755 -0
  44. data/docs/index.md +157 -0
  45. data/docs/installation.md +156 -0
  46. data/docs/quick-start.md +228 -0
  47. data/examples/README.md +2 -2
  48. data/examples/advanced_example.rb +2 -2
  49. data/examples/advanced_example_dsl.rb +224 -0
  50. data/examples/ai_enhanced_kbs.rb +1 -1
  51. data/examples/ai_enhanced_kbs_dsl.rb +538 -0
  52. data/examples/blackboard_demo_dsl.rb +50 -0
  53. data/examples/car_diagnostic.rb +1 -1
  54. data/examples/car_diagnostic_dsl.rb +54 -0
  55. data/examples/concurrent_inference_demo.rb +5 -5
  56. data/examples/concurrent_inference_demo_dsl.rb +363 -0
  57. data/examples/csv_trading_system.rb +1 -1
  58. data/examples/csv_trading_system_dsl.rb +525 -0
  59. data/examples/knowledge_base.db +0 -0
  60. data/examples/portfolio_rebalancing_system.rb +2 -2
  61. data/examples/portfolio_rebalancing_system_dsl.rb +613 -0
  62. data/examples/redis_trading_demo_dsl.rb +177 -0
  63. data/examples/run_all.rb +50 -0
  64. data/examples/run_all_dsl.rb +49 -0
  65. data/examples/stock_trading_advanced.rb +1 -1
  66. data/examples/stock_trading_advanced_dsl.rb +404 -0
  67. data/examples/temp.txt +7693 -0
  68. data/examples/temp_dsl.txt +8447 -0
  69. data/examples/timestamped_trading.rb +1 -1
  70. data/examples/timestamped_trading_dsl.rb +258 -0
  71. data/examples/trading_demo.rb +1 -1
  72. data/examples/trading_demo_dsl.rb +322 -0
  73. data/examples/working_demo.rb +1 -1
  74. data/examples/working_demo_dsl.rb +160 -0
  75. data/lib/kbs/blackboard/engine.rb +3 -3
  76. data/lib/kbs/blackboard/fact.rb +1 -1
  77. data/lib/kbs/condition.rb +1 -1
  78. data/lib/kbs/dsl/knowledge_base.rb +1 -1
  79. data/lib/kbs/dsl/variable.rb +1 -1
  80. data/lib/kbs/{rete_engine.rb → engine.rb} +1 -1
  81. data/lib/kbs/fact.rb +1 -1
  82. data/lib/kbs/version.rb +1 -1
  83. data/lib/kbs.rb +2 -2
  84. data/mkdocs.yml +181 -0
  85. metadata +66 -6
  86. data/examples/stock_trading_system.rb.bak +0 -563
@@ -0,0 +1,277 @@
1
+ # Architecture Overview
2
+
3
+ KBS is built on a layered architecture that separates concerns while maintaining high performance.
4
+
5
+ ## System Layers
6
+
7
+ ![KBS System Layers](../assets/images/system-layers.svg)
8
+
9
+ *KBS uses a layered architecture where facts flow from your application through the DSL, RETE engine, and working memory to one of two storage backends.*
10
+
11
+ ## Core Components
12
+
13
+ ### 1. RETE Engine
14
+
15
+ The heart of KBS. Implements Charles Forgy's RETE algorithm with modern optimizations.
16
+
17
+ **Key Files:**
18
+ - `lib/kbs/rete_engine.rb` - Main engine coordinator
19
+ - `lib/kbs/alpha_memory.rb` - Pattern-level fact storage
20
+ - `lib/kbs/beta_memory.rb` - Token (partial match) storage
21
+ - `lib/kbs/join_node.rb` - Inter-condition joins
22
+ - `lib/kbs/negation_node.rb` - Negated condition handling
23
+ - `lib/kbs/production_node.rb` - Rule firing coordination
24
+
25
+ **Responsibilities:**
26
+ - Compile rules into discrimination networks
27
+ - Propagate fact changes through the network
28
+ - Maintain partial matches (tokens)
29
+ - Fire rules when all conditions are satisfied
30
+
31
+ **Learn more**: [RETE Algorithm Details](rete-algorithm.md)
32
+
33
+ ### 2. Working Memory
34
+
35
+ Stores facts and notifies the RETE engine of changes using the Observer pattern.
36
+
37
+ **Variants:**
38
+ - **`WorkingMemory`**: Transient in-memory storage
39
+ - **`Blackboard::Memory`**: Persistent storage with audit trails
40
+
41
+ **Responsibilities:**
42
+ - Store facts
43
+ - Notify observers when facts are added/removed
44
+ - Support queries and bulk operations
45
+
46
+ **Learn more**: [Blackboard Architecture](blackboard.md)
47
+
48
+ ### 3. DSL Layer
49
+
50
+ Provides a Ruby-native interface for defining rules, conditions, and patterns.
51
+
52
+ **Key Classes:**
53
+ - `Rule` - Production rule with conditions and actions
54
+ - `Condition` - Pattern specification for fact matching
55
+ - `Fact` - Knowledge representation unit
56
+
57
+ **Example:**
58
+ ```ruby
59
+ Rule.new("alert") do |r|
60
+ r.conditions = [
61
+ Condition.new(:sensor, { temp: :t? }),
62
+ Condition.new(:threshold, { max: :max? })
63
+ ]
64
+
65
+ r.action = lambda { |facts, bindings|
66
+ puts "Alert!" if bindings[:t?] > bindings[:max?]
67
+ }
68
+ end
69
+ ```
70
+
71
+ ### 4. Blackboard System
72
+
73
+ Multi-agent collaboration framework with persistent shared memory.
74
+
75
+ **Components:**
76
+ - **Memory** - Central workspace for facts
77
+ - **MessageQueue** - Priority-based agent communication
78
+ - **AuditLog** - Complete history of changes
79
+ - **Persistence** - Pluggable storage backends (SQLite, Redis, Hybrid)
80
+
81
+ **Use Cases:**
82
+ - Multi-agent problem solving
83
+ - Audit requirements
84
+ - Long-running systems
85
+ - Distributed reasoning
86
+
87
+ **Learn more**: [Blackboard System Details](blackboard.md)
88
+
89
+ ## Data Flow
90
+
91
+ ### Adding a Fact
92
+
93
+ ```
94
+ User Code
95
+
96
+ ├─→ engine.add_fact(:stock, price: 150)
97
+
98
+
99
+ WorkingMemory.add_fact(fact)
100
+
101
+ ├─→ @facts << fact
102
+ └─→ notify_observers(:add, fact)
103
+
104
+
105
+ Engine.update(:add, fact)
106
+
107
+ └─→ For each AlphaMemory:
108
+ if fact.matches?(pattern)
109
+
110
+
111
+ AlphaMemory.activate(fact)
112
+
113
+ └─→ JoinNode.right_activate(fact)
114
+
115
+ └─→ Create tokens, propagate...
116
+
117
+
118
+ ProductionNode
119
+ ```
120
+
121
+ ### Firing Rules
122
+
123
+ ```
124
+ User Code
125
+
126
+ ├─→ engine.run()
127
+
128
+
129
+ For each ProductionNode:
130
+
131
+ ├─→ For each token:
132
+ │ │
133
+ │ └─→ rule.fire(token.facts)
134
+ │ │
135
+ │ └─→ Extract bindings
136
+ │ │
137
+ │ └─→ Execute action lambda
138
+ │ │
139
+ │ └─→ User code in action
140
+
141
+ └─→ Mark tokens as fired
142
+ ```
143
+
144
+ ## Network Compilation
145
+
146
+ When you add a rule, KBS compiles it into a discrimination network:
147
+
148
+ ```ruby
149
+ rule = Rule.new("example") do |r|
150
+ r.conditions = [
151
+ Condition.new(:stock, { symbol: :sym? }),
152
+ Condition.new(:alert, { symbol: :sym? }, negated: true)
153
+ ]
154
+ r.action = ->(facts, bindings) { puts bindings[:sym?] }
155
+ end
156
+
157
+ engine.add_rule(rule)
158
+ ```
159
+
160
+ **Compiled Network:**
161
+
162
+ ![Compiled RETE Network](../assets/images/compiled-network.svg)
163
+
164
+ *The rule compiles into a network with alpha memories for each condition type, join nodes to combine matches, a negation node for the NOT condition, and a production node that fires when all conditions are satisfied.*
165
+
166
+ **Learn more**: [Network Structure](network-structure.md)
167
+
168
+ ## Performance Characteristics
169
+
170
+ | Operation | Complexity | Notes |
171
+ |-----------|-----------|-------|
172
+ | Add rule | O(C × F) | C = conditions, F = existing facts |
173
+ | Add fact | O(N) | N = activated nodes (typically << total) |
174
+ | Remove fact | O(T) | T = tokens containing fact |
175
+ | Fire rules | O(M) | M = complete matches |
176
+ | Network sharing | O(1) | Same pattern → same alpha memory |
177
+
178
+ ## Design Principles
179
+
180
+ ### 1. Algorithm Fidelity
181
+ Maintain RETE correctness per Forgy's specifications. No shortcuts that break semantics.
182
+
183
+ ### 2. Separation of Concerns
184
+ - Engine: Pattern matching
185
+ - Memory: Storage
186
+ - DSL: User interface
187
+ - Blackboard: Collaboration
188
+
189
+ Each component is independently testable and swappable.
190
+
191
+ ### 3. Performance Through Clarity
192
+ Optimize algorithm first (unlinking, network sharing), then profile before micro-optimizations.
193
+
194
+ ### 4. Testability
195
+ Every method testable in isolation. Dependency injection for external services.
196
+
197
+ ### 5. Graceful Degradation
198
+ Optional features (Redis, AI) don't block core functionality. Fallback to SQLite or in-memory.
199
+
200
+ ### 6. Auditability
201
+ Complete audit trails for production systems. Know *why* a rule fired.
202
+
203
+ ## Extension Points
204
+
205
+ ### Custom Persistence
206
+
207
+ Implement `KBS::Blackboard::Persistence::Store`:
208
+
209
+ ```ruby
210
+ class MyStore
211
+ def save_fact(fact) ... end
212
+ def load_facts(type) ... end
213
+ def delete_fact(id) ... end
214
+ # ...
215
+ end
216
+
217
+ engine = KBS::Blackboard::Engine.new(store: MyStore.new)
218
+ ```
219
+
220
+ ### Custom Pattern Matching
221
+
222
+ Override `Fact#matches?`:
223
+
224
+ ```ruby
225
+ class MyFact < KBS::Fact
226
+ def matches?(pattern)
227
+ # Custom matching logic
228
+ end
229
+ end
230
+ ```
231
+
232
+ ### Custom Rule Actions
233
+
234
+ Actions are lambdas - inject any Ruby code:
235
+
236
+ ```ruby
237
+ r.action = lambda do |facts, bindings|
238
+ send_email(bindings[:alert?])
239
+ log_to_database(facts)
240
+ trigger_api_call(bindings)
241
+ end
242
+ ```
243
+
244
+ ## File Organization
245
+
246
+ ```
247
+ lib/kbs/
248
+ ├── rete_engine.rb # Main engine
249
+ ├── working_memory.rb # Fact storage
250
+ ├── fact.rb # Fact representation
251
+ ├── rule.rb # Rule definition
252
+ ├── condition.rb # Pattern specification
253
+ ├── token.rb # Partial match
254
+ ├── alpha_memory.rb # Pattern-level cache
255
+ ├── beta_memory.rb # Token storage
256
+ ├── join_node.rb # Inter-condition joins
257
+ ├── negation_node.rb # Negated conditions
258
+ ├── production_node.rb # Rule firing
259
+ └── blackboard/ # Persistent memory
260
+ ├── engine.rb # Blackboard-aware RETE
261
+ ├── memory.rb # Central workspace
262
+ ├── fact.rb # Persisted fact
263
+ ├── message_queue.rb # Agent communication
264
+ ├── audit_log.rb # Change history
265
+ └── persistence/ # Storage backends
266
+ ├── store.rb # Abstract interface
267
+ ├── sqlite_store.rb
268
+ ├── redis_store.rb
269
+ └── hybrid_store.rb
270
+ ```
271
+
272
+ ## Next Steps
273
+
274
+ - **[RETE Algorithm](rete-algorithm.md)** - Deep dive into pattern matching
275
+ - **[Blackboard System](blackboard.md)** - Persistent memory architecture
276
+ - **[Network Structure](network-structure.md)** - How rules compile into networks
277
+ - **[API Reference](../api/index.md)** - Complete class documentation
@@ -0,0 +1,343 @@
1
+ # Network Structure
2
+
3
+ How RETE compiles rules into an efficient discrimination network.
4
+
5
+ ## Overview
6
+
7
+ When you add a rule to the engine, KBS compiles it into a discrimination network—a directed acyclic graph (DAG) of nodes that efficiently matches patterns against facts. This document explains the compilation process, node types, and optimization strategies.
8
+
9
+ ## Network Compilation Process
10
+
11
+ ### Step 1: Parse Rule Conditions
12
+
13
+ ```ruby
14
+ rule = Rule.new("example") do |r|
15
+ r.conditions = [
16
+ Condition.new(:stock, { symbol: :sym?, price: :price? }),
17
+ Condition.new(:threshold, { symbol: :sym?, max: :max? })
18
+ ]
19
+ r.action = lambda { |facts, bindings| ... }
20
+ end
21
+ ```
22
+
23
+ The engine extracts:
24
+ - Condition types (`:stock`, `:threshold`)
25
+ - Patterns (attribute constraints)
26
+ - Variable bindings (`:sym?`, `:price?`, `:max?`)
27
+ - Join tests (`:sym?` appears in both conditions)
28
+
29
+ ### Step 2: Create or Reuse Alpha Memories
30
+
31
+ For each condition, the engine creates or reuses an `AlphaMemory` node:
32
+
33
+ ```ruby
34
+ # Pattern for first condition
35
+ pattern1 = { type: :stock, symbol: :sym?, price: :price? }
36
+ alpha1 = get_or_create_alpha_memory(pattern1)
37
+
38
+ # Pattern for second condition
39
+ pattern2 = { type: :threshold, symbol: :sym?, max: :max? }
40
+ alpha2 = get_or_create_alpha_memory(pattern2)
41
+ ```
42
+
43
+ **Network Sharing**: If another rule has the same pattern, they share the same alpha memory node.
44
+
45
+ ### Step 3: Build Join Network
46
+
47
+ Connect conditions through join nodes:
48
+
49
+ ```ruby
50
+ # Start with root beta memory (contains dummy token)
51
+ current_beta = @root_beta_memory
52
+
53
+ # For each condition
54
+ rule.conditions.each do |condition|
55
+ alpha_memory = get_or_create_alpha_memory(condition.pattern)
56
+
57
+ # Build join tests for variable consistency
58
+ tests = extract_join_tests(condition)
59
+
60
+ # Create join or negation node
61
+ if condition.negated
62
+ node = NegationNode.new(alpha_memory, current_beta, tests)
63
+ else
64
+ node = JoinNode.new(alpha_memory, current_beta, tests)
65
+ end
66
+
67
+ # Create beta memory to store results
68
+ new_beta = BetaMemory.new
69
+ node.successors << new_beta
70
+ current_beta = new_beta
71
+ end
72
+ ```
73
+
74
+ ### Step 4: Attach Production Node
75
+
76
+ ```ruby
77
+ production_node = ProductionNode.new(rule)
78
+ current_beta.successors << production_node
79
+ @production_nodes[rule.name] = production_node
80
+ ```
81
+
82
+ ## Node Types
83
+
84
+ ### Alpha Memory Nodes
85
+
86
+ **Purpose**: Store facts matching a specific pattern
87
+
88
+ **Structure**:
89
+ ```ruby
90
+ class AlphaMemory
91
+ attr_accessor :items # Facts that match pattern
92
+ attr_accessor :successors # Join nodes using this alpha
93
+ attr_accessor :pattern # Pattern to match
94
+ attr_reader :linked # Unlinking state
95
+ end
96
+ ```
97
+
98
+ **Example**:
99
+ ```
100
+ AlphaMemory(stock, symbol: "AAPL")
101
+ items: [stock(symbol: "AAPL", price: 150), ...]
102
+ successors: [JoinNode1, JoinNode2, ...]
103
+ ```
104
+
105
+ ### Beta Memory Nodes
106
+
107
+ **Purpose**: Store partial matches (tokens) as they propagate
108
+
109
+ **Structure**:
110
+ ```ruby
111
+ class BetaMemory
112
+ attr_accessor :tokens # Partial matches
113
+ attr_accessor :successors # Next nodes in network
114
+ attr_reader :linked # Unlinking state
115
+ end
116
+ ```
117
+
118
+ **Example**:
119
+ ```
120
+ BetaMemory
121
+ tokens: [
122
+ Token(parent: root, fact: stock(...)),
123
+ Token(parent: root, fact: stock(...))
124
+ ]
125
+ successors: [JoinNode2]
126
+ ```
127
+
128
+ ### Join Nodes
129
+
130
+ **Purpose**: Combine facts from alpha memory with tokens from beta memory
131
+
132
+ **Structure**:
133
+ ```ruby
134
+ class JoinNode
135
+ attr_accessor :alpha_memory # Right input
136
+ attr_accessor :beta_memory # Left input
137
+ attr_accessor :tests # Join tests to perform
138
+ attr_accessor :successors # Beta memory nodes
139
+ end
140
+ ```
141
+
142
+ **Join Tests**:
143
+ ```ruby
144
+ {
145
+ token_field_index: 0, # Check first fact in token
146
+ token_field: :symbol, # Get its :symbol attribute
147
+ fact_field: :symbol, # Compare with new fact's :symbol
148
+ operation: :eq # Must be equal
149
+ }
150
+ ```
151
+
152
+ ### Negation Nodes
153
+
154
+ **Purpose**: Implement negated conditions (match when pattern is absent)
155
+
156
+ **Structure**:
157
+ ```ruby
158
+ class NegationNode
159
+ attr_accessor :alpha_memory # Pattern to check
160
+ attr_accessor :beta_memory # Tokens to test
161
+ attr_accessor :tests # Join tests
162
+ attr_accessor :tokens_with_matches # Track inhibiting facts
163
+ end
164
+ ```
165
+
166
+ **Behavior**:
167
+ - Token arrives → check alpha memory for matches
168
+ - No matches found → propagate token (condition satisfied)
169
+ - Matches found → block token (condition not satisfied)
170
+ - Match removed → unblock token
171
+
172
+ ### Production Nodes
173
+
174
+ **Purpose**: Fire rule actions when all conditions match
175
+
176
+ **Structure**:
177
+ ```ruby
178
+ class ProductionNode
179
+ attr_accessor :rule # Rule to fire
180
+ attr_accessor :tokens # Complete matches ready to fire
181
+ end
182
+ ```
183
+
184
+ ## Complete Example
185
+
186
+ ### Rule Definition
187
+
188
+ ```ruby
189
+ rule = Rule.new("trading_signal") do |r|
190
+ r.conditions = [
191
+ Condition.new(:stock, { symbol: :sym?, price: :price? }),
192
+ Condition.new(:threshold, { symbol: :sym?, buy_below: :threshold? }),
193
+ Condition.new(:order, { symbol: :sym? }, negated: true)
194
+ ]
195
+
196
+ r.action = lambda do |facts, bindings|
197
+ if bindings[:price?] < bindings[:threshold?]
198
+ puts "BUY #{bindings[:sym?]}"
199
+ end
200
+ end
201
+ end
202
+ ```
203
+
204
+ ### Compiled Network
205
+
206
+ ![Trading Signal Network](../assets/images/trading-signal-network.svg)
207
+
208
+ *The trading signal rule compiles into a network with three join points. The first two join nodes combine stock and threshold facts based on matching symbols. The negation node ensures no existing order for that symbol. Tokens propagate through beta memories, carrying partial matches until reaching the production node.*
209
+
210
+ ## Optimization Strategies
211
+
212
+ ### Network Sharing
213
+
214
+ Multiple rules with common patterns share alpha memory nodes:
215
+
216
+ ```ruby
217
+ # Rule 1
218
+ Condition.new(:stock, { symbol: "AAPL" })
219
+
220
+ # Rule 2
221
+ Condition.new(:stock, { symbol: "AAPL" })
222
+
223
+ # Both use the same AlphaMemory node
224
+ # Only one pattern match, one fact storage
225
+ ```
226
+
227
+ ### Unlinking
228
+
229
+ Empty nodes automatically disconnect to avoid wasted computation:
230
+
231
+ ```ruby
232
+ # BetaMemory becomes empty
233
+ beta_memory.remove_token(last_token)
234
+ # => Calls unlink!
235
+
236
+ # Downstream nodes stop processing
237
+ join_node.left_activate(token) # Returns early if !@left_linked
238
+ ```
239
+
240
+ ### Condition Ordering
241
+
242
+ Place selective conditions first to minimize beta memory size:
243
+
244
+ ```ruby
245
+ # Good: Specific condition first
246
+ conditions = [
247
+ Condition.new(:critical_alert, { severity: "critical" }), # Few matches
248
+ Condition.new(:stock, { symbol: :sym? }) # Many matches
249
+ ]
250
+
251
+ # Bad: General condition first
252
+ conditions = [
253
+ Condition.new(:stock, { symbol: :sym? }), # Many matches
254
+ Condition.new(:critical_alert, { severity: "critical" }) # Few matches
255
+ ]
256
+ ```
257
+
258
+ ### Variable Binding Extraction
259
+
260
+ Variables create join tests automatically:
261
+
262
+ ```ruby
263
+ # Rule with :sym? in two conditions
264
+ tests = [
265
+ {
266
+ token_field_index: 0, # First fact in token (stock)
267
+ token_field: :symbol,
268
+ fact_field: :symbol, # New fact (threshold)
269
+ operation: :eq
270
+ }
271
+ ]
272
+ ```
273
+
274
+ ## Network Inspection
275
+
276
+ ### Debugging Network Structure
277
+
278
+ ```ruby
279
+ # See all alpha memories
280
+ engine.alpha_memories.each do |pattern, memory|
281
+ puts "Pattern: #{pattern}"
282
+ puts " Facts: #{memory.items.size}"
283
+ puts " Linked: #{memory.linked}"
284
+ puts " Successors: #{memory.successors.size}"
285
+ end
286
+
287
+ # See production nodes
288
+ engine.production_nodes.each do |name, node|
289
+ puts "Rule: #{name}"
290
+ puts " Tokens: #{node.tokens.size}"
291
+ end
292
+ ```
293
+
294
+ ### Visualizing Token Flow
295
+
296
+ Enable tracing in actions:
297
+
298
+ ```ruby
299
+ r.action = lambda do |facts, bindings|
300
+ puts "Rule '#{rule.name}' fired"
301
+ puts " Facts: #{facts.map(&:to_s).join(', ')}"
302
+ puts " Bindings: #{bindings.inspect}"
303
+ end
304
+ ```
305
+
306
+ ## Performance Implications
307
+
308
+ ### Time Complexity
309
+
310
+ | Operation | Complexity | Notes |
311
+ |-----------|-----------|-------|
312
+ | Add rule | O(C × F) | C = conditions, F = facts |
313
+ | Network sharing lookup | O(1) | Hash-based pattern cache |
314
+ | Join test | O(T) | T = number of tests |
315
+ | Token propagation | O(S) | S = successors |
316
+
317
+ ### Space Complexity
318
+
319
+ | Structure | Space | Notes |
320
+ |-----------|-------|-------|
321
+ | Alpha memories | O(P) | P = unique patterns across all rules |
322
+ | Beta memories | O(R × C) | R = rules, C = avg conditions |
323
+ | Tokens | O(M × C) | M = complete matches |
324
+ | Join nodes | O(R × C) | One per condition |
325
+
326
+ ### Optimization Tips
327
+
328
+ 1. **Maximize network sharing**: Design rules to reuse common patterns
329
+ 2. **Order conditions by selectivity**: Specific first, general last
330
+ 3. **Minimize negations**: Expensive to maintain
331
+ 4. **Use predicates sparingly**: Can't be shared across rules
332
+ 5. **Profile your rules**: Use debugging to identify bottlenecks
333
+
334
+ ## Next Steps
335
+
336
+ - **[RETE Algorithm](rete-algorithm.md)** - Understand the full execution cycle
337
+ - **[Blackboard System](blackboard.md)** - Persistent network state
338
+ - **[Performance Tuning](../advanced/performance.md)** - Optimize for production
339
+ - **[Debugging Guide](../advanced/debugging.md)** - Inspect network state
340
+
341
+ ---
342
+
343
+ *This document describes implementation details in `lib/kbs/rete_engine.rb:58` (network compilation) and related node classes.*