HeapDict-1.0.0/0000755000175500010010000000000011266111517012253 5ustar AgthorrNoneHeapDict-1.0.0/ez_setup.py0000644000175500010010000002276411164233725014501 0ustar AgthorrNone#!python """Bootstrap setuptools installation If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: from ez_setup import use_setuptools use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying the appropriate options to ``use_setuptools()``. This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c9" DEFAULT_URL = "http://pypi.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', 'setuptools-0.6c4-py2.3.egg': 'b0b9131acab32022bfac7f44c5d7971f', 'setuptools-0.6c4-py2.4.egg': '2a1f9656d4fbf3c97bf946c0a124e6e2', 'setuptools-0.6c4-py2.5.egg': '8f5a052e32cdb9c72bcf4b5526f28afc', 'setuptools-0.6c5-py2.3.egg': 'ee9fd80965da04f2f3e6b3576e9d8167', 'setuptools-0.6c5-py2.4.egg': 'afe2adf1c01701ee841761f5bcd8aa64', 'setuptools-0.6c5-py2.5.egg': 'a8d3f61494ccaa8714dfed37bccd3d5d', 'setuptools-0.6c6-py2.3.egg': '35686b78116a668847237b69d549ec20', 'setuptools-0.6c6-py2.4.egg': '3c56af57be3225019260a644430065ab', 'setuptools-0.6c6-py2.5.egg': 'b2f8a7520709a5b34f80946de5f02f53', 'setuptools-0.6c7-py2.3.egg': '209fdf9adc3a615e5115b725658e13e2', 'setuptools-0.6c7-py2.4.egg': '5a8f954807d46a0fb67cf1f26c55a82e', 'setuptools-0.6c7-py2.5.egg': '45d2ad28f9750e7434111fde831e8372', 'setuptools-0.6c8-py2.3.egg': '50759d29b349db8cfd807ba8303f1902', 'setuptools-0.6c8-py2.4.egg': 'cba38d74f7d483c06e9daa6070cce6de', 'setuptools-0.6c8-py2.5.egg': '1721747ee329dc150590a58b3e1ac95b', 'setuptools-0.6c9-py2.3.egg': 'a83c4020414807b496e4cfbe08507c03', 'setuptools-0.6c9-py2.4.egg': '260a2be2e5388d66bdaee06abec6342a', 'setuptools-0.6c9-py2.5.egg': 'fe67c3e5a17b12c0e7c541b7ea43a8e6', 'setuptools-0.6c9-py2.6.egg': 'ca37b1ff16fa2ede6e19383e7b59245a', } import sys, os try: from hashlib import md5 except ImportError: from md5 import md5 def _validate_md5(egg_name, data): if egg_name in md5_data: digest = md5(data).hexdigest() if digest != md5_data[egg_name]: print >>sys.stderr, ( "md5 validation of %s failed! (Possible download problem?)" % egg_name ) sys.exit(2) return data def use_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, download_delay=15 ): """Automatically find/download setuptools and make it available on sys.path `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where setuptools will be downloaded, if it is not already available. If `download_delay` is specified, it should be the number of seconds that will be paused before initiating a download, should one be required. If an older version of setuptools is installed, this routine will print a message to ``sys.stderr`` and raise SystemExit in an attempt to abort the calling script. """ was_imported = 'pkg_resources' in sys.modules or 'setuptools' in sys.modules def do_download(): egg = download_setuptools(version, download_base, to_dir, download_delay) sys.path.insert(0, egg) import setuptools; setuptools.bootstrap_install_from = egg try: import pkg_resources except ImportError: return do_download() try: pkg_resources.require("setuptools>="+version); return except pkg_resources.VersionConflict, e: if was_imported: print >>sys.stderr, ( "The required version of setuptools (>=%s) is not available, and\n" "can't be installed while this script is running. Please install\n" " a more recent version first, using 'easy_install -U setuptools'." "\n\n(Currently using %r)" ) % (version, e.args[0]) sys.exit(2) else: del pkg_resources, sys.modules['pkg_resources'] # reload ok return do_download() except pkg_resources.DistributionNotFound: return do_download() def download_setuptools( version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, delay = 15 ): """Download setuptools from a specified location and return its filename `version` should be a valid setuptools version number that is available as an egg for download under the `download_base` URL (which should end with a '/'). `to_dir` is the directory where the egg will be downloaded. `delay` is the number of seconds to pause before an actual download attempt. """ import urllib2, shutil egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) url = download_base + egg_name saveto = os.path.join(to_dir, egg_name) src = dst = None if not os.path.exists(saveto): # Avoid repeated downloads try: from distutils import log if delay: log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. (Note: if this machine does not have network access, please obtain the file %s and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", version, download_base, delay, url ); from time import sleep; sleep(delay) log.warn("Downloading %s", url) src = urllib2.urlopen(url) # Read/write all in one block, so we don't create a corrupt file # if the download is interrupted. data = _validate_md5(egg_name, src.read()) dst = open(saveto,"wb"); dst.write(data) finally: if src: src.close() if dst: dst.close() return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): """Install or upgrade setuptools and EasyInstall""" try: import setuptools except ImportError: egg = None try: egg = download_setuptools(version, delay=0) sys.path.insert(0,egg) from setuptools.command.easy_install import main return main(list(argv)+[egg]) # we're done here finally: if egg and os.path.exists(egg): os.unlink(egg) else: if setuptools.__version__ == '0.0.1': print >>sys.stderr, ( "You have an obsolete version of setuptools installed. Please\n" "remove it from your system entirely before rerunning this script." ) sys.exit(2) req = "setuptools>="+version import pkg_resources try: pkg_resources.require(req) except pkg_resources.VersionConflict: try: from setuptools.command.easy_install import main except ImportError: from easy_install import main main(list(argv)+[download_setuptools(delay=0)]) sys.exit(0) # try to force an exit else: if argv: from setuptools.command.easy_install import main main(argv) else: print "Setuptools version",version,"or greater has been installed." print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): """Update our built-in md5 registry""" import re for name in filenames: base = os.path.basename(name) f = open(name,'rb') md5_data[base] = md5(f.read()).hexdigest() f.close() data = [" %r: %r,\n" % it for it in md5_data.items()] data.sort() repl = "".join(data) import inspect srcfile = inspect.getsourcefile(sys.modules[__name__]) f = open(srcfile, 'rb'); src = f.read(); f.close() match = re.search("\nmd5_data = {\n([^}]+)}", src) if not match: print >>sys.stderr, "Internal error!" sys.exit(2) src = src[:match.start(1)] + repl + src[match.end(1):] f = open(srcfile,'w') f.write(src) f.close() if __name__=='__main__': if len(sys.argv)>2 and sys.argv[1]=='--md5update': update_md5(sys.argv[2:]) else: main(sys.argv[1:]) HeapDict-1.0.0/HeapDict.egg-info/0000755000175500010010000000000011266111517015426 5ustar AgthorrNoneHeapDict-1.0.0/HeapDict.egg-info/dependency_links.txt0000644000175500010010000000000111266111517021474 0ustar AgthorrNone HeapDict-1.0.0/HeapDict.egg-info/PKG-INFO0000644000175500010010000000413511266111517016526 0ustar AgthorrNoneMetadata-Version: 1.1 Name: HeapDict Version: 1.0.0 Summary: a heap with decrease-key and increase-key operations Home-page: http://stutzbachenterprises.com/ Author: Stutzbach Enterprises, LLC Author-email: daniel@stutzbachenterprises.com License: BSD Description: heapdict: a heap with decreased-key and increase-key operations =============================================================== heapdict implements the MutableMapping ABC, meaning it works pretty much like a regular Python dict. It's designed to be used as a priority queue, where items are added and consumed as follows: :: hd = heapdict() hd[obj1] = priority1 hd[obj2] = priority2 # ... obj = hd.pop() Compared to an ordinary dict, a heapdict has the following differences: popitem(): Remove and return the (key, priority) pair with the lowest priority, instead of a random object. peekitem(): Return the (key, priority) pair with the lowest priority, without removing it. Unlike the Python standard library's heapq module, the heapdict supports efficiently changing the priority of an existing object (often called "decrease-key" in textbooks). Altering the priority is important for many algorithms such as Dijkstra's Algorithm and A*. Keywords: heap decrease-key increase-key dictionary Dijkstra A* priority queue Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: OS Independent Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Provides: heapdict HeapDict-1.0.0/HeapDict.egg-info/SOURCES.txt0000644000175500010010000000040511266111517017311 0ustar AgthorrNoneLICENSE MANIFEST.in README.rst ez_setup.py heapdict.py setup.py test_heap.py HeapDict.egg-info/PKG-INFO HeapDict.egg-info/SOURCES.txt HeapDict.egg-info/dependency_links.txt HeapDict.egg-info/top_level.txt HeapDict.egg-info/zip-safe heapdict.egg-info/SOURCES.txtHeapDict-1.0.0/HeapDict.egg-info/top_level.txt0000644000175500010010000000001111266111517020150 0ustar AgthorrNoneheapdict HeapDict-1.0.0/HeapDict.egg-info/zip-safe0000644000175500010010000000000111164736507017067 0ustar AgthorrNone HeapDict-1.0.0/heapdict.py0000644000175500010010000000542411266104302014405 0ustar AgthorrNoneimport collections def doc(s): if hasattr(s, '__call__'): s = s.__doc__ def f(g): g.__doc__ = s return g return f class heapdict(collections.MutableMapping): __marker = object() @staticmethod def _parent(i): return ((i - 1) >> 1) @staticmethod def _left(i): return ((i << 1) + 1) @staticmethod def _right(i): return ((i+1) << 1) def __init__(self, *args, **kw): self.heap = [] self.d = {} self.update(*args, **kw) @doc(dict.clear) def clear(self): self.heap.clear() self.d.clear() @doc(dict.__setitem__) def __setitem__(self, key, value): if key in self.d: self.pop(key) wrapper = [value, key, len(self)] self.d[key] = wrapper self.heap.append(wrapper) self._decrease_key(len(self.heap)-1) def _min_heapify(self, i): l = self._left(i) r = self._right(i) n = len(self.heap) if l < n and self.heap[l][0] < self.heap[i][0]: low = l else: low = i if r < n and self.heap[r][0] < self.heap[low][0]: low = r if low != i: self._swap(i, low) self._min_heapify(low) def _decrease_key(self, i): while i: parent = self._parent(i) if self.heap[parent][0] < self.heap[i][0]: break self._swap(i, parent) i = parent def _swap(self, i, j): self.heap[i], self.heap[j] = self.heap[j], self.heap[i] self.heap[i][2] = i self.heap[j][2] = j @doc(dict.__delitem__) def __delitem__(self, key): wrapper = self.d[key] while wrapper[2]: parentpos = self._parent(wrapper[2]) parent = self.heap[parentpos] self._swap(wrapper[2], parent[2]) self.popitem() @doc(dict.__getitem__) def __getitem__(self, key): return self.d[key][0] @doc(dict.__iter__) def __iter__(self): return iter(self.d) def popitem(self): """D.popitem() -> (k, v), remove and return the (key, value) pair with lowest\nvalue; but raise KeyError if D is empty.""" wrapper = self.heap[0] if len(self.heap) == 1: self.heap.pop() else: self.heap[0] = self.heap.pop(-1) self.heap[0][2] = 0 self._min_heapify(0) del self.d[wrapper[1]] return wrapper[1], wrapper[0] @doc(dict.__len__) def __len__(self): return len(self.d) def peekitem(self): """D.peekitem() -> (k, v), return the (key, value) pair with lowest value;\n but raise KeyError if D is empty.""" return (self.heap[0][1], self.heap[0][0]) del doc __all__ = ['heapdict'] HeapDict-1.0.0/LICENSE0000644000175500010010000000265311164745516013277 0ustar AgthorrNoneCopyright 2009 Stutzbach Enterprises, LLC (daniel@stutzbachenterprises.com) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. HeapDict-1.0.0/MANIFEST.in0000644000175500010010000000016111266100232013777 0ustar AgthorrNoneinclude heapdict.py include ez_setup.py include LICENSE include test_heap.py include setup.py include README.rst HeapDict-1.0.0/PKG-INFO0000644000175500010010000000413511266111517013353 0ustar AgthorrNoneMetadata-Version: 1.1 Name: HeapDict Version: 1.0.0 Summary: a heap with decrease-key and increase-key operations Home-page: http://stutzbachenterprises.com/ Author: Stutzbach Enterprises, LLC Author-email: daniel@stutzbachenterprises.com License: BSD Description: heapdict: a heap with decreased-key and increase-key operations =============================================================== heapdict implements the MutableMapping ABC, meaning it works pretty much like a regular Python dict. It's designed to be used as a priority queue, where items are added and consumed as follows: :: hd = heapdict() hd[obj1] = priority1 hd[obj2] = priority2 # ... obj = hd.pop() Compared to an ordinary dict, a heapdict has the following differences: popitem(): Remove and return the (key, priority) pair with the lowest priority, instead of a random object. peekitem(): Return the (key, priority) pair with the lowest priority, without removing it. Unlike the Python standard library's heapq module, the heapdict supports efficiently changing the priority of an existing object (often called "decrease-key" in textbooks). Altering the priority is important for many algorithms such as Dijkstra's Algorithm and A*. Keywords: heap decrease-key increase-key dictionary Dijkstra A* priority queue Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: OS Independent Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Topic :: Software Development :: Libraries :: Python Modules Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.0 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Provides: heapdict HeapDict-1.0.0/README.rst0000644000175500010010000000173211266111464013746 0ustar AgthorrNoneheapdict: a heap with decreased-key and increase-key operations =============================================================== heapdict implements the MutableMapping ABC, meaning it works pretty much like a regular Python dict. It's designed to be used as a priority queue, where items are added and consumed as follows: :: hd = heapdict() hd[obj1] = priority1 hd[obj2] = priority2 # ... obj = hd.pop() Compared to an ordinary dict, a heapdict has the following differences: popitem(): Remove and return the (key, priority) pair with the lowest priority, instead of a random object. peekitem(): Return the (key, priority) pair with the lowest priority, without removing it. Unlike the Python standard library's heapq module, the heapdict supports efficiently changing the priority of an existing object (often called "decrease-key" in textbooks). Altering the priority is important for many algorithms such as Dijkstra's Algorithm and A*. HeapDict-1.0.0/setup.cfg0000644000175500010010000000007311266111517014074 0ustar AgthorrNone[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 HeapDict-1.0.0/setup.py0000644000175500010010000000255211266111464013772 0ustar AgthorrNone#!/usr/bin/env import sys if sys.version_info[0] <= 2: import ez_setup ez_setup.use_setuptools() from setuptools import setup, Extension else: from distutils.core import setup, Extension setup(name='HeapDict', version='1.0.0', description='a heap with decrease-key and increase-key operations', author='Stutzbach Enterprises, LLC', author_email='daniel@stutzbachenterprises.com', url='http://stutzbachenterprises.com/', license = "BSD", keywords = "heap decrease-key increase-key dictionary Dijkstra A* priority queue", provides = ['heapdict'], py_modules = ['heapdict'], test_suite = "test_heap", zip_safe = True, classifiers = [ 'Development Status :: 5 - Production/Stable', 'Operating System :: OS Independent', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Topic :: Software Development :: Libraries :: Python Modules', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.0', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', ], long_description=open('README.rst').read(), ) HeapDict-1.0.0/test_heap.py0000755000175500010010000000604711266106664014622 0ustar AgthorrNone#!/usr/bin/python from __future__ import print_function from heapdict import heapdict import random import unittest import sys try: import test.support as test_support # Python 3 except ImportError: import test.test_support as test_support # Python 2 N = 100 class TestHeap(unittest.TestCase): def check_invariants(self, h): for i in range(len(h)): self.assertEqual(h.heap[i][2], i) if i > 0: self.assertTrue(h.heap[h._parent(i)][0] <= h.heap[i][0]) def make_data(self): pairs = [(random.random(), random.random()) for i in range(N)] h = heapdict() d = {} for k, v in pairs: h[k] = v d[k] = v pairs.sort(key=lambda x: x[1], reverse=True) return h, pairs, d def test_popitem(self): h, pairs, d = self.make_data() while pairs: v = h.popitem() v2 = pairs.pop(-1) self.assertEqual(v, v2) self.assertEqual(len(h), 0) def test_popitem_ties(self): h = heapdict() for i in range(N): h[i] = 0 for i in range(N): k, v = h.popitem() self.assertEqual(v, 0) self.check_invariants(h) def test_peek(self): h, pairs, d = self.make_data() while pairs: v = h.peekitem()[0] h.popitem() v2 = pairs.pop(-1) self.assertEqual(v, v2[0]) self.assertEqual(len(h), 0) def test_iter(self): h, pairs, d = self.make_data() self.assertEqual(list(h), list(d)) def test_keys(self): h, pairs, d = self.make_data() self.assertEqual(list(sorted(h.keys())), list(sorted(d.keys()))) def test_values(self): h, pairs, d = self.make_data() self.assertEqual(list(sorted(h.values())), list(sorted(d.values()))) def test_del(self): h, pairs, d = self.make_data() k, v = pairs.pop(N//2) del h[k] while pairs: v = h.popitem() v2 = pairs.pop(-1) self.assertEqual(v, v2) self.assertEqual(len(h), 0) def test_change(self): h, pairs, d = self.make_data() k, v = pairs[N//2] h[k] = 0.5 pairs[N//2] = (k, 0.5) pairs.sort(key = lambda x: x[1], reverse=True) while pairs: v = h.popitem() v2 = pairs.pop(-1) self.assertEqual(v, v2) self.assertEqual(len(h), 0) #============================================================================== def test_main(verbose=None): from types import BuiltinFunctionType test_classes = [TestHeap] test_support.run_unittest(*test_classes) # verify reference counting if verbose and hasattr(sys, "gettotalrefcount"): import gc counts = [None] * 5 for i in xrange(len(counts)): test_support.run_unittest(*test_classes) gc.collect() counts[i] = sys.gettotalrefcount() print(counts) if __name__ == "__main__": test_main(verbose=True)