kbs 0.1.0 → 0.2.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/README.md +85 -57
- data/docs/advanced/performance.md +109 -76
- data/docs/advanced/testing.md +399 -263
- data/docs/api/blackboard.md +1 -1
- data/docs/api/engine.md +77 -8
- data/docs/api/facts.md +3 -3
- data/docs/api/rules.md +110 -40
- data/docs/architecture/blackboard.md +108 -117
- data/docs/assets/images/fact-rule-relationship.svg +65 -0
- data/docs/assets/images/fact-structure.svg +42 -0
- data/docs/assets/images/inference-cycle.svg +47 -0
- data/docs/assets/images/kb-components.svg +43 -0
- data/docs/assets/images/rule-structure.svg +44 -0
- data/docs/assets/images/trading-signal-network.svg +1 -1
- data/docs/examples/index.md +219 -5
- data/docs/guides/blackboard-memory.md +89 -58
- data/docs/guides/dsl.md +24 -24
- data/docs/guides/getting-started.md +109 -107
- data/docs/guides/writing-rules.md +470 -311
- data/docs/index.md +16 -18
- data/docs/quick-start.md +92 -99
- data/docs/what-is-a-fact.md +694 -0
- data/docs/what-is-a-knowledge-base.md +350 -0
- data/docs/what-is-a-rule.md +833 -0
- data/examples/.gitignore +1 -0
- data/examples/advanced_example_dsl.rb +1 -1
- data/examples/ai_enhanced_kbs_dsl.rb +1 -1
- data/examples/car_diagnostic_dsl.rb +1 -1
- data/examples/concurrent_inference_demo.rb +0 -1
- data/examples/concurrent_inference_demo_dsl.rb +0 -1
- data/examples/csv_trading_system_dsl.rb +1 -1
- data/examples/iot_demo_using_dsl.rb +1 -1
- data/examples/portfolio_rebalancing_system_dsl.rb +1 -1
- data/examples/rule_source_demo.rb +123 -0
- data/examples/stock_trading_advanced_dsl.rb +1 -1
- data/examples/temp_dsl.txt +6214 -5269
- data/examples/timestamped_trading_dsl.rb +1 -1
- data/examples/trading_demo_dsl.rb +1 -1
- data/examples/working_demo_dsl.rb +1 -1
- data/lib/kbs/decompiler.rb +204 -0
- data/lib/kbs/dsl/knowledge_base.rb +100 -1
- data/lib/kbs/dsl.rb +3 -1
- data/lib/kbs/engine.rb +41 -0
- data/lib/kbs/version.rb +1 -1
- data/lib/kbs.rb +14 -12
- data/mkdocs.yml +30 -30
- metadata +15 -10
- data/docs/DOCUMENTATION_STATUS.md +0 -158
- data/docs/examples/expert-systems.md +0 -1031
- data/docs/examples/multi-agent.md +0 -1335
- data/docs/examples/stock-trading.md +0 -488
- data/examples/knowledge_base.db +0 -0
- data/examples/temp.txt +0 -7693
|
@@ -62,30 +62,29 @@ RETE engine with persistent blackboard memory:
|
|
|
62
62
|
# Create engine with blackboard
|
|
63
63
|
engine = KBS::Blackboard::Engine.new(db_path: 'trading.db')
|
|
64
64
|
|
|
65
|
-
# Define rules (persisted in the database)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
})
|
|
65
|
+
# Define rules using DSL (persisted in the database)
|
|
66
|
+
kb = KBS.knowledge_base(engine: engine) do
|
|
67
|
+
rule "buy_signal" do
|
|
68
|
+
on :stock, symbol: :sym?, price: :price?
|
|
69
|
+
on :threshold, symbol: :sym?, max: :max?
|
|
70
|
+
|
|
71
|
+
perform do |facts, bindings|
|
|
72
|
+
if bindings[:price?] < bindings[:max?]
|
|
73
|
+
# Write new fact to blackboard
|
|
74
|
+
fact :order,
|
|
75
|
+
symbol: bindings[:sym?],
|
|
76
|
+
action: "BUY",
|
|
77
|
+
price: bindings[:price?]
|
|
78
|
+
end
|
|
80
79
|
end
|
|
81
80
|
end
|
|
82
|
-
end)
|
|
83
81
|
|
|
84
|
-
# Facts trigger rules, which create new facts
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
# => Creates :order fact in blackboard
|
|
82
|
+
# Facts trigger rules, which create new facts
|
|
83
|
+
fact :stock, symbol: "AAPL", price: 145.0
|
|
84
|
+
fact :threshold, symbol: "AAPL", max: 150.0
|
|
85
|
+
run
|
|
86
|
+
# => Creates :order fact in blackboard
|
|
87
|
+
end
|
|
89
88
|
```
|
|
90
89
|
|
|
91
90
|
**Implementation**: `lib/kbs/blackboard/engine.rb`
|
|
@@ -278,93 +277,77 @@ Trading system with four specialized agents:
|
|
|
278
277
|
|
|
279
278
|
```ruby
|
|
280
279
|
# Shared blackboard
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
# Agent 1: Market Data Collector
|
|
284
|
-
data_agent = KBS::Rule.new("collect_data", priority: 5) do |r|
|
|
285
|
-
r.conditions = [
|
|
286
|
-
Condition.new(:market_open, { status: true }),
|
|
287
|
-
Condition.new(:stock_data, { symbol: :sym? }, negated: true)
|
|
288
|
-
]
|
|
289
|
-
|
|
290
|
-
r.action = lambda do |facts, bindings|
|
|
291
|
-
price = fetch_current_price(bindings[:sym?])
|
|
292
|
-
blackboard.add_fact(:stock_data, {
|
|
293
|
-
symbol: bindings[:sym?],
|
|
294
|
-
price: price,
|
|
295
|
-
timestamp: Time.now
|
|
296
|
-
})
|
|
297
|
-
end
|
|
298
|
-
end
|
|
280
|
+
engine = KBS::Blackboard::Engine.new(db_path: 'trading.db')
|
|
299
281
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
]
|
|
282
|
+
kb = KBS.knowledge_base(engine: engine) do
|
|
283
|
+
# Agent 1: Market Data Collector
|
|
284
|
+
rule "collect_data", priority: 5 do
|
|
285
|
+
on :market_open, status: true
|
|
286
|
+
without :stock_data, symbol: :sym?
|
|
306
287
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
288
|
+
perform do |facts, bindings|
|
|
289
|
+
price = fetch_current_price(bindings[:sym?])
|
|
290
|
+
fact :stock_data,
|
|
310
291
|
symbol: bindings[:sym?],
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
})
|
|
292
|
+
price: price,
|
|
293
|
+
timestamp: Time.now
|
|
314
294
|
end
|
|
315
295
|
end
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
# Agent 3: Risk Manager
|
|
319
|
-
risk_agent = KBS::Rule.new("check_risk", priority: 20) do |r|
|
|
320
|
-
r.conditions = [
|
|
321
|
-
Condition.new(:signal, { symbol: :sym?, direction: :dir? }),
|
|
322
|
-
Condition.new(:portfolio, { symbol: :sym?, position: :pos? })
|
|
323
|
-
]
|
|
324
296
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
297
|
+
# Agent 2: Signal Generator
|
|
298
|
+
rule "generate_signals", priority: 10 do
|
|
299
|
+
on :stock_data, symbol: :sym?, price: :price?
|
|
300
|
+
on :sma_data, symbol: :sym?, sma: :sma?
|
|
301
|
+
|
|
302
|
+
perform do |facts, bindings|
|
|
303
|
+
if bindings[:price?] > bindings[:sma?]
|
|
304
|
+
fact :signal,
|
|
305
|
+
symbol: bindings[:sym?],
|
|
306
|
+
direction: "BUY",
|
|
307
|
+
strength: (bindings[:price?] / bindings[:sma?]) - 1.0
|
|
308
|
+
end
|
|
336
309
|
end
|
|
337
310
|
end
|
|
338
|
-
end
|
|
339
311
|
|
|
340
|
-
# Agent
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
312
|
+
# Agent 3: Risk Manager
|
|
313
|
+
rule "check_risk", priority: 20 do
|
|
314
|
+
on :signal, symbol: :sym?, direction: :dir?
|
|
315
|
+
on :portfolio, symbol: :sym?, position: :pos?
|
|
316
|
+
|
|
317
|
+
perform do |facts, bindings|
|
|
318
|
+
if bindings[:pos?] > 1000 && bindings[:dir?] == "BUY"
|
|
319
|
+
fact :risk_alert,
|
|
320
|
+
symbol: bindings[:sym?],
|
|
321
|
+
reason: "Position limit exceeded"
|
|
322
|
+
else
|
|
323
|
+
fact :approved_signal,
|
|
324
|
+
symbol: bindings[:sym?],
|
|
325
|
+
direction: bindings[:dir?]
|
|
326
|
+
end
|
|
327
|
+
end
|
|
354
328
|
end
|
|
355
|
-
end
|
|
356
329
|
|
|
357
|
-
#
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
330
|
+
# Agent 4: Order Executor
|
|
331
|
+
rule "execute_orders", priority: 30 do
|
|
332
|
+
on :approved_signal, symbol: :sym?, direction: :dir?
|
|
333
|
+
without :risk_alert, symbol: :sym?
|
|
361
334
|
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
335
|
+
perform do |facts, bindings|
|
|
336
|
+
execute_trade(bindings[:sym?], bindings[:dir?])
|
|
337
|
+
fact :execution,
|
|
338
|
+
symbol: bindings[:sym?],
|
|
339
|
+
direction: bindings[:dir?],
|
|
340
|
+
timestamp: Time.now
|
|
341
|
+
end
|
|
342
|
+
end
|
|
365
343
|
|
|
366
|
-
#
|
|
367
|
-
|
|
344
|
+
# Trigger the system
|
|
345
|
+
fact :market_open, status: true
|
|
346
|
+
fact :portfolio, symbol: "AAPL", position: 500
|
|
347
|
+
|
|
348
|
+
# Agents collaborate through blackboard
|
|
349
|
+
run
|
|
350
|
+
end
|
|
368
351
|
```
|
|
369
352
|
|
|
370
353
|
## Transactions
|
|
@@ -499,13 +482,13 @@ Agents activate when their preconditions are met:
|
|
|
499
482
|
|
|
500
483
|
```ruby
|
|
501
484
|
# Trigger fires only when specific fact exists
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
]
|
|
485
|
+
kb = KBS.knowledge_base(engine: engine) do
|
|
486
|
+
rule "on_critical_alert" do
|
|
487
|
+
on :alert, severity: "critical"
|
|
506
488
|
|
|
507
|
-
|
|
508
|
-
|
|
489
|
+
perform do |facts, bindings|
|
|
490
|
+
notify_team(facts[0])
|
|
491
|
+
end
|
|
509
492
|
end
|
|
510
493
|
end
|
|
511
494
|
```
|
|
@@ -516,17 +499,17 @@ Limit agent attention to relevant facts:
|
|
|
516
499
|
|
|
517
500
|
```ruby
|
|
518
501
|
# Agent only sees recent stock data
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
502
|
+
kb = KBS.knowledge_base(engine: engine) do
|
|
503
|
+
rule "analyze_recent" do
|
|
504
|
+
on :stock_data,
|
|
522
505
|
symbol: :sym?,
|
|
523
|
-
timestamp:
|
|
524
|
-
|
|
525
|
-
]
|
|
506
|
+
timestamp: :ts?,
|
|
507
|
+
predicate: lambda { |f| Time.now - f[:timestamp] < 300 } # Last 5 minutes
|
|
526
508
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
509
|
+
perform do |facts, bindings|
|
|
510
|
+
# Process recent data only
|
|
511
|
+
end
|
|
512
|
+
end
|
|
530
513
|
end
|
|
531
514
|
```
|
|
532
515
|
|
|
@@ -535,19 +518,27 @@ end
|
|
|
535
518
|
When multiple agents could act, use priorities:
|
|
536
519
|
|
|
537
520
|
```ruby
|
|
538
|
-
|
|
539
|
-
|
|
521
|
+
kb = KBS.knowledge_base(engine: engine) do
|
|
522
|
+
# High priority: Stop-loss overrides everything
|
|
523
|
+
rule "stop_loss", priority: 100 do
|
|
524
|
+
# ...
|
|
525
|
+
end
|
|
540
526
|
|
|
541
|
-
# Medium priority: Risk management
|
|
542
|
-
|
|
527
|
+
# Medium priority: Risk management
|
|
528
|
+
rule "risk_check", priority: 50 do
|
|
529
|
+
# ...
|
|
530
|
+
end
|
|
543
531
|
|
|
544
|
-
# Low priority: Normal trading signals
|
|
545
|
-
|
|
532
|
+
# Low priority: Normal trading signals
|
|
533
|
+
rule "buy", priority: 10 do
|
|
534
|
+
# ...
|
|
535
|
+
end
|
|
536
|
+
end
|
|
546
537
|
```
|
|
547
538
|
|
|
548
539
|
## Next Steps
|
|
549
540
|
|
|
550
541
|
- **[Network Structure](network-structure.md)** - How blackboard integrates with RETE
|
|
551
542
|
- **[Persistence Guide](../guides/persistence.md)** - Choosing and configuring backends
|
|
552
|
-
- **[
|
|
543
|
+
- **[Blackboard Examples](../examples/index.md#advanced-features)** - Complete working systems
|
|
553
544
|
- **[Custom Persistence](../advanced/custom-persistence.md)** - Build your own backend
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 380">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { fill: #1e293b; stroke: #60a5fa; stroke-width: 2; }
|
|
5
|
+
.text { fill: #e2e8f0; font-family: 'Courier New', monospace; font-size: 13px; }
|
|
6
|
+
.title { fill: #60a5fa; font-family: 'Courier New', monospace; font-size: 14px; font-weight: bold; }
|
|
7
|
+
.label { fill: #94a3b8; font-family: 'Courier New', monospace; font-size: 12px; }
|
|
8
|
+
.arrow { stroke: #60a5fa; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
|
|
9
|
+
.cycle-arrow { stroke: #22d3ee; stroke-width: 2; fill: none; marker-end: url(#arrowhead-cyan); }
|
|
10
|
+
</style>
|
|
11
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
12
|
+
<polygon points="0 0, 10 3, 0 6" fill="#60a5fa" />
|
|
13
|
+
</marker>
|
|
14
|
+
<marker id="arrowhead-cyan" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
15
|
+
<polygon points="0 0, 10 3, 0 6" fill="#22d3ee" />
|
|
16
|
+
</marker>
|
|
17
|
+
</defs>
|
|
18
|
+
|
|
19
|
+
<!-- Left side: Facts (DATA) -->
|
|
20
|
+
<text x="100" y="30" text-anchor="middle" class="title">Facts (DATA)</text>
|
|
21
|
+
<rect x="30" y="50" width="140" height="80" rx="5" class="box"/>
|
|
22
|
+
<text x="100" y="75" text-anchor="middle" class="label">Current State</text>
|
|
23
|
+
<text x="100" y="95" text-anchor="middle" class="label">:stock</text>
|
|
24
|
+
<text x="100" y="110" text-anchor="middle" class="label">:portfolio</text>
|
|
25
|
+
|
|
26
|
+
<!-- Right side: Rules (LOGIC) -->
|
|
27
|
+
<text x="500" y="30" text-anchor="middle" class="title">Rules (LOGIC)</text>
|
|
28
|
+
<rect x="430" y="50" width="140" height="80" rx="5" class="box"/>
|
|
29
|
+
<text x="500" y="75" text-anchor="middle" class="label">IF-THEN Logic</text>
|
|
30
|
+
<text x="500" y="95" text-anchor="middle" class="label">Conditions</text>
|
|
31
|
+
<text x="500" y="110" text-anchor="middle" class="label">Actions</text>
|
|
32
|
+
|
|
33
|
+
<!-- Arrow from Facts to Pattern Match -->
|
|
34
|
+
<path d="M 170 90 L 240 90" class="arrow"/>
|
|
35
|
+
|
|
36
|
+
<!-- Arrow from Rules to Pattern Match -->
|
|
37
|
+
<path d="M 430 90 L 360 90" class="arrow"/>
|
|
38
|
+
|
|
39
|
+
<!-- Center: Pattern Match and Execution -->
|
|
40
|
+
<rect x="210" y="170" width="180" height="140" rx="5" class="box"/>
|
|
41
|
+
<text x="300" y="195" text-anchor="middle" class="title">IF conditions</text>
|
|
42
|
+
<text x="300" y="215" text-anchor="middle" class="title">match facts</text>
|
|
43
|
+
|
|
44
|
+
<line x1="230" y1="230" x2="370" y2="230" stroke="#60a5fa" stroke-width="1" opacity="0.3"/>
|
|
45
|
+
|
|
46
|
+
<text x="300" y="255" text-anchor="middle" class="title">THEN execute</text>
|
|
47
|
+
<text x="300" y="275" text-anchor="middle" class="title">action</text>
|
|
48
|
+
|
|
49
|
+
<!-- Arrow pointing down to Pattern Match box -->
|
|
50
|
+
<path d="M 300 130 L 300 170" class="arrow"/>
|
|
51
|
+
|
|
52
|
+
<!-- Arrow from action box to new facts -->
|
|
53
|
+
<path d="M 300 310 L 300 340" class="arrow"/>
|
|
54
|
+
<text x="380" y="328" class="label">May create</text>
|
|
55
|
+
<text x="380" y="345" class="label">new facts</text>
|
|
56
|
+
|
|
57
|
+
<!-- New facts box at bottom -->
|
|
58
|
+
<rect x="210" y="345" width="180" height="30" rx="3" class="box"/>
|
|
59
|
+
<text x="300" y="365" text-anchor="middle" class="label">Facts added/removed</text>
|
|
60
|
+
|
|
61
|
+
<!-- Cycle arrow going back up -->
|
|
62
|
+
<path d="M 390 360 L 550 360 L 550 90 L 570 90" class="cycle-arrow"/>
|
|
63
|
+
<text x="555" y="225" class="label" fill="#22d3ee">↻</text>
|
|
64
|
+
<text x="490" y="372" class="label" fill="#22d3ee">(cycle continues)</text>
|
|
65
|
+
</svg>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 450 280">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { fill: #1e293b; stroke: #60a5fa; stroke-width: 2; }
|
|
5
|
+
.text { fill: #e2e8f0; font-family: 'Courier New', monospace; font-size: 14px; }
|
|
6
|
+
.title { fill: #60a5fa; font-family: 'Courier New', monospace; font-size: 16px; font-weight: bold; }
|
|
7
|
+
.label { fill: #94a3b8; font-family: 'Courier New', monospace; font-size: 13px; }
|
|
8
|
+
.value { fill: #a5f3fc; font-family: 'Courier New', monospace; font-size: 13px; }
|
|
9
|
+
</style>
|
|
10
|
+
</defs>
|
|
11
|
+
|
|
12
|
+
<!-- Main container box -->
|
|
13
|
+
<rect x="30" y="20" width="390" height="240" rx="5" class="box"/>
|
|
14
|
+
|
|
15
|
+
<!-- Title -->
|
|
16
|
+
<text x="225" y="50" text-anchor="middle" class="title">Fact</text>
|
|
17
|
+
|
|
18
|
+
<!-- Separator line -->
|
|
19
|
+
<line x1="50" y1="65" x2="400" y2="65" stroke="#60a5fa" stroke-width="1" opacity="0.3"/>
|
|
20
|
+
|
|
21
|
+
<!-- Type section -->
|
|
22
|
+
<text x="70" y="95" class="label">Type:</text>
|
|
23
|
+
<text x="140" y="95" class="value">:temperature</text>
|
|
24
|
+
|
|
25
|
+
<!-- Separator line -->
|
|
26
|
+
<line x1="50" y1="110" x2="400" y2="110" stroke="#60a5fa" stroke-width="1" opacity="0.3"/>
|
|
27
|
+
|
|
28
|
+
<!-- Attributes section -->
|
|
29
|
+
<text x="70" y="140" class="label">Attributes:</text>
|
|
30
|
+
|
|
31
|
+
<text x="90" y="170" class="label">location:</text>
|
|
32
|
+
<text x="200" y="170" class="value">"server_room"</text>
|
|
33
|
+
|
|
34
|
+
<text x="90" y="195" class="label">value:</text>
|
|
35
|
+
<text x="200" y="195" class="value">85</text>
|
|
36
|
+
|
|
37
|
+
<text x="90" y="220" class="label">timestamp:</text>
|
|
38
|
+
<text x="200" y="220" class="value">2025-01-15 10:30:00</text>
|
|
39
|
+
|
|
40
|
+
<text x="90" y="245" class="label">sensor_id:</text>
|
|
41
|
+
<text x="200" y="245" class="value">42</text>
|
|
42
|
+
</svg>
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 420">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.box { fill: #1e293b; stroke: #60a5fa; stroke-width: 2; }
|
|
5
|
+
.text { fill: #e2e8f0; font-family: 'Courier New', monospace; font-size: 14px; }
|
|
6
|
+
.title { fill: #60a5fa; font-family: 'Courier New', monospace; font-size: 12px; font-weight: bold; }
|
|
7
|
+
.arrow { stroke: #60a5fa; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
|
|
8
|
+
.code { fill: #94a3b8; font-family: 'Courier New', monospace; font-size: 11px; }
|
|
9
|
+
</style>
|
|
10
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
11
|
+
<polygon points="0 0, 10 3, 0 6" fill="#60a5fa" />
|
|
12
|
+
</marker>
|
|
13
|
+
</defs>
|
|
14
|
+
|
|
15
|
+
<!-- Step 1: Add Facts -->
|
|
16
|
+
<rect x="50" y="20" width="400" height="60" rx="5" class="box"/>
|
|
17
|
+
<text x="250" y="40" text-anchor="middle" class="title">1. ADD FACTS</text>
|
|
18
|
+
<text x="250" y="62" text-anchor="middle" class="code">kb.fact :temperature, value: 85</text>
|
|
19
|
+
|
|
20
|
+
<!-- Arrow 1 -->
|
|
21
|
+
<path d="M 250 80 L 250 110" class="arrow"/>
|
|
22
|
+
|
|
23
|
+
<!-- Step 2: Pattern Matching -->
|
|
24
|
+
<rect x="50" y="110" width="400" height="60" rx="5" class="box"/>
|
|
25
|
+
<text x="250" y="130" text-anchor="middle" class="title">2. PATTERN MATCHING</text>
|
|
26
|
+
<text x="250" y="152" text-anchor="middle" class="code">RETE network finds matching rules</text>
|
|
27
|
+
|
|
28
|
+
<!-- Arrow 2 -->
|
|
29
|
+
<path d="M 250 170 L 250 200" class="arrow"/>
|
|
30
|
+
|
|
31
|
+
<!-- Step 3: Fire Rules -->
|
|
32
|
+
<rect x="50" y="200" width="400" height="60" rx="5" class="box"/>
|
|
33
|
+
<text x="250" y="220" text-anchor="middle" class="title">3. FIRE RULES</text>
|
|
34
|
+
<text x="250" y="242" text-anchor="middle" class="code">Execute actions for complete matches</text>
|
|
35
|
+
|
|
36
|
+
<!-- Arrow 3 -->
|
|
37
|
+
<path d="M 250 260 L 250 290" class="arrow"/>
|
|
38
|
+
|
|
39
|
+
<!-- Step 4: Actions May Add/Remove Facts -->
|
|
40
|
+
<rect x="50" y="290" width="400" height="80" rx="5" class="box"/>
|
|
41
|
+
<text x="250" y="310" text-anchor="middle" class="title">4. ACTIONS MAY ADD/REMOVE FACTS</text>
|
|
42
|
+
<text x="250" y="332" text-anchor="middle" class="code">Cycle continues until no rules fire</text>
|
|
43
|
+
|
|
44
|
+
<!-- Feedback arrow -->
|
|
45
|
+
<path d="M 450 320 L 480 320 L 480 50 L 460 50" class="arrow"/>
|
|
46
|
+
<text x="485" y="185" class="text" font-size="11">↻</text>
|
|
47
|
+
</svg>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 420">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.outer-box { fill: none; stroke: #60a5fa; stroke-width: 2; }
|
|
5
|
+
.inner-box { fill: #1e293b; stroke: #94a3b8; stroke-width: 1.5; }
|
|
6
|
+
.text { fill: #e2e8f0; font-family: 'Courier New', monospace; font-size: 13px; }
|
|
7
|
+
.title { fill: #60a5fa; font-family: 'Courier New', monospace; font-size: 15px; font-weight: bold; }
|
|
8
|
+
.subtitle { fill: #94a3b8; font-family: 'Courier New', monospace; font-size: 11px; }
|
|
9
|
+
.arrow { stroke: #60a5fa; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
|
|
10
|
+
</style>
|
|
11
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
12
|
+
<polygon points="0 0, 10 3, 0 6" fill="#60a5fa" />
|
|
13
|
+
</marker>
|
|
14
|
+
</defs>
|
|
15
|
+
|
|
16
|
+
<!-- Outer container -->
|
|
17
|
+
<rect x="20" y="20" width="460" height="380" rx="5" class="outer-box"/>
|
|
18
|
+
<text x="250" y="45" text-anchor="middle" class="title">Knowledge Base</text>
|
|
19
|
+
|
|
20
|
+
<!-- DSL Layer -->
|
|
21
|
+
<rect x="50" y="60" width="400" height="70" rx="5" class="inner-box"/>
|
|
22
|
+
<text x="250" y="80" text-anchor="middle" class="text">DSL Layer (Your Interface)</text>
|
|
23
|
+
<text x="250" y="100" text-anchor="middle" class="subtitle">- rule(), fact(), run()</text>
|
|
24
|
+
|
|
25
|
+
<!-- Arrow DSL to Working Memory -->
|
|
26
|
+
<path d="M 250 130 L 250 155" class="arrow"/>
|
|
27
|
+
|
|
28
|
+
<!-- Working Memory -->
|
|
29
|
+
<rect x="50" y="155" width="400" height="70" rx="5" class="inner-box"/>
|
|
30
|
+
<text x="250" y="175" text-anchor="middle" class="text">Working Memory</text>
|
|
31
|
+
<text x="250" y="195" text-anchor="middle" class="subtitle">- Stores facts</text>
|
|
32
|
+
<text x="250" y="210" text-anchor="middle" class="subtitle">- Notifies observers</text>
|
|
33
|
+
|
|
34
|
+
<!-- Arrow Working Memory to RETE Engine -->
|
|
35
|
+
<path d="M 250 225 L 250 250" class="arrow"/>
|
|
36
|
+
|
|
37
|
+
<!-- RETE Engine -->
|
|
38
|
+
<rect x="50" y="250" width="400" height="90" rx="5" class="inner-box"/>
|
|
39
|
+
<text x="250" y="270" text-anchor="middle" class="text">RETE Engine</text>
|
|
40
|
+
<text x="250" y="290" text-anchor="middle" class="subtitle">- Pattern matching</text>
|
|
41
|
+
<text x="250" y="305" text-anchor="middle" class="subtitle">- Rule compilation</text>
|
|
42
|
+
<text x="250" y="320" text-anchor="middle" class="subtitle">- Inference execution</text>
|
|
43
|
+
</svg>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 520 380">
|
|
2
|
+
<defs>
|
|
3
|
+
<style>
|
|
4
|
+
.outer-box { fill: none; stroke: #60a5fa; stroke-width: 2; }
|
|
5
|
+
.inner-box { fill: #1e293b; stroke: #94a3b8; stroke-width: 1.5; }
|
|
6
|
+
.text { fill: #e2e8f0; font-family: 'Courier New', monospace; font-size: 13px; }
|
|
7
|
+
.title { fill: #60a5fa; font-family: 'Courier New', monospace; font-size: 16px; font-weight: bold; }
|
|
8
|
+
.subtitle { fill: #94a3b8; font-family: 'Courier New', monospace; font-size: 12px; }
|
|
9
|
+
.check { fill: #22c55e; font-size: 16px; }
|
|
10
|
+
.arrow { stroke: #60a5fa; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
|
|
11
|
+
</style>
|
|
12
|
+
<marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
|
|
13
|
+
<polygon points="0 0, 10 3, 0 6" fill="#60a5fa" />
|
|
14
|
+
</marker>
|
|
15
|
+
</defs>
|
|
16
|
+
|
|
17
|
+
<!-- Main container -->
|
|
18
|
+
<rect x="20" y="20" width="480" height="340" rx="5" class="outer-box"/>
|
|
19
|
+
<text x="260" y="45" text-anchor="middle" class="title">Rule: "high_temperature_alert"</text>
|
|
20
|
+
|
|
21
|
+
<!-- Metadata section -->
|
|
22
|
+
<rect x="40" y="60" width="440" height="80" rx="5" class="inner-box"/>
|
|
23
|
+
<text x="260" y="80" text-anchor="middle" class="title" font-size="14">METADATA</text>
|
|
24
|
+
<text x="80" y="105" class="subtitle">- Name: "high_temperature_alert"</text>
|
|
25
|
+
<text x="80" y="125" class="subtitle">- Description: "Alert when..."</text>
|
|
26
|
+
<text x="350" y="125" class="subtitle">- Priority: 10</text>
|
|
27
|
+
|
|
28
|
+
<!-- Conditions section -->
|
|
29
|
+
<rect x="40" y="155" width="440" height="80" rx="5" class="inner-box"/>
|
|
30
|
+
<text x="260" y="175" text-anchor="middle" class="title" font-size="14">CONDITIONS (IF)</text>
|
|
31
|
+
<text x="80" y="200" class="check">✓</text>
|
|
32
|
+
<text x="100" y="200" class="subtitle">temperature in server_room > 80°F</text>
|
|
33
|
+
<text x="80" y="220" class="check">✓</text>
|
|
34
|
+
<text x="100" y="220" class="subtitle">sensor in server_room is active</text>
|
|
35
|
+
|
|
36
|
+
<!-- Arrow -->
|
|
37
|
+
<path d="M 260 235 L 260 255" class="arrow"/>
|
|
38
|
+
<text x="290" y="250" class="subtitle">(when ALL match)</text>
|
|
39
|
+
|
|
40
|
+
<!-- Action section -->
|
|
41
|
+
<rect x="40" y="255" width="440" height="80" rx="5" class="inner-box"/>
|
|
42
|
+
<text x="260" y="275" text-anchor="middle" class="title" font-size="14">ACTION (THEN)</text>
|
|
43
|
+
<text x="80" y="300" class="subtitle">→ send_alert(...)</text>
|
|
44
|
+
</svg>
|
|
@@ -114,7 +114,7 @@
|
|
|
114
114
|
<rect x="160" y="810" width="280" height="90" class="prod-box" rx="5"/>
|
|
115
115
|
<text x="300" y="840" class="node-title" text-anchor="middle">ProductionNode</text>
|
|
116
116
|
<text x="300" y="860" class="label" text-anchor="middle">(rule: "trading_signal")</text>
|
|
117
|
-
<text x="300" y="880" class="detail" text-anchor="middle">Action: if price
|
|
117
|
+
<text x="300" y="880" class="detail" text-anchor="middle">Action: if price < threshold,</text>
|
|
118
118
|
<text x="300" y="892" class="detail" text-anchor="middle">BUY symbol</text>
|
|
119
119
|
|
|
120
120
|
<!-- Legend -->
|