Package: xanalogica.tumbler
=====================General Information=====================.. include:: <isonum.txt>.. sidebar:: A Brief Historical Note:subtitle: Is this software part of Project Xanadu\ |trade|?`Project Xanadu`_\ |trade| is a trademark and project of `Ted Nelson`_.This software is an independent derivation from the C source of the Xanadu\|trade| 88.1 version (renamed to `Udanax Green`_) of that project,simplified by taking advantage of the power of Python in representingtuples and infinite-precision integers.  Tumblers are a generally usefultool... _`Project Xanadu`: http://www.xanadu.com/.. _`Ted Nelson`: http://en.wikipedia.org/wiki/Ted_Nelson.. _`Udanax Green`: http://www.udanax.com/green/index.html.. contents::Setting Up for Development**************************::$ svn co https://www.taupro.com/pubsvn/Projects/Xanalogica/xanalogica.tumbler/trunk  xanalogica.tumbler$ cd xanalogica.tumbler$ python2.5 bootstrap.py$ bin/buildout$ bin/testAbstract********The xanalogica.tumbler package implements a basic one-dimensional coordinatetype for xanalogical storage systems.  It is useful as keys in mappings andB-trees, including xanalogical enfilades.  It is written purely in Python butthere are old versions written in C that may be resurrected as 'cTumbler' ifmore performance is needed... epigraph::Our Kingdom is already twice the size of Spain, and every day we driftmakes it bigger.-- The Kaiser in Werner Herzog's film, "Aguirre, The Wrath of God"Theory of Operation*******************Conceptual Overview===================A tumbler is an element of a coordinate system laid out along a number line,acting as forking multipart integers representing an unbounded, countable butfinite address space.  You've seen them in the numbering of an outline, asversioning notation or the Dewey Decimal System.  Mathematically they arerelated to a field of study called "transfinite arithmetic".Tumbler addressing is about storage management; the spontaneous creation ofplaces at which to put things, and to symbolically reference those locationsas individual points or ranges of points.Some are the advantages of tumblers are:1. There is always a tumbler between two different tumblers, so insertionsnever require renumbering.2. A set of tumblers can be ordered.3. The tumblers can be arranged to form a hierarchy, making it easy tospecify all tumblers that start with a shorter tumbler. This is used inthe Xanadu green system for queries like "all documents of thisuser". This is also useful for delegating assignment authority, in themanner of the Domain Name System (DNS) of the Internet.4. Arithmetic can be done with tumblers. Specifically addition andsubtraction, making it possible to compute ranges with tumblers... sidebar:: Whence Humbers?:subtitle: Leveraging Python in Providing Humungous NumbersIn Ted Nelson's book, **Literary Machines**, mention is made of Humbers,which stand for *humungous numbers*.  In the book they are used toefficiently represent integers of unbounded magnitudes, as digits within atumbler.  The Python language comes with a similar datatype called 'longs',which can represent such large integers.  And in Python 2.1 and later, thelanguage automatically converts traditional 'ints' to 'longs', as needed.Your Basic Tumbler==================Tumblers are implemented as a subclass of tuple, with certain arithmeticproperties of integers.  Being derived from tuples, tumblers are immutable.Representation--------------In Project Xanadu\|trade| tumblers are represented as a series of (unsigned)integers, separated by decimal points.  Since this syntax is not possible inthe native Python syntax, a choice of two forms is provided, either adotted-digits string, or a comma-delimited tuple.>>> from xanalogica.tumbler import Tumbler>>> Tumbler('1')Tumbler(1)>>> Tumbler('1.2')Tumbler(1,2)>>> Tumbler('1.2.3')Tumbler(1,2,3)>>> Tumbler("1.1.0.3.1.0.3")Tumbler(1,1,0,3,1,0,3)>>> Tumbler(1,1,0,3,1,0,3)Tumbler(1,1,0,3,1,0,3)>>> str(Tumbler(1,1,0,3,1,0,3))'1.1.0.3.1.0.3'>>> str(Tumbler('1'))'1'>>> str(Tumbler('1.2'))'1.2'>>> str(Tumbler('1.2.3'))'1.2.3'>>> Tumbler([1,2,3]) # accept a listTumbler(1,2,3)>>> Tumbler((1,2,3)) # accept a distinct tupleTumbler(1,2,3)>>> Tumbler(1,'a',2,3) # 0,'a',2 -> throw a TypeError exceptionTraceback (most recent call last):...TypeError: 'a' in (1, 'a', 2, 3) is not an integerThe Tumbler class behaves like other primitive types in Python, in thatconstructing one without a value results in a zero.>>> int()0>>> float()0.0>>> Tumbler()Tumbler(0)Kinds of Tumblers-----------------A tumbler can be of either of two kinds: an address along the number line or adifference between two such addresses.  Certain mathematical operations do notmake sense between the different kinds.Comparison of two tumblers for which is further to the right only makes sensefor address tumblers and not for difference tumblers.  Similarly, comparingtwo difference tumblers for"""Compare two tumblers.Note that you only compare address tumblers with other addresstumblers, and difference tumblers with difference tumblers.Comparing an address and a difference tumbler makes no mathematicalsense.A difference tumbler always begins with one or more leading zeros,except where it designates the entire docuverse, in which case itis 1.Every address tumblerstarts with a digit of 1, to permit referring to the entire docuverse.Comparison and Boolean Behavior-------------------------------Being conceptually laid out along a number line, tumblers can be compared toeach other.>>> Tumbler(1,2) < Tumbler(4,5,6)True>>> Tumbler(1,2,3) < Tumbler(4,5,6)True>>> Tumbler(4,5,6) > Tumbler(1,2,3)True>>> Tumbler(4,5,6) < Tumbler(1,2,3)False>>> Tumbler(1,2,3) == Tumbler(1,2,3)True>>> Tumbler(1,2,3) != Tumbler(1,2,4)TrueAnd they interact with Python's boolean mechanism as expected:>>> bool(Tumbler(1))  # a non-zero tumbler is trueTrue>>> bool(Tumbler(0)) # a zero tumbler is falseFalseSequence Behavior-----------------subscripting them returns a digit, slices return a tuple of their digitsTumbler Length-------------->>> len(Tumbler(1,2,3))3>>> len(Tumbler(1))1>>> len(Tumbler(0))1Tumbler Subscripting-------------------->>> Tumbler(1,2,3)[0]1>>> Tumbler(1,2,3)[1]2>>> Tumbler(1,2,3)[2]3>>> Tumbler(1,2,3)[-1]3>>> Tumbler(1,2,3)[-2]2>>> Tumbler(1,2,3)[-3]1>>> Tumbler(1,2,3)[1:](2, 3)Arithmetic Behavior-------------------they follow the numeric protocol of Python, for addition and subtractionto be coordinates rather than labels, operations can be performed on themTweak Digits------------>>> Tumbler(1,2,3).tweakdigit(-1, 1)Tumbler(1,3,3)>>> Tumbler(1,2,3).tweakdigit(-2, 1)Tumbler(2,2,3)>>> Tumbler(1,2,3).tweakdigit(-3, 1)Tumbler(1,2,4,1,2,3)>>> Tumbler(1,2,3).tweakdigit(0, 1)Tumbler(1,2,4)>>> Tumbler(1,2,3).tweakdigit(1, 1)Tumbler(1,2,3,1)>>> Tumbler(1,2,3).tweakdigit(2, 1)Tumbler(1,2,3,0,1)>>> Tumbler(0).tweakdigit(0, 1)Tumbler(1)>>> Tumbler(0).tweakdigit(0, 2)Tumbler(2)>>> Tumbler(0).tweakdigit(1, 1)Tumbler(0,1)Length Adjusts-------------->>> Tumbler(1,2,3).setlength(5)Tumbler(1,2,3,0,0)>>> Tumbler(1,2,3).setlength(4)Tumbler(1,2,3,0)>>> Tumbler(1,2,3).setlength(3)Tumbler(1,2,3)>>> Tumbler(1,2,3).setlength(2)Tumbler(1,2)>>> Tumbler(1,2,3).setlength(1)Tumbler(1)>>> isinstance(Tumbler(1,2,3).setlength(1), Tumbler)TrueAddress Tumblers================tumblers can be divided into two kinds; those that specify a position alongthe number line, called an Address Tumbler, and those representing the resultof subtracting two such positions, called Difference Tumblers.I defined a couple of subclasses to constrain the arithmetic operations tothose that have meaning.Default Value------------->>> from xanalogica.tumbler import AddrTumbler, DiffTumbler>>> str(AddrTumbler())'0'Parsing and Formatting---------------------->>> repr(AddrTumbler('1'))'AddrTumbler(1)'>>> repr(AddrTumbler('1.2'))'AddrTumbler(1,2)'>>> repr(AddrTumbler('1.2.3'))'AddrTumbler(1,2,3)'>>> str(AddrTumbler('1'))'1'>>> str(AddrTumbler('1.2'))'1.2'>>> str(AddrTumbler('1.2.3'))'1.2.3'Length Adjust------------->>> isinstance(AddrTumbler(1,2,3).setlength(1), AddrTumbler)TrueAddition-------->>> AddrTumbler(1,2,3) + DiffTumbler(0)AddrTumbler(1,2,3)>>> AddrTumbler(1,2,3) + DiffTumbler(0,1)AddrTumbler(1,3)>>> AddrTumbler(1,2,3) + DiffTumbler(0,1,2)AddrTumbler(1,3,2)>>> AddrTumbler(1,2,3) + DiffTumbler(0,1,2,3)AddrTumbler(1,3,2,3)>>> AddrTumbler(1,2,3) + DiffTumbler(0,1,2,3,4)AddrTumbler(1,3,2,3,4)>>> isinstance(AddrTumbler(1,2,3) + DiffTumbler(0,1,2,3,4), AddrTumbler)True>>> try:...     AddrTumbler(1,2,3) + Tumbler(4)... except TypeError, exc:...     print excTumbler(4) is not a DiffTumbler..## def test():##     return AddrTumbler(1,2,3) + AddrTumbler(4)## self.failUnlessRaises(TypeError, test)>>> AddrTumbler(1,2,3) + DiffTumbler(0,0,0)AddrTumbler(1,2,3)>>> AddrTumbler(1,2,3) + DiffTumbler(0,0,1)AddrTumbler(1,2,4)Subtraction-----------..self.failUnless(AddrTumbler(1,2,3) - AddrTumbler(1,1)     == DiffTumbler(0,1,3))self.failUnless(AddrTumbler(1,2,3) - AddrTumbler(1,1,1)   == DiffTumbler(0,1,3))self.failUnless(AddrTumbler(1,2,3) - AddrTumbler(1,1,1,1) == DiffTumbler(0,1,3))self.failUnless(AddrTumbler(1,2,3) - AddrTumbler(0,0,0)   == DiffTumbler(1,2,3))self.failUnless(AddrTumbler(1,2,3) - AddrTumbler(0,0,1)   == DiffTumbler(1,2,3))self.failUnless(isinstance(AddrTumbler(1,2,3) - AddrTumbler(0,0,1), DiffTumbler))## def test():##     AddrTumbler(1,2,3) - DiffTumbler(1,1)## self.failUnlessRaises(TypeError, test)IntDiff-------..self.failUnless(AddrTumbler(1,2,3).intdiff(AddrTumbler(1,2,3)) == 0)self.failUnless(AddrTumbler(1,2,3).intdiff(AddrTumbler(1,2,4)) == 1)self.failUnless(AddrTumbler(1,2,3,4).intdiff(AddrTumbler(1,2,4)) == 1)Classification--------------..self.failUnless(AddrTumbler(1,2,3).isaNodeAddress())self.failUnless(not AddrTumbler(1,2,3,0,4,5,6).isaNodeAddress())self.failUnless(AddrTumbler(1,2,3,0,4,5,6).isaAccountAddress())self.failUnless(not AddrTumbler(1,2,3).isaAccountAddress())self.failUnless(not AddrTumbler(1,2,3,0,4,5,6,0,7,8,9).isaAccountAddress())self.failUnless(not AddrTumbler(1,2,3,0,4,5,6).isaDocumentAddress())self.failUnless(not AddrTumbler(1,2,3).isaDocumentAddress())self.failUnless(AddrTumbler(1,2,3,0,4,5,6,0,7,8,9).isaDocumentAddress())self.failUnless(not AddrTumbler(1,2,3,0,4,5,6).isaAtomAddress())self.failUnless(not AddrTumbler(1,2,3).isaAtomAddress())self.failUnless(not AddrTumbler(1,2,3,0,4,5,6,0,7,8,9).isaAtomAddress())self.failUnless(AddrTumbler(1,2,3,0,4,5,6,0,7,8,9,0,1,35).isaAtomAddress())Relational Comparison---------------------..## def test():##     AddrTumbler(1,2) < DiffTumbler(0,1) # Non-Comparable Types## self.failUnlessRaises(TypeError, test)Difference Tumblers===================Default Value-------------..self.failUnless(str(DiffTumbler()) == '0')Parsing and Formatting----------------------..self.failUnless(repr(DiffTumbler('1'))      == 'DiffTumbler(1)')self.failUnless(repr(DiffTumbler('1.2'))    == 'DiffTumbler(1,2)')self.failUnless(repr(DiffTumbler('1.2.3'))  == 'DiffTumbler(1,2,3)')self.failUnless(str(DiffTumbler('1'))       == '1')self.failUnless(str(DiffTumbler('1.2'))     == '1.2')self.failUnless(str(DiffTumbler('1.2.3'))   == '1.2.3')Addition--------..## def test():##     DiffTumbler(1,2,3) + DiffTumbler(1,1)## self.failUnlessRaises(TypeError, test)## def test():##     DiffTumbler(1,2,3) + AddrTumbler(1,1)## self.failUnlessRaises(TypeError, test)## def test():##     DiffTumbler(1,2,3) + Tumbler(1,1)## self.failUnlessRaises(TypeError, test)Subtraction-----------..## def test():##     DiffTumbler(1,2,3) - DiffTumbler(1,1)## self.failUnlessRaises(TypeError, test)## def test():##     DiffTumbler(1,2,3) - AddrTumbler(1,1)## self.failUnlessRaises(TypeError, test)## def test():##     DiffTumbler(1,2,3) - Tumbler(1,1)## self.failUnlessRaises(TypeError, test)Relational Comparison---------------------..## def test():##     AddrTumbler(1,2) < DiffTumbler(0,1) # Non-Comparable Types## self.failUnlessRaises(TypeError, test)Span Arithmetic---------------..# def test_001_span_parsing_and_formatting(self):#     pass#        self.failUnless(repr(Span(AddrTumbler(1,2,3), DiffTumbler(1))) == 'Span((1,2,3), (1)')#        self.failUnless(repr(DiffTumbler('1.2'))    == 'DiffTumbler(1,2)')#        self.failUnless(repr(DiffTumbler('1.2.3'))  == 'DiffTumbler(1,2,3)')#        self.failUnless(str(DiffTumbler('1'))       == '1')#        self.failUnless(str(DiffTumbler('1.2'))     == '1.2')#        self.failUnless(str(DiffTumbler('1.2.3'))   == '1.2.3')# def test_002_span_inrange(self):#     self.failUnless(AddrTumbler(1,2,2) not in Span(AddrTumbler(1,2,3), DiffTumbler(0,0,5)))#     self.failUnless(AddrTumbler(1,2,3)     in Span(AddrTumbler(1,2,3), DiffTumbler(0,0,5)))#     self.failUnless(AddrTumbler(1,2,4)     in Span(AddrTumbler(1,2,3), DiffTumbler(0,0,5)))#     self.failUnless(AddrTumbler(1,2,5) not in Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)))#     self.failUnless(AddrTumbler(1,2,6) not in Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)))# def test_003_span_relational_compare_LT(self):#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,1,1))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,2))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,3))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,4))#     self.failUnless(    Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,5))#     self.failUnless(    Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,6))#     self.failUnless(    Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) <  AddrTumbler(1,2,7))# def test_004_span_relational_compare_GT(self):#     self.failUnless(    Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,1,1))#     self.failUnless(    Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,2))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,3))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,4))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,5))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,6))#     self.failUnless(not Span(AddrTumbler(1,2,3), DiffTumbler(0,0,2)) >  AddrTumbler(1,2,7))Basic Theory============About tumblers...Arithmetic Operations=====================>>> print 55>>> 5 == 4Falseentire docuverse placed between 1 and 2all differences placed between 0 and 1zero digits separate URI fieldsfour URI fields: server/user/document/versionallows for delegation of numbering to independent entitiesallows to range specifiers to encompass sections of the number lineThe tumbler has two primary functions: to represent addresses in the docuverseand to represent *spans* of addresses.  A span is represented by a pair oftumblers, either a pair of address tumblers or an address and differencetumbler.To-Do List*********** support comparison of tumbler to span* support comparison of span to tumbler* provide a tumbler-to-int converter that raises an exception if not possible __int__* how to reconcile addition with concatenation* study os.path and create equivalents for tumblers* AddrTumbler attributes: .node  .account  .document  .atom  .atomtype  .atomsuffix* consider: summation of spans creates a spec/vspec/sporgl/???Changes*******0.1 (2008-09-14)================Features Added--------------Initial check-in for new Python egg/buildout distribution methology.Download********All packaged distributions can be found on the package `home page`_ inthe Python Package Index.  Scroll to the very bottom of the page to findthe links.  In addition to these PyPI downloads, the developmentversions are available from the Tau Productions Inc. `public Subversionrepository`_... _`home page`: http://pypi.python.org/pypi/xanalogica.tumbler.. _`public Subversion repository`: https://www.taupro.com/pubsvn/Projects/Xanalogica/xanalogica.tumbler/trunk/#egg=xanalogica.tumbler-dev