A flat segment tree over priorities: sample in .
Parameters
capacityintRaises
ValueErrorcapacity is not positive.Notes
Schaul et al. describe exactly this: "a 'sum-tree' data structure, where every node is the sum of its children, with the priorities as the leaf nodes, which can be efficiently updated and sampled from."
It is here rather than expressed with tensors because the obvious tensor formulation is a cumulative sum plus a search, and that is in the buffer rather than in it. Measured on this machine at a million leaves: the cumulative-sum form takes 196 ms to draw a batch of 32, the tree 0.20 ms — a factor of 973, against a training step of about 120 ms. The bottleneck is the algorithm, not the language, which is also why this is Python and not a new engine op: having fixed the complexity, a C++ tree would save a further 0.2% of a step.
Examples
>>> from lucid.utils.rollout import SumTree
>>> tree = SumTree(4)
>>> tree.set(0, 1.0)
>>> tree.set(3, 3.0)
>>> tree.total
4.0
>>> tree.find(0.5), tree.find(2.0)
(0, 3)Used by 1
Constructors
1Properties
1Instance methods
3The leaf whose cumulative range contains prefix.
Parameters
prefixfloat[0, total).Returns
intLeaf index. Descends the tree, so the cost is the depth.
Read one leaf.
Parameters
indexintReturns
floatIts priority.
Write one leaf and repair the sums above it.
Parameters
indexint[0, capacity).priorityfloatRaises
ValueError