lex-semantic-priming 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 +7 -0
- data/.github/workflows/ci.yml +16 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +34 -0
- data/CLAUDE.md +138 -0
- data/Gemfile +13 -0
- data/README.md +62 -0
- data/lex-semantic-priming.gemspec +31 -0
- data/lib/legion/extensions/semantic_priming/client.rb +15 -0
- data/lib/legion/extensions/semantic_priming/helpers/connection.rb +73 -0
- data/lib/legion/extensions/semantic_priming/helpers/constants.rb +64 -0
- data/lib/legion/extensions/semantic_priming/helpers/priming_network.rb +202 -0
- data/lib/legion/extensions/semantic_priming/helpers/semantic_node.rb +77 -0
- data/lib/legion/extensions/semantic_priming/runners/semantic_priming.rb +116 -0
- data/lib/legion/extensions/semantic_priming/version.rb +9 -0
- data/lib/legion/extensions/semantic_priming.rb +17 -0
- metadata +77 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 4e40ba76b2f97ab9c12a1b004d3e7cdb577caaf2153fb8f6e189fa873fde8651
|
|
4
|
+
data.tar.gz: 353c181dddb932afd5c1c48cfcbc15bd01ab22a0da68b2b9368d21ea645170cd
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c8a442c55e237f69d9d172830f9f492a6236263d96620cb499e7e2361c325718166aadf31e5ffd849ae5bb25bc467fc7a6e1989db195fb7b64143358aca71ef9
|
|
7
|
+
data.tar.gz: ef60c29517d3e90cae46466fa73fc98248ed4af5619d5abaf2507b664b5951b5b8bb8890462194d698568f610cbf4d31658adecf52164f60e5db7d529d6e0a73
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
10
|
+
|
|
11
|
+
release:
|
|
12
|
+
needs: ci
|
|
13
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
|
+
secrets:
|
|
16
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
NewCops: enable
|
|
3
|
+
TargetRubyVersion: 3.4
|
|
4
|
+
|
|
5
|
+
Style/Documentation:
|
|
6
|
+
Enabled: false
|
|
7
|
+
|
|
8
|
+
Naming/PredicateMethod:
|
|
9
|
+
Enabled: false
|
|
10
|
+
|
|
11
|
+
Metrics/ClassLength:
|
|
12
|
+
Max: 150
|
|
13
|
+
|
|
14
|
+
Metrics/MethodLength:
|
|
15
|
+
Max: 25
|
|
16
|
+
|
|
17
|
+
Metrics/AbcSize:
|
|
18
|
+
Max: 25
|
|
19
|
+
|
|
20
|
+
Metrics/ParameterLists:
|
|
21
|
+
Max: 8
|
|
22
|
+
MaxOptionalParameters: 8
|
|
23
|
+
|
|
24
|
+
Layout/HashAlignment:
|
|
25
|
+
EnforcedColonStyle: table
|
|
26
|
+
EnforcedHashRocketStyle: table
|
|
27
|
+
|
|
28
|
+
Metrics/BlockLength:
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'spec/**/*'
|
|
31
|
+
|
|
32
|
+
Style/OneClassPerFile:
|
|
33
|
+
Exclude:
|
|
34
|
+
- 'spec/spec_helper.rb'
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# lex-semantic-priming
|
|
2
|
+
|
|
3
|
+
**Level 3 Leaf Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
- **Gem**: `lex-semantic-priming`
|
|
6
|
+
- **Version**: `0.1.0`
|
|
7
|
+
- **Namespace**: `Legion::Extensions::SemanticPriming`
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Implements spreading activation across a weighted semantic network. Nodes represent concepts; connections carry directional weights that grow stronger each time they are traversed (Hebbian reinforcement). When a seed concept is primed, activation spreads outward through connected nodes with both a per-hop decay factor and a weight-attenuated spread amount. Distinct from `lex-semantic-memory` (which stores named concept definitions with typed relations) — this stores activation states and connection weights for dynamic priming behavior.
|
|
12
|
+
|
|
13
|
+
## Gem Info
|
|
14
|
+
|
|
15
|
+
- **Gem name**: `lex-semantic-priming`
|
|
16
|
+
- **License**: MIT
|
|
17
|
+
- **Ruby**: >= 3.4
|
|
18
|
+
- **No runtime dependencies** beyond the Legion framework
|
|
19
|
+
|
|
20
|
+
## File Structure
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
lib/legion/extensions/semantic_priming/
|
|
24
|
+
version.rb # VERSION = '0.1.0'
|
|
25
|
+
helpers/
|
|
26
|
+
constants.rb # limits, activation params, weight params, node types
|
|
27
|
+
semantic_node.rb # SemanticNode class — concept node with activation state
|
|
28
|
+
connection.rb # Connection class — weighted directional edge, Hebbian traversal
|
|
29
|
+
priming_network.rb # PrimingNetwork class — full network with BFS spreading activation
|
|
30
|
+
runners/
|
|
31
|
+
semantic_priming.rb # Runners::SemanticPriming module — all public runner methods
|
|
32
|
+
client.rb # Client class including Runners::SemanticPriming
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Constants
|
|
36
|
+
|
|
37
|
+
| Constant | Value | Purpose |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `MAX_NODES` | 500 | Maximum nodes in the network |
|
|
40
|
+
| `MAX_CONNECTIONS` | 2000 | Maximum edges |
|
|
41
|
+
| `ACTIVATION_DECAY` | 0.05 | Per-tick activation decrease for all nodes |
|
|
42
|
+
| `SPREADING_FACTOR` | 0.6 | Base fraction of activation that spreads per hop |
|
|
43
|
+
| `PRIMING_BOOST` | 0.3 | Direct boost applied to a node when primed |
|
|
44
|
+
| `ACTIVATION_THRESHOLD` | 0.1 | Minimum activation to be considered active |
|
|
45
|
+
| `DEFAULT_WEIGHT` | 0.5 | Starting connection weight for new edges |
|
|
46
|
+
| `WEIGHT_GROWTH_RATE` | 0.02 | Weight increase on each traversal (Hebbian) |
|
|
47
|
+
| `WEIGHT_DECAY_RATE` | 0.01 | Weight decrease per decay cycle |
|
|
48
|
+
| `MIN_WEIGHT` | 0.05 | Floor for connection weights; pruned at or below |
|
|
49
|
+
| `MAX_SPREAD_DEPTH` | 3 | Maximum BFS hops during spreading activation |
|
|
50
|
+
| `DEPTH_DECAY_FACTOR` | 0.5 | Activation multiplier per depth level |
|
|
51
|
+
| `NODE_TYPES` | 7 symbols | `:concept`, `:entity`, `:action`, `:property`, `:relation`, `:event`, `:context` |
|
|
52
|
+
|
|
53
|
+
## Helpers
|
|
54
|
+
|
|
55
|
+
### `Helpers::SemanticNode`
|
|
56
|
+
|
|
57
|
+
Concept node with activation state and metadata.
|
|
58
|
+
|
|
59
|
+
- `initialize(id:, label:, node_type: :concept, domain: :general)` — initial activation = 0.0
|
|
60
|
+
- `prime!(amount = PRIMING_BOOST)` — boosts activation by amount, clamps to 1.0
|
|
61
|
+
- `decay!(rate = ACTIVATION_DECAY)` — decrements activation; floors at 0.0
|
|
62
|
+
- `access!` — records last_accessed timestamp
|
|
63
|
+
- `reset!` — sets activation back to 0.0
|
|
64
|
+
- `primed?` — activation >= 0.4
|
|
65
|
+
- `active?` — activation > ACTIVATION_THRESHOLD
|
|
66
|
+
- `activation_label` — `:dormant`, `:trace`, `:weak`, `:moderate`, `:strong`, `:peak` based on activation value
|
|
67
|
+
|
|
68
|
+
### `Helpers::Connection`
|
|
69
|
+
|
|
70
|
+
Weighted directional edge between two nodes.
|
|
71
|
+
|
|
72
|
+
- `initialize(source_id:, target_id:, weight: DEFAULT_WEIGHT)` — assigned UUID
|
|
73
|
+
- `strengthen!(amount = WEIGHT_GROWTH_RATE)` — increases weight, clamps to 1.0
|
|
74
|
+
- `weaken!(amount = WEIGHT_DECAY_RATE)` — decreases weight; removes when at or below MIN_WEIGHT
|
|
75
|
+
- `traverse!(source_activation)` — calls `strengthen!` (Hebbian) and returns `spreading_amount`
|
|
76
|
+
- `spreading_amount(source_activation)` — `source_activation * weight * SPREADING_FACTOR`
|
|
77
|
+
- `weight_label` — `:negligible`, `:weak`, `:moderate`, `:strong`, `:dominant`
|
|
78
|
+
|
|
79
|
+
### `Helpers::PrimingNetwork`
|
|
80
|
+
|
|
81
|
+
Full network with BFS spreading activation.
|
|
82
|
+
|
|
83
|
+
- `initialize` — empty nodes hash, connections hash (keyed by `source_id:target_id`)
|
|
84
|
+
- `add_node(label:, node_type: :concept, domain: :general)` — returns nil if at MAX_NODES
|
|
85
|
+
- `remove_node(node_id)` — removes node and all connections to/from it
|
|
86
|
+
- `connect(source_id:, target_id:, weight: DEFAULT_WEIGHT)` — creates or returns existing connection; returns nil if at MAX_CONNECTIONS
|
|
87
|
+
- `prime_node(node_id, amount: PRIMING_BOOST)` — calls `node.prime!`
|
|
88
|
+
- `spread_activation(node_id, depth: MAX_SPREAD_DEPTH, visited: {})` — recursive BFS; each level multiplied by `DEPTH_DECAY_FACTOR`; each edge traversal calls `connection.traverse!` for Hebbian strengthening
|
|
89
|
+
- `prime_and_spread(node_id, amount: PRIMING_BOOST, depth: MAX_SPREAD_DEPTH)` — primes seed, then spreads
|
|
90
|
+
- `decay_all!` — decays all node activations; weakens all connection weights (prunes at MIN_WEIGHT)
|
|
91
|
+
- `reset_all!` — resets all node activations to 0.0
|
|
92
|
+
- `find_node_by_label(label)` — substring or exact match search
|
|
93
|
+
- `neighbors(node_id)` — returns all outgoing connections
|
|
94
|
+
- `connection_between(source_id, target_id)` — direct lookup
|
|
95
|
+
- `primed_nodes` — nodes with `primed? == true`
|
|
96
|
+
- `active_nodes` — nodes with `active? == true`
|
|
97
|
+
- `most_primed(limit: 5)` — sorted by activation descending
|
|
98
|
+
- `strongest_connections(limit: 10)` — sorted by weight descending
|
|
99
|
+
- `average_activation` — mean activation across all nodes
|
|
100
|
+
- `network_density` — `connections.size.to_f / [nodes.size * (nodes.size - 1), 1].max`
|
|
101
|
+
- `priming_report` — summary hash including active/primed counts, average activation, density, top nodes
|
|
102
|
+
|
|
103
|
+
## Runners
|
|
104
|
+
|
|
105
|
+
All runners are in `Runners::SemanticPriming`. Callers may pass an optional `engine:` parameter to operate on a non-default network instance.
|
|
106
|
+
|
|
107
|
+
| Runner | Parameters | Returns |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `add_node` | `label:, node_type: :concept, domain: :general` | `{ success:, node_id:, label:, node_type: }` |
|
|
110
|
+
| `remove_node` | `node_id:` | `{ success: }` |
|
|
111
|
+
| `connect_nodes` | `source_id:, target_id:, weight: DEFAULT_WEIGHT` | `{ success:, connection_id:, source_id:, target_id:, weight: }` |
|
|
112
|
+
| `prime` | `node_id:, amount: PRIMING_BOOST` | `{ success:, node_id:, activation: }` |
|
|
113
|
+
| `prime_and_spread` | `node_id:, amount: PRIMING_BOOST, depth: MAX_SPREAD_DEPTH` | `{ success:, node_id:, activation:, spread_count: }` |
|
|
114
|
+
| `spread_activation` | `node_id:, depth: MAX_SPREAD_DEPTH` | `{ success:, node_id:, spread_count: }` |
|
|
115
|
+
| `decay` | (none) | `{ success:, active_nodes:, pruned_connections: }` |
|
|
116
|
+
| `reset` | (none) | `{ success: }` |
|
|
117
|
+
| `find_node` | `label:` | `{ success:, found:, node: }` |
|
|
118
|
+
| `neighbors` | `node_id:` | `{ success:, node_id:, neighbors:, count: }` |
|
|
119
|
+
| `primed_nodes` | (none) | `{ success:, nodes:, count: }` |
|
|
120
|
+
| `most_primed` | `limit: 5` | `{ success:, nodes:, count: }` |
|
|
121
|
+
| `priming_report` | (none) | Full `PrimingNetwork#priming_report` hash |
|
|
122
|
+
| `status` | (none) | Node count, connection count, average activation, density |
|
|
123
|
+
|
|
124
|
+
## Integration Points
|
|
125
|
+
|
|
126
|
+
- **lex-semantic-memory**: semantic-memory stores named concept definitions with relational structure; semantic-priming stores transient activation state and connection weights. They are complementary — semantic-memory provides the schema; semantic-priming provides the dynamic activation surface
|
|
127
|
+
- **lex-dream**: association walking in the dream cycle can use `prime_and_spread` to find conceptually adjacent concepts for contradiction resolution and agenda synthesis
|
|
128
|
+
- **lex-tick / lex-cortex**: `prime_and_spread` or `decay` can be wired as a tick phase handler for ongoing network maintenance
|
|
129
|
+
- **lex-memory**: when a memory trace is retrieved, its associated concept nodes can be primed to model recency effects on conceptual accessibility
|
|
130
|
+
|
|
131
|
+
## Development Notes
|
|
132
|
+
|
|
133
|
+
- Spreading activation is recursive, not iterative; depth is tracked via `visited` hash to prevent re-activation of already-visited nodes in the same spread call
|
|
134
|
+
- Each `traverse!` call on a connection triggers Hebbian strengthening — frequent traversals produce stronger connections over time, modeling use-dependent accessibility
|
|
135
|
+
- `DEPTH_DECAY_FACTOR = 0.5` means activation at depth 2 is 25% of the seed's activation; at depth 3, 12.5%
|
|
136
|
+
- `spreading_amount` = `source_activation * weight * SPREADING_FACTOR`; this triple-product means low-weight connections transmit very little even with high source activation
|
|
137
|
+
- `decay_all!` weaken-and-prune connections in the same pass; connections at or below `MIN_WEIGHT` are deleted
|
|
138
|
+
- The optional `engine:` parameter on all runners supports multiple independent networks in a single process
|
data/Gemfile
ADDED
data/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# lex-semantic-priming
|
|
2
|
+
|
|
3
|
+
Spreading activation network for LegionIO cognitive agents. Nodes represent concepts; connections carry weights that strengthen each time they are traversed (Hebbian reinforcement).
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
`lex-semantic-priming` maintains a weighted semantic network where priming one concept causes activation to spread to related concepts with depth-attenuated strength. The network learns from use: every edge traversal during spreading activation calls `strengthen!` on that connection, gradually building stronger pathways for frequently co-activated concepts.
|
|
8
|
+
|
|
9
|
+
- **Nodes**: typed concept nodes (`:concept`, `:entity`, `:action`, `:property`, `:relation`, `:event`, `:context`)
|
|
10
|
+
- **Connections**: directional weighted edges; weights grow on traversal (Hebbian), decay over time
|
|
11
|
+
- **Spreading activation**: BFS from a seed node across outgoing connections; activation decays by `DEPTH_DECAY_FACTOR` (0.5) per hop and by `weight * SPREADING_FACTOR` (0.6) per edge
|
|
12
|
+
- **Decay**: all node activations and connection weights decay each tick; connections pruned at MIN_WEIGHT (0.05)
|
|
13
|
+
- **Primed nodes**: activation >= 0.4; active nodes: activation > 0.1
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require 'legion/extensions/semantic_priming'
|
|
19
|
+
|
|
20
|
+
client = Legion::Extensions::SemanticPriming::Client.new
|
|
21
|
+
|
|
22
|
+
# Add concept nodes
|
|
23
|
+
ruby_id = client.add_node(label: 'ruby', node_type: :concept, domain: :programming)[:node_id]
|
|
24
|
+
oop_id = client.add_node(label: 'object_oriented', node_type: :concept, domain: :programming)[:node_id]
|
|
25
|
+
class_id = client.add_node(label: 'class', node_type: :concept, domain: :programming)[:node_id]
|
|
26
|
+
|
|
27
|
+
# Connect them
|
|
28
|
+
client.connect_nodes(source_id: ruby_id, target_id: oop_id)
|
|
29
|
+
client.connect_nodes(source_id: oop_id, target_id: class_id)
|
|
30
|
+
|
|
31
|
+
# Prime a seed and spread activation
|
|
32
|
+
result = client.prime_and_spread(node_id: ruby_id)
|
|
33
|
+
# => { success: true, node_id: ..., activation: 0.3, spread_count: 2 }
|
|
34
|
+
|
|
35
|
+
# See which nodes are primed (activation >= 0.4)
|
|
36
|
+
client.primed_nodes
|
|
37
|
+
# => { success: true, nodes: [...], count: 1 }
|
|
38
|
+
|
|
39
|
+
# Most activated nodes
|
|
40
|
+
client.most_primed(limit: 5)
|
|
41
|
+
# => { success: true, nodes: [{ label: 'ruby', activation: 0.3, ... }, ...], count: ... }
|
|
42
|
+
|
|
43
|
+
# Per-tick decay (call each cognitive cycle)
|
|
44
|
+
client.decay
|
|
45
|
+
# => { success: true, active_nodes: 2, pruned_connections: 0 }
|
|
46
|
+
|
|
47
|
+
# Network summary
|
|
48
|
+
client.priming_report
|
|
49
|
+
# => { node_count:, connection_count:, active_count:, primed_count:, average_activation:, density:, ... }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bundle install
|
|
56
|
+
bundle exec rspec
|
|
57
|
+
bundle exec rubocop
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/semantic_priming/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-semantic-priming'
|
|
7
|
+
spec.version = Legion::Extensions::SemanticPriming::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'Semantic priming and spreading activation network for LegionIO'
|
|
12
|
+
spec.description = 'Models spreading activation in semantic networks - priming one concept activates related ' \
|
|
13
|
+
'concepts with distance-based decay for rapid associative retrieval.'
|
|
14
|
+
spec.homepage = 'https://github.com/LegionIO/lex-semantic-priming'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
|
|
17
|
+
spec.required_ruby_version = '>= 3.4'
|
|
18
|
+
|
|
19
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
20
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-semantic-priming'
|
|
21
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-semantic-priming/blob/master/README.md'
|
|
22
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-semantic-priming/blob/master/CHANGELOG.md'
|
|
23
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-semantic-priming/issues'
|
|
24
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
25
|
+
|
|
26
|
+
spec.files = Dir.chdir(__dir__) do
|
|
27
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
|
28
|
+
end
|
|
29
|
+
spec.require_paths = ['lib']
|
|
30
|
+
spec.add_development_dependency 'legion-gaia'
|
|
31
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module SemanticPriming
|
|
6
|
+
class Client
|
|
7
|
+
include Runners::SemanticPriming
|
|
8
|
+
|
|
9
|
+
def initialize(engine: nil)
|
|
10
|
+
@default_engine = engine || Helpers::PrimingNetwork.new
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module SemanticPriming
|
|
8
|
+
module Helpers
|
|
9
|
+
class Connection
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :source_id, :target_id, :weight, :traversal_count, :created_at
|
|
13
|
+
|
|
14
|
+
def initialize(source_id:, target_id:, weight: DEFAULT_WEIGHT)
|
|
15
|
+
@id = SecureRandom.uuid
|
|
16
|
+
@source_id = source_id
|
|
17
|
+
@target_id = target_id
|
|
18
|
+
@weight = weight.to_f.clamp(MIN_WEIGHT, 1.0).round(10)
|
|
19
|
+
@traversal_count = 0
|
|
20
|
+
@created_at = Time.now.utc
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def strengthen!(amount: WEIGHT_GROWTH_RATE)
|
|
24
|
+
@weight = (@weight + amount).clamp(MIN_WEIGHT, 1.0).round(10)
|
|
25
|
+
self
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def weaken!(amount: WEIGHT_DECAY_RATE)
|
|
29
|
+
@weight = (@weight - amount).clamp(MIN_WEIGHT, 1.0).round(10)
|
|
30
|
+
self
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def traverse!
|
|
34
|
+
@traversal_count += 1
|
|
35
|
+
strengthen!(amount: WEIGHT_GROWTH_RATE)
|
|
36
|
+
self
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def strong?
|
|
40
|
+
@weight >= 0.7
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def weak?
|
|
44
|
+
@weight <= 0.2
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def spreading_amount(source_activation)
|
|
48
|
+
(source_activation * @weight * SPREADING_FACTOR).round(10)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def weight_label
|
|
52
|
+
match = WEIGHT_LABELS.find { |range, _| range.cover?(@weight) }
|
|
53
|
+
match ? match.last : :very_weak
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def to_h
|
|
57
|
+
{
|
|
58
|
+
id: @id,
|
|
59
|
+
source_id: @source_id,
|
|
60
|
+
target_id: @target_id,
|
|
61
|
+
weight: @weight,
|
|
62
|
+
weight_label: weight_label,
|
|
63
|
+
strong: strong?,
|
|
64
|
+
weak: weak?,
|
|
65
|
+
traversal_count: @traversal_count,
|
|
66
|
+
created_at: @created_at
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module SemanticPriming
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
# Network limits
|
|
9
|
+
MAX_NODES = 500
|
|
10
|
+
MAX_CONNECTIONS = 2000
|
|
11
|
+
|
|
12
|
+
# Activation dynamics
|
|
13
|
+
DEFAULT_ACTIVATION = 0.0
|
|
14
|
+
RESTING_ACTIVATION = 0.0
|
|
15
|
+
MAX_ACTIVATION = 1.0
|
|
16
|
+
ACTIVATION_DECAY = 0.05
|
|
17
|
+
SPREADING_FACTOR = 0.6
|
|
18
|
+
PRIMING_BOOST = 0.3
|
|
19
|
+
ACTIVATION_THRESHOLD = 0.1
|
|
20
|
+
|
|
21
|
+
# Connection properties
|
|
22
|
+
DEFAULT_WEIGHT = 0.5
|
|
23
|
+
WEIGHT_GROWTH_RATE = 0.02
|
|
24
|
+
WEIGHT_DECAY_RATE = 0.01
|
|
25
|
+
MIN_WEIGHT = 0.05
|
|
26
|
+
|
|
27
|
+
# Spreading activation
|
|
28
|
+
MAX_SPREAD_DEPTH = 3
|
|
29
|
+
DEPTH_DECAY_FACTOR = 0.5
|
|
30
|
+
|
|
31
|
+
# Node types
|
|
32
|
+
NODE_TYPES = %i[concept category feature relation action emotion context].freeze
|
|
33
|
+
|
|
34
|
+
# Activation labels
|
|
35
|
+
ACTIVATION_LABELS = {
|
|
36
|
+
(0.8..) => :highly_primed,
|
|
37
|
+
(0.6...0.8) => :primed,
|
|
38
|
+
(0.4...0.6) => :partially_primed,
|
|
39
|
+
(0.2...0.4) => :weakly_primed,
|
|
40
|
+
(..0.2) => :unprimed
|
|
41
|
+
}.freeze
|
|
42
|
+
|
|
43
|
+
# Connection strength labels
|
|
44
|
+
WEIGHT_LABELS = {
|
|
45
|
+
(0.8..) => :very_strong,
|
|
46
|
+
(0.6...0.8) => :strong,
|
|
47
|
+
(0.4...0.6) => :moderate,
|
|
48
|
+
(0.2...0.4) => :weak,
|
|
49
|
+
(..0.2) => :very_weak
|
|
50
|
+
}.freeze
|
|
51
|
+
|
|
52
|
+
# Priming effect labels
|
|
53
|
+
PRIMING_LABELS = {
|
|
54
|
+
(0.8..) => :massive,
|
|
55
|
+
(0.6...0.8) => :strong,
|
|
56
|
+
(0.4...0.6) => :moderate,
|
|
57
|
+
(0.2...0.4) => :mild,
|
|
58
|
+
(..0.2) => :negligible
|
|
59
|
+
}.freeze
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module SemanticPriming
|
|
6
|
+
module Helpers
|
|
7
|
+
class PrimingNetwork
|
|
8
|
+
include Constants
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@nodes = {}
|
|
12
|
+
@connections = {}
|
|
13
|
+
@adjacency = Hash.new { |h, k| h[k] = [] }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def add_node(label:, node_type: :concept)
|
|
17
|
+
prune_nodes_if_needed
|
|
18
|
+
node = SemanticNode.new(label: label, node_type: node_type)
|
|
19
|
+
@nodes[node.id] = node
|
|
20
|
+
node
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def remove_node(node_id:)
|
|
24
|
+
node = @nodes.delete(node_id)
|
|
25
|
+
return nil unless node
|
|
26
|
+
|
|
27
|
+
@adjacency.delete(node_id)
|
|
28
|
+
@adjacency.each_value { |list| list.reject! { |cid| connection_involves?(cid, node_id) } }
|
|
29
|
+
@connections.reject! { |_, c| c.source_id == node_id || c.target_id == node_id }
|
|
30
|
+
node
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def connect(source_id:, target_id:, weight: DEFAULT_WEIGHT)
|
|
34
|
+
return nil unless @nodes[source_id] && @nodes[target_id]
|
|
35
|
+
return nil if source_id == target_id
|
|
36
|
+
|
|
37
|
+
prune_connections_if_needed
|
|
38
|
+
conn = Connection.new(source_id: source_id, target_id: target_id, weight: weight)
|
|
39
|
+
@connections[conn.id] = conn
|
|
40
|
+
@adjacency[source_id] << conn.id
|
|
41
|
+
@adjacency[target_id] << conn.id
|
|
42
|
+
conn
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def prime_node(node_id:, amount: PRIMING_BOOST)
|
|
46
|
+
node = @nodes[node_id]
|
|
47
|
+
return nil unless node
|
|
48
|
+
|
|
49
|
+
node.prime!(amount: amount)
|
|
50
|
+
node
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def spread_activation(source_id:, depth: MAX_SPREAD_DEPTH)
|
|
54
|
+
source = @nodes[source_id]
|
|
55
|
+
return nil unless source
|
|
56
|
+
|
|
57
|
+
activated = {}
|
|
58
|
+
spread_recursive(source_id, source.activation, depth, 0, activated)
|
|
59
|
+
activated.map { |nid, amount| { node_id: nid, label: @nodes[nid]&.label, activation_added: amount } }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def prime_and_spread(node_id:, amount: PRIMING_BOOST, depth: MAX_SPREAD_DEPTH)
|
|
63
|
+
node = prime_node(node_id: node_id, amount: amount)
|
|
64
|
+
return nil unless node
|
|
65
|
+
|
|
66
|
+
node.access!
|
|
67
|
+
spread = spread_activation(source_id: node_id, depth: depth)
|
|
68
|
+
{ primed_node: node.to_h, spread: spread }
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def decay_all!
|
|
72
|
+
@nodes.each_value(&:decay!)
|
|
73
|
+
@connections.each_value { |c| c.weaken!(amount: WEIGHT_DECAY_RATE) }
|
|
74
|
+
prune_weak_connections
|
|
75
|
+
{ nodes_decayed: @nodes.size, connections_remaining: @connections.size }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def reset_all! = @nodes.each_value(&:reset!) && { nodes_reset: @nodes.size }
|
|
79
|
+
def find_node_by_label(label:) = @nodes.values.find { |n| n.label == label.to_s }
|
|
80
|
+
|
|
81
|
+
def neighbors(node_id:)
|
|
82
|
+
conn_ids = @adjacency[node_id] || []
|
|
83
|
+
conn_ids.filter_map do |cid|
|
|
84
|
+
conn = @connections[cid]
|
|
85
|
+
next unless conn
|
|
86
|
+
|
|
87
|
+
other_id = conn.source_id == node_id ? conn.target_id : conn.source_id
|
|
88
|
+
@nodes[other_id]
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def connection_between(source_id:, target_id:)
|
|
93
|
+
@connections.values.find do |c|
|
|
94
|
+
(c.source_id == source_id && c.target_id == target_id) ||
|
|
95
|
+
(c.source_id == target_id && c.target_id == source_id)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def primed_nodes = @nodes.values.select(&:primed?)
|
|
100
|
+
def active_nodes = @nodes.values.select(&:active?)
|
|
101
|
+
def most_primed(limit: 5) = @nodes.values.sort_by { |n| -n.activation }.first(limit)
|
|
102
|
+
def strongest_connections(limit: 5) = @connections.values.sort_by { |c| -c.weight }.first(limit)
|
|
103
|
+
|
|
104
|
+
def average_activation
|
|
105
|
+
return DEFAULT_ACTIVATION if @nodes.empty?
|
|
106
|
+
|
|
107
|
+
vals = @nodes.values.map(&:activation)
|
|
108
|
+
(vals.sum / vals.size).round(10)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def average_connection_weight
|
|
112
|
+
return DEFAULT_WEIGHT if @connections.empty?
|
|
113
|
+
|
|
114
|
+
vals = @connections.values.map(&:weight)
|
|
115
|
+
(vals.sum / vals.size).round(10)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def network_density
|
|
119
|
+
return 0.0 if @nodes.size < 2
|
|
120
|
+
|
|
121
|
+
(@connections.size.to_f / (@nodes.size * (@nodes.size - 1) / 2)).round(10)
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def priming_report
|
|
125
|
+
to_h.merge(
|
|
126
|
+
average_weight: average_connection_weight,
|
|
127
|
+
most_primed: most_primed(limit: 3).map(&:to_h),
|
|
128
|
+
strongest_connections: strongest_connections(limit: 3).map(&:to_h)
|
|
129
|
+
)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def to_h
|
|
133
|
+
{
|
|
134
|
+
total_nodes: @nodes.size,
|
|
135
|
+
total_connections: @connections.size,
|
|
136
|
+
primed_count: primed_nodes.size,
|
|
137
|
+
active_count: active_nodes.size,
|
|
138
|
+
average_activation: average_activation,
|
|
139
|
+
network_density: network_density
|
|
140
|
+
}
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
private
|
|
144
|
+
|
|
145
|
+
def spread_recursive(node_id, activation, max_depth, current_depth, activated)
|
|
146
|
+
return if current_depth >= max_depth || activation < ACTIVATION_THRESHOLD
|
|
147
|
+
|
|
148
|
+
each_neighbor(node_id) do |conn, other_id, target_node|
|
|
149
|
+
next if activated.key?(other_id)
|
|
150
|
+
|
|
151
|
+
amount = (conn.spreading_amount(activation) * (DEPTH_DECAY_FACTOR**current_depth)).round(10)
|
|
152
|
+
next if amount < ACTIVATION_THRESHOLD
|
|
153
|
+
|
|
154
|
+
conn.traverse!
|
|
155
|
+
target_node.prime!(amount: amount)
|
|
156
|
+
activated[other_id] = amount
|
|
157
|
+
spread_recursive(other_id, amount, max_depth, current_depth + 1, activated)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def each_neighbor(node_id)
|
|
162
|
+
(@adjacency[node_id] || []).each do |cid|
|
|
163
|
+
conn = @connections[cid]
|
|
164
|
+
next unless conn
|
|
165
|
+
|
|
166
|
+
other_id = conn.source_id == node_id ? conn.target_id : conn.source_id
|
|
167
|
+
target_node = @nodes[other_id]
|
|
168
|
+
yield conn, other_id, target_node if target_node
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def connection_involves?(cid, nid)
|
|
173
|
+
(c = @connections[cid]) && (c.source_id == nid || c.target_id == nid)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def prune_nodes_if_needed
|
|
177
|
+
return if @nodes.size < MAX_NODES
|
|
178
|
+
|
|
179
|
+
remove_node(node_id: @nodes.values.min_by(&:activation).id)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def prune_connections_if_needed
|
|
183
|
+
return if @connections.size < MAX_CONNECTIONS
|
|
184
|
+
|
|
185
|
+
remove_connection(@connections.values.min_by(&:weight).id)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def prune_weak_connections
|
|
189
|
+
@connections.each { |id, c| remove_connection(id) if c.weight <= MIN_WEIGHT }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def remove_connection(conn_id)
|
|
193
|
+
return unless (conn = @connections.delete(conn_id))
|
|
194
|
+
|
|
195
|
+
@adjacency[conn.source_id]&.delete(conn_id)
|
|
196
|
+
@adjacency[conn.target_id]&.delete(conn_id)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module SemanticPriming
|
|
8
|
+
module Helpers
|
|
9
|
+
class SemanticNode
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :label, :node_type, :activation, :prime_count,
|
|
13
|
+
:access_count, :created_at
|
|
14
|
+
|
|
15
|
+
def initialize(label:, node_type: :concept, activation: DEFAULT_ACTIVATION)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@label = label.to_s
|
|
18
|
+
@node_type = node_type.to_sym
|
|
19
|
+
@activation = activation.to_f.clamp(0.0, MAX_ACTIVATION).round(10)
|
|
20
|
+
@prime_count = 0
|
|
21
|
+
@access_count = 0
|
|
22
|
+
@created_at = Time.now.utc
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def prime!(amount: PRIMING_BOOST)
|
|
26
|
+
@activation = (@activation + amount).clamp(0.0, MAX_ACTIVATION).round(10)
|
|
27
|
+
@prime_count += 1
|
|
28
|
+
self
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def decay!
|
|
32
|
+
@activation = (@activation - ACTIVATION_DECAY).clamp(0.0, MAX_ACTIVATION).round(10)
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def access!
|
|
37
|
+
@access_count += 1
|
|
38
|
+
self
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reset!
|
|
42
|
+
@activation = RESTING_ACTIVATION
|
|
43
|
+
self
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def primed?
|
|
47
|
+
@activation >= 0.4
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def active?
|
|
51
|
+
@activation > ACTIVATION_THRESHOLD
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def activation_label
|
|
55
|
+
match = ACTIVATION_LABELS.find { |range, _| range.cover?(@activation) }
|
|
56
|
+
match ? match.last : :unprimed
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_h
|
|
60
|
+
{
|
|
61
|
+
id: @id,
|
|
62
|
+
label: @label,
|
|
63
|
+
node_type: @node_type,
|
|
64
|
+
activation: @activation,
|
|
65
|
+
activation_label: activation_label,
|
|
66
|
+
primed: primed?,
|
|
67
|
+
active: active?,
|
|
68
|
+
prime_count: @prime_count,
|
|
69
|
+
access_count: @access_count,
|
|
70
|
+
created_at: @created_at
|
|
71
|
+
}
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module SemanticPriming
|
|
6
|
+
module Runners
|
|
7
|
+
module SemanticPriming
|
|
8
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
9
|
+
|
|
10
|
+
def add_node(label:, node_type: :concept, engine: nil, **)
|
|
11
|
+
eng = engine || default_engine
|
|
12
|
+
node = eng.add_node(label: label, node_type: node_type)
|
|
13
|
+
{ success: true, node: node.to_h }
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def remove_node(node_id:, engine: nil, **)
|
|
17
|
+
eng = engine || default_engine
|
|
18
|
+
node = eng.remove_node(node_id: node_id)
|
|
19
|
+
return { success: false, error: 'node not found' } unless node
|
|
20
|
+
|
|
21
|
+
{ success: true, removed: node.to_h }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def connect_nodes(source_id:, target_id:, weight: nil, engine: nil, **)
|
|
25
|
+
eng = engine || default_engine
|
|
26
|
+
w = weight || Helpers::Constants::DEFAULT_WEIGHT
|
|
27
|
+
conn = eng.connect(source_id: source_id, target_id: target_id, weight: w)
|
|
28
|
+
return { success: false, error: 'invalid nodes or self-connection' } unless conn
|
|
29
|
+
|
|
30
|
+
{ success: true, connection: conn.to_h }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def prime(node_id:, amount: nil, engine: nil, **)
|
|
34
|
+
eng = engine || default_engine
|
|
35
|
+
amt = amount || Helpers::Constants::PRIMING_BOOST
|
|
36
|
+
node = eng.prime_node(node_id: node_id, amount: amt)
|
|
37
|
+
return { success: false, error: 'node not found' } unless node
|
|
38
|
+
|
|
39
|
+
{ success: true, node: node.to_h }
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def prime_and_spread(node_id:, amount: nil, depth: nil, engine: nil, **)
|
|
43
|
+
eng = engine || default_engine
|
|
44
|
+
amt = amount || Helpers::Constants::PRIMING_BOOST
|
|
45
|
+
d = depth || Helpers::Constants::MAX_SPREAD_DEPTH
|
|
46
|
+
result = eng.prime_and_spread(node_id: node_id, amount: amt, depth: d)
|
|
47
|
+
return { success: false, error: 'node not found' } unless result
|
|
48
|
+
|
|
49
|
+
{ success: true, **result }
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def spread_activation(source_id:, depth: nil, engine: nil, **)
|
|
53
|
+
eng = engine || default_engine
|
|
54
|
+
d = depth || Helpers::Constants::MAX_SPREAD_DEPTH
|
|
55
|
+
result = eng.spread_activation(source_id: source_id, depth: d)
|
|
56
|
+
return { success: false, error: 'node not found' } unless result
|
|
57
|
+
|
|
58
|
+
{ success: true, activated: result }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def decay(engine: nil, **)
|
|
62
|
+
eng = engine || default_engine
|
|
63
|
+
result = eng.decay_all!
|
|
64
|
+
{ success: true, **result }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def reset(engine: nil, **)
|
|
68
|
+
eng = engine || default_engine
|
|
69
|
+
result = eng.reset_all!
|
|
70
|
+
{ success: true, **result }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def find_node(label:, engine: nil, **)
|
|
74
|
+
eng = engine || default_engine
|
|
75
|
+
node = eng.find_node_by_label(label: label)
|
|
76
|
+
return { success: false, error: 'node not found' } unless node
|
|
77
|
+
|
|
78
|
+
{ success: true, node: node.to_h }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def neighbors(node_id:, engine: nil, **)
|
|
82
|
+
eng = engine || default_engine
|
|
83
|
+
nodes = eng.neighbors(node_id: node_id)
|
|
84
|
+
{ success: true, neighbors: nodes.map(&:to_h) }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def primed_nodes(engine: nil, **)
|
|
88
|
+
eng = engine || default_engine
|
|
89
|
+
{ success: true, nodes: eng.primed_nodes.map(&:to_h) }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def most_primed(limit: 5, engine: nil, **)
|
|
93
|
+
eng = engine || default_engine
|
|
94
|
+
{ success: true, nodes: eng.most_primed(limit: limit).map(&:to_h) }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def priming_report(engine: nil, **)
|
|
98
|
+
eng = engine || default_engine
|
|
99
|
+
{ success: true, report: eng.priming_report }
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def status(engine: nil, **)
|
|
103
|
+
eng = engine || default_engine
|
|
104
|
+
{ success: true, **eng.to_h }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
private
|
|
108
|
+
|
|
109
|
+
def default_engine
|
|
110
|
+
@default_engine ||= Helpers::PrimingNetwork.new
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'semantic_priming/version'
|
|
4
|
+
require_relative 'semantic_priming/helpers/constants'
|
|
5
|
+
require_relative 'semantic_priming/helpers/semantic_node'
|
|
6
|
+
require_relative 'semantic_priming/helpers/connection'
|
|
7
|
+
require_relative 'semantic_priming/helpers/priming_network'
|
|
8
|
+
require_relative 'semantic_priming/runners/semantic_priming'
|
|
9
|
+
require_relative 'semantic_priming/client'
|
|
10
|
+
|
|
11
|
+
module Legion
|
|
12
|
+
module Extensions
|
|
13
|
+
module SemanticPriming
|
|
14
|
+
extend Legion::Extensions::Core if defined?(Legion::Extensions::Core)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-semantic-priming
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Esity
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: legion-gaia
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
description: Models spreading activation in semantic networks - priming one concept
|
|
27
|
+
activates related concepts with distance-based decay for rapid associative retrieval.
|
|
28
|
+
email:
|
|
29
|
+
- matthewdiverson@gmail.com
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- ".github/workflows/ci.yml"
|
|
35
|
+
- ".gitignore"
|
|
36
|
+
- ".rspec"
|
|
37
|
+
- ".rubocop.yml"
|
|
38
|
+
- CLAUDE.md
|
|
39
|
+
- Gemfile
|
|
40
|
+
- README.md
|
|
41
|
+
- lex-semantic-priming.gemspec
|
|
42
|
+
- lib/legion/extensions/semantic_priming.rb
|
|
43
|
+
- lib/legion/extensions/semantic_priming/client.rb
|
|
44
|
+
- lib/legion/extensions/semantic_priming/helpers/connection.rb
|
|
45
|
+
- lib/legion/extensions/semantic_priming/helpers/constants.rb
|
|
46
|
+
- lib/legion/extensions/semantic_priming/helpers/priming_network.rb
|
|
47
|
+
- lib/legion/extensions/semantic_priming/helpers/semantic_node.rb
|
|
48
|
+
- lib/legion/extensions/semantic_priming/runners/semantic_priming.rb
|
|
49
|
+
- lib/legion/extensions/semantic_priming/version.rb
|
|
50
|
+
homepage: https://github.com/LegionIO/lex-semantic-priming
|
|
51
|
+
licenses:
|
|
52
|
+
- MIT
|
|
53
|
+
metadata:
|
|
54
|
+
homepage_uri: https://github.com/LegionIO/lex-semantic-priming
|
|
55
|
+
source_code_uri: https://github.com/LegionIO/lex-semantic-priming
|
|
56
|
+
documentation_uri: https://github.com/LegionIO/lex-semantic-priming/blob/master/README.md
|
|
57
|
+
changelog_uri: https://github.com/LegionIO/lex-semantic-priming/blob/master/CHANGELOG.md
|
|
58
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-semantic-priming/issues
|
|
59
|
+
rubygems_mfa_required: 'true'
|
|
60
|
+
rdoc_options: []
|
|
61
|
+
require_paths:
|
|
62
|
+
- lib
|
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '3.4'
|
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
69
|
+
requirements:
|
|
70
|
+
- - ">="
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0'
|
|
73
|
+
requirements: []
|
|
74
|
+
rubygems_version: 3.6.9
|
|
75
|
+
specification_version: 4
|
|
76
|
+
summary: Semantic priming and spreading activation network for LegionIO
|
|
77
|
+
test_files: []
|