From 4c0b782955fe01b8fe366b056abe77f047d9fbc7 Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Thu, 31 Jan 2013 22:53:40 -0800 Subject: [PATCH 1/8] gitignore adding a gitignore file --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a60d365 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +*.un~ From 2705e555d1c1c71dc80d87dd7a8e633359d5db29 Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Thu, 31 Jan 2013 22:55:15 -0800 Subject: [PATCH 2/8] pyflakes: no "import *" --- mpython.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/mpython.py b/mpython.py index c8bfe70..dd53d81 100755 --- a/mpython.py +++ b/mpython.py @@ -1,21 +1,21 @@ #!/usr/bin/python -from ast import * +import ast import sys def name(x, ctx): - return Name(id = x, ctx = ctx, lineno = 0, col_offset = 0) + return ast.Name(id = x, ctx = ctx, lineno = 0, col_offset = 0) def call(f, *args): - f = name(f, Load()) - return Call(func = f, args = list(args), lineno = 0, + f = name(f, ast.Load()) + return ast.Call(func = f, args = list(args), lineno = 0, col_offset = 0, keywords = [], vararg = None) def func(args, body): - return Lambda(args = arguments(args = args, defaults = []), + return ast.Lambda(args = ast.arguments(args = args, defaults = []), body = body, vararg = None, lineno = 0, col_offset = 0) -unit = Tuple(elts = [], lineno=0, col_offset = 0, ctx = Load()) +unit = ast.Tuple(elts = [], lineno=0, col_offset = 0, ctx = ast.Load()) def transform(elt, generators): elt = call("__singleton__", elt) @@ -23,17 +23,17 @@ def transform(elt, generators): for generator in generators[-1::-1]: for i in generator.ifs[-1::-1]: elt = call("__concatMap__", - func([name('_', Param())], elt), - IfExp(i, + func([name('_', ast.Param())], elt), + ast.IfExp(i, call('__singleton__', unit), call('__fail__'), lineno=0, col_offset=0)) elt = call("__concatMap__", - func([name(generator.target.id, Param())], elt), + func([name(generator.target.id, ast.Param())], elt), generator.iter) return elt -class RewriteComp(NodeTransformer): +class RewriteComp(ast.NodeTransformer): def visit_ListComp(self, node): return transform(RewriteComp().visit(node.elt), [RewriteComp().visit(generator) for generator in node.generators]) @@ -48,9 +48,9 @@ def __fail__(): return [] source = open(sys.argv[1]).read() -e = compile(source, "", "exec", PyCF_ONLY_AST) +e = compile(source, "", "exec", ast.PyCF_ONLY_AST) e = RewriteComp().visit(e) f = compile(e, sys.argv[1], "exec") print f exec f -print "Done" \ No newline at end of file +print "Done" From 4fc82a906968ef9b9069b94d03965542e831b25a Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Thu, 31 Jan 2013 23:23:14 -0800 Subject: [PATCH 3/8] pep8 clean up No functional changes. --- mpython.py | 55 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/mpython.py b/mpython.py index dd53d81..6d0a98b 100755 --- a/mpython.py +++ b/mpython.py @@ -3,49 +3,60 @@ import ast import sys + def name(x, ctx): - return ast.Name(id = x, ctx = ctx, lineno = 0, col_offset = 0) + return ast.Name(id=x, ctx=ctx, lineno=0, col_offset=0) + def call(f, *args): - f = name(f, ast.Load()) - return ast.Call(func = f, args = list(args), lineno = 0, - col_offset = 0, keywords = [], vararg = None) + f = name(f, ast.Load()) + return ast.Call(func=f, args=list(args), lineno=0, + col_offset=0, keywords=[], vararg=None) + def func(args, body): - return ast.Lambda(args = ast.arguments(args = args, defaults = []), - body = body, vararg = None, lineno = 0, col_offset = 0) + return ast.Lambda(args=ast.arguments(args=args, defaults=[]), + body=body, vararg=None, lineno=0, col_offset=0) + + +unit = ast.Tuple(elts=[], lineno=0, col_offset=0, ctx=ast.Load()) -unit = ast.Tuple(elts = [], lineno=0, col_offset = 0, ctx = ast.Load()) def transform(elt, generators): - elt = call("__singleton__", elt) + elt = call("__singleton__", elt) - for generator in generators[-1::-1]: - for i in generator.ifs[-1::-1]: - elt = call("__concatMap__", - func([name('_', ast.Param())], elt), - ast.IfExp(i, - call('__singleton__', unit), - call('__fail__'), lineno=0, col_offset=0)) + for generator in generators[-1::-1]: + for i in generator.ifs[-1::-1]: + elt = call("__concatMap__", + func([name('_', ast.Param())], elt), + ast.IfExp(i, + call('__singleton__', unit), + call('__fail__'), lineno=0, col_offset=0)) elt = call("__concatMap__", func([name(generator.target.id, ast.Param())], elt), generator.iter) - return elt + return elt + class RewriteComp(ast.NodeTransformer): - def visit_ListComp(self, node): - return transform(RewriteComp().visit(node.elt), - [RewriteComp().visit(generator) for generator in node.generators]) + def visit_ListComp(self, node): + return transform(RewriteComp().visit(node.elt), + [RewriteComp().visit(generator) + for generator in node.generators]) + def __concatMap__(f, x): - return [z for y in x for z in f(y)] + return [z for y in x for z in f(y)] + def __singleton__(x): - return [x] + return [x] + def __fail__(): - return [] + return [] + source = open(sys.argv[1]).read() e = compile(source, "", "exec", ast.PyCF_ONLY_AST) From 5fca7d9feeb45b8ff22c1efb8cc7ee6be8ad48af Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Fri, 1 Feb 2013 00:32:18 -0800 Subject: [PATCH 4/8] Indenting Fail. Reverting issue with previous commit. --- mpython.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mpython.py b/mpython.py index 6d0a98b..64da53d 100755 --- a/mpython.py +++ b/mpython.py @@ -33,9 +33,9 @@ def transform(elt, generators): call('__singleton__', unit), call('__fail__'), lineno=0, col_offset=0)) - elt = call("__concatMap__", - func([name(generator.target.id, ast.Param())], elt), - generator.iter) + elt = call("__concatMap__", + func([name(generator.target.id, ast.Param())], elt), + generator.iter) return elt From 84c844a4724f97786df5f25bcd9bf36d9845367b Mon Sep 17 00:00:00 2001 From: Barnaby Robson Date: Tue, 30 Apr 2013 13:06:39 -0700 Subject: [PATCH 5/8] pep8 clean up. just went through all the code with flake8 --- test1.py | 30 ++++++---- test2.py | 33 +++++++---- test3.py | 163 ++++++++++++++++++++++++++++++++----------------------- 3 files changed, 134 insertions(+), 92 deletions(-) diff --git a/test1.py b/test1.py index 01ff8e1..5f11a1f 100644 --- a/test1.py +++ b/test1.py @@ -1,21 +1,27 @@ # Some simple regression tests -a = [(x, y, z) for x in [0, 1, 2] - for y in [0, 1, 2] - for z in [0, 1, 2]] +a = [ + (x, y, z) + for x in [0, 1, 2] + for y in [0, 1, 2] + for z in [0, 1, 2]] print len(a) -b = [(x, y) for x in [0,1] - for y in [0,1] - if x+y < 2] +b = [ + (x, y) + for x in [0, 1] + for y in [0, 1] + if x+y < 2] print b -c = [(x, y, z) for x in range(1, 10) - for y in range(1, 10) - if x < y - for z in range(1, 10) - if x*x+y*y == z*z] +c = [ + (x, y, z) + for x in range(1, 10) + for y in range(1, 10) + if x < y + for z in range(1, 10) + if x*x+y*y == z*z] -print c \ No newline at end of file +print c diff --git a/test2.py b/test2.py index 5ed6fca..2660f12 100644 --- a/test2.py +++ b/test2.py @@ -1,30 +1,39 @@ import math + def __concatMap__(k, m): - return lambda c:m(lambda a:k(a)(c)) + return lambda c: m(lambda a: k(a)(c)) + def __singleton__(x): - return lambda f:f(x) + return lambda f: f(x) + def callCC(f): - return lambda c:f(lambda a:lambda _:c(a))(c) + return lambda c: f(lambda a: lambda _: c(a))(c) + def __fail__(): - raise "Failure is not an option for continuations" + raise "Failure is not an option for continuations" + def ret(x): - return __singleton__(x) + return __singleton__(x) + def id(x): - return x + return x + def solve(a, b, c): - return callCC(lambda throw: [((-b-d)/(2*a), (-b+d)/(2*a)) - for a0 in (ret(a) if a!=0 else throw("Not quadratic")) - for d2 in ret(b*b-4*a*c) - for d in (ret(math.sqrt(d2)) if d2>=0 else throw("No roots")) - ]) + return callCC( + lambda throw: [ + ((-b-d)/(2*a), (-b+d)/(2*a)) + for a0 in (ret(a) if a != 0 else throw("Not quadratic")) + for d2 in ret(b*b-4*a*c) + for d in (ret(math.sqrt(d2)) if d2 >= 0 else throw("No roots")) + ]) print solve(1, 0, -9)(id) print solve(1, 1, 9)(id) -print solve(0, 1, 9)(id) \ No newline at end of file +print solve(0, 1, 9)(id) diff --git a/test3.py b/test3.py index e8f7fdd..909dcc2 100644 --- a/test3.py +++ b/test3.py @@ -7,61 +7,72 @@ # to mean something like "the probability of x supposing a is drawn from # distribution b and then c is drawn from d, conditioned on a # + + class PDF(dict): def __hash__(self): return hash(tuple(sorted(self.iteritems()))) + def scale(alpha, ps): - result = PDF() - for k in ps: - result[k] = alpha*ps[k] - return result + result = PDF() + for k in ps: + result[k] = alpha*ps[k] + return result + def combine(pdf1, pdf2): - result = pdf1.copy() - for k in pdf2.keys(): - if result.has_key(k): - result[k] += pdf2[k] - else: - result[k] = pdf2[k] - return result + result = pdf1.copy() + for k in pdf2.keys(): + if k in result: + result[k] += pdf2[k] + else: + result[k] = pdf2[k] + return result + def __concatMap__(f, pps): - result = PDF() - for k0 in pps.keys(): - p = pps[k0] - k = f(k0) - result = combine(result, scale(pps[k0], f(k0))) - return result + result = PDF() + for k0 in pps.keys(): + p = pps[k0] + k = f(k0) + result = combine(result, scale(p, k)) + return result + def __singleton__(x): - return PDF([(x, 1)]) + return PDF([(x, 1)]) + def __fail__(x): - return PDF() + return PDF() + def certain(x): - return __singleton__(x) + return __singleton__(x) + def expectation(pdf): - total = 0.0; - for k in pdf.keys(): - total += pdf[k]*k - return total + total = 0.0 + for k in pdf.keys(): + total += pdf[k]*k + return total + def probability(condition, pdf): - return expectation([1 if condition(k) else 0 for k in pdf]) + return expectation([1 if condition(k) else 0 for k in pdf]) -################################################################################ +############################################################################### # Test code starts here -################################################################################ +############################################################################### + -def bernoulli(p, a = True, b = False): - """ - A sample from bernoulli(p, a, b) has probability p of taking the value - a and probabilty 1-p of taking the value b. - """ - return PDF([(a, p), (b, 1-p)]) +def bernoulli(p, a=True, b=False): + """ + A sample from bernoulli(p, a, b) has probability p of taking the value + a and probabilty 1-p of taking the value b. + """ + return PDF([(a, p), (b, 1-p)]) # Straightforward coin toss. test1 = [x for x in bernoulli(0.5)] @@ -69,53 +80,64 @@ def bernoulli(p, a = True, b = False): print "test1 =", test1 # A pair of coin tosses. -test2 = [(x, y) for x in bernoulli(0.5) - for y in bernoulli(0.5)] +test2 = [ + (x, y) + for x in bernoulli(0.5) + for y in bernoulli(0.5)] print "test2 =", test2 # The sum of the result of three coin tosses. -test3 = [a+b+c for a in bernoulli(0.5, 1, 0) - for b in bernoulli(0.5, 1, 0) - for c in bernoulli(0.5, 1, 0)] +test3 = [ + a+b+c + for a in bernoulli(0.5, 1, 0) + for b in bernoulli(0.5, 1, 0) + for c in bernoulli(0.5, 1, 0)] print "test3 =", test3 -################################################################################ +############################################################################### # Chinese restaurant code # http://en.wikipedia.org/wiki/Chinese_restaurant_process -################################################################################ +############################################################################### + def addGuest(i, tables): - if i==len(tables): - return tables+(1,) - else: - tableList = list(tables) - tableList[i] += 1 + if i == len(tables): + return tables+(1,) + else: + tableList = list(tables) + tableList[i] += 1 return tuple(tableList) + def selectTable(tables): - newTables = list(tables)+[1] - n = sum(newTables) - return PDF(zip(range(len(newTables)), map(lambda x: float(x)/n, newTables))) + newTables = list(tables)+[1] + n = sum(newTables) + return PDF( + zip(range(len(newTables)), map(lambda x: float(x)/n, newTables))) + def chineseRestaurantProcess(n): - """ - Simulates the Chinese restaurant process to n steps - """ + """ + Simulates the Chinese restaurant process to n steps + """ + + if n == 0: + return certain(()) + else: + return [ + addGuest(guestTable, tables) + for tables in chineseRestaurantProcess(n-1) + for guestTable in selectTable(tables)] - if n==0: - return certain(()) - else: - return [addGuest(guestTable, tables) for tables in chineseRestaurantProcess(n-1) - for guestTable in selectTable(tables)] # Expected table size (occupancy) given by theory. def theoreticalTableSize(n): - total = 0.0 - for k in range(0, n): - total += 1.0/(k+1) - return total + total = 0.0 + for k in range(0, n): + total += 1.0/(k+1) + return total # Compare theoretical and simulated expected table size. # Should be equal to machine precision. @@ -128,18 +150,23 @@ def theoreticalTableSize(n): # is probably much more accurate than a Monte-Carlo simulation using the same # amount of CPU time. for i in range(1, 16): - test5a = probability(lambda table: min(table)==1, chineseRestaurantProcess(i)) - print i, test5a + test5a = probability( + lambda table: min(table) == 1, chineseRestaurantProcess(i)) + print i, test5a test5b = 1-math.exp(-1) print "test5 =", math.fabs(test5a-test5b) < 1e-9 # Maybe you recognise the 1-1/e above from this problem: -# n people visit a restaurant (another one) and hang up their hats. When they leave -# they pick a hat at random. What's the probability of anyone getting their original +# n people visit a restaurant (another one) and hang up their hats. +# When they leave they pick a hat at random. +# What's the probability of anyone getting their original # hat back? The connection between that problem and the CRP is a beautiful bit -# of mathematics about the permutation group. I'll leave it as a puzzle to figure +# of mathematics about the permutation group. +# I'll leave it as a puzzle to figure # out why problems have the same solution. -# PS I only realised this fact because I'd written code to compute this stuff to machine -# precision and recognised 1-1/e. It's fortuitous that I chose this problem completely at -# random and was led to see the connection. (I admit I got some help from the web...) +# PS I only realised this fact because I'd written code to compute +# this stuff to machine precision and recognised 1-1/e. +# It's fortuitous that I chose this problem completely at +# random and was led to see the connection. +# (I admit I got some help from the web...) From 2a3d1ff4a831ad3af43d1bc0e9e5edbb6d014a1c Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Tue, 30 Apr 2013 23:08:21 -0700 Subject: [PATCH 6/8] update shebang just in case --- mpython.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mpython.py b/mpython.py index 64da53d..61518ff 100755 --- a/mpython.py +++ b/mpython.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import ast import sys From 9c085e89567446f7141991fa69ca860bba9fa340 Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Tue, 30 Apr 2013 23:08:56 -0700 Subject: [PATCH 7/8] ocd don't create temp list. --- mpython.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mpython.py b/mpython.py index 61518ff..0abba31 100755 --- a/mpython.py +++ b/mpython.py @@ -25,8 +25,8 @@ def func(args, body): def transform(elt, generators): elt = call("__singleton__", elt) - for generator in generators[-1::-1]: - for i in generator.ifs[-1::-1]: + for generator in reversed(generators): + for i in reversed(generator.ifs): elt = call("__concatMap__", func([name('_', ast.Param())], elt), ast.IfExp(i, From 491615caf10dc1aa2f522ac3b9e7eadc1ebf4596 Mon Sep 17 00:00:00 2001 From: barnabyrobson Date: Tue, 30 Apr 2013 23:12:31 -0700 Subject: [PATCH 8/8] Maybe Monad Added an implementation of the Maybe monad. --- test4.py | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 test4.py diff --git a/test4.py b/test4.py new file mode 100644 index 0000000..9fb5c22 --- /dev/null +++ b/test4.py @@ -0,0 +1,21 @@ +# Maybe Monad + +def __concatMap__(f, m): + return None if m is None else f(m) + +def __singleton__(x): + return x + +def __fail__(): + return None + +def ret(x): + return __singleton__(x) + +print [ + x + for x in 242 + for y in x + 30 + for z in y + 40 + for q in None] +