Saturday, May 10, 2014

Sum of all natural numbers is minus one-twelfth

A curious infinite sum investigated with Python.

An investigation of the the following curious result:
k=1k=1+2+3+4+5+=112

Tracking the explanation given on Numberphile.
In [1]:
from IPython.display import YouTubeVideo
YouTubeVideo("w-I6XTVZXww")
Out[1]:

Series definitions

The video starts with an introduction, then at ~1:40 into the video he defines three series S1, S2 and S.
I would like to be able to define those same series in an as nearly as simple Python format, so defined a dummy class so I could concentrate on getting a nice description in Python.
Note: The class captures the series not the Sum of the series.
In [2]:
class Series(object):
    "placeholder"
    def __init__(self, **kwargs):
        pass
In [3]:
# Numberphile 1:40
S1 = Series(fk=lambda k: (-1)**(k - 1),   starts=[1, -1,  1, -1,  1, -1]) 
S2 = Series(fk=lambda k: (k*(-1)**(k - 1) if k > 1 else 1), 
                                          starts=[1, -2,  3, -4,  5, -6]) 
S  = Series(fk=lambda k: k,               starts=[1,  2,  3,  4,  5,  6]) 

Sum of the infinite series

At ~1:55 we need to find the sum of an infinite series by looking at the sum approaches.
I'll flesh out the Series class definition to handle what we have so far...
In [4]:
from fractions import Fraction
from itertools import islice, izip, count, chain

class Series(object):
    "Represents infinite series by its generating function"
    
    STARTSMAX = 10     # Limit on starts
    
    def __init__(self, fk, starts=[]):
        '''
        Arguments
            fk:     Generating function
            starts: Sample starting values of series. (checked)
        '''
        self.fk = fk
        assert all(fk(k) == start for k, start in enumerate(starts, 1)),\
               "Generating function does not create same starting values"
        self.starts = [fk(k) for k in range(1, self.STARTSMAX + 1)]
        
    def __call__(self):
        "Generate successive values of the series"
        k = 1
        while True:
            yield self.fk(k)
            k += 1
                       
        
In [5]:
# Numberphile 1:40
S1 = Series(fk=lambda k: (-1)**(k - 1),   starts=[1, -1,  1, -1,  1, -1]) 
S2 = Series(fk=lambda k: (k*(-1)**(k - 1) if k > 1 else 1), 
                                          starts=[1, -2,  3, -4,  5, -6]) 
S  = Series(fk=lambda k: k,               starts=[1,  2,  3,  4,  5,  6]) 
Lets doodle...
In [6]:
S1.starts
Out[6]:
[1, -1, 1, -1, 1, -1, 1, -1, 1, -1]
In [7]:
[x for n, x in zip(range(15), S2())]
Out[7]:
[1, -2, 3, -4, 5, -6, 7, -8, 9, -10, 11, -12, 13, -14, 15]
In [8]:
S.starts
Out[8]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
So you can see that .starts is a list of the first ten generated values, and calling an instance of the class gives a generator of successive values of the series (with no fixed upper limit).

Sum S1 = 1 + -1 +1 + -1 ... == 1/2

From 2:00 minutes into the video he shows that the sum of the terms of S1 alternate between 1 and zero
In [9]:
running_sums = [sum(islice(S1(), termcount)) for termcount in range(1,21)]
running_sums
Out[9]:
[1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
Lets take the infinite sum as the average of the sums i.e.
Sum S1 = 1 -1 +1 -1 +1 ... = 0.5

2 * (Sum S2) == Sum S1

From 2:45 in the video.
Lets take S2, and S2 with an initial 0 inserted . (Adding zeroes will not affect the sum of the series remember).
In [10]:
S2.starts
Out[10]:
[1, -2, 3, -4, 5, -6, 7, -8, 9, -10]
In [11]:
# S2 with an initial +0
[0] + S2.starts
Out[11]:
[0, 1, -2, 3, -4, 5, -6, 7, -8, 9, -10]
In [12]:
added_terms = (x + y  for x, y in izip(S2(), chain([0], S2())))
list(islice(added_terms, 10))
Out[12]:
[1, -1, 1, -1, 1, -1, 1, -1, 1, -1]
So, for the purposes of summation, 2 * S2 == S1 = 0.5
And therefore Sum S2 = 0.25

S - S2

From 4:08 in Video.
In [13]:
S.starts
Out[13]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
In [14]:
S2.starts
Out[14]:
[1, -2, 3, -4, 5, -6, 7, -8, 9, -10]
Lets do the subtraction by subtracting the generating functions this time.
In [15]:
S_sub_S2 = Series(fk=lambda k: S.fk(k) - S2.fk(k))
S_sub_S2.starts
Out[15]:
[0, 4, 0, 8, 0, 12, 0, 16, 0, 20]
Take a factor of four out and ignore the zeroes (as they do nothing for infinite sums).
In [16]:
list(islice((x/4 for x in S_sub_S2() if x), 10))
Out[16]:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

End run

So:
sum(S) - sum(S2) = 4*(1+2+3+4+...) = 4 * ( sum(S) )
Solving:
sum(S) - 1/4 = 4*sum(S)

- 1/4 = 3*sum(S)

- 1/(4*3) = sum(S)

sum(S) = -1/12
Proving that the infinite sum 1+2+3+4+... = -1/12

The proof is in the eating

Remember that although it is a weird result, when used in scientific experiments we can predict nature.
For me, I now know that when dealing with equations involving infinite series I will annotate then with "There be dragons".

Tuesday, May 06, 2014

Python PyPy interpreter in Javascript: Firefox beats CPython beats Chrome!

Ryan Kelly posted info on PyPy.js an implementation of Python written in Javascript. available here
I tried it on Chrome Version 34.0.1847.131 m (the latest). using the pystone benchmark:


In cPython 3.4.0b1  I got:


And in Firefox 29.0 I got:

These were the latest versions at the time of writing (I think) and taking the fastest of their four runs on the same machine gives:

PlatformBest of 4 PystoneMultiplier
Chrome14013.5100%
cPython37424.7267%
Firefox66934.4478%
See the original article for caveats on the state of PyPy.js - it may only run pystone for all I know.

Of course it doesn't say much about Python speed but it may say something about Chrome vs Firefox speed? Who knows - lies, damned lies, and statistics!