Last active
March 11, 2016 20:12
-
-
Save jeinarsson/b8bcdad10adbfb23f694 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"cells": [ | |
{ | |
"cell_type": "code", | |
"execution_count": 1, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"%matplotlib inline\n", | |
"import matplotlib.pyplot as plt\n", | |
"from itertools import combinations\n", | |
"from timeit import timeit\n", | |
"\n", | |
"primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541,547,557,563,569,571,577,587,593,599,601,607,613,617,619,631,641,643,647,653,659,661,673,677,683,691,701,709,719,727,733,739,743,751,757,761,769,773,787,797,809,811,821,823,827,829,839,853,857,859,863,877,881,883,887,907,911,919,929,937,941,947,953,967,971,977,983,991,997,1009,1013,1019,1021,1031,1033,1039,1049,1051,1061,1063,1069,1087,1091,1093,1097,1103,1109,1117,1123,1129,1151,1153,1163,1171,1181,1187,1193,1201,1213,1217,1223,1229,1231,1237,1249,1259,1277,1279,1283,1289,1291,1297,1301,1303,1307,1319,1321,1327,1361,1367,1373,1381,1399,1409,1423,1427,1429,1433,1439,1447,1451,1453,1459,1471,1481,1483,1487,1489,1493,1499,1511,1523,1531,1543,1549,1553,1559,1567,1571,1579,1583,1597,1601,1607,1609,1613,1619,1621,1627,1637,1657,1663,1667,1669,1693,1697,1699,1709,1721,1723,1733,1741,1747,1753,1759,1777,1783,1787,1789,1801,1811,1823,1831,1847,1861,1867,1871,1873,1877,1879,1889]" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"direct(N) is a naive brute force SSP solver that enumerates all subsets and computes their sums." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 3, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"def direct(N):\n", | |
"\tS = primes[0:N]\n", | |
"\tT = sum(S)\n", | |
"\t\n", | |
"\tR = [False for k in range(1+T)]\n", | |
"\tR[0] = True\n", | |
"\t\n", | |
"\tfor l in range(N):\n", | |
"\t\tfor s in combinations(S,l):\n", | |
"\t\t\tR[sum(s)] = True\n", | |
"\n", | |
"\treturn R" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"dp(N) is a dynamic programming algorithm that computes all subset-sums of a set of positive integers, and thereby solves the NP-complete subset-sum problem. Given a set $S={x_1, ..., x_N}$ of $N$ positive integers whose total sum is $T=\\sum x_i$, the algorithm proceeds as follows.\n", | |
"\n", | |
"- allocate a boolean array $R$ of size $T+1$, set the first value to True, the rest to False. This array represents the values at the final row of the biological device where $R[k]$ is True if $k$ is a subset-sum of $S$, and False otherwise. \n", | |
"- for $i=1..N$ (for each member in the set)\n", | |
" - for $y=T-x_i..0$ (go through the result array backwards)\n", | |
" - if $R[y]==True$, then $R[y+x_i]=True$ (if y is a subset sum, then y+x_i is too)\n", | |
"\n", | |
"The complexity of this algorithm is $O(NT)$, that is polynomial in the number of integers and their total sum. As the authors point out, this is $O(N^2)$ if the elements of $S$ are approximately evenly spaced, because then $T\\sim N$. Contrary to the claim by Nicolau et. al., the subset-sum problem for sets of sequential primes is in fact solved for $N=100$ in a fraction of a second on a laptop." | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 4, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [ | |
"def dp(N):\n", | |
"\tS = primes[0:N]\n", | |
"\tT = sum(S)\n", | |
"\n", | |
"\tR = [False for k in range(1+T)]\n", | |
"\tR[0] = True\n", | |
"\n", | |
"\tfor i in range(N):\n", | |
"\t\tfor y in reversed(range(T-S[i])):\n", | |
"\t\t\tif R[y]:\n", | |
"\t\t\t\tR[y+S[i]] = True\n", | |
"\n", | |
"\treturn R" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Make sure that the DP solution returns same result as the direct brute force solution:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 53, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"name": "stdout", | |
"output_type": "stream", | |
"text": [ | |
"N = 1 OK.\n", | |
"N = 2 OK.\n", | |
"N = 3 OK.\n", | |
"N = 4 OK.\n", | |
"N = 5 OK.\n", | |
"N = 6 OK.\n", | |
"N = 7 OK.\n", | |
"N = 8 OK.\n", | |
"N = 9 OK.\n", | |
"N = 10 OK.\n", | |
"N = 11 OK.\n", | |
"N = 12 OK.\n", | |
"N = 13 OK.\n", | |
"N = 14 OK.\n", | |
"N = 15 OK.\n", | |
"N = 16 OK.\n", | |
"N = 17 OK.\n", | |
"N = 18 OK.\n", | |
"N = 19 OK.\n", | |
"N = 20 OK.\n", | |
"N = 21 OK.\n", | |
"N = 22 OK.\n", | |
"N = 23 OK.\n", | |
"N = 24 OK.\n" | |
] | |
} | |
], | |
"source": [ | |
"for N in range(1,25):\n", | |
" assert(all(a==b for (a,b) in zip(direct(N), dp(N))))\n", | |
" print('N = {} OK.'.format(N))" | |
] | |
}, | |
{ | |
"cell_type": "markdown", | |
"metadata": {}, | |
"source": [ | |
"Measure and plot the speed of the two algorithms:" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 5, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"def measure(f, N, n=1000):\n", | |
" def g():\n", | |
" f(N)\n", | |
" return timeit(g, number = n)/n\n", | |
" " | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 7, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"directN = list(range(1,22))\n", | |
"directTimes = list(map(lambda N: measure(direct, N), directN))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 8, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [], | |
"source": [ | |
"dpN = list(range(1,100))\n", | |
"dpTimes = list(map(lambda N: measure(dp, N), dpN))" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": 9, | |
"metadata": { | |
"collapsed": false | |
}, | |
"outputs": [ | |
{ | |
"data": { | |
"image/png": "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\n+OFuZj5q1CgfM2aM33LLLe7ufvvtt/t+++3nO+ywgx966KH+2GOP5SxPc3OzDx061LfbbjsfM2aM\nb9q0yVevXu3HH3+8jxs3zt/73vf6T3/60977t7e3+2c/+1lvaWnx7bff3ufNm+dbtmzx//iP//Dm\n5mYfO3asH3jggb5q1Sp3d3/66ad95syZPm7cON977717y5dLHBpuXsEYNlj8yld3D/7oebGucxKt\nXOdJFPEnimMoflU/ftVqAd4JwEtpl1cBB6Xfwd1/CfyykIO1t7f3/q2tr/rrWwMqc9X1wdaASu14\n0LO2hwljJ+Rdlb3WC+yWqtxFhqNcpDhl48aN3HzzzXz0ox/NuP7GG2/kN7/5DQcffDDvvPNOzsem\nFnu87777GDJkCI8//jhNTcHn9ac//YkzzzyTO+64gwMOOIAFCxZw/PHH89xzz7HNNttkHOeFF16g\nqamJa665hunTpwPwD//wD3zwgx/klVde4amnnmLmzJlMmTKlt64tWrSIn//851x//fW88847fO97\n3+Pmm2/mzjvvZMqUKTz++OOMHDmSjRs3MmvWLL71rW9x11138dhjjzFz5kw+8IEPsPfee+d9X2K4\n1VVkMWyg+JVZd7tgXCuMfpFX3nmLGy64TbNIG1gU8SfqGKb4lVvk8aucVl+h/+j/a/UzwNVpl1uA\nH5Z47LytXQmU0h2ehCHQQuU7R+LU4zZmzBjfcccdfZtttvEJEyb4E0880Xv7nDlz/LTTTst4TK5f\nrB/72Md6L5tZxlDDOeec49/4RmYP61577eXLli3LW6bUr+iXXnrJhw0b5hs2bOi9/eKLL/bTTz/d\n3YNfrEcccUS/Y99+++39jnvzzTf74YcfnnHd2Wef7d/85jdzliPfZ0fte9wiiWGDxa++uvuEs1d9\n1EcpXq7zJE49bopf1Y1ftZpV2gNMTLu8e3hdSdrb2+P2azxWmpomsXjxecyefRnTp7cxe/Zlg05M\naL28tW9tNoDh0PnBTlovb61OoaugmEWGK/H4dLfddhtvvPEG77zzDldeeSWHH344r776au/te+yx\nR9HHTLdy5Uq+973vMW7cOMaNG8eOO+7IqlWrWL168JmIq1evZty4cYwcObL3ukmTJtHT01dls8v3\n0ksv5UwsXrlyJcuXL88oxw033MArr7xS0OtYunRpRg9VDUUWwwaKX6m6O3n/k+Ez9V0fpThRxJ+o\n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\n", | |
"text/plain": [ | |
"<matplotlib.figure.Figure at 0x7fa3ae49e940>" | |
] | |
}, | |
"metadata": {}, | |
"output_type": "display_data" | |
} | |
], | |
"source": [ | |
"fig, (ax1, ax2) = plt.subplots(1,2,figsize=(10,4))\n", | |
"ax1.loglog(directN, directTimes, marker='o', ls='none', label='Brute force')\n", | |
"ax1.loglog(dpN, dpTimes, marker='o', ls='none', label='DP')\n", | |
"ax2.semilogy(directN, directTimes, marker='o', ls='none', label='Brute force')\n", | |
"ax2.semilogy(dpN, dpTimes, marker='o', ls='none', label='DP')\n", | |
"\n", | |
"ax1.set_title('SSP for first N primes numbers (loglog)')\n", | |
"ax2.set_title('SSP for first N primes numbers (linlog)')\n", | |
"for ax in (ax1, ax2):\n", | |
" ax.set_xlabel('N')\n", | |
" ax.set_ylabel('Run time')\n", | |
" ax.legend(loc='lower right')" | |
] | |
}, | |
{ | |
"cell_type": "code", | |
"execution_count": null, | |
"metadata": { | |
"collapsed": true | |
}, | |
"outputs": [], | |
"source": [] | |
} | |
], | |
"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+" | |
} | |
}, | |
"nbformat": 4, | |
"nbformat_minor": 0 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment