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.
- checksums.yaml +4 -4
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/CHANGELOG.md +68 -2
- data/README.md +235 -334
- data/docs/DOCUMENTATION_STATUS.md +158 -0
- data/docs/advanced/custom-persistence.md +775 -0
- data/docs/advanced/debugging.md +726 -0
- data/docs/advanced/index.md +8 -0
- data/docs/advanced/performance.md +832 -0
- data/docs/advanced/testing.md +691 -0
- data/docs/api/blackboard.md +1157 -0
- data/docs/api/engine.md +978 -0
- data/docs/api/facts.md +1212 -0
- data/docs/api/index.md +12 -0
- data/docs/api/rules.md +1034 -0
- data/docs/architecture/blackboard.md +553 -0
- data/docs/architecture/index.md +277 -0
- data/docs/architecture/network-structure.md +343 -0
- data/docs/architecture/rete-algorithm.md +737 -0
- data/docs/assets/css/custom.css +83 -0
- data/docs/assets/images/blackboard-architecture.svg +136 -0
- data/docs/assets/images/compiled-network.svg +101 -0
- data/docs/assets/images/fact-assertion-flow.svg +117 -0
- data/docs/assets/images/kbs.jpg +0 -0
- data/docs/assets/images/pattern-matching-trace.svg +136 -0
- data/docs/assets/images/rete-network-layers.svg +96 -0
- data/docs/assets/images/system-layers.svg +69 -0
- data/docs/assets/images/trading-signal-network.svg +139 -0
- data/docs/assets/js/mathjax.js +17 -0
- data/docs/examples/expert-systems.md +1031 -0
- data/docs/examples/index.md +9 -0
- data/docs/examples/multi-agent.md +1335 -0
- data/docs/examples/stock-trading.md +488 -0
- data/docs/guides/blackboard-memory.md +558 -0
- data/docs/guides/dsl.md +1321 -0
- data/docs/guides/facts.md +652 -0
- data/docs/guides/getting-started.md +383 -0
- data/docs/guides/index.md +23 -0
- data/docs/guides/negation.md +529 -0
- data/docs/guides/pattern-matching.md +561 -0
- data/docs/guides/persistence.md +451 -0
- data/docs/guides/variable-binding.md +491 -0
- data/docs/guides/writing-rules.md +755 -0
- data/docs/index.md +157 -0
- data/docs/installation.md +156 -0
- data/docs/quick-start.md +228 -0
- data/examples/README.md +2 -2
- data/examples/advanced_example.rb +2 -2
- data/examples/advanced_example_dsl.rb +224 -0
- data/examples/ai_enhanced_kbs.rb +1 -1
- data/examples/ai_enhanced_kbs_dsl.rb +538 -0
- data/examples/blackboard_demo_dsl.rb +50 -0
- data/examples/car_diagnostic.rb +1 -1
- data/examples/car_diagnostic_dsl.rb +54 -0
- data/examples/concurrent_inference_demo.rb +5 -5
- data/examples/concurrent_inference_demo_dsl.rb +363 -0
- data/examples/csv_trading_system.rb +1 -1
- data/examples/csv_trading_system_dsl.rb +525 -0
- data/examples/knowledge_base.db +0 -0
- data/examples/portfolio_rebalancing_system.rb +2 -2
- data/examples/portfolio_rebalancing_system_dsl.rb +613 -0
- data/examples/redis_trading_demo_dsl.rb +177 -0
- data/examples/run_all.rb +50 -0
- data/examples/run_all_dsl.rb +49 -0
- data/examples/stock_trading_advanced.rb +1 -1
- data/examples/stock_trading_advanced_dsl.rb +404 -0
- data/examples/temp.txt +7693 -0
- data/examples/temp_dsl.txt +8447 -0
- data/examples/timestamped_trading.rb +1 -1
- data/examples/timestamped_trading_dsl.rb +258 -0
- data/examples/trading_demo.rb +1 -1
- data/examples/trading_demo_dsl.rb +322 -0
- data/examples/working_demo.rb +1 -1
- data/examples/working_demo_dsl.rb +160 -0
- data/lib/kbs/blackboard/engine.rb +3 -3
- data/lib/kbs/blackboard/fact.rb +1 -1
- data/lib/kbs/condition.rb +1 -1
- data/lib/kbs/dsl/knowledge_base.rb +1 -1
- data/lib/kbs/dsl/variable.rb +1 -1
- data/lib/kbs/{rete_engine.rb → engine.rb} +1 -1
- data/lib/kbs/fact.rb +1 -1
- data/lib/kbs/version.rb +1 -1
- data/lib/kbs.rb +2 -2
- data/mkdocs.yml +181 -0
- metadata +66 -6
- data/examples/stock_trading_system.rb.bak +0 -563
data/docs/index.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# KBS - Knowledge-Based Systems for Ruby
|
|
4
|
+
|
|
5
|
+
**A Ruby implementation of the RETE algorithm for building intelligent, rule-based systems with persistent memory.**
|
|
6
|
+
|
|
7
|
+
[](https://badge.fury.io/rb/kbs)
|
|
8
|
+
[](https://www.ruby-lang.org/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
## What is KBS?
|
|
12
|
+
|
|
13
|
+
KBS (Knowledge-Based Systems) is a powerful Ruby gem that brings production rule systems to your applications. At its core is the **RETE algorithm**, a highly optimized pattern-matching engine originally developed for expert systems and now used in modern applications ranging from trading systems to IoT automation.
|
|
14
|
+
|
|
15
|
+
### Key Features
|
|
16
|
+
|
|
17
|
+
- **🚀 RETE Algorithm**: State-of-the-art pattern matching with unlinking optimization
|
|
18
|
+
- **💾 Persistent Blackboard Memory**: SQLite, Redis, or hybrid storage for facts and audit trails
|
|
19
|
+
- **🎯 Declarative DSL**: Write rules in natural, readable Ruby syntax
|
|
20
|
+
- **🔄 Incremental Matching**: Process only changes, not entire fact sets
|
|
21
|
+
- **🚫 Negation Support**: Express "absence of pattern" conditions naturally
|
|
22
|
+
- **📊 Multi-Agent Systems**: Build collaborative systems with message passing
|
|
23
|
+
- **🔍 Full Auditability**: Complete history of fact changes and rule firings
|
|
24
|
+
- **⚡ High Performance**: Handle millions of facts with sub-millisecond updates
|
|
25
|
+
|
|
26
|
+
## Quick Example
|
|
27
|
+
|
|
28
|
+
```ruby
|
|
29
|
+
require 'kbs'
|
|
30
|
+
|
|
31
|
+
# Create a rule-based trading system
|
|
32
|
+
engine = KBS::Engine.new
|
|
33
|
+
|
|
34
|
+
# Define a rule using the DSL
|
|
35
|
+
engine.add_rule(Rule.new("buy_signal") do |r|
|
|
36
|
+
r.conditions = [
|
|
37
|
+
# Stock price is below threshold
|
|
38
|
+
Condition.new(:stock, { symbol: :symbol?, price: :price? }),
|
|
39
|
+
Condition.new(:threshold, { symbol: :symbol?, buy_below: :threshold? }),
|
|
40
|
+
|
|
41
|
+
# No pending order exists (negation)
|
|
42
|
+
Condition.new(:order, { symbol: :symbol? }, negated: true)
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
r.action = lambda do |facts, bindings|
|
|
46
|
+
if bindings[:price?] < bindings[:threshold?]
|
|
47
|
+
puts "BUY #{bindings[:symbol?]} at #{bindings[:price?]}"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end)
|
|
51
|
+
|
|
52
|
+
# Add facts to working memory
|
|
53
|
+
engine.add_fact(:stock, symbol: "AAPL", price: 145.50)
|
|
54
|
+
engine.add_fact(:threshold, symbol: "AAPL", buy_below: 150.0)
|
|
55
|
+
|
|
56
|
+
# Fire matching rules
|
|
57
|
+
engine.run # => BUY AAPL at 145.5
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Why RETE?
|
|
61
|
+
|
|
62
|
+
Traditional rule engines re-evaluate all rules against all facts on every change—extremely inefficient. RETE solves this through:
|
|
63
|
+
|
|
64
|
+
1. **Network Compilation**: Rules are compiled into a discrimination network that shares common patterns
|
|
65
|
+
2. **State Preservation**: Partial matches are cached between cycles
|
|
66
|
+
3. **Incremental Updates**: Only changed facts propagate through the network
|
|
67
|
+
4. **Unlinking Optimization (RETE)**: Empty nodes automatically disconnect to skip unnecessary work
|
|
68
|
+
|
|
69
|
+
Result: **Near-constant time** per fact change, regardless of rule set size.
|
|
70
|
+
|
|
71
|
+
## Use Cases
|
|
72
|
+
|
|
73
|
+
### 💹 Algorithmic Trading
|
|
74
|
+
Real-time market analysis, signal detection, and automated order execution with complex multi-condition rules.
|
|
75
|
+
|
|
76
|
+
### 🏭 Industrial Automation
|
|
77
|
+
IoT sensor monitoring, predictive maintenance, and automated control systems with temporal reasoning.
|
|
78
|
+
|
|
79
|
+
### 🏥 Expert Systems
|
|
80
|
+
Medical diagnosis, troubleshooting assistants, and decision support systems with knowledge representation.
|
|
81
|
+
|
|
82
|
+
### 🤖 Multi-Agent Systems
|
|
83
|
+
Collaborative agents with shared blackboard memory for distributed problem-solving.
|
|
84
|
+
|
|
85
|
+
### 📧 Business Rules Engines
|
|
86
|
+
Policy enforcement, workflow automation, and compliance checking with auditable decision trails.
|
|
87
|
+
|
|
88
|
+
## Architecture
|
|
89
|
+
|
|
90
|
+
KBS consists of several integrated components:
|
|
91
|
+
|
|
92
|
+
- **RETE Engine**: Core pattern matching and rule execution
|
|
93
|
+
- **Working Memory**: Transient in-memory fact storage
|
|
94
|
+
- **Blackboard System**: Persistent memory with SQLite/Redis backends
|
|
95
|
+
- **DSL**: Natural language rule definition syntax
|
|
96
|
+
- **Message Queue**: Priority-based inter-agent communication
|
|
97
|
+
- **Audit Log**: Complete history for compliance and debugging
|
|
98
|
+
|
|
99
|
+
See [Architecture Overview](architecture/index.md) for details.
|
|
100
|
+
|
|
101
|
+
## Getting Started
|
|
102
|
+
|
|
103
|
+
1. **[Installation](installation.md)** - Add KBS to your project
|
|
104
|
+
2. **[Quick Start](quick-start.md)** - Build your first rule-based system in 5 minutes
|
|
105
|
+
3. **[RETE Algorithm](architecture/rete-algorithm.md)** - Deep dive into how it works
|
|
106
|
+
4. **[Writing Rules](guides/writing-rules.md)** - Master the DSL and pattern matching
|
|
107
|
+
5. **[Examples](examples/index.md)** - Learn from real-world applications
|
|
108
|
+
|
|
109
|
+
## Performance
|
|
110
|
+
|
|
111
|
+
KBS is built for production workloads:
|
|
112
|
+
|
|
113
|
+
- **Fact Addition**: O(N) where N = activated nodes (typically << total nodes)
|
|
114
|
+
- **Rule Firing**: O(M) where M = matched tokens
|
|
115
|
+
- **Memory Efficient**: Network sharing reduces redundant storage
|
|
116
|
+
- **Scalable**: Tested with millions of facts, thousands of rules
|
|
117
|
+
|
|
118
|
+
Benchmarks on M2 Max:
|
|
119
|
+
- Add 100,000 facts: ~500ms
|
|
120
|
+
- Match complex 5-condition rule: <1ms per fact
|
|
121
|
+
- Redis backend: 100x faster than SQLite for high-frequency updates
|
|
122
|
+
|
|
123
|
+
## Project Status
|
|
124
|
+
|
|
125
|
+
KBS is **actively maintained**:
|
|
126
|
+
|
|
127
|
+
- ✅ Core RETE implementation complete
|
|
128
|
+
- ✅ Persistent blackboard with multiple backends
|
|
129
|
+
- ✅ Full DSL support with negation
|
|
130
|
+
- ✅ Comprehensive test coverage
|
|
131
|
+
- ✅ Real-world usage in trading systems
|
|
132
|
+
- 🚧 Additional examples and guides in progress
|
|
133
|
+
|
|
134
|
+
## Community & Support
|
|
135
|
+
|
|
136
|
+
- **GitHub**: [madbomber/kbs](https://github.com/madbomber/kbs)
|
|
137
|
+
- **RubyGems**: [kbs](https://rubygems.org/gems/kbs)
|
|
138
|
+
- **Issues**: [Report bugs or request features](https://github.com/madbomber/kbs/issues)
|
|
139
|
+
- **Discussions**: [Ask questions](https://github.com/madbomber/kbs/discussions)
|
|
140
|
+
|
|
141
|
+
## License
|
|
142
|
+
|
|
143
|
+
KBS is released under the [MIT License](https://opensource.org/licenses/MIT).
|
|
144
|
+
|
|
145
|
+
Copyright © 2024 Dewayne VanHoozer
|
|
146
|
+
|
|
147
|
+
## Acknowledgments
|
|
148
|
+
|
|
149
|
+
The RETE algorithm was invented by Charles Forgy in 1979. This implementation draws inspiration from:
|
|
150
|
+
|
|
151
|
+
- Forgy, C. (1982). "Rete: A Fast Algorithm for the Many Pattern/Many Object Pattern Match Problem"
|
|
152
|
+
- Doorenbos, R. (1995). "Production Matching for Large Learning Systems" (RETE/UL)
|
|
153
|
+
- Modern production rule systems: Drools, Jess, CLIPS
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
**Ready to build intelligent systems?** Start with the [Quick Start Guide](quick-start.md)!
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Installation
|
|
2
|
+
|
|
3
|
+
## Requirements
|
|
4
|
+
|
|
5
|
+
- **Ruby**: 2.7 or higher
|
|
6
|
+
- **SQLite3**: For persistent blackboard memory (optional)
|
|
7
|
+
- **Redis**: For high-performance persistence (optional)
|
|
8
|
+
|
|
9
|
+
## Installing the Gem
|
|
10
|
+
|
|
11
|
+
### From RubyGems
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
gem install kbs
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Using Bundler
|
|
18
|
+
|
|
19
|
+
Add to your `Gemfile`:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
gem 'kbs'
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Then run:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
bundle install
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### From Source
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
git clone https://github.com/madbomber/kbs.git
|
|
35
|
+
cd kbs
|
|
36
|
+
bundle install
|
|
37
|
+
rake install
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Optional Dependencies
|
|
41
|
+
|
|
42
|
+
### SQLite3 (Default Blackboard Backend)
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
gem install sqlite3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Or in your `Gemfile`:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
gem 'sqlite3'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Redis (High-Performance Backend)
|
|
55
|
+
|
|
56
|
+
Install Redis server:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# macOS
|
|
60
|
+
brew install redis
|
|
61
|
+
brew services start redis
|
|
62
|
+
|
|
63
|
+
# Ubuntu/Debian
|
|
64
|
+
sudo apt-get install redis-server
|
|
65
|
+
sudo systemctl start redis
|
|
66
|
+
|
|
67
|
+
# Docker
|
|
68
|
+
docker run -d -p 6379:6379 redis:latest
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Install Ruby Redis gem:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
gem install redis
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Or in your `Gemfile`:
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
gem 'redis'
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Verification
|
|
84
|
+
|
|
85
|
+
Verify the installation:
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
require 'kbs'
|
|
89
|
+
|
|
90
|
+
puts "KBS version: #{KBS::VERSION}"
|
|
91
|
+
# => KBS version: 0.1.0
|
|
92
|
+
|
|
93
|
+
# Test basic functionality
|
|
94
|
+
engine = KBS::Engine.new
|
|
95
|
+
engine.add_fact(:test, value: 42)
|
|
96
|
+
puts "✓ KBS is working!"
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Development Setup
|
|
100
|
+
|
|
101
|
+
For contributing or running tests:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
git clone https://github.com/madbomber/kbs.git
|
|
105
|
+
cd kbs
|
|
106
|
+
bundle install
|
|
107
|
+
|
|
108
|
+
# Run tests
|
|
109
|
+
bundle exec rake test
|
|
110
|
+
|
|
111
|
+
# Run examples
|
|
112
|
+
bundle exec ruby examples/working_demo.rb
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Troubleshooting
|
|
116
|
+
|
|
117
|
+
### SQLite3 Installation Issues
|
|
118
|
+
|
|
119
|
+
On macOS with M1/M2:
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
gem install sqlite3 -- --with-sqlite3-include=/opt/homebrew/opt/sqlite/include \
|
|
123
|
+
--with-sqlite3-lib=/opt/homebrew/opt/sqlite/lib
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
On Ubuntu/Debian:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
sudo apt-get install libsqlite3-dev
|
|
130
|
+
gem install sqlite3
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Redis Connection Issues
|
|
134
|
+
|
|
135
|
+
Check Redis is running:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
redis-cli ping
|
|
139
|
+
# => PONG
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Test connection from Ruby:
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
require 'redis'
|
|
146
|
+
redis = Redis.new(url: 'redis://localhost:6379/0')
|
|
147
|
+
redis.ping
|
|
148
|
+
# => "PONG"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Next Steps
|
|
152
|
+
|
|
153
|
+
- **[Quick Start Guide](quick-start.md)** - Build your first rule-based system
|
|
154
|
+
- **[RETE Algorithm](architecture/rete-algorithm.md)** - Understand the engine
|
|
155
|
+
- **[Writing Rules](guides/writing-rules.md)** - Master the DSL
|
|
156
|
+
- **[Examples](examples/index.md)** - See real-world applications
|
data/docs/quick-start.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Quick Start Guide
|
|
2
|
+
|
|
3
|
+
Get up and running with KBS in 5 minutes.
|
|
4
|
+
|
|
5
|
+
## Your First Rule-Based System
|
|
6
|
+
|
|
7
|
+
Let's build a simple temperature monitoring system that alerts when readings are abnormal.
|
|
8
|
+
|
|
9
|
+
### Step 1: Create the Engine
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
require 'kbs'
|
|
13
|
+
|
|
14
|
+
# Create a RETE engine
|
|
15
|
+
engine = KBS::Engine.new
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Step 2: Define Rules
|
|
19
|
+
|
|
20
|
+
```ruby
|
|
21
|
+
# Rule 1: Alert on high temperature
|
|
22
|
+
high_temp_rule = KBS::Rule.new("high_temperature_alert") do |r|
|
|
23
|
+
r.conditions = [
|
|
24
|
+
KBS::Condition.new(:sensor, { id: :id?, temp: :temp? })
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
r.action = lambda do |facts, bindings|
|
|
28
|
+
if bindings[:temp?] > 75
|
|
29
|
+
puts "⚠️ HIGH TEMP Alert: Sensor #{bindings[:id?]} at #{bindings[:temp?]}°F"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
engine.add_rule(high_temp_rule)
|
|
35
|
+
|
|
36
|
+
# Rule 2: Alert when cooling system is offline AND temp is high
|
|
37
|
+
critical_rule = KBS::Rule.new("critical_condition", priority: 10) do |r|
|
|
38
|
+
r.conditions = [
|
|
39
|
+
KBS::Condition.new(:sensor, { id: :id?, temp: :temp? }),
|
|
40
|
+
KBS::Condition.new(:cooling, { id: :id?, status: "offline" })
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
r.action = lambda do |facts, bindings|
|
|
44
|
+
if bindings[:temp?] > 75
|
|
45
|
+
puts "🚨 CRITICAL: Sensor #{bindings[:id?]} at #{bindings[:temp?]}°F with cooling OFFLINE!"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
engine.add_rule(critical_rule)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Step 3: Add Facts
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
# Add sensor readings
|
|
57
|
+
engine.add_fact(:sensor, id: "room_101", temp: 72)
|
|
58
|
+
engine.add_fact(:sensor, id: "server_rack", temp: 82)
|
|
59
|
+
engine.add_fact(:sensor, id: "storage", temp: 65)
|
|
60
|
+
|
|
61
|
+
# Add cooling system status
|
|
62
|
+
engine.add_fact(:cooling, id: "server_rack", status: "offline")
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Step 4: Run Rules
|
|
66
|
+
|
|
67
|
+
```ruby
|
|
68
|
+
engine.run
|
|
69
|
+
# Output:
|
|
70
|
+
# => ⚠️ HIGH TEMP Alert: Sensor server_rack at 82°F
|
|
71
|
+
# => 🚨 CRITICAL: Sensor server_rack at 82°F with cooling OFFLINE!
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Understanding What Happened
|
|
75
|
+
|
|
76
|
+
1. **Engine Creation**: `Engine.new` builds an empty RETE network
|
|
77
|
+
2. **Rule Addition**: Rules are compiled into the discrimination network
|
|
78
|
+
3. **Fact Assertion**: Facts propagate through the network, creating partial matches
|
|
79
|
+
4. **Rule Firing**: `engine.run()` executes actions for all complete matches
|
|
80
|
+
|
|
81
|
+
The critical rule fires because:
|
|
82
|
+
- Sensor "server_rack" temp (82°F) > 75
|
|
83
|
+
- Cooling system for "server_rack" is offline
|
|
84
|
+
- Both conditions are joined on the same `:id?` variable
|
|
85
|
+
|
|
86
|
+
## Using Negation
|
|
87
|
+
|
|
88
|
+
Rules can match on the **absence** of facts:
|
|
89
|
+
|
|
90
|
+
```ruby
|
|
91
|
+
# Alert when sensor has NO recent reading
|
|
92
|
+
stale_sensor_rule = KBS::Rule.new("stale_sensor") do |r|
|
|
93
|
+
r.conditions = [
|
|
94
|
+
KBS::Condition.new(:sensor_registered, { id: :id? }),
|
|
95
|
+
# No recent reading exists (negation!)
|
|
96
|
+
KBS::Condition.new(:sensor, { id: :id? }, negated: true)
|
|
97
|
+
]
|
|
98
|
+
|
|
99
|
+
r.action = lambda do |facts, bindings|
|
|
100
|
+
puts "⚠️ No reading from sensor #{bindings[:id?]}"
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
engine.add_rule(stale_sensor_rule)
|
|
105
|
+
|
|
106
|
+
# Register sensors
|
|
107
|
+
engine.add_fact(:sensor_registered, id: "room_101")
|
|
108
|
+
engine.add_fact(:sensor_registered, id: "room_102")
|
|
109
|
+
|
|
110
|
+
# Only add reading for room_101
|
|
111
|
+
engine.add_fact(:sensor, id: "room_101", temp: 70)
|
|
112
|
+
|
|
113
|
+
engine.run
|
|
114
|
+
# => ⚠️ No reading from sensor room_102
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Persistent Blackboard Memory
|
|
118
|
+
|
|
119
|
+
For production systems, use persistent storage:
|
|
120
|
+
|
|
121
|
+
```ruby
|
|
122
|
+
require 'kbs/blackboard'
|
|
123
|
+
|
|
124
|
+
# SQLite backend (default)
|
|
125
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'monitoring.db')
|
|
126
|
+
|
|
127
|
+
# Facts survive restarts
|
|
128
|
+
engine.add_fact(:sensor, id: "room_101", temp: 72)
|
|
129
|
+
|
|
130
|
+
# Query historical data
|
|
131
|
+
memory = engine.working_memory
|
|
132
|
+
audit = memory.audit_log.recent_changes(limit: 10)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Next Steps
|
|
136
|
+
|
|
137
|
+
### Learn the Fundamentals
|
|
138
|
+
|
|
139
|
+
- **[Writing Rules](guides/writing-rules.md)** - Master rule syntax and patterns
|
|
140
|
+
- **[Pattern Matching](guides/pattern-matching.md)** - Understand how facts match conditions
|
|
141
|
+
- **[Variable Binding](guides/variable-binding.md)** - Use variables to join conditions
|
|
142
|
+
- **[Negation](guides/negation.md)** - Express "absence" conditions
|
|
143
|
+
|
|
144
|
+
### Explore Examples
|
|
145
|
+
|
|
146
|
+
- **[Stock Trading](examples/stock-trading.md)** - Build a trading signal system
|
|
147
|
+
- **[Expert Systems](examples/expert-systems.md)** - Diagnostic and decision support
|
|
148
|
+
- **[Multi-Agent Systems](examples/multi-agent.md)** - Collaborative problem-solving
|
|
149
|
+
|
|
150
|
+
### Advanced Topics
|
|
151
|
+
|
|
152
|
+
- **[Blackboard Memory](guides/blackboard-memory.md)** - Persistent storage and audit trails
|
|
153
|
+
- **[Performance Tuning](advanced/performance.md)** - Optimize for production workloads
|
|
154
|
+
- **[Debugging](advanced/debugging.md)** - Trace rule execution and network state
|
|
155
|
+
|
|
156
|
+
### Understand the Engine
|
|
157
|
+
|
|
158
|
+
- **[RETE Algorithm](architecture/rete-algorithm.md)** - Deep dive into pattern matching
|
|
159
|
+
- **[Network Structure](architecture/network-structure.md)** - How rules are compiled
|
|
160
|
+
- **[API Reference](api/index.md)** - Complete class documentation
|
|
161
|
+
|
|
162
|
+
## Common Patterns
|
|
163
|
+
|
|
164
|
+
### Time-Based Rules
|
|
165
|
+
|
|
166
|
+
```ruby
|
|
167
|
+
rule = KBS::Rule.new("recent_spike") do |r|
|
|
168
|
+
r.conditions = [
|
|
169
|
+
KBS::Condition.new(:reading, {
|
|
170
|
+
sensor: :id?,
|
|
171
|
+
temp: :temp?,
|
|
172
|
+
timestamp: ->(ts) { Time.now - ts < 300 } # Within 5 minutes
|
|
173
|
+
})
|
|
174
|
+
]
|
|
175
|
+
|
|
176
|
+
r.action = lambda do |facts, bindings|
|
|
177
|
+
puts "Recent spike: #{bindings[:temp?]}°F"
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Threshold Comparison
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
rule = KBS::Rule.new("above_threshold") do |r|
|
|
186
|
+
r.conditions = [
|
|
187
|
+
KBS::Condition.new(:reading, { sensor: :id?, value: :val? }),
|
|
188
|
+
KBS::Condition.new(:threshold, { sensor: :id?, max: :max? })
|
|
189
|
+
]
|
|
190
|
+
|
|
191
|
+
r.action = lambda do |facts, bindings|
|
|
192
|
+
if bindings[:val?] > bindings[:max?]
|
|
193
|
+
puts "Threshold exceeded!"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### State Machine
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
# Transition from "init" to "ready"
|
|
203
|
+
transition_rule = KBS::Rule.new("init_to_ready") do |r|
|
|
204
|
+
r.conditions = [
|
|
205
|
+
KBS::Condition.new(:state, { current: "init" }),
|
|
206
|
+
KBS::Condition.new(:sensor, { initialized: true }),
|
|
207
|
+
# No "ready" state exists yet
|
|
208
|
+
KBS::Condition.new(:state, { current: "ready" }, negated: true)
|
|
209
|
+
]
|
|
210
|
+
|
|
211
|
+
r.action = lambda do |facts|
|
|
212
|
+
# Remove old state
|
|
213
|
+
engine.remove_fact(facts[0])
|
|
214
|
+
# Add new state
|
|
215
|
+
engine.add_fact(:state, current: "ready")
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Tips
|
|
221
|
+
|
|
222
|
+
1. **Use descriptive rule names**: Makes debugging easier
|
|
223
|
+
2. **Set priorities**: Higher priority rules fire first
|
|
224
|
+
3. **Call `run()` explicitly**: Rules don't fire automatically
|
|
225
|
+
4. **Leverage negation**: Express "when X is absent" naturally
|
|
226
|
+
5. **Profile performance**: Use `advanced/debugging.md` techniques
|
|
227
|
+
|
|
228
|
+
Ready to dive deeper? Check out the [Writing Rules Guide](guides/writing-rules.md)!
|
data/examples/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# KBS Examples
|
|
2
2
|
|
|
3
|
-
This directory contains comprehensive examples demonstrating the capabilities of the KBS (Knowledge-Based System) gem. Each example showcases different features and use cases of the RETE
|
|
3
|
+
This directory contains comprehensive examples demonstrating the capabilities of the KBS (Knowledge-Based System) gem. Each example showcases different features and use cases of the RETE inference engine and blackboard architecture.
|
|
4
4
|
|
|
5
5
|
## Table of Contents
|
|
6
6
|
|
|
@@ -421,7 +421,7 @@ export OLLAMA_MODEL=gpt-oss:latest
|
|
|
421
421
|
## Summary of Capabilities
|
|
422
422
|
|
|
423
423
|
### Core KBS Features
|
|
424
|
-
- ✅ RETE
|
|
424
|
+
- ✅ RETE inference engine
|
|
425
425
|
- ✅ Forward-chaining reasoning
|
|
426
426
|
- ✅ Pattern matching
|
|
427
427
|
- ✅ Negated conditions
|
|
@@ -4,7 +4,7 @@ require_relative '../lib/kbs'
|
|
|
4
4
|
|
|
5
5
|
class StockTradingExpertSystem
|
|
6
6
|
def initialize
|
|
7
|
-
@engine = KBS::
|
|
7
|
+
@engine = KBS::Engine.new
|
|
8
8
|
setup_rules
|
|
9
9
|
end
|
|
10
10
|
|
|
@@ -137,7 +137,7 @@ end
|
|
|
137
137
|
|
|
138
138
|
class NetworkDiagnosticSystem
|
|
139
139
|
def initialize
|
|
140
|
-
@engine = KBS::
|
|
140
|
+
@engine = KBS::Engine.new
|
|
141
141
|
setup_network_rules
|
|
142
142
|
end
|
|
143
143
|
|