Skip to main content

poincare-memory

Hierarchy-aware, time-aware memory for LLM agents and RAG, on the Poincaré ball.

CI PyPI License Paper

poincare-memory is the official open-source reference implementation of the geometry-aware memory component of

D. Mojila, "LLM Orchestration with Geometry-Aware Memory," 2026 2nd International Conference on Big Data & Machine Learning (ICBDML), Bhopal, India, Feb. 2026, pp. 1–7. doi:10.1109/ICBDML68582.2026.11544690

Vector stores treat every memory as a point in flat space, so a taxonomy of a few thousand concepts ends up crowded and shapeless. Hyperbolic space has exponentially more room near its boundary, which is exactly the shape of a hierarchy: this library puts each memory in the Poincaré ball with its direction from the text embedding and its depth from its place in the hierarchy, weights it by age at query time, and lets you see all of it.

Provenance. This package was written after the paper, from the paper's description and the primary literature. The system used for the paper's experiments is not released, and the numbers in this repository's benchmarks come only from the code here.

Interactive inspector: Poincaré disk, time slider, table and tree views

Install

pip install poincare-memory                 # NumPy only
pip install "poincare-memory[embed]"        # + sentence-transformers embedder
pip install "poincare-memory[viz,pandas]"   # + matplotlib plot, DataFrame export

Python ≥ 3.10. No GPU, no services.

Thirty seconds

from datetime import datetime, timedelta, timezone
from poincare_memory import Memory, HalfLife

mem = Memory(decay=HalfLife(hours=24 * 30))  # memories lose weight with a 30-day half-life

body = mem.add("Human musculoskeletal system")
lower = mem.add("Lower limb musculature", parent=body)
hams = mem.add("Hamstring group: knee flexion and hip extension", parent=lower)
bf = mem.add("Biceps femoris: lateral hamstring", parent=hams)
mem.add(
    "Athlete A reported tight hamstrings after 400 m repeats",
    parent=hams,
    t=datetime.now(timezone.utc) - timedelta(days=30),
)
mem.add(
    "Athlete A: flexibility improved after two weeks of eccentric work",
    parent=hams,
    t=datetime.now(timezone.utc) - timedelta(days=3),
)

for r in mem.search("hamstring tightness", k=3):
    print(f"{r.score:6.2f}  depth={r.depth:.1f}  w={r.time_weight:.2f}  {r.text}")

mem.search("knee", mode="subtree", root=lower)  # only the lower-limb branch
mem.search(mode="ancestors", root=bf)  # hams → lower → body
mem.inspect("memory.html", open_browser=True)  # disk + table + tree, offline, self-contained
mem.save("memory.db")  # SQLite; Memory.load("memory.db")

The default embedder is a deterministic hashing embedder so everything runs offline; pass embedder=SentenceTransformerEmbedder() or any callable for real semantics.

What you get

Need How
Hierarchy encoded in geometry depth = hyperbolic distance from the origin; children sit at depth_step beyond their parent, pulled toward its direction by inherit
Structural retrieval mode="subtree" / "children" / "ancestors" / "siblings" and mode="cone" (entailment cones, Ganea et al. 2018)
Temporal weighting named policies: HalfLife, Ebbinghaus (access-strengthened), ValidityWindow, Product; evaluate at any at_time
Visual inspection mem.inspect() → one HTML file with an interactive Poincaré disk, a sortable table and a collapsible tree; mem.plot() for matplotlib; mem.tree() / mem.table() / mem.to_dataframe() in the terminal; Jupyter renders mem inline
Exact tree embedding sarkar_layout(edges): Sarkar's training-free construction (2-D exact, n-D spread) with a float64 safety check
Learned embeddings fit_poincare_embeddings(closure): Riemannian SGD (Nickel & Kiela 2017) in NumPy, plus a Euclidean twin for fair baselines, and reconstruction() (MAP, mean rank)
Any vector database to_lorentz + to_mips_vectors turn hyperbolic nearest-neighbour search into a plain dot-product query
Persistence save() / load() to a single SQLite file; to_json() / from_json() for portability
Scale build_index() with NumPy or FAISS; add_many() embeds in one batch; update(), stats(); thread-safe

How scoring works (and why not raw hyperbolic distance)

search ranks by -distance + depth_bias * depth + time_coef * log(time_weight).

