Showing posts with label permutations. Show all posts
Showing posts with label permutations. Show all posts

Saturday, October 22, 2016

perm_facts version with list comps and functional programming

By Vasudev Ram



Cartoon attribution

A little after writing the program (perm_facts.py) in my recent post:

Permutation facts

(which showed that the number of permutations of n things was the same as n factorial), I saw that I could replace the program's for loops with list comprehensions. So I did that, in the functions num_perms_upto and factorials_upto.

Then I also changed the recursive factorial function to the iterative version shown in the code below. (Although people sometimes use recursive algorithms instead of iterative ones, because they can be simpler to implement, often by using elegant divide and conquer methods), in this case, the recursive version is not really simpler than the iterative one.)

However, I then realized that I could replace the iterative version by a one-line functional version using reduce and operator.mul. So here is the program, perm_fact2.py, with all the changes mentioned above (the iterative version is left in, as comments, but the for loops from the original perm_fact.py are gone, replaced by shorter list comprehensions).

A small benefit of the changes is that the number of lines comes down by a few (if you don't count the commented lines for the iterative version, which I left in there, since it was not in the original), but that was not the goal of the exercise - I was just exploring different ways of doing it.

And whether the code is clearer or not after the changes, may be a matter of personal opinion. For those used to the procedural / imperative style, the changes may make it a bit harder to read, but I think the functional part (reduce with operator.mul, here) and list comprehensions seem to have a certain elegance, and they take slightly less LOC.

Excessive use of reduce, map, etc., just for the sake of it, isn't good, though. And up to 3 or so nested list comprehensions is easy to understand, IME. The thing to remember is that the nested for's (in a nested list comp) run in the same order (leftmost or outermost first) as in a nested for loop. (This is mentioned in the Python docs, and I think they did it that way to be intuitive.)

I ran the program the same way as the previous one, and it gave the same output (verified by DOS's "fc /l outfile1 outfile2", so I will not show the output again here.
#--------------------------------------------------------------
# perm_fact2.py
# Modified version of perm_fact.py, with:
# - two for loops replaced by list comprehensions;
# - recursive factorial() replaced by iterative function;
# - iterative factorial() in turn replaced by 
#   functional version, using reduce().
# Author: Vasudev Ram
# Copyright 2016 Vasudev Ram
# Web site: https://vasudevram.github.io
# Blog: http://jugad2.blotspot.com
# Product store: https://gumroad.com/vasudevram
#--------------------------------------------------------------

import sys
from itertools import permutations
from operator import mul

def num_perms_upto(n):
    return [ len(list(permutations(range(i)))) for i in range(1, n + 1) ]

def factorial(n):
    if n < 0:
        print "Argument n should be >= 0"
        sys.exit(0)
    #-------------------------------------------------------
    #Iterative computation of factorial.
    #f = 1
    #for i in range(1, n + 1):
    #    f *= i
    #return f
    #-------------------------------------------------------
    # Functional computation of factorial, using reduce().
    return reduce(mul, range(1, n + 1), 1)

def factorials_upto(n):
    return [ factorial(i) for i in range(1, n + 1) ]

print "Number of permutations of 1 .. n, where n in 1 .. 10:"
print num_perms_upto(10)
print "Factorial of n, where n in 1 .. 10:"
print factorials_upto(10)
I also timed the runs of both perm_fact.py and perm_fact2.py (and perm_fact2.py separately for both the iterative and functional versions of factorial), a few times each, but did not notice any significant difference. Sometimes one was a bit faster, sometimes the other was, sometimes nearly the same.

(One reason why I thought of timing it in the first place, was because I had read somewhere recently that using map on a sequence can be faster than processing its items in a for loop; haven't tested that, so don't know whether is right or not, but it could be - IIRC, the reason given was that the iteration then happens inside the C implementation of map, and if true, that probably holds for reduce too.)

Also, due to the small amount of code in each, and only a few iterations happening in the code, versus the size of the Python interpreter, it is likely that a good (relative) chunk of the total run time was taken by the loading and initialization of the interpreter, and maybe by parsing the .py files. Other random OS processes running on my machine could also account for the variations. Anyway, the goal here was not really to see if the changes made it faster.

- Vasudev Ram - Online Python training and consulting

FlyWheel - Managed WordPress Hosting

Get updates on my software products / ebooks / courses.

Jump to posts: Python   DLang   xtopdf

Subscribe to my blog by email

My ActiveState recipes



Thursday, October 20, 2016

Permutation facts

By Vasudev Ram



Nicomachus theorem 3D image attribution

Today, I was using the permutations function in Python's itertools module to generate permutations for a few different values of integers, as part of some work I was doing. Looking at the lengths (1, 2, 6, 24, ...) of a few sets of permutations, I noticed a pattern that seemed familiar, so I wrote this program to verify my guess about what it meant:
#--------------------------------------------------------------
# perm_fact.py
# Author: Vasudev Ram
# Copyright 2016 Vasudev Ram
# Web site: https://vasudevram.github.io
# Blog: http://jugad2.blotspot.com
# Product store: https://gumroad.com/vasudevram
#--------------------------------------------------------------

import sys
from itertools import permutations

def num_perms_upto(n):
    num_perms = []
    for i in range(1, n + 1):
        num_perms.append(len(list(permutations(range(i)))))
    return num_perms

def factorial(n):
    if n < 0:
        print "Argument n should be >= 0"
        sys.exit(0)
    if n == 0:
        return 1
    return n * factorial(n - 1)

def factorials_upto(n):
    factorials = []
    for i in range(1, n + 1):
        factorials.append(factorial(i))
    return factorials

print "Number of permutations of 1 .. n, where n in 1 .. 10:"
print num_perms_upto(10)
print "Factorial of n, where n in 1 .. 10:"
print factorials_upto(10)
which, when run, gave this output:
$ python perm_fact.py
Number of permutations of 1 .. n, where n in 1 .. 10:
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
Factorial of n, where n in 1 .. 10:
[1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800]
This confirmed (empirically, of course) that the number of permutations of n items (taken n at a time), is just n factorial.

Then I looked up factorial in Wikipedia, and found some interesting facts (pun intended). Here are some excerpts from that page:

[
The factorial operation is encountered in many areas of mathematics, notably in combinatorics, algebra, and mathematical analysis.
...
Its most basic occurrence is the fact that there are n! ways to arrange n distinct objects into a sequence (i.e., permutations of the set of objects). This fact was known at least as early as the 12th century, to Indian scholars. Fabian Stedman, in 1677, described factorials as applied to change ringing.
...
Although the factorial function has its roots in combinatorics, formulas involving factorials occur in many areas of mathematics.
...
Factorials occur in algebra for various reasons, such as via the already mentioned coefficients of the binomial formula.
...
Factorials also turn up in calculus; for example they occur in the denominators of the terms of Taylor's formula.
...
Factorials are also used extensively in probability theory.
...
As n grows, the factorial n! increases faster than all polynomials and exponential functions (but slower than double exponential functions) in n.
...
(Hence) ln n! ~ n ln n ... This result plays a key role in the analysis of the computational complexity of sorting algorithms
...
Factorials have many applications in number theory.
...
The reciprocals of factorials produce a convergent series whose sum is Euler's number e:
...
In mathematics, the gamma function (represented by the capital Greek letter G) is an extension of the factorial function, with its argument shifted down by 1, to real and complex numbers.
...
The gamma function is applicable in the fields of probability and statistics, as well as combinatorics.
...
There are several other integer sequences similar to the factorial that are used in mathematics:
...
Double factorial
...
Quadruple factorial
...
Superfactorial
...
Hyperfactorial
...
Bhargava factorial
]

I did a double take (or should that be factorial take? :) when I saw that one, because I didn't expect a factorial type to be named after a person (but why not, really); the person is Fields Medal-winning mathematician Manjul Bhargava.

All the above factorial-related terms are mentioned in the Wikipedia factorial article, and there are also links to some of them there.

And did you know that triangular numbers are the additive analogues of factorials?

The image at the top of the post is a visual representation of Nicomachus's theorem, which involves what are called squared triangular numbers. His theorem says that:

The sum of the first n cubes is the square of the nth triangular number. That is,

1 cubed + 2 cubed + 3 cubed + ... + n cubed = (1 + 2 + 3 + ... + n) squared,

where the nth triangular number is the sum of the natural numbers from 1 to n.

Speaking of mathematics, you may also like this earlier post by me:

Bhaskaracharya and the man who found zero. In fact, the Wikipedia article on permutations says that the relationship between permutations and factorials (described above) was known to mathematicians in India by around 1150 A.D.

- Enjoy.

- Vasudev Ram - Online Python training and consulting

Get updates on my software products / ebooks / courses.

Jump to posts: Python   DLang   xtopdf

Subscribe to my blog by email

My ActiveState recipes

FlyWheel - Managed WordPress Hosting