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.
Files changed (45) hide show
  1. mda_memory-0.1.1/LICENSE +67 -0
  2. mda_memory-0.1.1/PKG-INFO +22 -0
  3. mda_memory-0.1.1/README.md +195 -0
  4. mda_memory-0.1.1/mda/__init__.py +3 -0
  5. mda_memory-0.1.1/mda/core/__init__.py +0 -0
  6. mda_memory-0.1.1/mda/core/bind.py +39 -0
  7. mda_memory-0.1.1/mda/core/encoder.py +688 -0
  8. mda_memory-0.1.1/mda/core/entity.py +319 -0
  9. mda_memory-0.1.1/mda/core/neuron.py +83 -0
  10. mda_memory-0.1.1/mda/core/registry.py +157 -0
  11. mda_memory-0.1.1/mda/data/__init__.py +22 -0
  12. mda_memory-0.1.1/mda/data/stopwords.txt +733 -0
  13. mda_memory-0.1.1/mda/data/stopwords_content.txt +57 -0
  14. mda_memory-0.1.1/mda/inference/__init__.py +0 -0
  15. mda_memory-0.1.1/mda/inference/associative.py +190 -0
  16. mda_memory-0.1.1/mda/inference/broca.py +204 -0
  17. mda_memory-0.1.1/mda/inference/memory.py +119 -0
  18. mda_memory-0.1.1/mda/inference/reasoning.py +169 -0
  19. mda_memory-0.1.1/mda/inference/translator.py +218 -0
  20. mda_memory-0.1.1/mda/integrations/__init__.py +0 -0
  21. mda_memory-0.1.1/mda/integrations/cli.py +500 -0
  22. mda_memory-0.1.1/mda/integrations/engine.py +837 -0
  23. mda_memory-0.1.1/mda/integrations/loader.py +646 -0
  24. mda_memory-0.1.1/mda/mda.py +561 -0
  25. mda_memory-0.1.1/mda/training/__init__.py +0 -0
  26. mda_memory-0.1.1/mda/training/checkpoint.py +192 -0
  27. mda_memory-0.1.1/mda_memory.egg-info/PKG-INFO +22 -0
  28. mda_memory-0.1.1/mda_memory.egg-info/SOURCES.txt +43 -0
  29. mda_memory-0.1.1/mda_memory.egg-info/dependency_links.txt +1 -0
  30. mda_memory-0.1.1/mda_memory.egg-info/entry_points.txt +2 -0
  31. mda_memory-0.1.1/mda_memory.egg-info/requires.txt +15 -0
  32. mda_memory-0.1.1/mda_memory.egg-info/top_level.txt +1 -0
  33. mda_memory-0.1.1/pyproject.toml +36 -0
  34. mda_memory-0.1.1/setup.cfg +4 -0
  35. mda_memory-0.1.1/tests/test_associative.py +179 -0
  36. mda_memory-0.1.1/tests/test_bind.py +168 -0
  37. mda_memory-0.1.1/tests/test_broca.py +195 -0
  38. mda_memory-0.1.1/tests/test_encoder.py +93 -0
  39. mda_memory-0.1.1/tests/test_engine.py +310 -0
  40. mda_memory-0.1.1/tests/test_entity.py +301 -0
  41. mda_memory-0.1.1/tests/test_mda.py +236 -0
  42. mda_memory-0.1.1/tests/test_memory.py +206 -0
  43. mda_memory-0.1.1/tests/test_neuron.py +172 -0
  44. mda_memory-0.1.1/tests/test_reasoning.py +179 -0
  45. mda_memory-0.1.1/tests/test_registry.py +162 -0
@@ -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: SSPL](https://img.shields.io/badge/License-SSPL-blue.svg)](LICENSE)
6
+ [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](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
@@ -0,0 +1,3 @@
1
+ from mda.mda import MDA
2
+
3
+ __all__ = ["MDA"]
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))