{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Brute force" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sources:\n", "\n", "1. Guttag, *Introduction to Computation and Programming Using Python*, Revised and Expanded Ed. (2013)\n", "2. Cormen et al., *Introduction to Algorithms*, 3rd ed. (2009)\n", "3. [Brute force](https://en.wikipedia.org/wiki/Brute_force)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In *Introduction to Computation and Programming Using Python*, Guttag provides this code (modified) for finding the integer cube root of an integer." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def int_cube_root(n):\n", " result = 0\n", " while result ** 3 < abs(n):\n", " result += 1\n", " if result ** 3 != abs(n):\n", " return '{} is not a perfect cube'.format(n)\n", " else:\n", " if n < 0:\n", " result = -result\n", " return result" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'7 is not a perfect cube'" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int_cube_root(7)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "int_cube_root(8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"The algorithmic technique used in this program,\" Guttag writes, \"is a variant of **guess and check** called **exhaustive enumeration**. We enumerate all possibilities until we get to the right answer or exhaust the space of possibilities.\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The term **guess and check** is used in algebra to refer to a trial and error approach to solving equations." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The term **[brute force](https://en.wikipedia.org/wiki/Brute_force)** is perhaps more often used to mean what Guttag means by **exhaustive enumeration**." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Guttag's subsequent remarks downplay the value of algorithmic optimization:\n", "\n", "\"At first blush, this may seem like an incredibly stupid way to solve a problem. Surprisingly, however, exhaustive enumeration algorithms are often the most practical way to solve a problem. They are typically easy to implement and easy to understand. And, in many cases, they run fast enough for all practical purposes. [...] try finding the cube root of 1957816251. The program will seem to finish almost instantaneously.\"" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 791 µs, sys: 1 µs, total: 792 µs\n", "Wall time: 796 µs\n" ] }, { "data": { "text/plain": [ "1251" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "\n", "int_cube_root(1957816251)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1000 loops, best of 3: 791 µs per loop\n" ] } ], "source": [ "%timeit int_cube_root(1957816251)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"Now,\" Guttag continues, \"try 7406961012236344616.\"" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 1.37 s, sys: 7.04 ms, total: 1.38 s\n", "Wall time: 1.38 s\n" ] }, { "data": { "text/plain": [ "1949306" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%%time\n", "\n", "int_cube_root(7406961012236344616)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 loop, best of 3: 1.34 s per loop\n" ] } ], "source": [ "%timeit int_cube_root(7406961012236344616)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"As you can see,\" Guttag concludes, \"even if millions of guesses are required, it’s not usually a problem. Modern computers are amazingly fast. It takes on the order of one nanosecond — one billionth of a second — to execute an instruction. It’s a bit hard to appreciate how fast that is. For perspective, it takes slightly more than a nanosecond for light to travel a single foot (0.3 meters). Another way to think about this is that in the time it takes for the sound of your voice to travel a hundred feet, a modern computer can execute millions of instructions.\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "However, Guttag then provides this code (modified) implementing an algorithm to find an approximation to a square root:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def my_sqrt(n, epsilon):\n", " step = epsilon ** 2\n", " guesses = 0\n", " result = 0.0\n", " while abs(result ** 2 - n) > epsilon and result * result <= n:\n", " result += step\n", " guesses += 1\n", " if abs(result ** 2 - n) >= epsilon:\n", " return 'Failed ({} guesses)'.format(guesses)\n", " return '{} ({} guesses)'.format(result, guesses)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here we use exhaustive enumeration to find an approximation that lies within the constant `episilon` of the actual answer. The example Guttag provides, of using it to find an approximation of the square root of 25, demonstrates that, as he puts it, \"**exhaustive enumeration is a search technique that works only if the set of values being searched includes the answer**\":" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'4.999000000001688 (49990 guesses)'" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_sqrt(25, 0.01)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, if we reduce our `epsilon` value to 1, the number of guesses needed is much fewer:" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'5.0 (5 guesses)'" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_sqrt(25, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But this is not possible if we want to find an approximation of the square root of 2, for example, since the square root of 2 is not a rational number." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'Failed (1 guesses)'" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_sqrt(2, 1)" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "'1.410699999999861 (14107 guesses)'" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "my_sqrt(2, 0.01)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\"The time has come,\" Guttag concludes, \"to look for a different way to attack the problem. We need to choose a better algorithm rather than fine tune the current one.\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## See also" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In *Introduction to Algorithms*, Cormen et al. describe their insertion sort implementation as taking an **incremental** approach, processing one element of the collection to be sorted at a time. They contrast this incremental approach with so-called **divide and conquer** approaches." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.4.3" }, "widgets": { "state": {}, "version": "1.1.0" } }, "nbformat": 4, "nbformat_minor": 0 }