quantum-memory-graph 1.1.1__tar.gz → 1.2.0__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 (52) hide show
  1. quantum_memory_graph-1.2.0/PKG-INFO +234 -0
  2. quantum_memory_graph-1.2.0/README.md +203 -0
  3. quantum_memory_graph-1.2.0/benchmarks/data_collector.py +209 -0
  4. quantum_memory_graph-1.2.0/benchmarks/fast_longmemeval.py +199 -0
  5. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench.py +0 -2
  6. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v2.py +0 -1
  7. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v3.py +0 -1
  8. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v4.py +0 -2
  9. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v5.py +0 -1
  10. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v6.py +0 -2
  11. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/longmemeval_bench_v7.py +0 -2
  12. quantum_memory_graph-1.2.0/benchmarks/run_longmemeval_chunked_staged.py +336 -0
  13. quantum_memory_graph-1.2.0/pyproject.toml +3 -0
  14. quantum_memory_graph-1.2.0/quantum_memory_graph/__init__.py +21 -0
  15. quantum_memory_graph-1.2.0/quantum_memory_graph/api.py +201 -0
  16. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph/graph.py +34 -46
  17. quantum_memory_graph-1.2.0/quantum_memory_graph/pce_optimizer.py +466 -0
  18. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph/pipeline.py +27 -12
  19. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph/subgraph_optimizer.py +62 -66
  20. quantum_memory_graph-1.2.0/quantum_memory_graph.egg-info/PKG-INFO +234 -0
  21. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph.egg-info/SOURCES.txt +5 -11
  22. quantum_memory_graph-1.2.0/quantum_memory_graph.egg-info/requires.txt +17 -0
  23. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/setup.cfg +3 -3
  24. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/tests/test_full_pipeline.py +0 -1
  25. quantum_memory_graph-1.1.1/PKG-INFO +0 -328
  26. quantum_memory_graph-1.1.1/README.md +0 -296
  27. quantum_memory_graph-1.1.1/benchmarks/dedup_benchmark.py +0 -183
  28. quantum_memory_graph-1.1.1/pyproject.toml +0 -29
  29. quantum_memory_graph-1.1.1/quantum_memory_graph/__init__.py +0 -44
  30. quantum_memory_graph-1.1.1/quantum_memory_graph/api.py +0 -328
  31. quantum_memory_graph-1.1.1/quantum_memory_graph/dedup.py +0 -196
  32. quantum_memory_graph-1.1.1/quantum_memory_graph/obsidian.py +0 -315
  33. quantum_memory_graph-1.1.1/quantum_memory_graph/sharing.py +0 -250
  34. quantum_memory_graph-1.1.1/quantum_memory_graph/tiers.py +0 -320
  35. quantum_memory_graph-1.1.1/quantum_memory_graph.egg-info/PKG-INFO +0 -328
  36. quantum_memory_graph-1.1.1/quantum_memory_graph.egg-info/entry_points.txt +0 -2
  37. quantum_memory_graph-1.1.1/quantum_memory_graph.egg-info/requires.txt +0 -22
  38. quantum_memory_graph-1.1.1/tests/test_dedup.py +0 -122
  39. quantum_memory_graph-1.1.1/tests/test_recency.py +0 -211
  40. quantum_memory_graph-1.1.1/tests/test_sharing.py +0 -118
  41. quantum_memory_graph-1.1.1/tests/test_tiers.py +0 -163
  42. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/LICENSE +0 -0
  43. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/__init__.py +0 -0
  44. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/generate_scenarios.py +0 -0
  45. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/memcombine.py +0 -0
  46. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/run_final.py +0 -0
  47. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/run_full_benchmark.py +0 -0
  48. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/benchmarks/run_full_benchmark_v2.py +0 -0
  49. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph/__main__.py +0 -0
  50. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph/recency.py +0 -0
  51. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph.egg-info/dependency_links.txt +0 -0
  52. {quantum_memory_graph-1.1.1 → quantum_memory_graph-1.2.0}/quantum_memory_graph.egg-info/top_level.txt +0 -0
