Skip to content

Topic tree

The topic tree groups memories by embedding similarity. An insert follows one path to a leaf. Background jobs split, merge, or rebalance leaves as their contents change.

One insert, one path. The memory takes the closest centroid at each level, and a tie goes to the smaller topic_key. The same tree answers a query by keeping several children per level.

Each topic keeps a compact summary of its member vectors. The CF triplet stores the count, the vector sum, and the sum of squared lengths:

CF⁡=(n,LS,SS),LS=∑i=1nxi,SS=∑i=1n∥xi∥2\begin{aligned} \operatorname{CF} &= (n, \mathbf{LS}, SS), \\ \mathbf{LS} &= \sum_{i=1}^{n} \mathbf{x}_i, \\ SS &= \sum_{i=1}^{n} \lVert \mathbf{x}_i \rVert^2 \end{aligned}

CF stands for clustering feature. It is a compact summary of a group of vectors:

  • n is the number of members.
  • LS is their vector sum.
  • SS is the sum of their squared lengths.

The tree derives the centroid as LS divided by n, and the radius from SS and LS. It stores this summary instead of every member, so a topic takes little space and an update is fast.

The tree calculates the centroid and radius from this summary. Insert routing compares a memory with the children of its current topic and follows the closest child. A tie goes to the smaller topic key.

A split is the only way a new topic appears. The children must each be big enough and together be cleaner than the parent, or the topic stays as it is. Child keys are hashes of the canonical vectors, never memory ids.

The default leaf limit is 128 memories. A write beyond that limit queues a split job. The job divides members around two distant seeds. It accepts the split only when both groups meet the minimum size and improve the combined weighted radius.

If a split is rejected, the leaf stays in use. After the leaf exceeds the hard limit, which defaults to 512, a later attempt forces the split even if it fails those checks.

An underfilled leaf gets members back. Borrowing takes only what the leaf needs. A merge has to keep the result under the budget, so two small leaves can join and a nearly full one cannot.

When a leaf falls below the default minimum of 32, the tree first tries to borrow from a larger sibling. If borrowing cannot fill it, the tree can merge it with a nearby sibling when the combined leaf stays within the limit.

Rebalancing can move a borderline memory from a much larger sibling when the move preserves or improves the radii. Dimple never moves a manual_lock membership automatically.