{
  "markdown": "# grounded-reasoning — Grounded, Guaranteed Reasoning for LLMs & Agents\n\n[![CI](https://github.com/ALEXaquarius/grounded-reasoning/actions/workflows/ci.yml/badge.svg)](https://github.com/ALEXaquarius/grounded-reasoning/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11%2B-blue.svg)](pyproject.toml)\n[![PyPI](https://img.shields.io/pypi/v/grounded-reasoning.svg)](https://pypi.org/project/grounded-reasoning/)\n[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/ALEXaquarius/grounded-reasoning/blob/main/examples/quickstart.ipynb)\n\n> **TL;DR.** LLMs hallucinate on multi-hop relational reasoning. This is a\n> **relation-algebra verifier** an agent calls to check a claim *before* asserting it:\n> **zero model tokens**, **precision-guaranteed** (accepts a claim iff a grounded proof\n> path exists), language-agnostic, and provider-agnostic. Plugs in as a **library**, a\n> **function-calling tool**, or an **MCP server**. Validated on **real LLMs** (DeepSeek\n> et al.) and the public **CLUTRR** benchmark. See [docs/integration.md](docs/integration.md).\n\n📄 Full paper: **[PAPER.md](PAPER.md)** · Integration guide: **[docs/integration.md](docs/integration.md)** · Try it in 30 seconds: **[quickstart notebook](https://colab.research.google.com/github/ALEXaquarius/grounded-reasoning/blob/main/examples/quickstart.ipynb)**\n\nĐọc bằng tiếng Việt: **[README.vi.md](README.vi.md)**\n\n---\n\n## Why this exists\n\nLLMs are solid on one-hop facts but **collapse on composition** — chaining several\ncorrect facts into a multi-step conclusion. On CLUTRR (kinship reasoning), DeepSeek's\naccuracy **falls off with depth**, while a grounded operator-composition solver holds\n**~100% flat — at zero tokens**:\n\n```\nacc\n100% ●─────●─────●─────●─────●─────●─────●   ● Grounded solver (algebra, 0 tokens)\n 90% |\n 80% ○\n 70% |  ╲\n 60% |   ╲\n 50% |    ╲\n 40% |     ○           ○                     ○ DeepSeek (LLM)\n 30% |      ╲         ╱ ╲\n 20% |       ○─────○     ╲\n 10% |                    ○─────○\n  0% +──┴─────┴─────┴─────┴─────┴─────┴─────┴─\n      hop 2    3     4     5     6     7     8   (composition steps)\n\n     hop:      2     3     4     5     6     7     8\n     DeepSeek: 83%   42%   25%   25%   42%   17%   8%\n     Solver:   100%  100%  100%  100%  100%  100%  100%\n```\n\n*(CLUTRR/v1 gen_train234_test2to10, clean-chain, n=12/hop; full test set n=635: solver\ncovers 99.5%, accuracy 99.2%. `grounded_reasoning/experiments/clutrr_eval.py`.)*\n\n---\n\n## What it is / is NOT (honestly)\n\n**Is:** a guaranteed reasoning-verification layer built on relation operator algebra.\n- **Precision = 1.0, guaranteed** (Theorem G) — accepts a claim only if a grounded proof path exists.\n- **Zero extra tokens** — local matrix multiplication, no LLM call. Compare to\n  \"have the LLM self-verify,\" which costs +110% tokens for 34% precision.\n- **Two-sided guarantee** (Theorem I) — precision *and* recall both have tight bounds.\n- **No external KB required** (SGDC) — uses the LLM's own internal consistency.\n  Precision=1.0 is conditional on the LLM's own atomic facts being sound; that\n  assumption can be measured too — `calibrate_transitivity` doesn't care\n  whether facts came from an external KB or the model's own assertions, so it\n  already calibrates SGDC's real output precision with zero new code (see\n  [`self_grounded_calibration_eval.py`](grounded_reasoning/experiments/self_grounded_calibration_eval.py),\n  PAPER.md §6's remark).\n\n**Is not:** an \"unprecedented breakthrough.\" The Katz index, the Neumann series,\ngraph reachability, and neuro-symbolic grounding are all classical math and\ntechnique. The contribution here is unification, a measured guarantee, and\nbenchmark numbers — not a new primitive. The guard needs a relation graph\n(supplied, or extracted from LLM facts); flexibility is bounded (see\n[PAPER §5](PAPER.md)).\n\n### Two sharp edges the algebra itself can't see (and how to guard them)\n\nRaised in review, reproduced, and fixed with an opt-in guard each — not swept\nunder the rug:\n\n- **Entity identity is exact-string by default.** If an LLM extraction is\n  inconsistent about one entity's surface form (`\"Bob\"` vs `\"bob\"`), the graph\n  treats them as two nodes and a real path silently breaks — the guard then\n  (correctly, per its own contract) rejects a claim that is actually true.\n  Fix (binary): `GroundedReasoner(normalize=lambda s: s.strip().casefold())`\n  folds surface-form variants together before they become graph keys; proofs\n  still display each entity's original first-seen spelling. **Theorem N**\n  characterizes exactly when this is safe: precision stays *exactly* 1.0 as\n  long as `normalize` never merges two genuinely distinct entities — that's\n  the *only* way it can go wrong, so it's exactly what\n  `gr.calibrate_normalization(labeled_pairs)` measures from held-out evidence,\n  reusing the same Clopper-Pearson machinery as Theorem M.\n- **Theorem G doesn't know if `via` is transitive in reality.** It guarantees\n  \"a path exists under the closure of `via`,\" not \"`via` actually composes in\n  the world.\" Compose a relation that's only partially/conditionally\n  transitive (`\"trusts\"`: A trusts B, B trusts C, does not imply A trusts C)\n  and you get a confident, mathematically correct `grounded=True` that answers\n  a different question than the one you meant to ask. Fix (binary):\n  `GroundedReasoner(transitive_relations={\"parent\", \"is_a\", ...})` makes the\n  guard raise `ValueError` for any undeclared relation, turning a silent\n  modeling assumption into an explicit, checked one. Fix (measured — **Theorem\n  M**): `gr.calibrate_transitivity(rel, labeled_pairs)` replaces the binary\n  declare-or-reject with an actual number — a Clopper-Pearson lower confidence\n  bound on \"a graph-grounded claim for `rel` is really true,\" computed from\n  held-out labeled pairs. Where the binary guard can only guess or block\n  outright, the calibrated bound tells you *how much* to trust it.\n\nBoth opt-in guards are off by default (identical behavior to previous\nreleases). Reproductions: `tests/test_agent.py::TestEntityNormalization`,\n`::TestTransitiveRelationsGuard`, `::TestTransitivityCalibration`,\n`::TestNormalizationCalibration`; the A/B comparisons:\n[`transitivity_calibration_eval.py`](grounded_reasoning/experiments/transitivity_calibration_eval.py),\n[`normalization_calibration_eval.py`](grounded_reasoning/experiments/normalization_calibration_eval.py).\n\n**Heterogeneous relation chains.** `verify(via=rel)` composes ONE relation with\nitself; `gr.verify_path(subject, obj, via=[\"parent\",\"employer\"])` composes an\nexact sequence of *different* relations (e.g. a derived \"financially dependent\non\" claim) — not new math (`OperatorRelationAlgebra.follow` already composes\nmixed-relation chains exactly per Theorem G, this just exposes it at the\nfacade with proof-path reconstruction) — and `gr.calibrate_path(via,\nlabeled_pairs)` calibrates that fixed pattern with the same Clopper-Pearson\nengine as `calibrate_transitivity` (see PAPER.md §5.3.4). Checked against\nindependent ground-truth BFS across 8,000 triples with zero mismatches:\n`tests/test_agent.py::TestHeterogeneousPathVerification`,\n[`heterogeneous_path_calibration_eval.py`](grounded_reasoning/experiments/heterogeneous_path_calibration_eval.py).\n\n### How this differs from the usual fixes\n\n| Approach | Extra tokens | Guarantee | Needs an external KB |\n|---|---|---|---|\n| LLM self-verification (2nd call) | +110% | none (measured 34% precision) | no |\n| Self-consistency / majority vote | multiplies with sample count | none, statistical only | no |\n| RAG / external KG grounding | varies | only as good as retrieval | yes |\n| **This guard** | **+0** | **precision = 1.0** (Theorem G) | no |\n| **This guard, self-grounded (SGDC)** | **+0** | precision = 1.0 given sound atomic facts (Theorem I) | no |\n| **This guard, conformal** | **+0** | coverage ≥ 1−α, distribution-free (Theorem K) | no |\n\n---\n\n## Three theorems, one operator (F = G = H)\n\nThe reasoning core rests on a single unification (numerically verified, zero error):\n\n| View | Theorem | Content |\n|------|---------|---------|\n| Fuzzy diffusion inference | **F** | conf(a→b) = Σ αᵏ(Pᵏ)[a,b], calibrated + grounded |\n| Relation operator algebra | **G** | composition = operator product, transitive closure = Σ powers |\n| Spectral analysis (Katz) | **H** | `engine.infer` = resolvent (I−αP)⁻¹−I (matches **0.0** error) |\n\n⟹ fuzzy inference **is** spectral analysis of the relation operator. `grounded_reasoning/reasoning/`.\n\nSix further theorems extend this core: **I** (two-sided precision/recall guarantee\nfor a self-grounded, no-external-KB variant), **J** (closure-learning completeness,\nvalidated on CLUTRR), **K** (conformal reasoning — distribution-free coverage under a\n*noisy* relation graph, including one extracted by an LLM from raw text), **L**\n(Horn forward-chaining, generalizing transitive closure to conjunctive rules),\n**M** (empirical transitivity calibration — a Clopper-Pearson confidence bound\nreplacing a blind transitivity assumption with a measured one), and **N**\n(normalization precision isolation — precision=1.0 breaks only via an\nover-merge, and *only* that is what needs calibrating). All\nnine are stated, proved, and numerically verified in [PAPER.md](PAPER.md).\n\n---\n\n## Evidence on real LLMs (DeepSeek)\n\n| Experiment | Result |\n|------------|--------|\n| Hallucination guard (kinship) | precision **33% → 100%**, catches 92/92 (two seeds), 0 false rejects |\n| Hallucination guard, harder stress test (48-person tree, sibling/spouse distractor facts, shuffled prose, T=0.7, guaranteed-empty trap questions) | raw DeepSeek precision **4.6%** (2124 fabricated names, 86/90 trap questions answered with a fabrication); guarded precision **100%**, 0 leaked, 0 correct answers dropped — [`guard_llm_stress_eval.py`](grounded_reasoning/experiments/guard_llm_stress_eval.py) |\n| Guard token cost | **+0 tokens** (vs. LLM self-verify: +110% tokens, 34% precision) |\n| SGDC (self-grounded, no external KB) | precision **78% → 100%** from internal consistency alone |\n| Dense, anti-commonsense ontology | precision **31% → 100%**, catches 106/106, 0 false rejects — [`nl_ontology_eval.run_dense`](grounded_reasoning/experiments/nl_ontology_eval.py) |\n| CLUTRR (public benchmark) | solver **~100% at every hop** vs. DeepSeek 83%→8% |\n| Hard passage (9-step chain, 8 questions) | DeepSeek **fabricates 1/8** (wrong direction); grounded system **8/8**, with proofs — [`examples/hallucination_demo.py`](examples/hallucination_demo.py) |\n\n---\n\n## Guaranteed reasoning over a graph an LLM extracted from raw text\n\nThe guard/solver needs a **clean** graph. But if you let an **LLM extract** relations\nfrom natural-language text, the graph is **noisy** (missing/spurious edges).\n**Conformal Reasoning** (Theorem K) fixes exactly that: use operator confidence as a\nscore, calibrate a threshold ⟹ **distribution-free coverage ≥ 1−α**, even on a noisy\ngraph.\n\nEnd-to-end demo: **DeepSeek extracts an \"is a\" graph from text** → conformal runs on\nthat extracted graph (ground truth is used only for scoring):\n\n| Text | LLM extraction (P / R) | Coverage (target ≥90%) | Efficiency (FPR) |\n|------|------------------------:|----------------------------:|------------------:|\n| Easy | 100% / 99.7% | **91.3%** | 0.0 |\n| Hard (nested clauses + near-miss distractors) | 99.5% / **68.5%** | **93.0%** | 0.77 |\n\n> The LLM's extraction **drops 31% of the edges** (a genuinely noisy graph) →\n> **the coverage guarantee still holds** (93% ≥ 90%), only efficiency degrades.\n> *Validity always holds; efficiency scales with graph quality.*\n\n⟹ A path to guaranteed reasoning over **natural-language relations** — where the hard\nguard can't reach. `grounded_reasoning/experiments/conformal_llm_eval.py`.\n\n**Efficiency can be pushed further under dropout-dominant noise, at no cost to\nvalidity.** `ConformalReasoner.calibrate(..., group_fn=...)` calibrates a\nseparate threshold per group instead of one global one (Mondrian conformal —\nclassical, not new); `redundancy_group` groups a pair by whether it has more\nthan one walk in the extracted graph, computable with no ground truth. A\n*different* grouping tried first (hop-distance) was numerically **falsified**\nbefore shipping — it made efficiency worse, not better, and was discarded.\nRedundancy grouping cuts FPR from 98.7% → **80.8%** when dropped edges\ndominate the noise (matching this system's real LLM-extraction noise mode)\nwhile coverage still holds ≥90% — and honestly gives ~no benefit when\nspurious *added* edges dominate instead.\n[`redundancy_conformal_eval.py`](grounded_reasoning/experiments/redundancy_conformal_eval.py),\nPAPER.md §7.1's remark.\n\n**A different, orthogonal weakness — the noise level DRIFTING over time, not\nbeing heterogeneous — needs a different classical tool.** Split-conformal\n(and its Mondrian extension above) assumes calibration and test data share a\ndistribution; that breaks if extraction quality changes between document\nbatches. `AdaptiveConformalReasoner` (Adaptive Conformal Inference — Gibbs &\nCandès, 2021, classical, not new) updates its threshold from a stream of\nconfirmed-true examples instead of freezing it after one calibration. When\nnoise shifts partway through a stream (p_drop 0.05 → 0.45), a frozen\nthreshold's coverage **collapses from 88.6% to 47.6%** — well below the 90%\ntarget, silently — while ACI recovers to **89.6%**, in 15/15 trials tested.\n[`drift_conformal_eval.py`](grounded_reasoning/experiments/drift_conformal_eval.py),\nPAPER.md §7.1's remark.\n\n**Strongest efficiency result: removing the specific bad edges beats calibrating\naround them.** `identify_suspect_edges` removes any edge that appears on a\nheld-out FALSE-labeled claim's proof path and NO true-labeled claim's — a\nsimple decision rule, not a statistical guarantee. Verified across 5 noise\nregimes (60 seeds each): FPR drops substantially and consistently\neverywhere, e.g. **77.0% → 49.2%** (dropout-dominant) and **58.7% → 15.7%**\n(spurious-dominant, where `redundancy_group` gives almost nothing) —\ncoverage on the remaining graph essentially unaffected. Unlike every\ncalibration method above, this one carries **no false-discovery-rate\nguarantee** — a real, measured tradeoff: at the default configuration\n(`identify_frac=0.5, min_evidence=1`), the pooled wrongly-removed rate\nranges **13.2%–32.2%** across regimes. At the recommended configuration\n(`identify_frac=0.85, min_evidence=2`, found by a Pareto sweep — the\ndefault of `identify_and_prune_edges`, which applies it automatically so\nit's the path of least resistance), it drops to **1.5%–3.1%** (95% upper\nconfidence bound 2.6%–6.6%), at the cost of cleaned FPR rising somewhat\n(e.g. ~49% → ~59% in the dropout-dominant regime, still far below the 77%\nraw baseline) and a smaller reserved evaluation set. Checked against a real\nLLM (DeepSeek), not just simulated noise, on data where each candidate\nedge is backed by exactly one labeled encounter (no query repeated — the\nrealistic case for a deployment that verifies each claim once): the\ncount-based rules above (`min_evidence≥2`, and its hub-aware\n`use_propagation=True` variant) never fire at all on this regime, since\nthey require an edge to independently clear the evidence bar twice, which\nnever happens with single-encounter evidence. Lowering to\n`min_evidence=1` does block real hallucinated edges, but on its own makes\ndownstream FPR *worse* than doing nothing (63.0% → 70.7%, beats raw in\nonly 4/15 splits) — traced to the diffusion engine's row-normalization\nconcentrating transition probability onto a source's surviving edges once\nits OTHER edges are pruned. Pairing that same blocking decision with\n`masked_infer` (normalizes by each source's pre-prune degree, so removal\nonly ever removes confidence mass, never redistributes it) recovers a\nreal improvement: 63.0% → 54.0%, beats raw in 12/15 splits, with no\nregression on the synthetic benchmark. A learned (logistic regression)\nalternative was also tried and rejected: it failed to generalize from\nsynthetic training data to the real data at all. Pruning also costs real\nrecall for any true claim that depended solely on a removed edge, and it\nedits the graph in place (a one-way change, unlike calibration which only\nadjusts a threshold).\n[`edge_pruning_eval.py`](grounded_reasoning/experiments/edge_pruning_eval.py),\n[`edge_pruning_llm_eval.py`](grounded_reasoning/experiments/edge_pruning_llm_eval.py),\nPAPER.md §7.1's remark.\n\n---\n\n## Self-verification with NO external knowledge base (SGDC)\n\nThe guard above needs *some* relation graph handed to it. Self-Grounded\nDeductive Consistency (Theorem I) removes even that: it exploits the fact\nthat LLMs are reliably accurate on **atomic (1-hop) facts** but hallucinate on\n**composition**. Take the model's own confident 1-hop facts, build the\noperator closure from *those*, then reject any of the model's own multi-hop\nconclusions that fall outside its *own* closure — self-contradiction is the\nhallucination signal, not disagreement with an external source.\n\n```python\nfrom grounded_reasoning import GroundedReasoner\n\n# the LLM's OWN atomic facts (no external KB) -- taken at face value\ngr = GroundedReasoner()\ngr.add_facts([(\"sparrow\", \"is_a\", \"bird\"), (\"bird\", \"is_a\", \"animal\")])\n\n# the LLM's OWN multi-hop conclusion, self-verified against ITS OWN facts above\ngr.verify(\"sparrow\", \"animal\", via=\"is_a\")   # grounded=True: self-consistent\ngr.verify(\"sparrow\", \"plant\",  via=\"is_a\")   # grounded=False: self-contradiction, blocked\n```\n\n| | precision | recall |\n|---|---:|---:|\n| Raw multi-hop (LLM) | 78% | 87% |\n| **SGDC (self-grounded, zero external knowledge)** | **100%** | 72% |\n| Ceiling: filtering with an external graph | 100% | 87% |\n\nThe honest cost is recall (72% vs. 87%): self-closure is conservative. And\nTheorem I's precision=1.0 is *conditional* — it holds if the model's own\natomic facts are sound; in a counter-prior domain (e.g. \"a whale is a fish\"),\natomic precision itself can drop, and recall suffers with it (PAPER.md §6\nrecords this honestly rather than hiding it).\n\n**That assumption can be measured too, with zero new code.**\n`gr.calibrate_transitivity(rel, labeled_pairs)` (Theorem M) doesn't care\nwhether `gr`'s facts came from an external KB or the model's own atomic\nself-assertions — so calling it on a reasoner built purely from an LLM's own\nfacts calibrates SGDC's *actual* output precision directly, from held-out\nevidence, instead of assuming atomic soundness. In a synthetic domain with\n15% of the atomic facts deliberately wrong, SGDC's real precision fell to\n~74% (**not** the naively-expected ~85% — a single wrong atomic edge\ncomposes into several downstream claims, amplifying its damage), and the\ncalibrated bound correctly stayed below that in 98.3% of trials —\n[`self_grounded_calibration_eval.py`](grounded_reasoning/experiments/self_grounded_calibration_eval.py),\nPAPER.md §6's remark.\n\nRunnable: [`examples/self_grounded_demo.py`](examples/self_grounded_demo.py)\n(offline) · live on DeepSeek:\n`grounded_reasoning/experiments/self_grounded_eval.py`.\n\n---\n\n## Quickstart\n\n```bash\npip install grounded-reasoning\n\n# or, for development (tests + lint):\ngit clone https://github.com/ALEXaquarius/grounded-reasoning\ncd grounded-reasoning && pip install -e \".[dev]\"\npytest tests/                       # every theorem + offline-locked logic, no network needed\n\n# Use it right now (no LLM/network needed):\npython -c \"from grounded_reasoning import GroundedReasoner as G; r=G(); r.add_facts([('a','p','b'),('b','p','c')]); print(r.verify('a','c',via='p'))\"\n\n# Real-LLM experiments (need a key — read from an env var, NEVER hardcoded):\nexport DEEPSEEK_API_KEY=sk-...        # bring your own; .env is gitignored\npython -m grounded_reasoning.experiments.guard_llm_eval        # hallucination guard\npython -m grounded_reasoning.experiments.guard_llm_stress_eval # harder: distractors + traps + high temperature\npython -m grounded_reasoning.experiments.self_grounded_eval    # SGDC\npython -m grounded_reasoning.experiments.clutrr_eval           # public CLUTRR benchmark\npython -m grounded_reasoning.experiments.conformal_llm_eval    # end-to-end conformal (LLM-extracted graph)\npython -m grounded_reasoning.experiments.guard_cost_eval       # token cost: guard vs. LLM self-verify\npython -m grounded_reasoning.experiments.nl_ontology_eval      # dense anti-commonsense ontology (add run_dense() for the 106/106 result)\n```\n\n---\n\n## Integrating with an Agent / LLM (`grounded_reasoning/agent/`)\n\nA **relation-reasoning verifier** for agents: check a multi-hop claim **before\nasserting it** — zero model tokens, precision guaranteed (accepts iff a grounded proof\npath exists).\n\n```python\nfrom grounded_reasoning import GroundedReasoner\ngr = GroundedReasoner()\ngr.add_facts([(\"alice\",\"parent\",\"bob\"),(\"bob\",\"parent\",\"carol\")])\ngr.verify(\"alice\",\"carol\", via=\"parent\")   # Verdict(grounded=True, proof=['alice','bob','carol'], confidence=0.36, relation='parent')\ngr.verify(\"alice\",\"zed\",   via=\"parent\")   # Verdict(grounded=False, proof=None, confidence=0.0, relation='parent')  ← hallucination blocked\n```\n\nThree integration paths (details: [docs/integration.md](docs/integration.md)):\n- **Library**: `GroundedReasoner.verify / filter_claims / contradictions`.\n- **Function-calling**: `TOOL_SPEC` (Anthropic) / `openai_tool_spec()` (OpenAI) + `run_tool` — a stateless `verify_relation` tool.\n- **MCP server**: `python -m grounded_reasoning.agent.mcp_server` — plugs into Claude or any MCP-compatible agent.\n\n**Multi-provider** (not just DeepSeek): `LLMClient(provider=...)` for DeepSeek / OpenAI /\nGroq / OpenRouter / Together / Mistral / Ollama (local) — all OpenAI-compatible, switch\nproviders without changing code. **Multilingual**: entities/relations are opaque\nUnicode strings ⟹ works with any language (`cha`, `父`, `والد`…) with zero configuration.\n\nA real function-calling demo (agent verifies itself, blocks hallucination):\n`python -m grounded_reasoning.experiments.agent_demo`. When the graph is **noisy** (relations\nextracted by an LLM from text), use `ConformalReasoner` for a **coverage ≥1−α**\nguarantee instead of hard precision.\n\n---\n\n## Source map\n\n| Path | Content |\n|------|---------|\n| `grounded_reasoning/` | Public package — `GroundedReasoner`, `verify_relation`, `TOOL_SPEC`, `ConformalReasoner`, `AdaptiveConformalReasoner`, `LLMClient` |\n| `grounded_reasoning/agent/{verifier,tool,mcp_server}.py` | Public API implementation — HallucinationGuard, function-calling tool, MCP server |\n| `grounded_reasoning/reasoning/abstract_inference.py` | FuzzyInferenceEngine, TypedInferenceEngine, HallucinationGuard (Theorem F) |\n| `grounded_reasoning/reasoning/operator_algebra.py` | Relation operator algebra (Theorem G) |\n| `grounded_reasoning/reasoning/relation_spectrum.py` | Spectrum, nilpotency, Katz resolvent (Theorem H) |\n| `grounded_reasoning/reasoning/conformal_reasoning.py` | Conformal — coverage guarantee under noise (Theorem K) |\n| `grounded_reasoning/reasoning/composition_algebra.py` | Composition-table learning, validated on CLUTRR (Theorem J) |\n| `grounded_reasoning/reasoning/horn.py` | Horn forward-chaining, least-model semantics (Theorem L) |\n| `grounded_reasoning/reasoning/transitivity_calibration.py` | Clopper-Pearson calibration — reused for both the transitivity assumption (Theorem M) and the normalization over-merge risk (Theorem N) |\n| `grounded_reasoning/reasoning/edge_pruning.py` | Held-out-evidence edge pruning — a heuristic decision rule, not a Theorem, with its own measured tradeoffs |\n| `grounded_reasoning/reasoning/llm_client.py` | Provider-agnostic LLM client (key read from an env var) |\n| `grounded_reasoning/theory/theorems.py` | **Nine theorems (F–N)** with numerical verification |\n| `grounded_reasoning/experiments/{guard_llm,guard_llm_stress,self_grounded,self_grounded_calibration,nl_ontology,guard_cost,clutrr,conformal_llm,redundancy_conformal,drift_conformal,inference,transitivity_calibration,normalization_calibration,heterogeneous_path_calibration,edge_pruning,edge_pruning_llm}_eval.py` | Real-LLM and benchmark experiments backing every claim above |\n| `examples/hallucination_demo.py` | End-to-end function-calling demo (real LLM, needs a key) |\n| `examples/self_grounded_demo.py` | SGDC (Theorem I): self-verify a model's own multi-hop claim with NO external KB (offline) |\n| `examples/rag_pipeline_demo.py` | `filter_claims` as a RAG/agent post-processing guard, heterogeneous claims (offline) |\n| `examples/calibration_demo.py` | Theorem M + N side by side: measuring transitivity and normalization trust instead of assuming it (offline) |\n| `examples/conformal_demo.py` | Coverage guarantee vs. noise tradeoff, clean vs. noisy graph side by side (offline) |\n| `examples/quickstart.ipynb` | Runnable tour of the library (offline, Colab-ready) |\n\n---\n\n## Origin story\n\nThis project began as an attempt to invent an embedding-free retrieval algorithm that\ncould compete with dense/RAG retrieval. That research question reached a rigorous,\nfully honest **negative** conclusion (ties BM25, loses significantly to dense\nembeddings — with a proof of why). The same mathematical toolkit — operator algebra,\nspectral analysis — turned out to have real, measurable value on a different problem:\n**guaranteeing** multi-hop relational reasoning. This repository ships only that\nvalidated, tested reasoning system; the full retrieval research trail (including every\nfailed attempt, honestly recorded) lives in a separate research repository and is not\npart of this package. See [PAPER.md §1](PAPER.md) for the full framing.\n\n---\n\n## Contributing & Community\n\n- How to contribute + research principles: [CONTRIBUTING.md](CONTRIBUTING.md)\n- Code of conduct: [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) · Security: [SECURITY.md](SECURITY.md)\n- Version history: [CHANGELOG.md](CHANGELOG.md) · Citation: [CITATION.cff](CITATION.cff)\n- License: **MIT** ([LICENSE](LICENSE))\n\n---\n\n*Principle: proof before code, formal definitions, falsifiability, and honest\nreporting of negative results — see [CONTRIBUTING.md](CONTRIBUTING.md).*\n\n<!-- mcp-name: io.github.ALEXaquarius/grounded-reasoning -->\n",
  "bytes": 26327,
  "sha": "63513d70066bcceb17f9b89fa78fefc99c39802b5eafea0d31d195e604b65a9d",
  "repo_slug": "alexaquarius/grounded-reasoning",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_alexaquarius_grounded_reasonin_8231cb17/readme"
}