@@ -0,0 +1,234 @@
1
+ Metadata-Version: 2.4
2
+ Name: quantum-memory-graph
3
+ Version: 1.2.0
4
+ Summary: Quantum-optimized knowledge graph memory for AI agents. Relationship-aware subgraph selection via QAOA.
5
+ Home-page: https://github.com/Dustin-a11y/quantum-memory-graph
6
+ Author: Coinkong (Chef's Attraction)
7
+ License: MIT
8
+ Keywords: quantum,memory,knowledge-graph,agents,qaoa,ai
9
+ Classifier: Development Status :: 4 - Beta
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: License :: OSI Approved :: MIT License
12
+ Classifier: Programming Language :: Python :: 3
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: quantum-agent-memory>=0.1.0
17
+ Requires-Dist: sentence-transformers>=2.2.0
18
+ Requires-Dist: networkx>=3.0
19
+ Requires-Dist: numpy>=1.24.0
20
+ Requires-Dist: qiskit>=1.0.0
21
+ Requires-Dist: qiskit-aer>=0.13.0
22
+ Provides-Extra: api
23
+ Requires-Dist: fastapi>=0.100.0; extra == "api"
24
+ Requires-Dist: uvicorn>=0.20.0; extra == "api"
25
+ Provides-Extra: ibm
26
+ Requires-Dist: qiskit-ibm-runtime>=0.20.0; extra == "ibm"
27
+ Provides-Extra: dev
28
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
29
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
30
+ Dynamic: license-file
31
+
32
+ # Quantum Memory Graph ⚛️🧠
33
+
34
+ **Relationship-aware memory for AI agents. Knowledge graphs + quantum-optimized subgraph selection.**
35
+
36
+ Every memory system treats memories as independent documents — search, rank, stuff into context. But memories aren't independent. They have *relationships*. "The team chose React" becomes 10x more useful paired with "because of ecosystem maturity" and "FastAPI handles the backend."
37
+
38
+ Quantum Memory Graph maps these relationships, then uses QAOA to find the optimal *combination* of memories — not just the most relevant individuals, but the best connected subgraph that gives your agent maximum context.
39
+
40
+ ## Benchmark: MemCombine
41
+
42
+ We created MemCombine to test what no existing benchmark measures — **memory combination quality**.
43
+
44
+ | Method | Coverage | Evidence Recall | F1 | Perfect |
45
+ |--------|----------|----------------|----|---------|
46
+ | Embedding Top-K | 69.9% | 65.6% | 68.1% | 1/5 |
47
+ | **Graph + QAOA** | **96.7%** | **91.0%** | **92.6%** | **4/5** |
48
+ | **Advantage** | **+26.8%** | **+25.4%** | **+24.5%** | |
49
+
50
+ When the task is "find memories that work *together*," graph-aware quantum selection crushes pure similarity search.
51
+ ## 🏆 #1 on LongMemEval (ICLR 2025 Benchmark)
52
+
53
+ Tested on the official [LongMemEval benchmark](https://arxiv.org/abs/2410.10813) for long-term memory in AI agents:
54
+
55
+ | Method | R@1 | R@5 | R@10 | NDCG@10 |
56
+ |--------|:---:|:---:|:----:|:-------:|
57
+ | OMEGA (prev SOTA) | — | 89.2% | 94.1% | 87.5% |
58
+ | Mastra OM | — | 91.0% | 95.2% | 89.1% |
59
+ | **QMG v1.1 (published #1)** | — | **95.8%** | **98.85%** | **93.2%** |
60
+ | **QMG v1.2 (official, this repo)** 🏆 | **90.6%** | **98.6%** | **99.4%** | **0.9426** |
61
+
62
+ **Benchmark run:** 500 questions, chunked gte-large embeddings (500-char blocks, 100-char overlap, mean-of-top-3 session scoring). Verified on DGX Spark GB10 (CUDA, ~53 min).
63
+
64
+ **Chunking technique:** Each session split into overlapping 500-char chunks → gte-large embedding → per-session score = mean of top-3 chunk scores → rank by score. This recovers the v7 methodology that achieved our original #1, now verified with a clean reproducible pipeline.
65
+
66
+ **See:** `benchmarks/run_longmemeval_chunked_staged.py` for the exact benchmark code, `benchmarks/longmemeval_chunked_staged_results.json` for full per-question results.
67
+
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install quantum-memory-graph
73
+ ```
74
+
75
+ ## Quick Start
76
+
77
+ ```python
78
+ from quantum_memory_graph import store, recall
79
+
80
+ # Store memories — automatically builds knowledge graph
81
+ store("Project Alpha uses React frontend with TypeScript.")
82
+ store("Project Alpha backend is FastAPI with PostgreSQL.")
83
+ store("FastAPI connects to PostgreSQL via SQLAlchemy ORM.")
84
+ store("React components use Material UI for styling.")
85
+ store("Team had pizza for lunch. Pepperoni was great.")
86
+
87
+ # Recall — graph traversal + QAOA finds the optimal combination
88
+ result = recall("What is Project Alpha's full tech stack?", K=4)
89
+
90
+ for memory in result["memories"]:
91
+ print(f" {memory['text']}")
92
+ print(f" Connected to {len(memory['connections'])} other selected memories")
93
+ ```
94
+
95
+ Output: Returns React, FastAPI, PostgreSQL, and SQLAlchemy memories — connected, complete, no noise. The pizza memory is excluded because it has no graph connections to the tech stack cluster.
96
+
97
+ ## How It Works
98
+
99
+ ```
100
+ Query: "What's the tech stack?"
101
+
102
+
103
+ ┌─────────────────────┐
104
+ │ 1. Graph Search │ Embedding similarity + multi-hop traversal
105
+ │ Find neighbors │ Discovers memories connected to relevant ones
106
+ └────────┬────────────┘
107
+ │ 14 candidates
108
+
109
+ ┌─────────────────────┐
110
+ │ 2. Subgraph Data │ Extract adjacency matrix + relevance scores
111
+ │ Build problem │ Encode relationships as optimization weights
112
+ └────────┬────────────┘
113
+ │ NP-hard selection
114
+
115
+ ┌─────────────────────┐
116
+ │ 3. QAOA Optimize │ Quantum approximate optimization
117
+ │ Find best K │ Maximizes: relevance + connectivity + coverage
118
+ └────────┬────────────┘
119
+ │ K memories
120
+
121
+ ┌─────────────────────┐
122
+ │ 4. Return with │ Each memory includes its connections
123
+ │ relationships │ to other selected memories
124
+ └─────────────────────┘
125
+ ```
126
+
127
+ ### Why Quantum?
128
+
129
+ Optimal subgraph selection is NP-hard. Given N candidate memories, finding the best K that maximize relevance, connectivity, AND coverage has exponential classical complexity. QAOA provides polynomial-time approximate solutions that beat greedy heuristics — this is the one problem where quantum computing has a genuine algorithmic advantage over classical approaches.
130
+
131
+ ## Architecture
132
+
133
+ ### Three Layers
134
+
135
+ 1. **Knowledge Graph** (`graph.py`) — Memories are nodes. Relationships are weighted edges based on:
136
+ - Semantic similarity (embedding cosine distance)
137
+ - Entity co-occurrence (shared people, projects, concepts)
138
+ - Temporal proximity (memories close in time)
139
+ - Source proximity (same conversation/document)
140
+
141
+ 2. **Subgraph Optimizer** (`subgraph_optimizer.py`) — QAOA circuit that maximizes:
142
+ - α × relevance (individual memory scores)
143
+ - β × connectivity (edge weights within selected subgraph)
144
+ - γ × coverage (topic diversity across selection)
145
+
146
+ 3. **Pipeline** (`pipeline.py`) — Unified `store()` and `recall()` interface.
147
+
148
+ ```
149
+
150
+ ## API Server
151
+
152
+ ```bash
153
+ pip install quantum-memory-graph[api]
154
+ python -m quantum_memory_graph.api
155
+ ```
156
+
157
+ Endpoints:
158
+ - `POST /store` — Store a memory
159
+ - `POST /recall` — Graph + QAOA recall
160
+ - `POST /store-batch` — Batch store
161
+ - `GET /stats` — Graph statistics
162
+ - `GET /` — Health check
163
+
164
+ ## Advanced Usage
165
+
166
+ ### Custom Graph
167
+
168
+ ```python
169
+ from quantum_memory_graph import MemoryGraph, recall
170
+ from quantum_memory_graph.pipeline import set_graph
171
+
172
+ # Tune similarity threshold for edge creation
173
+ graph = MemoryGraph(similarity_threshold=0.25)
174
+ set_graph(graph)
175
+
176
+ # Store and recall as normal
177
+ ```
178
+
179
+ ### Tune QAOA Parameters
180
+
181
+ ```python
182
+ result = recall(
183
+ "query",
184
+ K=5,
185
+ alpha=0.4, # Relevance weight
186
+ beta_conn=0.35, # Connectivity weight
187
+ gamma_cov=0.25, # Coverage/diversity weight
188
+ hops=3, # Graph traversal depth
189
+ top_seeds=7, # Initial seed nodes
190
+ max_candidates=14, # Max qubits for QAOA
191
+ )
192
+ ```
193
+
194
+ ### Run MemCombine Benchmark
195
+
196
+ ```python
197
+ from benchmarks.memcombine import run_benchmark
198
+
199
+ def my_recall(memories, query, K):
200
+ # Your recall implementation
201
+ return selected_indices # List[int]
202
+
203
+ results = run_benchmark(my_recall, K=5)
204
+ print(f"Coverage: {results['avg_coverage']*100:.1f}%")
205
+ ```
206
+
207
+ ## IBM Quantum Hardware
208
+
209
+ For production workloads, run QAOA on real quantum hardware:
210
+
211
+ ```bash
212
+ pip install quantum-memory-graph[ibm]
213
+ export IBM_QUANTUM_TOKEN=your_token
214
+ ```
215
+
216
+ Validated on `ibm_fez` and `ibm_kingston` backends.
217
+
218
+ ## Requirements
219
+
220
+ - Python ≥ 3.9
221
+ - sentence-transformers
222
+ - networkx
223
+ - qiskit + qiskit-aer
224
+ - numpy
225
+
226
+ ## License
227
+
228
+ MIT License — Copyright 2026 Coinkong (Chef's Attraction)
229
+
230
+
231
+ ## Links
232
+
233
+ - [quantum-agent-memory](https://github.com/Dustin-a11y/quantum-agent-memory) — The QAOA optimization engine
234
+ - [MemCombine Benchmark](benchmarks/memcombine.py) — Test memory combination quality
@@ -0,0 +1,203 @@
1
+ # Quantum Memory Graph ⚛️🧠
2
+
3
+ **Relationship-aware memory for AI agents. Knowledge graphs + quantum-optimized subgraph selection.**
4
+
5
+ Every memory system treats memories as independent documents — search, rank, stuff into context. But memories aren't independent. They have *relationships*. "The team chose React" becomes 10x more useful paired with "because of ecosystem maturity" and "FastAPI handles the backend."
6
+
7
+ Quantum Memory Graph maps these relationships, then uses QAOA to find the optimal *combination* of memories — not just the most relevant individuals, but the best connected subgraph that gives your agent maximum context.
8
+
9
+ ## Benchmark: MemCombine
10
+
11
+ We created MemCombine to test what no existing benchmark measures — **memory combination quality**.
12
+
13
+ | Method | Coverage | Evidence Recall | F1 | Perfect |
14
+ |--------|----------|----------------|----|---------|
15
+ | Embedding Top-K | 69.9% | 65.6% | 68.1% | 1/5 |
16
+ | **Graph + QAOA** | **96.7%** | **91.0%** | **92.6%** | **4/5** |
17
+ | **Advantage** | **+26.8%** | **+25.4%** | **+24.5%** | |
18
+
19
+ When the task is "find memories that work *together*," graph-aware quantum selection crushes pure similarity search.
20
+ ## 🏆 #1 on LongMemEval (ICLR 2025 Benchmark)
21
+
22
+ Tested on the official [LongMemEval benchmark](https://arxiv.org/abs/2410.10813) for long-term memory in AI agents:
23
+
24
+ | Method | R@1 | R@5 | R@10 | NDCG@10 |
25
+ |--------|:---:|:---:|:----:|:-------:|
26
+ | OMEGA (prev SOTA) | — | 89.2% | 94.1% | 87.5% |
27
+ | Mastra OM | — | 91.0% | 95.2% | 89.1% |
28
+ | **QMG v1.1 (published #1)** | — | **95.8%** | **98.85%** | **93.2%** |
29
+ | **QMG v1.2 (official, this repo)** 🏆 | **90.6%** | **98.6%** | **99.4%** | **0.9426** |
30
+
31
+ **Benchmark run:** 500 questions, chunked gte-large embeddings (500-char blocks, 100-char overlap, mean-of-top-3 session scoring). Verified on DGX Spark GB10 (CUDA, ~53 min).
32
+
33
+ **Chunking technique:** Each session split into overlapping 500-char chunks → gte-large embedding → per-session score = mean of top-3 chunk scores → rank by score. This recovers the v7 methodology that achieved our original #1, now verified with a clean reproducible pipeline.
34
+
35
+ **See:** `benchmarks/run_longmemeval_chunked_staged.py` for the exact benchmark code, `benchmarks/longmemeval_chunked_staged_results.json` for full per-question results.
36
+
37
+
38
+ ## Install
39
+
40
+ ```bash
41
+ pip install quantum-memory-graph
42
+ ```
43
+
44
+ ## Quick Start
45
+
46
+ ```python
47
+ from quantum_memory_graph import store, recall
48
+
49
+ # Store memories — automatically builds knowledge graph
50
+ store("Project Alpha uses React frontend with TypeScript.")
51
+ store("Project Alpha backend is FastAPI with PostgreSQL.")
52
+ store("FastAPI connects to PostgreSQL via SQLAlchemy ORM.")
53
+ store("React components use Material UI for styling.")
54
+ store("Team had pizza for lunch. Pepperoni was great.")
55
+
56
+ # Recall — graph traversal + QAOA finds the optimal combination
57
+ result = recall("What is Project Alpha's full tech stack?", K=4)
58
+
59
+ for memory in result["memories"]:
60
+ print(f" {memory['text']}")
61
+ print(f" Connected to {len(memory['connections'])} other selected memories")
62
+ ```
63
+
64
+ Output: Returns React, FastAPI, PostgreSQL, and SQLAlchemy memories — connected, complete, no noise. The pizza memory is excluded because it has no graph connections to the tech stack cluster.
65
+
66
+ ## How It Works
67
+
68
+ ```
69
+ Query: "What's the tech stack?"
70
+
71
+
72
+ ┌─────────────────────┐
73
+ │ 1. Graph Search │ Embedding similarity + multi-hop traversal
74
+ │ Find neighbors │ Discovers memories connected to relevant ones
75
+ └────────┬────────────┘
76
+ │ 14 candidates
77
+
78
+ ┌─────────────────────┐
79
+ │ 2. Subgraph Data │ Extract adjacency matrix + relevance scores
80
+ │ Build problem │ Encode relationships as optimization weights
81
+ └────────┬────────────┘
82
+ │ NP-hard selection
83
+
84
+ ┌─────────────────────┐
85
+ │ 3. QAOA Optimize │ Quantum approximate optimization
86
+ │ Find best K │ Maximizes: relevance + connectivity + coverage
87
+ └────────┬────────────┘
88
+ │ K memories
89
+
90
+ ┌─────────────────────┐
91
+ │ 4. Return with │ Each memory includes its connections
92
+ │ relationships │ to other selected memories
93
+ └─────────────────────┘
94
+ ```
95
+
96
+ ### Why Quantum?
97
+
98
+ Optimal subgraph selection is NP-hard. Given N candidate memories, finding the best K that maximize relevance, connectivity, AND coverage has exponential classical complexity. QAOA provides polynomial-time approximate solutions that beat greedy heuristics — this is the one problem where quantum computing has a genuine algorithmic advantage over classical approaches.
99
+
100
+ ## Architecture
101
+
102
+ ### Three Layers
103
+
104
+ 1. **Knowledge Graph** (`graph.py`) — Memories are nodes. Relationships are weighted edges based on:
105
+ - Semantic similarity (embedding cosine distance)
106
+ - Entity co-occurrence (shared people, projects, concepts)
107
+ - Temporal proximity (memories close in time)
108
+ - Source proximity (same conversation/document)
109
+
110
+ 2. **Subgraph Optimizer** (`subgraph_optimizer.py`) — QAOA circuit that maximizes:
111
+ - α × relevance (individual memory scores)
112
+ - β × connectivity (edge weights within selected subgraph)
113
+ - γ × coverage (topic diversity across selection)
114
+
115
+ 3. **Pipeline** (`pipeline.py`) — Unified `store()` and `recall()` interface.
116
+
117
+ ```
118
+
119
+ ## API Server
120
+
121
+ ```bash
122
+ pip install quantum-memory-graph[api]
123
+ python -m quantum_memory_graph.api
124
+ ```
125
+
126
+ Endpoints:
127
+ - `POST /store` — Store a memory
128
+ - `POST /recall` — Graph + QAOA recall
129
+ - `POST /store-batch` — Batch store
130
+ - `GET /stats` — Graph statistics
131
+ - `GET /` — Health check
132
+
133
+ ## Advanced Usage
134
+
135
+ ### Custom Graph
136
+
137
+ ```python
138
+ from quantum_memory_graph import MemoryGraph, recall
139
+ from quantum_memory_graph.pipeline import set_graph
140
+
141
+ # Tune similarity threshold for edge creation
142
+ graph = MemoryGraph(similarity_threshold=0.25)
143
+ set_graph(graph)
144
+
145
+ # Store and recall as normal
146
+ ```
147
+
148
+ ### Tune QAOA Parameters
149
+
150
+ ```python
151
+ result = recall(
152
+ "query",
153
+ K=5,
154
+ alpha=0.4, # Relevance weight
155
+ beta_conn=0.35, # Connectivity weight
156
+ gamma_cov=0.25, # Coverage/diversity weight
157
+ hops=3, # Graph traversal depth
158
+ top_seeds=7, # Initial seed nodes
159
+ max_candidates=14, # Max qubits for QAOA
160
+ )
161
+ ```
162
+
163
+ ### Run MemCombine Benchmark
164
+
165
+ ```python
166
+ from benchmarks.memcombine import run_benchmark
167
+
168
+ def my_recall(memories, query, K):
169
+ # Your recall implementation
170
+ return selected_indices # List[int]
171
+
172
+ results = run_benchmark(my_recall, K=5)
173
+ print(f"Coverage: {results['avg_coverage']*100:.1f}%")
174
+ ```
175
+
176
+ ## IBM Quantum Hardware
177
+
178
+ For production workloads, run QAOA on real quantum hardware:
179
+
180
+ ```bash
181
+ pip install quantum-memory-graph[ibm]
182
+ export IBM_QUANTUM_TOKEN=your_token
183
+ ```
184
+
185
+ Validated on `ibm_fez` and `ibm_kingston` backends.
186
+
187
+ ## Requirements
188
+
189
+ - Python ≥ 3.9
190
+ - sentence-transformers
191
+ - networkx
192
+ - qiskit + qiskit-aer
193
+ - numpy
194
+
195
+ ## License
196
+
197
+ MIT License — Copyright 2026 Coinkong (Chef's Attraction)
198
+
199
+
200
+ ## Links
201
+
202
+ - [quantum-agent-memory](https://github.com/Dustin-a11y/quantum-agent-memory) — The QAOA optimization engine
203
+ - [MemCombine Benchmark](benchmarks/memcombine.py) — Test memory combination quality
@@ -0,0 +1,209 @@
1
+ """
2
+ QMG Benchmark Data Collector.
3
+
4
+ Logs every benchmark run with full metadata for study and analysis.
5
+ Data is append-only, timestamped, and structured for easy analysis.
6
+
7
+ DK 🦍
8
+
9
+ Usage:
10
+ from benchmarks.data_collector import QMGBenchmarkLogger
11
+
12
+ logger = QMGBenchmarkLogger()
13
+ logger.log_memcombine_run(method, results, params)
14
+ logger.log_qaoa_run(n_candidates, n_qubits, selection_result, timing)
15
+ logger.export_csv() # Export all data for study
16
+ """
17
+
18
+ import json
19
+ import os
20
+ import time
21
+ from datetime import datetime
22
+ from typing import Dict, List, Optional
23
+ from pathlib import Path
24
+
25
+
26
+ BENCHMARK_LOG_DIR = Path(os.environ.get(
27
+ "QMG_BENCHMARK_LOG",
28
+ "/home/dt/.hermes/profiles/dk/quantum-tracker/benchmarks"
29
+ ))
30
+
31
+
32
+ class QMGBenchmarkLogger:
33
+ """Append-only benchmark data logger."""
34
+
35
+ def __init__(self, log_dir: str = None):
36
+ self.log_dir = Path(log_dir) if log_dir else BENCHMARK_LOG_DIR
37
+ self.log_dir.mkdir(parents=True, exist_ok=True)
38
+ self._session_id = f"session_{datetime.now().strftime('%Y%m%d_%H%M%S')}"
39
+
40
+ def log_memcombine_run(self, method: str, results: Dict, params: Dict = None):
41
+ """Log a MemCombine benchmark run."""
42
+ entry = {
43
+ "type": "memcombine_run",
44
+ "session_id": self._session_id,
45
+ "timestamp": datetime.now().isoformat(),
46
+ "unix_time": time.time(),
47
+ "method": method,
48
+ "results": {
49
+ "coverage": results.get("avg_coverage", results.get("coverage")),
50
+ "evidence_recall": results.get("avg_evidence_recall", results.get("evidence_recall")),
51
+ "f1": results.get("avg_f1", results.get("f1")),
52
+ "perfect": results.get("perfect_coverage", results.get("perfect")),
53
+ "perfect_pct": results.get("perfect_coverage_pct", results.get("perfect_pct")),
54
+ "n_scenarios": results.get("n_scenarios", len(results.get("per_scenario", []))),
55
+ },
56
+ "params": params or {},
57
+ "per_scenario": results.get("per_scenario", []),
58
+ }
59
+ self._write("memcombine", entry)
60
+ return entry
61
+
62
+ def log_longmemeval_run(self, method: str, results: Dict, model: str = None, params: Dict = None):
63
+ """Log a LongMemEval benchmark run."""
64
+ entry = {
65
+ "type": "longmemeval_run",
66
+ "session_id": self._session_id,
67
+ "timestamp": datetime.now().isoformat(),
68
+ "unix_time": time.time(),
69
+ "model": model or "unknown",
70
+ "method": method,
71
+ "results": {
72
+ "recall_at_5": results.get("recall_at_5"),
73
+ "recall_at_10": results.get("recall_at_10"),
74
+ "ndcg_at_10": results.get("ndcg_at_10"),
75
+ "n": results.get("n"),
76
+ },
77
+ "params": params or {},
78
+ }
79
+ self._write("longmemeval", entry)
80
+ return entry
81
+
82
+ def log_qaoa_run(self,
83
+ n_candidates: int,
84
+ n_qubits: int,
85
+ K: int,
86
+ p_layers: int,
87
+ method: str,
88
+ selection_result: Dict,
89
+ timing_ms: float,
90
+ params: Dict = None):
91
+ """Log a single QAOA optimization run."""
92
+ entry = {
93
+ "type": "qaoa_run",
94
+ "session_id": self._session_id,
95
+ "timestamp": datetime.now().isoformat(),
96
+ "unix_time": time.time(),
97
+ "n_candidates": n_candidates,
98
+ "n_qubits": n_qubits,
99
+ "K": K,
100
+ "p_layers": p_layers,
101
+ "method": method,
102
+ "compression_ratio": selection_result.get("compression_ratio", f"{n_candidates}→{n_qubits}"),
103
+ "qaoa_score": selection_result.get("score"),
104
+ "qaoa_vs_greedy_pct": selection_result.get("qaoa_vs_greedy_pct"),
105
+ "qaoa_vs_optimal_pct": selection_result.get("qaoa_vs_optimal_pct"),
106
+ "timing_ms": timing_ms,
107
+ "params": params or {},
108
+ }
109
+ self._write("qaoa", entry)
110
+ return entry
111
+
112
+ def log_graph_stats(self, graph_stats: Dict, tag: str = ""):
113
+ """Log memory graph statistics."""
114
+ entry = {
115
+ "type": "graph_stats",
116
+ "session_id": self._session_id,
117
+ "timestamp": datetime.now().isoformat(),
118
+ "unix_time": time.time(),
119
+ "tag": tag,
120
+ "nodes": graph_stats.get("nodes"),
121
+ "edges": graph_stats.get("edges"),
122
+ "density": graph_stats.get("density"),
123
+ "components": graph_stats.get("components"),
124
+ "avg_degree": graph_stats.get("avg_degree"),
125
+ }
126
+ self._write("graph", entry)
127
+ return entry
128
+
129
+ def log_hardware_run(self, backend: str, n_qubits: int, result: Dict, timing_ms: float):
130
+ """Log a hardware execution run (IBM Quantum)."""
131
+ entry = {
132
+ "type": "hardware_run",
133
+ "session_id": self._session_id,
134
+ "timestamp": datetime.now().isoformat(),
135
+ "unix_time": time.time(),
136
+ "backend": backend,
137
+ "n_qubits": n_qubits,
138
+ "result": {
139
+ "score": result.get("score"),
140
+ "method": result.get("method"),
141
+ "error_mitigation": result.get("error_mitigation", "none"),
142
+ },
143
+ "timing_ms": timing_ms,
144
+ }
145
+ self._write("hardware", entry)
146
+ return entry
147
+
148
+ def _write(self, category: str, entry: Dict):
149
+ """Append entry to category log file."""
150
+ log_file = self.log_dir / f"{category}_log.jsonl"
151
+ with open(log_file, "a") as f:
152
+ f.write(json.dumps(entry) + "\n")
153
+
154
+ def export_csv(self, category: str = None) -> str:
155
+ """
156
+ Export logged data as CSV for analysis.
157
+ Returns path to CSV file.
158
+ """
159
+ import csv
160
+ from collections import OrderedDict
161
+
162
+ categories = [category] if category else ["memcombine", "longmemeval", "qaoa", "graph", "hardware"]
163
+ output_paths = []
164
+
165
+ for cat in categories:
166
+ log_file = self.log_dir / f"{cat}_log.jsonl"
167
+ if not log_file.exists():
168
+ continue
169
+
170
+ csv_path = self.log_dir / f"{cat}_export.csv"
171
+ entries = []
172
+ with open(log_file) as f:
173
+ for line in f:
174
+ line = line.strip()
175
+ if line:
176
+ entries.append(json.loads(line))
177
+
178
+ if not entries:
179
+ continue
180
+
181
+ # Gather all keys
182
+ all_keys = []
183
+ for e in entries:
184
+ for k in e.keys():
185
+ if k not in all_keys:
186
+ all_keys.append(k)
187
+
188
+ with open(csv_path, "w", newline="") as f:
189
+ writer = csv.DictWriter(f, fieldnames=all_keys, extrasaction="ignore")
190
+ writer.writeheader()
191
+ for e in entries:
192
+ writer.writerow(e)
193
+
194
+ output_paths.append(str(csv_path))
195
+
196
+ return ", ".join(output_paths) if output_paths else "No data logged yet"
197
+
198
+ def summary(self) -> Dict:
199
+ """Quick summary of all logged data."""
200
+ result = {}
201
+ for cat in ["memcombine", "longmemeval", "qaoa", "graph", "hardware"]:
202
+ log_file = self.log_dir / f"{cat}_log.jsonl"
203
+ if log_file.exists():
204
+ with open(log_file) as f:
205
+ lines = [l for l in f if l.strip()]
206
+ result[cat] = len(lines)
207
+ else:
208
+ result[cat] = 0
209
+ return result