{ "metadata": { "name": "Random function with wrapper to check for trivial cases" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Functions that return random number are many times the computational bottlenecks of my programs.\n", "On top of that, I like to write generic but sometimes the result is that I call a random function that has a trivial domain, \n", "that is, there is only one value it can even possible return.\n", "I wondered if *NumPy* knows how to handle that, but it turns out it doesn't. I'll show you.\n", "\n", "First I define a function that returns a discrete uniform number between 0 and *n*:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from numpy.random import random_integers\n", "from timeit import timeit\n", "def uniform(n):\n", " return random_integers(0,n)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next I define a *smart* function that returns discrete uniform, but first checks that the domain is not trivial, an dif it is, it returns the trivial value:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "def smart_uniform(n):\n", " if n==0: \n", " return 0\n", " else: \n", " return random_integers(0,n)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "def trivial():\n", " return 0" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now I define a factory function that for a given function (which will be either *uniform* or *smart_uniform*) returns two versions - one with a range limit 0 and one with a range limit 1, both given as the first argument. This is used by the *timeit* function timer later on." ] }, { "cell_type": "code", "collapsed": false, "input": [ "def function_factory(func):\n", " def f0():\n", " return func(0)\n", " def f1():\n", " return func(1)\n", " return f0,f1\n", "\n", "uniform0,uniform1 = function_factory(uniform)\n", "smart_uniform0,smart_uniform1 = function_factory(smart_uniform)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now I use the *timeit* function timer to time how long each function calls takes. *timeit* is nice, it calls the function many times and calculates the average time. But as far as I know it doesn't take arguments, which is why I needed the above function factory.\n", "\n", "As you can see, the uniform functions take roughly the same time, although *uniform 0* is trivial and always returns 0.\n", "The smart function for the trivial case does take less time than the regular version - \n", "because it doesn't do the random draws - but still takes longer than the trivial version, probably because of the *if* calls.\n", "\n", "The bad news are that the non-trivial smart uniform function takes much longer than the regular version, which means this is not a good implementation." ] }, { "cell_type": "code", "collapsed": false, "input": [ "print \"trivial 0:\",timeit(trivial)\n", "print \"uniform 0:\",timeit(uniform0)\n", "print \"uniform 1:\",timeit(uniform1)\n", "print \"smart uniform 0:\",timeit(smart_uniform0)\n", "print \"smart uniform 1:\",timeit(smart_uniform1)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "trivial 0: " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "0.380914433709\n", "uniform 0: " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "1.632382798\n", "uniform 1: " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "1.66399043729\n", "smart uniform 0: " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "1.00784697256\n", "smart uniform 1: " ] }, { "output_type": "stream", "stream": "stdout", "text": [ "2.23995387685\n" ] } ], "prompt_number": 6 } ], "metadata": {} } ] }