knowlytix-knowledge 0.0.1__py3-none-any.whl
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.
- knowlytix/knowledge/DESIGN.md +818 -0
- knowlytix/knowledge/LICENSE +200 -0
- knowlytix/knowledge/__init__.py +40 -0
- knowlytix/knowledge/__main__.py +7 -0
- knowlytix/knowledge/cli.py +410 -0
- knowlytix/knowledge/compare.py +297 -0
- knowlytix/knowledge/config.py +227 -0
- knowlytix/knowledge/convert.py +426 -0
- knowlytix/knowledge/extract.py +244 -0
- knowlytix/knowledge/fixtures/__init__.py +5 -0
- knowlytix/knowledge/fixtures/smoke/__init__.py +2 -0
- knowlytix/knowledge/fixtures/smoke/sample.md +57 -0
- knowlytix/knowledge/ingest.py +265 -0
- knowlytix/knowledge/learn.py +679 -0
- knowlytix/knowledge/llm_backend.py +185 -0
- knowlytix/knowledge/mcp_server.py +610 -0
- knowlytix/knowledge/query.py +778 -0
- knowlytix/knowledge/store.py +531 -0
- knowlytix/knowledge/verify.py +244 -0
- knowlytix/knowledge/web_agent.py +394 -0
- knowlytix_knowledge-0.0.1.dist-info/METADATA +163 -0
- knowlytix_knowledge-0.0.1.dist-info/RECORD +23 -0
- knowlytix_knowledge-0.0.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
# DocGMS: Geometric Expert System with LLM-Augmented Learning
|
|
2
|
+
|
|
3
|
+
## 1. Vision
|
|
4
|
+
|
|
5
|
+
DocGMS is a **persistent geometric expert system** that combines:
|
|
6
|
+
- **GMS** (Geometric Memory Systems) as the structured knowledge back-end: exact recall, contradiction detection, consistency checking, relational reasoning
|
|
7
|
+
- **LLM** (Claude or local models) as the reasoning/language front-end: open-ended reasoning, natural language understanding, zero-shot generalization
|
|
8
|
+
|
|
9
|
+
The system ingests documents, builds a geometric knowledge store on the hypersphere, answers queries with geometric confidence, and **grows smarter over time** by learning verified knowledge from LLM interactions.
|
|
10
|
+
|
|
11
|
+
**Key principle:** The LLM proposes. GMS verifies. Verified knowledge grows GMS. GMS gets smarter.
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## 2. Architecture
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
┌──────────────────────────────┐
|
|
19
|
+
│ LLM (Claude) │
|
|
20
|
+
│ - Open-ended reasoning │
|
|
21
|
+
│ - NLU / ambiguous questions │
|
|
22
|
+
│ - Zero-shot generalization │
|
|
23
|
+
└──────────┬───────────────────┘
|
|
24
|
+
│ answer text
|
|
25
|
+
▼
|
|
26
|
+
┌──────────────────────────────┐
|
|
27
|
+
│ Triple Extraction (LLM) │
|
|
28
|
+
│ answer → (h, r, t) triples │
|
|
29
|
+
│ + numeric values │
|
|
30
|
+
└──────────┬───────────────────┘
|
|
31
|
+
│ extracted triples
|
|
32
|
+
▼
|
|
33
|
+
┌────────────────────────────────────────┐
|
|
34
|
+
│ GMS Verification Layer │
|
|
35
|
+
│ │
|
|
36
|
+
│ 1. score_triple(h, r, t) │
|
|
37
|
+
│ → geodesic distance on S^{m-1} │
|
|
38
|
+
│ → lower = more plausible │
|
|
39
|
+
│ │
|
|
40
|
+
│ 2. tension_energy(a, b) │
|
|
41
|
+
│ → Clifford algebra: E = 2sin(θ/2) │
|
|
42
|
+
│ → 0=agree, √2=irrelevant, 2=contra │
|
|
43
|
+
│ │
|
|
44
|
+
│ 3. path_holonomy(path, direct) │
|
|
45
|
+
│ → ‖R_path R_direct^{-1} - I‖_F │
|
|
46
|
+
│ → 0=consistent, high=inconsistent │
|
|
47
|
+
└──────┬─────────────────┬───────────────┘
|
|
48
|
+
│ │
|
|
49
|
+
contradicts? consistent?
|
|
50
|
+
│ │
|
|
51
|
+
▼ ▼
|
|
52
|
+
┌──────────┐ ┌────────────────────┐
|
|
53
|
+
│ REJECT │ │ LEARN (grow GMS) │
|
|
54
|
+
│ + report │ │ 1. Expand embeddings│
|
|
55
|
+
│ why │ │ 2. Sentence-xformer │
|
|
56
|
+
└──────────┘ │ init │
|
|
57
|
+
│ 3. Freeze existing │
|
|
58
|
+
│ 4. Riemannian GD on │
|
|
59
|
+
│ new embeddings │
|
|
60
|
+
│ 5. ENM write for │
|
|
61
|
+
│ numeric facts │
|
|
62
|
+
│ 6. Post-verify │
|
|
63
|
+
└────────────────────┘
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 2.1 The Query Loop
|
|
67
|
+
|
|
68
|
+
Every query follows this flow:
|
|
69
|
+
|
|
70
|
+
1. **GMS first**: Attempt structured answer via ENM lookup, triple scoring, phase check, or relational transport. If confident answer found, return immediately.
|
|
71
|
+
|
|
72
|
+
2. **LLM augmented**: If GMS cannot answer (open-ended, ambiguous, or novel domain), query the LLM with GMS context prepended for grounding:
|
|
73
|
+
- Relevant triples from the store
|
|
74
|
+
- Exact numeric values from ENM
|
|
75
|
+
- Phase-encoded threshold results
|
|
76
|
+
- Known contradictions and tensions
|
|
77
|
+
|
|
78
|
+
3. **Extract**: Decompose LLM answer into (head, relation, tail) triples + numeric values.
|
|
79
|
+
|
|
80
|
+
4. **Verify**: Score each extracted triple against GMS:
|
|
81
|
+
- `score_triple()`: geodesic distance — is this fact plausible given the manifold?
|
|
82
|
+
- `tension_energy()`: does this contradict existing entities?
|
|
83
|
+
- `path_holonomy()`: is this consistent with existing relational paths?
|
|
84
|
+
|
|
85
|
+
5. **Learn or Reject**:
|
|
86
|
+
- If verified (no contradictions, consistent paths) and contains novel facts:
|
|
87
|
+
- Expand GMS embedding tables for new entities
|
|
88
|
+
- Initialize via sentence-transformers
|
|
89
|
+
- Freeze existing embeddings
|
|
90
|
+
- Riemannian gradient descent on new embeddings only
|
|
91
|
+
- Write numeric values to ENM
|
|
92
|
+
- The store grows — future queries benefit
|
|
93
|
+
- If contradictions detected:
|
|
94
|
+
- Reject the write
|
|
95
|
+
- Report which facts contradicted and why (tension energy values, holonomy defects)
|
|
96
|
+
|
|
97
|
+
6. **Return**: Answer with full provenance — source, confidence, verification report, whether new facts were learned.
|
|
98
|
+
|
|
99
|
+
### 2.2 GMS vs LLM: Complementary Strengths
|
|
100
|
+
|
|
101
|
+
| Capability | GMS Handles | LLM Handles |
|
|
102
|
+
|---|---|---|
|
|
103
|
+
| Exact numeric recall | ENM register (100%, lossless, SHA-256) | - |
|
|
104
|
+
| Contradiction detection | Tension energy E(a,b) in u-space | - |
|
|
105
|
+
| Path consistency | Holonomy defect via rotor composition | - |
|
|
106
|
+
| Threshold/inequality | Phase encoding on S^1 | - |
|
|
107
|
+
| Multi-hop reasoning | Cayley rotor transport: R_L...R_1 @ v_h | - |
|
|
108
|
+
| Link prediction | score_all_tails(): geodesic ranking | - |
|
|
109
|
+
| Open-ended reasoning | - | Natural language generation |
|
|
110
|
+
| Ambiguous questions | - | NLU + intent classification |
|
|
111
|
+
| Novel domains (zero-shot) | - | Generalization from pretraining |
|
|
112
|
+
| Explanation generation | - | Articulate reasoning in text |
|
|
113
|
+
| Answer verification | Scores + checks LLM outputs | - |
|
|
114
|
+
| Knowledge growth | Riemannian GD on verified facts | Proposes new facts for verification |
|
|
115
|
+
|
|
116
|
+
### 2.3 Why GMS + LLM Beats LLM Alone
|
|
117
|
+
|
|
118
|
+
1. **Exact Numerical Recall**: GMS 100% vs LLM ~2%. ENM stores IEEE 754 float64 with SHA-256 integrity.
|
|
119
|
+
|
|
120
|
+
2. **Contradiction Detection**: Tension energy (Clifford algebra) is a continuous geometric signal, not pattern matching. F1 = 0.71 vs 0.57 in paper experiments.
|
|
121
|
+
|
|
122
|
+
3. **Every LLM Answer is Audited**: Extracted triples are scored on the manifold. The system quantifies how plausible each claim is and flags contradictions — the LLM never gets the final word unverified.
|
|
123
|
+
|
|
124
|
+
4. **Persistent Memory**: The store persists to disk and grows over sessions. An LLM's context window is ephemeral.
|
|
125
|
+
|
|
126
|
+
5. **Integrity Protection**: Contradiction gates prevent bad knowledge from entering the store. RAG has no such mechanism.
|
|
127
|
+
|
|
128
|
+
6. **Speed**: Structured queries answered in <1ms (manifold ops) vs ~2s (API call).
|
|
129
|
+
|
|
130
|
+
7. **The Store Gets Smarter**: Every verified interaction that introduces novel, consistent facts expands the manifold. Link prediction improves, contradiction detection refines, multi-hop paths become richer.
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
## 3. File Structure
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
docgms/
|
|
138
|
+
__init__.py # Package + public API exports
|
|
139
|
+
__main__.py # Entry: python -m docgms
|
|
140
|
+
cli.py # CLI: ingest, query, compare, status
|
|
141
|
+
config.py # Configuration dataclasses
|
|
142
|
+
convert.py # PDF/TeX/MD -> markdown conversion
|
|
143
|
+
llm_backend.py # Unified LLM interface (Anthropic + local)
|
|
144
|
+
store.py # GMSExpertStore: persistent geometric knowledge store
|
|
145
|
+
ingest.py # Document ingestion into store
|
|
146
|
+
extract.py # LLM answer -> triple extraction + GMS scoring
|
|
147
|
+
verify.py # Contradiction (tension) + consistency (holonomy)
|
|
148
|
+
learn.py # Runtime memory growth via Riemannian GD
|
|
149
|
+
query.py # Query engine: the full GMS + LLM + verify + learn loop
|
|
150
|
+
compare.py # GMS+LLM vs LLM-only evaluation
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4. Module Specifications
|
|
156
|
+
|
|
157
|
+
### 4.1 `config.py` — Configuration
|
|
158
|
+
|
|
159
|
+
```python
|
|
160
|
+
@dataclass
|
|
161
|
+
class ConvertConfig:
|
|
162
|
+
llm_model: str = "claude-sonnet-4-20250514"
|
|
163
|
+
llm_backend: str = "anthropic" # "anthropic" or "local"
|
|
164
|
+
local_model_name: str = ""
|
|
165
|
+
max_pages: int = 200
|
|
166
|
+
|
|
167
|
+
@dataclass
|
|
168
|
+
class VerifyConfig:
|
|
169
|
+
tau_contra: float = 1.7 # tension energy contradiction threshold
|
|
170
|
+
tau_ent: float = 0.8 # entailment threshold
|
|
171
|
+
tau_path: float = 0.5 # holonomy consistency threshold
|
|
172
|
+
holonomy_alpha: float = 0.1 # decay for effective holonomy
|
|
173
|
+
min_plausibility: float = 1.0 # max geodesic dist for plausible triple
|
|
174
|
+
|
|
175
|
+
@dataclass
|
|
176
|
+
class LearnConfig:
|
|
177
|
+
n_steps: int = 50 # Riemannian GD steps for new entities
|
|
178
|
+
lr_write: float = 5e-3
|
|
179
|
+
freeze_existing: bool = True
|
|
180
|
+
contradiction_gate: bool = True # reject writes that introduce contradictions
|
|
181
|
+
auto_learn: bool = True # auto-write verified novel facts from Q&A
|
|
182
|
+
|
|
183
|
+
@dataclass
|
|
184
|
+
class DocGMSConfig:
|
|
185
|
+
convert: ConvertConfig
|
|
186
|
+
geometry: GeometryConfig # from knowlytix.core.config (d_v=128, d_u=128, m=64)
|
|
187
|
+
loss: LossConfig # from knowlytix.core.config
|
|
188
|
+
train: TrainConfig # from knowlytix.core.config
|
|
189
|
+
memory: MemoryConfig # from knowlytix.core.config
|
|
190
|
+
verify: VerifyConfig
|
|
191
|
+
learn: LearnConfig
|
|
192
|
+
store_path: str = "docgms_store/" # persistent store directory
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Imports from: `knowlytix.core.config.GeometryConfig`, `LossConfig`, `TrainConfig`, `MemoryConfig`
|
|
196
|
+
|
|
197
|
+
### 4.2 `llm_backend.py` — LLM Interface
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
class LLMBackend(ABC):
|
|
201
|
+
def call(self, system: str, user: str, max_tokens: int = 2048) -> str: ...
|
|
202
|
+
|
|
203
|
+
class AnthropicBackend(LLMBackend):
|
|
204
|
+
"""Anthropic API. Pattern from knowlytix/benchmark/llm_caller.py."""
|
|
205
|
+
def __init__(self, model: str = "claude-sonnet-4-20250514"): ...
|
|
206
|
+
|
|
207
|
+
class LocalTransformersBackend(LLMBackend):
|
|
208
|
+
"""HuggingFace model on GPU via transformers."""
|
|
209
|
+
def __init__(self, model_name: str, device: str = "cuda"): ...
|
|
210
|
+
|
|
211
|
+
def create_backend(config: ConvertConfig) -> LLMBackend: ...
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 4.3 `convert.py` — Document Conversion
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
def detect_format(path: str) -> str:
|
|
218
|
+
"""Returns 'pdf', 'tex', 'md', 'txt', 'docx'."""
|
|
219
|
+
|
|
220
|
+
def convert_pdf_to_markdown(path: str, config: ConvertConfig, llm_fn: Callable) -> str:
|
|
221
|
+
"""PyMuPDF for text extraction. LLM for complex table reconstruction."""
|
|
222
|
+
|
|
223
|
+
def convert_tex_to_markdown(path: str, config: ConvertConfig, llm_fn: Callable) -> str:
|
|
224
|
+
"""pandoc subprocess for structure. Post-process LaTeX remnants.
|
|
225
|
+
LLM fallback for tabular environments."""
|
|
226
|
+
|
|
227
|
+
def convert_document(path: str, config: ConvertConfig, llm_fn: Callable) -> str:
|
|
228
|
+
"""Top-level dispatcher. .md files read directly."""
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Dependencies: `pymupdf`, system `pandoc`
|
|
232
|
+
|
|
233
|
+
### 4.4 `store.py` — GMSExpertStore (the core)
|
|
234
|
+
|
|
235
|
+
```python
|
|
236
|
+
class GMSExpertStore:
|
|
237
|
+
"""Persistent geometric expert system store.
|
|
238
|
+
|
|
239
|
+
Manages: trained GKG model, ENM register, compression memory,
|
|
240
|
+
transport layer, adapter mappings. Supports ingestion of new
|
|
241
|
+
documents and runtime growth from verified Q&A.
|
|
242
|
+
|
|
243
|
+
Disk layout (store_path/):
|
|
244
|
+
model.pt — GKG weights
|
|
245
|
+
enm.json — ENM key-value pairs
|
|
246
|
+
adapter.json — entity/relation vocabularies
|
|
247
|
+
metadata.json — ingestion history, stats
|
|
248
|
+
documents/ — ingested markdown copies
|
|
249
|
+
"""
|
|
250
|
+
|
|
251
|
+
def __init__(self, config: DocGMSConfig, device: torch.device): ...
|
|
252
|
+
|
|
253
|
+
# --- Core state ---
|
|
254
|
+
model: GeometricKnowledgeGraph
|
|
255
|
+
adapter: GraphToGMS
|
|
256
|
+
enm: ExactNumericalMemory
|
|
257
|
+
doc_graph: DocumentGraph
|
|
258
|
+
transport: RelationalTransport
|
|
259
|
+
compression: CompressionMemory
|
|
260
|
+
router: MemoryRouter
|
|
261
|
+
|
|
262
|
+
# --- Persistence ---
|
|
263
|
+
def save(self): ...
|
|
264
|
+
def load(self) -> bool: ...
|
|
265
|
+
def exists(self) -> bool: ...
|
|
266
|
+
|
|
267
|
+
# --- GMS Operations (thin wrappers around model/transport/enm) ---
|
|
268
|
+
def score_triple(self, head: str, rel: str, tail: str) -> float:
|
|
269
|
+
"""Geodesic distance on S^{m-1}. Lower = more plausible."""
|
|
270
|
+
|
|
271
|
+
def tension_energy(self, entity_a: str, entity_b: str) -> float:
|
|
272
|
+
"""Clifford tension energy. 0=agree, sqrt(2)=irrelevant, 2=contradict.
|
|
273
|
+
Uses: knowlytix.core.graph.gkg.tension_energy_pairs() -> knowlytix.core.geometry.clifford.tension_energy()"""
|
|
274
|
+
|
|
275
|
+
def check_holonomy(self, relation_path: list[str], direct_relation: str) -> float:
|
|
276
|
+
"""Holonomy defect. Uses: transport.path_holonomy()"""
|
|
277
|
+
|
|
278
|
+
def is_path_consistent(self, relation_path: list[str], direct: str) -> bool:
|
|
279
|
+
"""True if holonomy defect <= tau_path. Uses: transport.is_path_consistent()"""
|
|
280
|
+
|
|
281
|
+
def lookup_enm(self, category: str, entity_id: str) -> float | None:
|
|
282
|
+
"""Exact numeric lookup with SHA-256 integrity."""
|
|
283
|
+
|
|
284
|
+
def link_predict(self, head: str, relation: str, top_k: int = 10) -> list[tuple[str, float]]:
|
|
285
|
+
"""Top-k tail predictions using model.score_all_tails()."""
|
|
286
|
+
|
|
287
|
+
def query_triples(self, head=None, relation=None, tail=None) -> list[tuple]:
|
|
288
|
+
"""Pattern match on doc_graph.triples."""
|
|
289
|
+
|
|
290
|
+
def find_contradictions(self) -> list[tuple]:
|
|
291
|
+
"""doc_graph.find_contradictions()."""
|
|
292
|
+
|
|
293
|
+
def stats(self) -> dict:
|
|
294
|
+
"""entities, relations, triples, enm_entries, documents ingested."""
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
Imports:
|
|
298
|
+
- `knowlytix.core.graph.gkg.GeometricKnowledgeGraph`
|
|
299
|
+
- `knowlytix.core.graph.transport.RelationalTransport`
|
|
300
|
+
- `knowlytix.core.memory.enm.ExactNumericalMemory`, `ENMKey`
|
|
301
|
+
- `knowlytix.core.memory.compression.CompressionMemory`
|
|
302
|
+
- `knowlytix.core.memory.router.MemoryRouter`
|
|
303
|
+
- `knowlytix.core.train_finstructbench.GraphToGMS`
|
|
304
|
+
- `knowlytix.benchmark.graph.DocumentGraph`
|
|
305
|
+
|
|
306
|
+
### 4.5 `ingest.py` — Document Ingestion
|
|
307
|
+
|
|
308
|
+
```python
|
|
309
|
+
def ingest_document(store: GMSExpertStore, document_path: str,
|
|
310
|
+
llm_backend: LLMBackend, config: DocGMSConfig,
|
|
311
|
+
device: torch.device) -> IngestResult:
|
|
312
|
+
"""Ingest a document into the expert store.
|
|
313
|
+
|
|
314
|
+
First document: full pipeline
|
|
315
|
+
1. convert_document(path) -> markdown
|
|
316
|
+
2. ingest_markdown(path) -> DocumentGraph [knowlytix.benchmark.ingest]
|
|
317
|
+
3. GraphToGMS(doc_graph) -> adapter [knowlytix.core.train_finstructbench]
|
|
318
|
+
4. train_gms(adapter, device) -> model [knowlytix.core.train_finstructbench]
|
|
319
|
+
5. populate_enm(doc_graph, adapter) -> enm [knowlytix.core.train_finstructbench]
|
|
320
|
+
6. Create transport, compression, router
|
|
321
|
+
7. Save store
|
|
322
|
+
|
|
323
|
+
Subsequent documents: incremental growth
|
|
324
|
+
1. convert_document(path) -> markdown
|
|
325
|
+
2. ingest_markdown(path) -> new DocumentGraph
|
|
326
|
+
3. Identify new entities and triples not in store
|
|
327
|
+
4. learn.expand_and_optimize(new_triples, store) [learn.py]
|
|
328
|
+
5. Add new ENM entries
|
|
329
|
+
6. Merge doc_graph triples into store.doc_graph
|
|
330
|
+
7. Save store
|
|
331
|
+
|
|
332
|
+
Returns IngestResult(new_entities, new_triples, new_enm, stats).
|
|
333
|
+
"""
|
|
334
|
+
|
|
335
|
+
def ingest_markdown_text(store, markdown_text, config, device) -> IngestResult:
|
|
336
|
+
"""Ingest raw markdown string (for programmatic use)."""
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### 4.6 `extract.py` — Triple Extraction + GMS Scoring
|
|
340
|
+
|
|
341
|
+
```python
|
|
342
|
+
@dataclass
|
|
343
|
+
class ExtractedTriple:
|
|
344
|
+
head: str
|
|
345
|
+
relation: str
|
|
346
|
+
tail: str
|
|
347
|
+
numeric_value: float | None = None # if triple contains a number
|
|
348
|
+
|
|
349
|
+
@dataclass
|
|
350
|
+
class ScoredTriple:
|
|
351
|
+
triple: ExtractedTriple
|
|
352
|
+
gms_score: float # geodesic distance (lower = better)
|
|
353
|
+
head_match: str | None # nearest entity in store, or None
|
|
354
|
+
tail_match: str | None
|
|
355
|
+
is_novel: bool # True if entity not in store
|
|
356
|
+
|
|
357
|
+
@dataclass
|
|
358
|
+
class PlausibilityReport:
|
|
359
|
+
plausible: bool
|
|
360
|
+
mean_score: float
|
|
361
|
+
worst_score: float
|
|
362
|
+
novel_count: int
|
|
363
|
+
scored_triples: list[ScoredTriple]
|
|
364
|
+
|
|
365
|
+
def extract_triples(answer_text: str, question: str,
|
|
366
|
+
llm_backend: LLMBackend) -> list[ExtractedTriple]:
|
|
367
|
+
"""Prompt LLM to decompose answer into structured triples.
|
|
368
|
+
|
|
369
|
+
Prompt template:
|
|
370
|
+
Given this question and answer, extract all factual claims as
|
|
371
|
+
(subject, relationship, object) triples. For numeric facts,
|
|
372
|
+
include the exact value. Format: one triple per line as
|
|
373
|
+
TRIPLE: subject | relationship | object [| numeric_value]
|
|
374
|
+
"""
|
|
375
|
+
|
|
376
|
+
def score_triples(triples: list[ExtractedTriple],
|
|
377
|
+
store: GMSExpertStore,
|
|
378
|
+
device: torch.device) -> list[ScoredTriple]:
|
|
379
|
+
"""Score each triple against GMS manifold.
|
|
380
|
+
|
|
381
|
+
For each triple:
|
|
382
|
+
1. Fuzzy-match head/tail to nearest entity in store.adapter vocab
|
|
383
|
+
(normalized string matching + optional semantic matching via
|
|
384
|
+
encode_texts + cosine similarity against store embeddings)
|
|
385
|
+
2. If matched: store.score_triple(h, r, t) -> geodesic distance
|
|
386
|
+
3. If not matched: mark is_novel=True (candidate for learning)
|
|
387
|
+
4. For numeric values: cross-check against ENM if entity exists
|
|
388
|
+
"""
|
|
389
|
+
|
|
390
|
+
def assess_plausibility(scored: list[ScoredTriple],
|
|
391
|
+
threshold: float = 1.0) -> PlausibilityReport:
|
|
392
|
+
"""Aggregate triple scores into overall plausibility verdict."""
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### 4.7 `verify.py` — Contradiction + Consistency Checking
|
|
396
|
+
|
|
397
|
+
```python
|
|
398
|
+
@dataclass
|
|
399
|
+
class ContradictionResult:
|
|
400
|
+
entity_a: str
|
|
401
|
+
entity_b: str
|
|
402
|
+
tension_energy: float # 0=agree, sqrt(2)=irrelevant, 2=contradict
|
|
403
|
+
is_contradiction: bool # E > tau_contra
|
|
404
|
+
is_entailment: bool # E < tau_ent
|
|
405
|
+
|
|
406
|
+
@dataclass
|
|
407
|
+
class HolonomyResult:
|
|
408
|
+
path: list[str] # relation path [r1, r2, ...]
|
|
409
|
+
direct: str # direct relation
|
|
410
|
+
defect: float # holonomy defect value
|
|
411
|
+
is_consistent: bool # defect <= tau_path
|
|
412
|
+
|
|
413
|
+
@dataclass
|
|
414
|
+
class VerificationReport:
|
|
415
|
+
contradictions: list[ContradictionResult]
|
|
416
|
+
inconsistencies: list[HolonomyResult]
|
|
417
|
+
overall_consistent: bool
|
|
418
|
+
confidence: float # 1.0=fully verified, 0.0=many issues
|
|
419
|
+
|
|
420
|
+
def check_contradictions(entity_pairs: list[tuple[str, str]],
|
|
421
|
+
store: GMSExpertStore,
|
|
422
|
+
config: VerifyConfig) -> list[ContradictionResult]:
|
|
423
|
+
"""Tension energy check for each entity pair.
|
|
424
|
+
|
|
425
|
+
Uses store.tension_energy(a, b) which calls:
|
|
426
|
+
knowlytix.core.graph.gkg.tension_energy_pairs(idx_a, idx_b)
|
|
427
|
+
-> knowlytix.core.geometry.clifford.tension_energy(u_a, u_b)
|
|
428
|
+
-> E = 2 * sin(theta/2)
|
|
429
|
+
"""
|
|
430
|
+
|
|
431
|
+
def check_holonomy(triples: list[ExtractedTriple],
|
|
432
|
+
store: GMSExpertStore,
|
|
433
|
+
config: VerifyConfig) -> list[HolonomyResult]:
|
|
434
|
+
"""Find relation triangles formed by new triples + existing graph.
|
|
435
|
+
|
|
436
|
+
For each new triple (h, r_new, t):
|
|
437
|
+
- Find existing paths from h to t through intermediate entities
|
|
438
|
+
- Compute path_holonomy(existing_path, r_new)
|
|
439
|
+
- Flag if defect > tau_path
|
|
440
|
+
|
|
441
|
+
Uses store.check_holonomy() which calls:
|
|
442
|
+
transport.path_holonomy(relation_path, direct_relation)
|
|
443
|
+
-> compose_rotors(path) @ R_direct^{-1} - I -> Frobenius norm
|
|
444
|
+
-> effective_holonomy(raw_defect, path_length, alpha)
|
|
445
|
+
"""
|
|
446
|
+
|
|
447
|
+
def verify_answer(scored_triples: list[ScoredTriple],
|
|
448
|
+
store: GMSExpertStore,
|
|
449
|
+
config: VerifyConfig) -> VerificationReport:
|
|
450
|
+
"""Combined verification: contradictions + holonomy + confidence.
|
|
451
|
+
|
|
452
|
+
1. For all pairs of (new entity, existing entity): check_contradictions
|
|
453
|
+
2. For all new triples forming paths: check_holonomy
|
|
454
|
+
3. Compute confidence: 1.0 - (n_contradictions + n_inconsistencies) / n_triples
|
|
455
|
+
"""
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### 4.8 `learn.py` — Runtime Memory Growth
|
|
459
|
+
|
|
460
|
+
```python
|
|
461
|
+
@dataclass
|
|
462
|
+
class LearnResult:
|
|
463
|
+
accepted: bool
|
|
464
|
+
reason: str # "consistent" or "contradiction: ..."
|
|
465
|
+
new_entities: list[str]
|
|
466
|
+
scores_before: list[float] # geodesic scores pre-optimization
|
|
467
|
+
scores_after: list[float] # geodesic scores post-optimization
|
|
468
|
+
tension_before: list[float]
|
|
469
|
+
tension_after: list[float]
|
|
470
|
+
n_steps_run: int
|
|
471
|
+
|
|
472
|
+
class RuntimeLearner:
|
|
473
|
+
"""Grow GMS by writing verified knowledge via Riemannian gradient descent.
|
|
474
|
+
|
|
475
|
+
Follows the protocol from scripts/experiment_llm_knowlytix.core.py Experiment 7:
|
|
476
|
+
1. Freeze trained GKG (rotors, projections, existing embeddings)
|
|
477
|
+
2. Expand embedding tables with new entities
|
|
478
|
+
3. Init new entity embeddings via sentence-transformers (encode_texts)
|
|
479
|
+
4. Riemannian GD on new embeddings only, minimizing:
|
|
480
|
+
- Triple scoring loss: d_geo(R_r @ v_h, v_t) for new triples
|
|
481
|
+
- Tension energy targets: E=0 for consistent pairs, E=2 for contradictory
|
|
482
|
+
5. Post-write verification
|
|
483
|
+
6. If contradiction gate enabled and post-write contradictions found -> rollback
|
|
484
|
+
"""
|
|
485
|
+
|
|
486
|
+
def __init__(self, store: GMSExpertStore, config: LearnConfig): ...
|
|
487
|
+
|
|
488
|
+
def learn_triples(self, new_triples: list[ExtractedTriple],
|
|
489
|
+
device: torch.device) -> LearnResult:
|
|
490
|
+
"""Full learning pipeline with contradiction guard.
|
|
491
|
+
|
|
492
|
+
Steps:
|
|
493
|
+
a. Identify new entities (not in store.adapter)
|
|
494
|
+
b. Pre-check: verify_answer() on new triples against store
|
|
495
|
+
c. If contradiction_gate and contradictions -> return rejected
|
|
496
|
+
d. Expand embedding tables
|
|
497
|
+
(pattern: experiment_llm_knowlytix.core.py:1889-1939)
|
|
498
|
+
e. Encode new entities: encode_texts() for v-space and u-space
|
|
499
|
+
(using sentence-transformers/all-MiniLM-L6-v2 and nli-mpnet-base-v2)
|
|
500
|
+
f. Freeze existing params
|
|
501
|
+
g. Create new-entity-only params (v, u_proj, specificity, confidence)
|
|
502
|
+
h. Riemannian GD loop for n_steps
|
|
503
|
+
(pattern: experiment_llm_knowlytix.core.py:1982-2138)
|
|
504
|
+
i. Post-verification: re-check tension + holonomy
|
|
505
|
+
j. If still contradictory -> rollback (restore original weights)
|
|
506
|
+
k. Update adapter mappings (entity_to_idx, idx_to_entity)
|
|
507
|
+
l. Return LearnResult with before/after metrics
|
|
508
|
+
"""
|
|
509
|
+
|
|
510
|
+
def learn_enm(self, category: str, entity_id: str, value: float) -> bool:
|
|
511
|
+
"""Write exact numeric value to ENM. Always accepts (no contradiction
|
|
512
|
+
possible for exact storage)."""
|
|
513
|
+
|
|
514
|
+
def _expand_embeddings(self, new_names: list[str], device): ...
|
|
515
|
+
def _riemannian_optimize(self, triple_tensors, tension_targets, device): ...
|
|
516
|
+
def _rollback(self): ...
|
|
517
|
+
```
|
|
518
|
+
|
|
519
|
+
Imports:
|
|
520
|
+
- `knowlytix.core.graph.encoders.encode_texts` — sentence-transformer encoding
|
|
521
|
+
- `knowlytix.core.geometry.sphere.normalize` — sphere projection
|
|
522
|
+
- `knowlytix.core.memory.enm.ENMKey` — ENM key construction
|
|
523
|
+
- Pattern from `scripts/experiment_llm_knowlytix.core.py:1848-2238`
|
|
524
|
+
|
|
525
|
+
### 4.9 `query.py` — The Expert System Query Engine
|
|
526
|
+
|
|
527
|
+
```python
|
|
528
|
+
@dataclass
|
|
529
|
+
class QueryResult:
|
|
530
|
+
answer: Any # the answer
|
|
531
|
+
source: str # "enm"|"triple"|"phase"|"transport"|"llm"|"gms+llm"
|
|
532
|
+
confidence: float # GMS-derived confidence
|
|
533
|
+
extracted_triples: list[ScoredTriple] # triples from LLM answer (if LLM was used)
|
|
534
|
+
verification: VerificationReport | None # contradiction + holonomy (if LLM used)
|
|
535
|
+
learned: bool # True if novel facts were written to store
|
|
536
|
+
learn_result: LearnResult | None # details of learning (if it happened)
|
|
537
|
+
gms_context: str # GMS context provided to LLM (if augmented)
|
|
538
|
+
|
|
539
|
+
class QueryEngine:
|
|
540
|
+
"""Expert system query interface.
|
|
541
|
+
|
|
542
|
+
The full query loop:
|
|
543
|
+
1. GMS attempts structured answer
|
|
544
|
+
2. If insufficient: LLM answers (with GMS context)
|
|
545
|
+
3. Extract triples from LLM answer
|
|
546
|
+
4. Score + verify (contradiction + holonomy)
|
|
547
|
+
5. If verified + novel + auto_learn: grow GMS
|
|
548
|
+
6. Return answer with full provenance
|
|
549
|
+
"""
|
|
550
|
+
|
|
551
|
+
def __init__(self, store: GMSExpertStore, llm_backend: LLMBackend,
|
|
552
|
+
config: DocGMSConfig): ...
|
|
553
|
+
|
|
554
|
+
def query(self, question: str, mode: str = "gms_llm") -> QueryResult:
|
|
555
|
+
"""Query the expert system.
|
|
556
|
+
|
|
557
|
+
Modes:
|
|
558
|
+
"gms_only" — structured GMS answer only
|
|
559
|
+
"llm_only" — LLM answer only (still verified by GMS)
|
|
560
|
+
"gms_llm" — GMS attempts first, LLM augments, verified, learned
|
|
561
|
+
"""
|
|
562
|
+
|
|
563
|
+
def query_batch(self, questions: list[str], mode: str = "gms_llm") -> list[QueryResult]:
|
|
564
|
+
"""Batch query."""
|
|
565
|
+
|
|
566
|
+
# --- Internal routing ---
|
|
567
|
+
|
|
568
|
+
def _classify_question(self, question: str) -> str:
|
|
569
|
+
"""Heuristic classification:
|
|
570
|
+
- 'exact value', 'what is the', 'how much' -> exact_recall
|
|
571
|
+
- 'above', 'below', 'exceeds', 'threshold' -> threshold
|
|
572
|
+
- 'contradict', 'conflict', 'inconsistent' -> contradiction
|
|
573
|
+
- 'path', 'chain', 'leads to', 'through' -> multi_hop
|
|
574
|
+
- 'both', 'intersection', 'and also' -> cross_reference
|
|
575
|
+
- 'how many', 'count' -> counting
|
|
576
|
+
- default -> open_ended
|
|
577
|
+
"""
|
|
578
|
+
|
|
579
|
+
def _gms_answer(self, question: str, qtype: str) -> tuple[Any, float] | None:
|
|
580
|
+
"""Attempt GMS-only answer based on question type.
|
|
581
|
+
|
|
582
|
+
exact_recall: ENM lookup -> store.lookup_enm()
|
|
583
|
+
threshold: Phase check -> doc_graph phase encoders
|
|
584
|
+
contradiction: Tension energy -> store.tension_energy()
|
|
585
|
+
multi_hop: Transport -> transport.path_score()
|
|
586
|
+
cross_reference: Triple intersection -> store.query_triples()
|
|
587
|
+
counting: Triple count -> len(store.query_triples())
|
|
588
|
+
|
|
589
|
+
Returns (answer, confidence) or None if GMS can't answer.
|
|
590
|
+
"""
|
|
591
|
+
|
|
592
|
+
def _gather_gms_context(self, question: str) -> str:
|
|
593
|
+
"""Build GMS context for LLM augmentation.
|
|
594
|
+
|
|
595
|
+
1. Keyword-match entities in store.adapter vocab
|
|
596
|
+
2. For matched entities: gather related triples
|
|
597
|
+
3. For matched entities: lookup ENM values
|
|
598
|
+
4. For matched entities: check phase thresholds
|
|
599
|
+
5. Format as structured context string
|
|
600
|
+
"""
|
|
601
|
+
|
|
602
|
+
def _llm_answer(self, question: str, gms_context: str | None) -> str:
|
|
603
|
+
"""Call LLM. If gms_context provided, prepend to prompt.
|
|
604
|
+
|
|
605
|
+
System prompt:
|
|
606
|
+
You are an expert analyst backed by a geometric knowledge store.
|
|
607
|
+
Use the provided structured context as ground truth.
|
|
608
|
+
For numeric values, prefer the exact values from the knowledge store.
|
|
609
|
+
If the context contradicts your knowledge, flag the discrepancy.
|
|
610
|
+
|
|
611
|
+
User prompt:
|
|
612
|
+
<context>{gms_context}</context>
|
|
613
|
+
<question>{question}</question>
|
|
614
|
+
"""
|
|
615
|
+
|
|
616
|
+
def _attempt_learn(self, scored_triples: list[ScoredTriple],
|
|
617
|
+
verification: VerificationReport,
|
|
618
|
+
device: torch.device) -> LearnResult | None:
|
|
619
|
+
"""If auto_learn=True and verification.overall_consistent and novel triples exist:
|
|
620
|
+
call RuntimeLearner.learn_triples() to grow GMS."""
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
### 4.10 `compare.py` — GMS+LLM vs LLM-Only Evaluation
|
|
624
|
+
|
|
625
|
+
```python
|
|
626
|
+
@dataclass
|
|
627
|
+
class ComparisonRow:
|
|
628
|
+
qid: str
|
|
629
|
+
category: str
|
|
630
|
+
question: str
|
|
631
|
+
ground_truth: Any
|
|
632
|
+
# GMS-only
|
|
633
|
+
gms_answer: Any
|
|
634
|
+
gms_correct: bool
|
|
635
|
+
# LLM-only (verified by GMS)
|
|
636
|
+
llm_answer: Any
|
|
637
|
+
llm_correct: bool
|
|
638
|
+
llm_plausibility: float
|
|
639
|
+
llm_contradictions: int
|
|
640
|
+
llm_holonomy_violations: int
|
|
641
|
+
# GMS+LLM (augmented, verified, learned)
|
|
642
|
+
gms_llm_answer: Any
|
|
643
|
+
gms_llm_correct: bool
|
|
644
|
+
gms_llm_plausibility: float
|
|
645
|
+
gms_llm_contradictions: int
|
|
646
|
+
gms_llm_learned: bool
|
|
647
|
+
|
|
648
|
+
@dataclass
|
|
649
|
+
class ComparisonReport:
|
|
650
|
+
document: str
|
|
651
|
+
total_questions: int
|
|
652
|
+
scores: dict[str, int] # {mode: n_correct}
|
|
653
|
+
by_category: dict[str, dict]
|
|
654
|
+
rows: list[ComparisonRow]
|
|
655
|
+
plausibility_summary: dict[str, float] # {mode: mean_plausibility}
|
|
656
|
+
contradiction_summary: dict[str, int] # {mode: total_contradictions}
|
|
657
|
+
facts_learned: int # novel facts added to GMS
|
|
658
|
+
timestamp: str
|
|
659
|
+
|
|
660
|
+
class ComparisonRunner:
|
|
661
|
+
"""Three-way comparison: gms_only vs llm_only vs gms_llm.
|
|
662
|
+
|
|
663
|
+
Uses knowlytix.benchmark.generators.default_generators() to auto-generate
|
|
664
|
+
questions from store.doc_graph topology.
|
|
665
|
+
"""
|
|
666
|
+
|
|
667
|
+
def __init__(self, store: GMSExpertStore, query_engine: QueryEngine,
|
|
668
|
+
config: DocGMSConfig): ...
|
|
669
|
+
|
|
670
|
+
def run(self) -> ComparisonReport:
|
|
671
|
+
"""
|
|
672
|
+
1. Generate questions: default_generators().generate(store.doc_graph)
|
|
673
|
+
2. For each question, run query_engine.query(q, mode) for all 3 modes
|
|
674
|
+
3. Score: knowlytix.benchmark.scorers.score_answer(answer, ground_truth)
|
|
675
|
+
4. Aggregate: accuracy + plausibility + contradictions + facts learned
|
|
676
|
+
"""
|
|
677
|
+
|
|
678
|
+
def print_report(self, report: ComparisonReport): ...
|
|
679
|
+
def save_report(self, report: ComparisonReport, path: str): ...
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
Imports:
|
|
683
|
+
- `knowlytix.benchmark.generators.default_generators` — question generation
|
|
684
|
+
- `knowlytix.benchmark.scorers.score_answer`, `PARSERS` — scoring
|
|
685
|
+
|
|
686
|
+
### 4.11 `cli.py` + `__main__.py`
|
|
687
|
+
|
|
688
|
+
```
|
|
689
|
+
Usage:
|
|
690
|
+
docgms ingest <document> # Ingest PDF/TeX/MD into expert store
|
|
691
|
+
docgms query "question" # Query the expert system
|
|
692
|
+
docgms query --interactive # Interactive Q&A session
|
|
693
|
+
docgms compare <document> # Three-way comparison
|
|
694
|
+
docgms status # Show store statistics
|
|
695
|
+
docgms export <path> # Export store state
|
|
696
|
+
|
|
697
|
+
Global flags:
|
|
698
|
+
--store-path PATH # Store directory (default: docgms_store/)
|
|
699
|
+
--device cuda|cpu
|
|
700
|
+
--mode gms_only|llm_only|gms_llm
|
|
701
|
+
--auto-learn / --no-auto-learn
|
|
702
|
+
--model MODEL # LLM model name
|
|
703
|
+
--epochs N # Training epochs (first ingest only)
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 5. Reuse Map
|
|
709
|
+
|
|
710
|
+
| Component | Source | Usage |
|
|
711
|
+
|---|---|---|
|
|
712
|
+
| `ingest_markdown()` | `knowlytix.benchmark.ingest` | Markdown → DocumentGraph |
|
|
713
|
+
| `GraphToGMS` | `knowlytix.core.train_finstructbench` | DocumentGraph → training tensors |
|
|
714
|
+
| `train_gms()` | `knowlytix.core.train_finstructbench` | Training loop with Riemannian SGD |
|
|
715
|
+
| `populate_enm()` | `knowlytix.core.train_finstructbench` | DocumentGraph ENM → GMS ENM |
|
|
716
|
+
| `default_generators()` | `knowlytix.benchmark.generators` | Auto-generate evaluation questions |
|
|
717
|
+
| `score_answer()`, `PARSERS` | `knowlytix.benchmark.scorers` | Score answers + parse LLM output |
|
|
718
|
+
| `GeometricKnowledgeGraph` | `knowlytix.core.graph.gkg` | Triple scoring, tension energy |
|
|
719
|
+
| `RelationalTransport` | `knowlytix.core.graph.transport` | Multi-hop, holonomy |
|
|
720
|
+
| `ExactNumericalMemory` | `knowlytix.core.memory.enm` | Exact numeric storage |
|
|
721
|
+
| `CompressionMemory` | `knowlytix.core.memory.compression` | Approximate memory |
|
|
722
|
+
| `MemoryRouter` | `knowlytix.core.memory.router` | ENM vs compression dispatch |
|
|
723
|
+
| `encode_texts()` | `knowlytix.core.graph.encoders` | Sentence-transformer encoding |
|
|
724
|
+
| `RiemannianSGD` | `knowlytix.core.optim.riemannian` | Manifold-aware optimization |
|
|
725
|
+
| `GMSLoss` | `knowlytix.core.losses.combined` | Multi-component loss |
|
|
726
|
+
| `PhaseEncoder` | `knowlytix.core.geometry.phase` | Numeric threshold queries |
|
|
727
|
+
| `tension_energy()` | `knowlytix.core.geometry.clifford` | Clifford algebra contradiction |
|
|
728
|
+
| `holonomy_defect()` | `knowlytix.core.geometry.cayley` | Rotor composition consistency |
|
|
729
|
+
| Test-time write pattern | `scripts/experiment_llm_knowlytix.core.py:1848-2238` | Adapted in learn.py |
|
|
730
|
+
| LLM call pattern | `knowlytix/benchmark/llm_caller.py` | Adapted in llm_backend.py |
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## 6. Data Flow Summary
|
|
735
|
+
|
|
736
|
+
```
|
|
737
|
+
Document (PDF/TeX/MD)
|
|
738
|
+
│
|
|
739
|
+
▼
|
|
740
|
+
[convert.py] ──────────────────────────► Markdown text
|
|
741
|
+
│
|
|
742
|
+
▼
|
|
743
|
+
[knowlytix.benchmark.ingest] ───────────────► DocumentGraph
|
|
744
|
+
│ (ENM + triples + phase)
|
|
745
|
+
▼
|
|
746
|
+
[knowlytix.core.train_finstructbench] ────────────► Trained GKG + ENM + Transport
|
|
747
|
+
│
|
|
748
|
+
▼
|
|
749
|
+
[store.py: GMSExpertStore] ────────────► Persistent on disk
|
|
750
|
+
│
|
|
751
|
+
▼
|
|
752
|
+
[query.py: QueryEngine]
|
|
753
|
+
│
|
|
754
|
+
├── GMS answers structured queries (ENM, triples, phase, transport)
|
|
755
|
+
│
|
|
756
|
+
├── LLM answers open-ended/ambiguous/zero-shot
|
|
757
|
+
│ │
|
|
758
|
+
│ ▼
|
|
759
|
+
│ [extract.py] → (h, r, t) triples
|
|
760
|
+
│ │
|
|
761
|
+
│ ▼
|
|
762
|
+
│ [verify.py] → tension energy + holonomy
|
|
763
|
+
│ │
|
|
764
|
+
│ ├── Contradicts → REJECT + report
|
|
765
|
+
│ │
|
|
766
|
+
│ └── Consistent → [learn.py] → GROW GMS
|
|
767
|
+
│ │
|
|
768
|
+
│ ├── Expand embeddings
|
|
769
|
+
│ ├── Riemannian GD
|
|
770
|
+
│ ├── Post-verify
|
|
771
|
+
│ └── Save store
|
|
772
|
+
│
|
|
773
|
+
▼
|
|
774
|
+
QueryResult (answer + provenance + verification + learning)
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## 7. Implementation Order
|
|
780
|
+
|
|
781
|
+
| Phase | Files | Dependency | Estimated Lines |
|
|
782
|
+
|---|---|---|---|
|
|
783
|
+
| 1 | `config.py`, `__init__.py` | None | ~70 |
|
|
784
|
+
| 2 | `llm_backend.py` | config | ~100 |
|
|
785
|
+
| 3 | `convert.py` | llm_backend | ~250 |
|
|
786
|
+
| 4 | `store.py` | config, gms.*, knowlytix.benchmark.* | ~300 |
|
|
787
|
+
| 5 | `ingest.py` | store, convert | ~150 |
|
|
788
|
+
| 6 | `extract.py` | store, llm_backend | ~200 |
|
|
789
|
+
| 7 | `verify.py` | store | ~180 |
|
|
790
|
+
| 8 | `learn.py` | store, verify | ~250 |
|
|
791
|
+
| 9 | `query.py` | store, extract, verify, learn, llm_backend | ~300 |
|
|
792
|
+
| 10 | `compare.py` | query, knowlytix.benchmark.generators/scorers | ~150 |
|
|
793
|
+
| 11 | `cli.py`, `__main__.py` | all | ~120 |
|
|
794
|
+
| **Total** | | | **~2070** |
|
|
795
|
+
|
|
796
|
+
---
|
|
797
|
+
|
|
798
|
+
## 8. Testing Strategy
|
|
799
|
+
|
|
800
|
+
| Test | Validates | Expected |
|
|
801
|
+
|---|---|---|
|
|
802
|
+
| Ingest model_validation.md | Full pipeline | ~5000 triples, ~260 ENM |
|
|
803
|
+
| ENM exact recall | store.lookup_enm() | 100% accuracy |
|
|
804
|
+
| Score known triple | store.score_triple() | Low geodesic distance |
|
|
805
|
+
| Score random triple | store.score_triple() | High geodesic distance |
|
|
806
|
+
| Tension: contradictory pair | store.tension_energy() | E > 1.7 |
|
|
807
|
+
| Tension: consistent pair | store.tension_energy() | E < 0.8 |
|
|
808
|
+
| Holonomy: valid path | store.check_holonomy() | defect < 0.5 |
|
|
809
|
+
| Extract triples from LLM | extract_triples() | Parseable triples |
|
|
810
|
+
| Score extracted triples | score_triples() | Scores + entity matches |
|
|
811
|
+
| Verify consistent answer | verify_answer() | overall_consistent=True |
|
|
812
|
+
| Verify contradictory answer | verify_answer() | overall_consistent=False |
|
|
813
|
+
| Learn consistent triples | learn_triples() | accepted=True, store grows |
|
|
814
|
+
| Learn contradictory triples | learn_triples() | accepted=False, rollback |
|
|
815
|
+
| Multi-document ingest | Second ingest | Store expands |
|
|
816
|
+
| Store save/load roundtrip | save() + load() | Identical state |
|
|
817
|
+
| Compare on auto-questions | ComparisonRunner.run() | 3-column report |
|
|
818
|
+
| End-to-end: ingest PDF + query | Full pipeline | Answer with provenance |
|