By default distance is measured on a reference shell: the query and the memory are both moved to the root depth and the hyperbolic distance between them measures semantic mismatch in hyperbolic units, comparable across levels. The raw distance to a memory's real point (metric="hyperbolic") is also available, but be aware of the geometry: a root at depth 1 is close to everything, and a leaf at depth 3 only beats it when the query's direction is within roughly 25° of the leaf's. With off-the-shelf text embeddings that almost never happens, so raw hyperbolic distance degenerates into "return the most general memory". The shell metric keeps semantics in charge and leaves generality versus specificity to depth_bias and to the structural modes, which is where hyperbolic geometry earns its keep. Use metric="hyperbolic" with embedders that are themselves hyperbolic (for example Hierarchy Transformers).

Mapping to the paper

Paper (Section III–IV) Here
Poincaré ball, metric tensor, distance (eq. 1–3) PoincareBall.distance, distance_arcosh, conformal_factor
Structured knowledge representation with hierarchy Memory.add(parent=…), sarkar_layout, fit_poincare_embeddings
Temporal context management, time-weighted embeddings temporal.HalfLife / Ebbinghaus / ValidityWindow, search(at_time=…)
Efficient retrieval over hierarchical structure search(mode=…), entailment cones, Lorentz dot-product trick
Cross-domain integration in one geometric space one ball, many roots: Memory.roots()

The metacognitive controller, provider-agnostic ensemble and response synthesis of the paper live in the companion package poincare-orchestra.

Benchmarks

benchmarks/wordnet_reconstruction.py reproduces the classic WordNet reconstruction protocol (transitive closure, MAP and mean rank) for Poincaré versus Euclidean embeddings at equal dimension, with this library's NumPy trainer. On the mammal.n.01 subtree (1,170 nodes, 200 epochs, 2026-10-10):

dim Poincaré MAP Euclidean MAP
2 0.779 0.533
5 0.975 0.802
10 0.957 0.837

WordNet mammals reconstruction MAP, Poincaré vs Euclidean

Full table, environment and raw JSON in benchmarks/README.md; run it yourself with pip install "poincare-memory[bench]".

Documentation

Full docs at https://dhruvmojila.github.io/poincare-memory (getting started, concepts, guides, API, FAQ). Every code example in the docs is executed in CI.

Command line

poincare-memory demo -o demo --open    # build the anatomy demo, save demo.db, open demo.html
poincare-memory inspect memory.db      # write memory.html
poincare-memory tree memory.db
poincare-memory search memory.db "calf strain" -k 5 --mode subtree --root lower
poincare-memory stats memory.db
poincare-memory export memory.db memory.json

Citing

If you use this library, please cite the paper (and, for the software itself, the Zenodo release in CITATION.cff):

@inproceedings{mojila2026llmorchestration,
  author    = {Mojila, Dhruv},
  title     = {{LLM} Orchestration with Geometry-Aware Memory},
  booktitle = {2026 2nd International Conference on Big Data \& Machine Learning (ICBDML)},
  year      = {2026},
  pages     = {1--7},
  publisher = {IEEE},
  address   = {Bhopal, India},
  doi       = {10.1109/ICBDML68582.2026.11544690}
}

Development

git clone https://github.com/dhruvmojila/poincare-memory && cd poincare-memory
uv venv && uv pip install -e ".[dev,viz,pandas]"
pytest            # property-based geometry tests + store tests
ruff check . && mypy
mkdocs serve      # docs

Clean-room note for contributors: implement from the papers cited in the docstrings. Several canonical hyperbolic-embedding repositories are unlicensed or non-commercial; do not copy from them.

Licence

Apache-2.0. © 2026 Dhruv Mojila.

Metadata

Release files for poincare-memory 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for poincare-memory 0.1.1
File Size Uploaded Provenance
poincare_memory-0.1.1.tar.gz 56.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for poincare-memory 0.1.1
File Interpreter ABI Platform
poincare_memory-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 115.6 kB

Release files / poincare_memory-0.1.1.tar.gz

Download URL poincare_memory-0.1.1.tar.gz
Size 56.6 kB
Tags Source
SHA-256 checksum
How to use checksums
a37ce396aa18b5ac89ab5645251b80ff87e7aee85e253eb0fda62649bd5cfe8b
BLAKE2b-256 checksum
How to use checksums
7aa580fc9dfd4453d843f8587c5462107894051a6fb0fc9e6813840f0d882416
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Release files / poincare_memory-0.1.1-py3-none-any.whl

Download URL poincare_memory-0.1.1-py3-none-any.whl
Size 59.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
684e2797c13a23f132b854a924962e63a8cafd81ad205656affd954b45b0564b
BLAKE2b-256 checksum
How to use checksums
a28a63e276cd2c8d4c9d7ef984a2ba540a56328873bffc39f32e3c5b5e786aa7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

Security for poincare-memory 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for poincare_memory-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 22, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page