mda-memory 0.1.1__tar.gz
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.
- mda_memory-0.1.1/LICENSE +67 -0
- mda_memory-0.1.1/PKG-INFO +22 -0
- mda_memory-0.1.1/README.md +195 -0
- mda_memory-0.1.1/mda/__init__.py +3 -0
- mda_memory-0.1.1/mda/core/__init__.py +0 -0
- mda_memory-0.1.1/mda/core/bind.py +39 -0
- mda_memory-0.1.1/mda/core/encoder.py +688 -0
- mda_memory-0.1.1/mda/core/entity.py +319 -0
- mda_memory-0.1.1/mda/core/neuron.py +83 -0
- mda_memory-0.1.1/mda/core/registry.py +157 -0
- mda_memory-0.1.1/mda/data/__init__.py +22 -0
- mda_memory-0.1.1/mda/data/stopwords.txt +733 -0
- mda_memory-0.1.1/mda/data/stopwords_content.txt +57 -0
- mda_memory-0.1.1/mda/inference/__init__.py +0 -0
- mda_memory-0.1.1/mda/inference/associative.py +190 -0
- mda_memory-0.1.1/mda/inference/broca.py +204 -0
- mda_memory-0.1.1/mda/inference/memory.py +119 -0
- mda_memory-0.1.1/mda/inference/reasoning.py +169 -0
- mda_memory-0.1.1/mda/inference/translator.py +218 -0
- mda_memory-0.1.1/mda/integrations/__init__.py +0 -0
- mda_memory-0.1.1/mda/integrations/cli.py +500 -0
- mda_memory-0.1.1/mda/integrations/engine.py +837 -0
- mda_memory-0.1.1/mda/integrations/loader.py +646 -0
- mda_memory-0.1.1/mda/mda.py +561 -0
- mda_memory-0.1.1/mda/training/__init__.py +0 -0
- mda_memory-0.1.1/mda/training/checkpoint.py +192 -0
- mda_memory-0.1.1/mda_memory.egg-info/PKG-INFO +22 -0
- mda_memory-0.1.1/mda_memory.egg-info/SOURCES.txt +43 -0
- mda_memory-0.1.1/mda_memory.egg-info/dependency_links.txt +1 -0
- mda_memory-0.1.1/mda_memory.egg-info/entry_points.txt +2 -0
- mda_memory-0.1.1/mda_memory.egg-info/requires.txt +15 -0
- mda_memory-0.1.1/mda_memory.egg-info/top_level.txt +1 -0
- mda_memory-0.1.1/pyproject.toml +36 -0
- mda_memory-0.1.1/setup.cfg +4 -0
- mda_memory-0.1.1/tests/test_associative.py +179 -0
- mda_memory-0.1.1/tests/test_bind.py +168 -0
- mda_memory-0.1.1/tests/test_broca.py +195 -0
- mda_memory-0.1.1/tests/test_encoder.py +93 -0
- mda_memory-0.1.1/tests/test_engine.py +310 -0
- mda_memory-0.1.1/tests/test_entity.py +301 -0
- mda_memory-0.1.1/tests/test_mda.py +236 -0
- mda_memory-0.1.1/tests/test_memory.py +206 -0
- mda_memory-0.1.1/tests/test_neuron.py +172 -0
- mda_memory-0.1.1/tests/test_reasoning.py +179 -0
- mda_memory-0.1.1/tests/test_registry.py +162 -0
mda_memory-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Server Side Public License
|
|
2
|
+
VERSION 1, OCTOBER 16, 2018
|
|
3
|
+
|
|
4
|
+
Copyright (C) 2026 Mert Polat <mert@kairfy.com>
|
|
5
|
+
|
|
6
|
+
Everyone is permitted to copy and distribute verbatim copies of this
|
|
7
|
+
license document, but changing it is not allowed.
|
|
8
|
+
|
|
9
|
+
PREAMBLE
|
|
10
|
+
|
|
11
|
+
The Server Side Public License (this document, or "SSPL") is based on the
|
|
12
|
+
GNU General Public License, version 3 ("GPL"). The goal of SSPL is to
|
|
13
|
+
ensure that companies that use and benefit from open source software
|
|
14
|
+
provide meaningful access to the source code of the tools they use to
|
|
15
|
+
provide their services.
|
|
16
|
+
|
|
17
|
+
If you modify the Program, or if you make it available over a network, you
|
|
18
|
+
must provide the source code of the entire program stack being used,
|
|
19
|
+
including the service source code.
|
|
20
|
+
|
|
21
|
+
TERMS AND CONDITIONS
|
|
22
|
+
|
|
23
|
+
0. Definitions.
|
|
24
|
+
|
|
25
|
+
"This License" refers to version 1 of the Server Side Public License.
|
|
26
|
+
|
|
27
|
+
"The Program" refers to any copyrightable work licensed under this License.
|
|
28
|
+
|
|
29
|
+
"You" refers to the licensee.
|
|
30
|
+
|
|
31
|
+
"Service" means making the functionality of the Program, or a modified
|
|
32
|
+
version thereof, available to third parties as a service.
|
|
33
|
+
|
|
34
|
+
1. Personal and Internal Use
|
|
35
|
+
|
|
36
|
+
You may use, copy, modify, and distribute this software for personal or
|
|
37
|
+
internal business purposes, free of charge, under the following conditions:
|
|
38
|
+
|
|
39
|
+
a) You do not make the software available as a service to third parties.
|
|
40
|
+
b) You retain all copyright and license notices.
|
|
41
|
+
|
|
42
|
+
2. Service Use
|
|
43
|
+
|
|
44
|
+
If you use this software or a modified version of it to provide a service
|
|
45
|
+
to third parties, you must make the complete corresponding source code of
|
|
46
|
+
the entire program stack — including all modules, services, and tooling
|
|
47
|
+
required to deploy and run the service — available under this License.
|
|
48
|
+
|
|
49
|
+
3. No Sublicensing
|
|
50
|
+
|
|
51
|
+
You may not sublicense the software under any other license. All copies
|
|
52
|
+
and derivative works must carry this License.
|
|
53
|
+
|
|
54
|
+
4. No Warranty
|
|
55
|
+
|
|
56
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
57
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
58
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
59
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
60
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
61
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
62
|
+
THE SOFTWARE.
|
|
63
|
+
|
|
64
|
+
5. Contact
|
|
65
|
+
|
|
66
|
+
For commercial licensing inquiries (cloud deployment, SaaS integration,
|
|
67
|
+
or enterprise use), contact: mert@kairfy.com
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: mda-memory
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Online associative memory for LLMs
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Requires-Dist: numpy
|
|
8
|
+
Requires-Dist: torch
|
|
9
|
+
Requires-Dist: rich
|
|
10
|
+
Requires-Dist: prompt_toolkit
|
|
11
|
+
Requires-Dist: python-dotenv
|
|
12
|
+
Requires-Dist: requests
|
|
13
|
+
Requires-Dist: anthropic
|
|
14
|
+
Requires-Dist: ollama
|
|
15
|
+
Requires-Dist: chromadb
|
|
16
|
+
Requires-Dist: sentence-transformers
|
|
17
|
+
Requires-Dist: tqdm
|
|
18
|
+
Requires-Dist: matplotlib
|
|
19
|
+
Requires-Dist: ijson
|
|
20
|
+
Requires-Dist: deep-translator
|
|
21
|
+
Requires-Dist: langdetect
|
|
22
|
+
Dynamic: license-file
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
# MDA — Modular Dynamic Architecture
|
|
2
|
+
|
|
3
|
+
**Online associative memory for LLMs. Learns during inference. No backpropagation. No GPU required.**
|
|
4
|
+
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
[](https://www.python.org/)
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## What is MDA?
|
|
11
|
+
|
|
12
|
+
Large language models can reason but cannot remember. RAG partially addresses this — but it cannot update during a conversation, and it cannot learn from the conversation itself.
|
|
13
|
+
|
|
14
|
+
MDA fills precisely these gaps.
|
|
15
|
+
|
|
16
|
+
It encodes knowledge as **256-dimensional Holographic Distributed Representations (HDRs)**, connects concepts through a **sparse synapse graph**, and retrieves context by activating entity networks — not by text-chunk similarity search. New knowledge is integrated immediately, without rebuilding any index.
|
|
17
|
+
|
|
18
|
+
**MDA is not a RAG replacement. It is the persistent learning layer that RAG and LLMs are missing.**
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Key Properties
|
|
23
|
+
|
|
24
|
+
- **Token-free** — no tokenizer, no vocabulary
|
|
25
|
+
- **Attention-free** — no transformer encoder required
|
|
26
|
+
- **Online learning** — learns during inference via the Oja rule
|
|
27
|
+
- **No catastrophic forgetting** — entities are independent; new knowledge never overwrites old
|
|
28
|
+
- **CPU-only** — runs entirely on numpy, no GPU required
|
|
29
|
+
- **Model-agnostic** — works with Ollama, OpenAI, Anthropic, or any LLM
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Benchmark Results
|
|
34
|
+
|
|
35
|
+
Evaluated against a strong RAG baseline (bge-large-en-v1.5 + ChromaDB, top-6 retrieval) across 80 questions spanning 8 cognitive categories:
|
|
36
|
+
|
|
37
|
+
| Category | RAG | MDA | Δ |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| ATOMIC_RECALL | 100% | 85% | −15% |
|
|
40
|
+
| MULTI_HOP | 90% | 90% | 0% |
|
|
41
|
+
| CROSS_DOCUMENT | 80% | 70% | −10% |
|
|
42
|
+
| REASONING | 70% | 90% | **+20%** |
|
|
43
|
+
| INCREMENTAL_LEARNING | 0% | 60% | **+60%** |
|
|
44
|
+
| NOISE_RESISTANCE | 100% | 100% | 0% |
|
|
45
|
+
| MEMORY_COMPRESSION | 90% | 70% | −20% |
|
|
46
|
+
| BOUNDARY | 100% | 100% | 0% |
|
|
47
|
+
| **OVERALL** | **78.8%** | **83.1%** | **+4.3%** |
|
|
48
|
+
|
|
49
|
+
MDA uses **3.1× less context per query** than RAG while achieving higher overall accuracy.
|
|
50
|
+
|
|
51
|
+
**Long-context retention (200 turns):** RAG 0% — MDA 92%.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Quick Start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/Rangle2/mda
|
|
59
|
+
cd mda
|
|
60
|
+
pip install -r requirements.txt
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> **Note:** `pip install mda-memory` coming in v0.2. Clone-based install is the supported method for now.
|
|
64
|
+
|
|
65
|
+
### Basic Usage
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from mda import MDA
|
|
69
|
+
|
|
70
|
+
memory = MDA()
|
|
71
|
+
|
|
72
|
+
# Teach facts
|
|
73
|
+
memory.learn("The capital of Veloria is Aranthos.")
|
|
74
|
+
memory.learn("Aranthos was founded by Queen Seraphel in 412 AE.")
|
|
75
|
+
|
|
76
|
+
# Retrieve context — returns memory string ready for LLM injection
|
|
77
|
+
context = memory.context_for("Who founded the capital?")
|
|
78
|
+
print(context)
|
|
79
|
+
# → [MEMORY] Aranthos was founded by Queen Seraphel in 412 AE.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### With Ollama
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# Start Ollama with any model
|
|
86
|
+
ollama pull qwen3:4b
|
|
87
|
+
|
|
88
|
+
# Run MDA CLI
|
|
89
|
+
python -m integrations.cli --model qwen3:4b
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### With Anthropic (Claude)
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Set your API key
|
|
96
|
+
export ANTHROPIC_API_KEY=your_key_here
|
|
97
|
+
|
|
98
|
+
# Run MDA CLI with Claude
|
|
99
|
+
python -m integrations.cli --model claude-haiku-4-5-20251001 --provider anthropic
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Running Benchmarks
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
# Main benchmark — Ollama
|
|
106
|
+
python benchmark/benchmark.py --model qwen3:4b
|
|
107
|
+
|
|
108
|
+
# Main benchmark — Anthropic
|
|
109
|
+
python benchmark/benchmark.py --model claude-haiku-4-5-20251001 --provider anthropic
|
|
110
|
+
|
|
111
|
+
# Long-context retention benchmark — Ollama
|
|
112
|
+
python benchmark/long_context_benchmark.py --model qwen3:4b
|
|
113
|
+
|
|
114
|
+
# Long-context retention benchmark — Anthropic
|
|
115
|
+
python benchmark/long_context_benchmark.py --model claude-haiku-4-5-20251001 --provider anthropic
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Project Structure
|
|
121
|
+
|
|
122
|
+
```
|
|
123
|
+
mda/
|
|
124
|
+
├── mda.py # Public API — MDA class
|
|
125
|
+
├── core/
|
|
126
|
+
│ ├── bind.py # HDR ops: bind, unbind, normalize, cosine
|
|
127
|
+
│ ├── encoder.py # HolisticEncoder: text → 256-dim vector
|
|
128
|
+
│ ├── entity.py # Entity: v, r, h, W, neurons, synapses, senses
|
|
129
|
+
│ ├── neuron.py # Neuron (Oja rule), Synapse (Hebbian)
|
|
130
|
+
│ └── registry.py # EntityRegistry: surface → Entity lookup
|
|
131
|
+
├── inference/
|
|
132
|
+
│ ├── associative.py # AssociativeChain: multi-hop traversal
|
|
133
|
+
│ ├── broca.py # BrocaModule: W-hybrid context scoring
|
|
134
|
+
│ ├── reasoning.py # ReasoningEngine: cross-entity inference
|
|
135
|
+
│ └── memory.py # ConversationMemory: multi-turn context
|
|
136
|
+
├── training/
|
|
137
|
+
│ └── checkpoint.py # save/load: float32, atomic write
|
|
138
|
+
├── integrations/
|
|
139
|
+
│ ├── engine.py # MDAEngine: LLM bridge (Ollama / Anthropic)
|
|
140
|
+
│ └── cli.py # Interactive CLI (Rich + prompt_toolkit)
|
|
141
|
+
├── benchmark/
|
|
142
|
+
│ ├── benchmark.py # 80-question main benchmark
|
|
143
|
+
│ └── long_context_benchmark.py # 200-turn retention benchmark
|
|
144
|
+
└── tests/ # pytest test suite
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## How It Works
|
|
150
|
+
|
|
151
|
+
### Entity & W Matrix
|
|
152
|
+
Every concept is an `Entity` with a 256-dim identity vector `v` and a lazy-initialized Hebbian weight matrix `W`. `W` is `None` until the entity is first activated — memory overhead is proportional to usage.
|
|
153
|
+
|
|
154
|
+
### Online Learning (Oja Rule)
|
|
155
|
+
```
|
|
156
|
+
ΔW = η(yxᵀ − y²W)
|
|
157
|
+
```
|
|
158
|
+
where `x` is the query vector and `y = Wx`. No backpropagation. No gradient descent. Runs in O(d²) per entity per turn.
|
|
159
|
+
|
|
160
|
+
### AssociativeChain
|
|
161
|
+
Query → origin entity → breadth-first synapse traversal (depth 3) → context assembly. Dynamic inhibition prevents context flooding.
|
|
162
|
+
|
|
163
|
+
### BrocaModule
|
|
164
|
+
Facts are scored with a W-hybrid formula:
|
|
165
|
+
```
|
|
166
|
+
score = 0.35·s_query + 0.45·s_W + 0.20·s_sense
|
|
167
|
+
```
|
|
168
|
+
Facts below 0.20 are suppressed.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Running Tests
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
pytest tests/
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Roadmap
|
|
181
|
+
|
|
182
|
+
- [ ] **GPU acceleration** — PyTorch tensor ops, parallel entity traversal
|
|
183
|
+
- [ ] **Low-rank W** — W ≈ A×B factorization for higher-dimensional HDRs
|
|
184
|
+
- [ ] **`mda.cloud` API** — persistent memory as a service
|
|
185
|
+
- [ ] **MDA + RAG hybrid** — offline corpus retrieval + online conversational learning
|
|
186
|
+
- [ ] **Real-world corpus evaluation** — beyond fictional benchmark domains
|
|
187
|
+
- [ ] **Independent benchmark** — community-constructed evaluation set
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
[SSPL 1.0](LICENSE) — free for research and personal use. Commercial use requires a separate agreement.
|
|
194
|
+
|
|
195
|
+
For commercial licensing: mert@kairfy.com
|
|
File without changes
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
DIM = 256
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def normalize(v: np.ndarray) -> np.ndarray:
|
|
7
|
+
n = np.linalg.norm(v)
|
|
8
|
+
return v / (n + 1e-8)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def random_vector(dim: int = DIM, seed: int = None) -> np.ndarray:
|
|
12
|
+
rng = np.random.default_rng(seed)
|
|
13
|
+
return normalize(rng.normal(0, 1, dim))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def zero_vector(dim: int = DIM) -> np.ndarray:
|
|
17
|
+
return np.zeros(dim)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def bind(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
21
|
+
return np.real(np.fft.ifft(np.fft.fft(a) * np.fft.fft(b)))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def unbind(compound: np.ndarray, b: np.ndarray) -> np.ndarray:
|
|
25
|
+
F_b = np.fft.fft(b)
|
|
26
|
+
F_b_inv = np.conj(F_b) / (np.abs(F_b) ** 2 + 1e-6)
|
|
27
|
+
b_inv = np.real(np.fft.ifft(F_b_inv))
|
|
28
|
+
return np.real(np.fft.ifft(np.fft.fft(compound) * np.fft.fft(b_inv)))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def bind_many(*vectors: np.ndarray) -> np.ndarray:
|
|
32
|
+
result = vectors[0].copy()
|
|
33
|
+
for v in vectors[1:]:
|
|
34
|
+
result = bind(result, v)
|
|
35
|
+
return result
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def cosine(a: np.ndarray, b: np.ndarray) -> float:
|
|
39
|
+
return float(np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-8))
|