Persistence in the context of data structures is divided into 4 different types. The particular code logic I implemented was a simple proof-of-concept for 'partial persistence'. For more information on the other three types - full, confluent, functional - please refer to details in Tarjan et. al. in [1].
In partial persistence, updates are always done on the latest version and time-travel only supports read-only queries on earlier versions back in time. In the following, we demonstrate an implementation of a persistent BST and the ability to "time-travel" back to earlier versions of itself.
See this zip file for the full implementation.
[1] Neil Sarnak, Robert E. Tarjan (1986). "Planar Point Location Using Persistent Search Trees" (PDF). Communications of the ACM. 29 (7): 669–679. doi:10.1145/6138.6151.
import persistent_tree
from persistent_tree import PersistentBST
def make_tree():
t = PersistentBST()
l = [ 'E', 'C', 'M', 'O', 'A', 'I', 'G', 'K', 'J' ]
for i, x in enumerate( l ):
print 'Inserting item %s in version %s' % ( x, i )
t.insert( x )
for ii, x in enumerate(['M', 'E', 'A']):
print 'Deleting item %s in version %s' % ( x, ii+i+1 )
t.delete( x )
return t
t = make_tree()
with persistent_tree.context( version=0 ):
t.print_tree_dot( 'Tree structure (version=0)\nInorder traversal : %s' % t.inorder_traverse() )
with persistent_tree.context( version=1 ):
t.print_tree_dot( 'Tree structure (version=1)\nInorder traversal : %s' % t.inorder_traverse() )
with persistent_tree.context( version=2 ):
t.print_tree_dot( 'Tree structure (version=2)\nInorder traversal : %s' % t.inorder_traverse() )
with persistent_tree.context( version=5 ):
t.print_tree_dot( 'Tree structure (version=5)\nInorder traversal : %s' % t.inorder_traverse(),
width=240, height=160 )
with persistent_tree.context( version=12):
t.print_tree_dot( 'Tree structure (version=12)\nInorder traversal : %s' % t.inorder_traverse(),
width=240, height=160 )