| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  | """Sort performance test.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | See main() for command line syntax. | 
					
						
							|  |  |  | See tabulate() for output format. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | import time | 
					
						
							| 
									
										
										
										
											2002-04-10 14:54:39 +00:00
										 |  |  | import random | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  | import marshal | 
					
						
							|  |  |  | import tempfile | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | td = tempfile.gettempdir() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  | def randfloats(n): | 
					
						
							|  |  |  |     """Return a list of n random floats in [0, 1).""" | 
					
						
							|  |  |  |     # Generating floats is expensive, so this writes them out to a file in | 
					
						
							|  |  |  |     # a temp directory.  If the file already exists, it just reads them | 
					
						
							|  |  |  |     # back in and shuffles them a bit. | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     fn = os.path.join(td, "rr%06d" % n) | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         fp = open(fn, "rb") | 
					
						
							| 
									
										
										
										
											2012-12-25 16:47:37 +02:00
										 |  |  |     except OSError: | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         r = random.random | 
					
						
							| 
									
										
										
										
											2007-05-07 22:24:25 +00:00
										 |  |  |         result = [r() for i in range(n)] | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |         try: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 fp = open(fn, "wb") | 
					
						
							|  |  |  |                 marshal.dump(result, fp) | 
					
						
							|  |  |  |                 fp.close() | 
					
						
							|  |  |  |                 fp = None | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 if fp: | 
					
						
							|  |  |  |                     try: | 
					
						
							|  |  |  |                         os.unlink(fn) | 
					
						
							| 
									
										
										
										
											2012-12-18 22:02:39 +02:00
										 |  |  |                     except OSError: | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |                         pass | 
					
						
							| 
									
										
										
										
											2012-12-25 16:47:37 +02:00
										 |  |  |         except OSError as msg: | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |             print("can't write", fn, ":", msg) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     else: | 
					
						
							|  |  |  |         result = marshal.load(fp) | 
					
						
							|  |  |  |         fp.close() | 
					
						
							|  |  |  |         # Shuffle it a bit... | 
					
						
							|  |  |  |         for i in range(10): | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |             i = random.randrange(n) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |             temp = result[:i] | 
					
						
							|  |  |  |             del result[:i] | 
					
						
							|  |  |  |             temp.reverse() | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |             result.extend(temp) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |             del temp | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |     assert len(result) == n | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     return result | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  | def flush(): | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     sys.stdout.flush() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def doit(L): | 
					
						
							| 
									
										
										
										
											2012-04-29 03:01:20 +02:00
										 |  |  |     t0 = time.perf_counter() | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     L.sort() | 
					
						
							| 
									
										
										
										
											2012-04-29 03:01:20 +02:00
										 |  |  |     t1 = time.perf_counter() | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |     print("%6.2f" % (t1-t0), end=' ') | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |     flush() | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def tabulate(r): | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  |     r"""Tabulate sort speed for lists of various sizes.
 | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     The sizes are 2**i for i in r (the argument, a list). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     The output displays i, 2**i, and the time to sort arrays of 2**i | 
					
						
							|  |  |  |     floating point numbers with the following properties: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     *sort: random data | 
					
						
							|  |  |  |     \sort: descending data | 
					
						
							|  |  |  |     /sort: ascending data | 
					
						
							| 
									
										
										
										
											2002-07-21 17:37:03 +00:00
										 |  |  |     3sort: ascending, then 3 random exchanges | 
					
						
							|  |  |  |     +sort: ascending, then 10 random at the end | 
					
						
							| 
									
										
										
										
											2002-08-02 05:46:09 +00:00
										 |  |  |     %sort: ascending, then randomly replace 1% of the elements w/ random values | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  |     ~sort: many duplicates | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |     =sort: all equal | 
					
						
							| 
									
										
										
										
											1998-05-26 15:05:12 +00:00
										 |  |  |     !sort: worst case scenario | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											2002-08-02 05:46:09 +00:00
										 |  |  |     cases = tuple([ch + "sort" for ch in r"*\/3+%~=!"]) | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |     fmt = ("%2s %7s" + " %6s"*len(cases)) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |     print(fmt % (("i", "2**i") + cases)) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     for i in r: | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         n = 1 << i | 
					
						
							|  |  |  |         L = randfloats(n) | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print("%2d %7d" % (i, n), end=' ') | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         flush() | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |         doit(L) # *sort | 
					
						
							|  |  |  |         L.reverse() | 
					
						
							|  |  |  |         doit(L) # \sort | 
					
						
							|  |  |  |         doit(L) # /sort | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-20 04:21:51 +00:00
										 |  |  |         # Do 3 random exchanges. | 
					
						
							|  |  |  |         for dummy in range(3): | 
					
						
							|  |  |  |             i1 = random.randrange(n) | 
					
						
							|  |  |  |             i2 = random.randrange(n) | 
					
						
							|  |  |  |             L[i1], L[i2] = L[i2], L[i1] | 
					
						
							|  |  |  |         doit(L) # 3sort | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-21 17:37:03 +00:00
										 |  |  |         # Replace the last 10 with random floats. | 
					
						
							|  |  |  |         if n >= 10: | 
					
						
							|  |  |  |             L[-10:] = [random.random() for dummy in range(10)] | 
					
						
							|  |  |  |         doit(L) # +sort | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-08-02 05:46:09 +00:00
										 |  |  |         # Replace 1% of the elements at random. | 
					
						
							| 
									
										
										
										
											2007-05-07 22:24:25 +00:00
										 |  |  |         for dummy in range(n // 100): | 
					
						
							| 
									
										
										
										
											2002-08-02 05:46:09 +00:00
										 |  |  |             L[random.randrange(n)] = random.random() | 
					
						
							|  |  |  |         doit(L) # %sort | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         # Arrange for lots of duplicates. | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |         if n > 4: | 
					
						
							| 
									
										
										
										
											1998-05-12 13:21:31 +00:00
										 |  |  |             del L[4:] | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |             L = L * (n // 4) | 
					
						
							|  |  |  |             # Force the elements to be distinct objects, else timings can be | 
					
						
							|  |  |  |             # artificially low. | 
					
						
							| 
									
										
										
										
											2010-08-01 08:07:49 +00:00
										 |  |  |             L = list(map(lambda x: --x, L)) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |         doit(L) # ~sort | 
					
						
							| 
									
										
										
										
											1998-05-12 13:21:31 +00:00
										 |  |  |         del L | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # All equal.  Again, force the elements to be distinct objects. | 
					
						
							| 
									
										
										
										
											2010-08-01 08:07:49 +00:00
										 |  |  |         L = list(map(abs, [-0.5] * n)) | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         doit(L) # =sort | 
					
						
							|  |  |  |         del L | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # This one looks like [3, 2, 1, 0, 0, 1, 2, 3].  It was a bad case | 
					
						
							|  |  |  |         # for an older implementation of quicksort, which used the median | 
					
						
							| 
									
										
										
										
											2002-07-21 17:37:03 +00:00
										 |  |  |         # of the first, last and middle elements as the pivot. | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         half = n // 2 | 
					
						
							| 
									
										
										
										
											2010-08-01 08:07:49 +00:00
										 |  |  |         L = list(range(half - 1, -1, -1)) | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |         L.extend(range(half)) | 
					
						
							|  |  |  |         # Force to float, so that the timings are comparable.  This is | 
					
						
							| 
									
										
										
										
											2020-02-03 17:47:20 +01:00
										 |  |  |         # significantly faster if we leave them as ints. | 
					
						
							| 
									
										
										
										
											2010-08-01 08:07:49 +00:00
										 |  |  |         L = list(map(float, L)) | 
					
						
							| 
									
										
										
										
											1998-05-26 15:05:12 +00:00
										 |  |  |         doit(L) # !sort | 
					
						
							| 
									
										
										
										
											2007-02-09 05:37:30 +00:00
										 |  |  |         print() | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | def main(): | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  |     """Main program when invoked as a script.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     One argument: tabulate a single row. | 
					
						
							|  |  |  |     Two arguments: tabulate a range (inclusive). | 
					
						
							|  |  |  |     Extra arguments are used to seed the random generator. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     """
 | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     # default range (inclusive) | 
					
						
							|  |  |  |     k1 = 15 | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |     k2 = 20 | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     if sys.argv[1:]: | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  |         # one argument: single point | 
					
						
							| 
									
										
										
										
											2001-02-09 11:51:27 +00:00
										 |  |  |         k1 = k2 = int(sys.argv[1]) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |         if sys.argv[2:]: | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  |             # two arguments: specify range | 
					
						
							| 
									
										
										
										
											2001-02-09 11:51:27 +00:00
										 |  |  |             k2 = int(sys.argv[2]) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |             if sys.argv[3:]: | 
					
						
							|  |  |  |                 # derive random seed from remaining arguments | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |                 x = 1 | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |                 for a in sys.argv[3:]: | 
					
						
							| 
									
										
										
										
											2002-07-18 15:53:32 +00:00
										 |  |  |                     x = 69069 * x + hash(a) | 
					
						
							|  |  |  |                 random.seed(x) | 
					
						
							| 
									
										
										
										
											1998-05-10 18:27:29 +00:00
										 |  |  |     r = range(k1, k2+1)                 # include the end point | 
					
						
							| 
									
										
										
										
											1998-05-10 18:20:05 +00:00
										 |  |  |     tabulate(r) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == '__main__': | 
					
						
							|  |  |  |     main() |