Skip to content

Instantly share code, notes, and snippets.

@neworderofjamie
Last active October 28, 2021 11:38
Show Gist options
  • Save neworderofjamie/fb27c79d5839ffe781051cf2a0be86dc to your computer and use it in GitHub Desktop.
Save neworderofjamie/fb27c79d5839ffe781051cf2a0be86dc to your computer and use it in GitHub Desktop.
Spike propagation through Toeplitz matrix
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import cv2\n",
"\n",
"from scipy.linalg import toeplitz"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Test data"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [],
"source": [
"INPUT_SIZE = 64\n",
"INPUT_CHANNELS = 1\n",
"OUTPUT_SIZE = 62\n",
"OUTPUT_CHANNELS = 1\n",
"\n",
"if INPUT_CHANNELS == 1:\n",
" spike_indices = np.asarray([65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75,\n",
" 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,\n",
" 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97,\n",
" 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108,\n",
" 109, 110, 129, 130, 131, 132, 133, 134, 135, 136, 137,\n",
" 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,\n",
" 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,\n",
" 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170,\n",
" 171, 172, 173, 174, 193, 194, 195, 196, 197, 198, 199,\n",
" 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210,\n",
" 211, 212, 213, 214, 215, 257, 258, 259, 260, 261, 262,\n",
" 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273,\n",
" 274, 275, 276, 277, 278, 279, 321, 322, 323, 324, 325,\n",
" 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336,\n",
" 337, 338, 339, 340, 341, 342, 343, 385, 386, 387, 388,\n",
" 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399,\n",
" 400, 401, 402, 403, 404, 405, 406, 407, 449, 450, 451,\n",
" 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462,\n",
" 463, 464, 465, 466, 467, 468, 469, 470, 471, 507, 508,\n",
" 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523,\n",
" 524, 525, 526, 527, 528, 529, 530, 531, 532, 533, 534,\n",
" 535, 568, 569, 570, 571, 577, 578, 579, 580, 581, 582,\n",
" 583, 584, 585, 586, 587, 588, 589, 590, 591, 592, 593,\n",
" 594, 595, 596, 597, 598, 599, 629, 630, 631, 632, 633,\n",
" 634, 641, 642, 643, 644, 645, 646, 647, 648, 649, 650,\n",
" 651, 652, 653, 654, 655, 656, 657, 658, 659, 660, 661,\n",
" 662, 663, 690, 691, 692, 693, 694, 695, 696, 697, 705,\n",
" 706, 707, 708, 709, 710, 711, 712, 713, 714, 715, 716,\n",
" 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727,\n",
" 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760,\n",
" 769, 770, 771, 772, 773, 774, 775, 776, 777, 778, 779,\n",
" 780, 781, 782, 783, 784, 785, 786, 787, 788, 789, 790,\n",
" 791, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819,\n",
" 820, 821, 822, 823, 833, 834, 835, 836, 837, 838, 839,\n",
" 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850,\n",
" 851, 852, 853, 854, 855, 871, 872, 873, 874, 875, 876,\n",
" 877, 878, 879, 880, 881, 882, 883, 884, 885, 886, 897,\n",
" 898, 899, 900, 901, 902, 903, 904, 905, 906, 907, 908,\n",
" 909, 910, 911, 912, 913, 914, 915, 916, 917, 918, 919,\n",
" 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942,\n",
" 943, 944, 945, 946, 947, 948, 949, 992, 993, 994, 995,\n",
" 996, 997, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005, 1006,\n",
" 1007, 1008, 1009, 1010, 1011, 1012, 1053, 1054, 1055, 1056, 1057,\n",
" 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066, 1067, 1068,\n",
" 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1114, 1115, 1116, 1117,\n",
" 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128,\n",
" 1129, 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1174,\n",
" 1175, 1176, 1177, 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185,\n",
" 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 1194, 1195, 1196,\n",
" 1197, 1198, 1199, 1200, 1201, 1217, 1218, 1219, 1220, 1221, 1222,\n",
" 1223, 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, 1232, 1235,\n",
" 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243, 1244, 1245, 1246,\n",
" 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257,\n",
" 1258, 1259, 1260, 1261, 1262, 1263, 1264, 1281, 1282, 1283, 1284,\n",
" 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295,\n",
" 1296, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1308,\n",
" 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, 1317, 1318, 1319,\n",
" 1320, 1321, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1345, 1346,\n",
" 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357,\n",
" 1358, 1359, 1360, 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373,\n",
" 1374, 1375, 1376, 1377, 1378, 1379, 1380, 1381, 1382, 1383, 1384,\n",
" 1385, 1386, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1409, 1410,\n",
" 1411, 1412, 1413, 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421,\n",
" 1422, 1423, 1424, 1433, 1434, 1435, 1436, 1437, 1438, 1439, 1440,\n",
" 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1448, 1449, 1450, 1451,\n",
" 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1473, 1474, 1475, 1476,\n",
" 1477, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, 1486, 1487,\n",
" 1488, 1501, 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, 1510,\n",
" 1511, 1512, 1513, 1514, 1515, 1516, 1517, 1518, 1519, 1520, 1521,\n",
" 1522, 1523, 1537, 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545,\n",
" 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1568, 1569, 1570, 1571,\n",
" 1572, 1573, 1574, 1575, 1576, 1577, 1578, 1579, 1580, 1581, 1582,\n",
" 1583, 1584, 1585, 1586, 1587, 1588, 1601, 1602, 1603, 1604, 1605,\n",
" 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615, 1616,\n",
" 1636, 1637, 1638, 1639, 1640, 1641, 1642, 1643, 1644, 1645, 1646,\n",
" 1647, 1648, 1649, 1650, 1651, 1652, 1653, 1665, 1666, 1667, 1668,\n",
" 1669, 1670, 1671, 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679,\n",
" 1680, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, 1712,\n",
" 1713, 1714, 1715, 1716, 1717, 1718, 1729, 1730, 1731, 1732, 1733,\n",
" 1734, 1735, 1736, 1737, 1738, 1739, 1740, 1741, 1742, 1743, 1744,\n",
" 1770, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 1779, 1780,\n",
" 1781, 1782, 1783, 1793, 1794, 1795, 1796, 1797, 1798, 1799, 1800,\n",
" 1801, 1802, 1803, 1804, 1805, 1806, 1807, 1808, 1837, 1838, 1839,\n",
" 1840, 1841, 1842, 1843, 1844, 1845, 1846, 1847, 1848, 1857, 1858,\n",
" 1859, 1860, 1861, 1862, 1863, 1864, 1865, 1866, 1867, 1868, 1869,\n",
" 1870, 1871, 1872, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911,\n",
" 1912, 1913, 1921, 1922, 1923, 1924, 1925, 1926, 1927, 1928, 1929,\n",
" 1930, 1931, 1932, 1933, 1934, 1935, 1936, 1972, 1973, 1974, 1975,\n",
" 1976, 1977, 1978, 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992,\n",
" 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2039, 2040, 2041,\n",
" 2042, 2043, 2049, 2050, 2051, 2052, 2053, 2054, 2055, 2056, 2057,\n",
" 2058, 2059, 2060, 2061, 2062, 2063, 2064, 2106, 2107, 2108, 2267,\n",
" 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278,\n",
" 2279, 2280, 2281, 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2305,\n",
" 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316,\n",
" 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2331, 2332, 2333, 2334,\n",
" 2335, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345,\n",
" 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2370, 2371, 2372, 2373,\n",
" 2374, 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, 2383, 2384,\n",
" 2385, 2386, 2387, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2402,\n",
" 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 2412, 2413,\n",
" 2414, 2415, 2416, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2442,\n",
" 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2459, 2460,\n",
" 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 2470, 2471,\n",
" 2472, 2473, 2474, 2475, 2476, 2477, 2478, 2479, 2480, 2500, 2501,\n",
" 2502, 2503, 2504, 2505, 2506, 2507, 2508, 2509, 2510, 2511, 2512,\n",
" 2513, 2514, 2515, 2523, 2524, 2525, 2526, 2527, 2528, 2529, 2530,\n",
" 2531, 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, 2540, 2541,\n",
" 2542, 2543, 2544, 2565, 2566, 2567, 2568, 2569, 2570, 2571, 2572,\n",
" 2573, 2574, 2575, 2576, 2577, 2578, 2579, 2587, 2588, 2589, 2590,\n",
" 2591, 2592, 2593, 2594, 2595, 2596, 2597, 2598, 2599, 2600, 2601,\n",
" 2602, 2603, 2604, 2605, 2606, 2607, 2608, 2630, 2631, 2632, 2633,\n",
" 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 2651,\n",
" 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, 2660, 2661, 2662,\n",
" 2663, 2664, 2665, 2666, 2667, 2668, 2669, 2670, 2671, 2672, 2695,\n",
" 2696, 2697, 2698, 2699, 2700, 2701, 2702, 2703, 2704, 2705, 2706,\n",
" 2707, 2715, 2716, 2717, 2718, 2719, 2720, 2721, 2722, 2723, 2724,\n",
" 2725, 2726, 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, 2735,\n",
" 2736, 2760, 2761, 2762, 2763, 2764, 2765, 2766, 2767, 2768, 2769,\n",
" 2770, 2771, 2779, 2780, 2781, 2782, 2783, 2784, 2785, 2786, 2787,\n",
" 2788, 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, 2797, 2798,\n",
" 2799, 2800, 2825, 2826, 2827, 2828, 2829, 2830, 2831, 2832, 2833,\n",
" 2834, 2835, 2843, 2844, 2845, 2846, 2847, 2848, 2849, 2850, 2851,\n",
" 2852, 2853, 2854, 2855, 2856, 2857, 2858, 2859, 2860, 2861, 2862,\n",
" 2863, 2864, 2890, 2891, 2892, 2893, 2894, 2895, 2896, 2897, 2898,\n",
" 2899, 2907, 2908, 2909, 2910, 2911, 2912, 2913, 2914, 2915, 2916,\n",
" 2917, 2918, 2919, 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927,\n",
" 2928, 2955, 2956, 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2971,\n",
" 2972, 2973, 2974, 2975, 2976, 2977, 2978, 2979, 2980, 2981, 2982,\n",
" 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 2992, 3020,\n",
" 3021, 3022, 3023, 3024, 3025, 3026, 3027, 3035, 3036, 3037, 3038,\n",
" 3039, 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, 3048, 3049,\n",
" 3050, 3051, 3052, 3053, 3054, 3055, 3056, 3085, 3086, 3087, 3088,\n",
" 3089, 3090, 3091, 3099, 3100, 3101, 3102, 3103, 3104, 3105, 3106,\n",
" 3107, 3108, 3109, 3110, 3111, 3112, 3113, 3114, 3115, 3116, 3117,\n",
" 3118, 3119, 3120, 3150, 3151, 3152, 3153, 3154, 3155, 3215, 3216,\n",
" 3217, 3218, 3219, 3280, 3281, 3282, 3283, 3345, 3346, 3347, 3410,\n",
" 3411, 3475, 3547, 3548, 3549, 3550, 3551, 3608, 3609, 3610, 3611,\n",
" 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3669, 3670, 3671, 3672,\n",
" 3673, 3674, 3675, 3676, 3677, 3678, 3679, 3680, 3681, 3682, 3683,\n",
" 3684, 3685, 3686, 3730, 3731, 3732, 3733, 3734, 3735, 3736, 3737,\n",
" 3738, 3739, 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, 3748,\n",
" 3749, 3750, 3751, 3752, 3753, 3790, 3791, 3792, 3793, 3794, 3795,\n",
" 3796, 3797, 3798, 3799, 3800, 3801, 3802, 3803, 3804, 3805, 3806,\n",
" 3807, 3808, 3809, 3810, 3811, 3812, 3813, 3814, 3815, 3816, 3817,\n",
" 3818, 3819, 3820, 3851, 3852, 3853, 3854, 3855, 3856, 3857, 3858,\n",
" 3859, 3860, 3861, 3862, 3863, 3864, 3865, 3866, 3867, 3868, 3869,\n",
" 3870, 3871, 3872, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880,\n",
" 3881, 3882, 3883, 3884, 3885, 3886, 3887, 3912, 3913, 3914, 3915,\n",
" 3916, 3917, 3918, 3919, 3920, 3921, 3922, 3923, 3924, 3925, 3926,\n",
" 3927, 3928, 3929, 3930, 3931, 3932, 3933, 3934, 3935, 3936, 3937,\n",
" 3938, 3939, 3940, 3941, 3942, 3943, 3944, 3945, 3946, 3947, 3948,\n",
" 3949, 3950, 3951, 3952, 3953, 3954, 3973, 3974, 3975, 3976, 3977,\n",
" 3978, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3988,\n",
" 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999,\n",
" 4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, 4008, 4009, 4010,\n",
" 4011, 4012, 4013, 4014, 4015, 4016, 4017, 4018, 4019, 4020, 4021,\n",
" 4022, 4035, 4036, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044,\n",
" 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055,\n",
" 4056, 4057, 4058, 4059, 4060, 4061, 4062, 4063, 4064, 4065, 4066,\n",
" 4067, 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, 4076, 4077,\n",
" 4078, 4079, 4080, 4081, 4082, 4083, 4084, 4085, 4086, 4087, 4088], dtype=int)\n",
" if OUTPUT_CHANNELS == 1:\n",
" filt = np.asarray([[[[1, 2, 1],\n",
" [0, 0, 0],\n",
" [-1, -2, -1]]]])\n",
" elif OUTPUT_CHANNELS == 2:\n",
" filt = np.asarray([[[[1, 2, 1],\n",
" [0, 0, 0],\n",
" [-1, -2, -1]]],\n",
" [[[0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111]]]])\n",
" else:\n",
" assert False\n",
"elif INPUT_CHANNELS == 3:\n",
" spike_indices = np.asarray([197, 200, 203, 206, 209, 212, 215, 218, 221, 224,\n",
" 227, 230, 233, 236, 239, 242, 245, 248, 251, 254,\n",
" 257, 260, 263, 266, 269, 272, 275, 278, 281, 284,\n",
" 287, 290, 293, 296, 299, 302, 305, 308, 311, 314,\n",
" 317, 320, 323, 326, 329, 332, 389, 392, 395, 398,\n",
" 401, 404, 407, 410, 413, 416, 419, 422, 425, 428,\n",
" 431, 434, 437, 440, 443, 446, 449, 452, 455, 458,\n",
" 461, 464, 467, 470, 473, 476, 479, 482, 485, 488,\n",
" 491, 494, 497, 500, 503, 506, 509, 512, 515, 518,\n",
" 521, 524, 581, 584, 587, 590, 593, 596, 599, 602,\n",
" 605, 608, 611, 614, 617, 620, 623, 626, 629, 632,\n",
" 635, 638, 641, 644, 647, 773, 776, 779, 782, 785,\n",
" 788, 791, 794, 797, 800, 803, 806, 809, 812, 815,\n",
" 818, 821, 824, 827, 830, 833, 836, 839, 965, 968,\n",
" 971, 974, 977, 980, 983, 986, 989, 992, 995, 998,\n",
" 1001, 1004, 1007, 1010, 1013, 1016, 1019, 1022, 1025, 1028,\n",
" 1031, 1157, 1160, 1163, 1166, 1169, 1172, 1175, 1178, 1181,\n",
" 1184, 1187, 1190, 1193, 1196, 1199, 1202, 1205, 1208, 1211,\n",
" 1214, 1217, 1220, 1223, 1349, 1352, 1355, 1358, 1361, 1364,\n",
" 1367, 1370, 1373, 1376, 1379, 1382, 1385, 1388, 1391, 1394,\n",
" 1397, 1400, 1403, 1406, 1409, 1412, 1415, 1521, 1523, 1524,\n",
" 1526, 1541, 1544, 1547, 1550, 1553, 1556, 1559, 1562, 1565,\n",
" 1568, 1571, 1574, 1577, 1580, 1583, 1586, 1589, 1592, 1595,\n",
" 1598, 1601, 1604, 1607, 1704, 1706, 1707, 1709, 1710, 1712,\n",
" 1713, 1715, 1733, 1736, 1739, 1742, 1745, 1748, 1751, 1754,\n",
" 1757, 1760, 1763, 1766, 1769, 1772, 1775, 1778, 1781, 1784,\n",
" 1787, 1790, 1793, 1796, 1799, 1887, 1889, 1890, 1892, 1893,\n",
" 1895, 1896, 1898, 1899, 1901, 1902, 1904, 1925, 1928, 1931,\n",
" 1934, 1937, 1940, 1943, 1946, 1949, 1952, 1955, 1958, 1961,\n",
" 1964, 1967, 1970, 1973, 1976, 1979, 1982, 1985, 1988, 1991,\n",
" 2070, 2072, 2073, 2075, 2076, 2078, 2079, 2081, 2082, 2084,\n",
" 2085, 2087, 2088, 2090, 2091, 2093, 2117, 2120, 2123, 2126,\n",
" 2129, 2132, 2135, 2138, 2141, 2144, 2147, 2150, 2153, 2156,\n",
" 2159, 2162, 2165, 2168, 2171, 2174, 2177, 2180, 2183, 2250,\n",
" 2252, 2253, 2255, 2256, 2258, 2259, 2261, 2262, 2264, 2265,\n",
" 2267, 2268, 2270, 2271, 2273, 2274, 2276, 2277, 2279, 2280,\n",
" 2282, 2309, 2312, 2315, 2318, 2321, 2324, 2327, 2330, 2333,\n",
" 2336, 2339, 2342, 2345, 2348, 2351, 2354, 2357, 2360, 2363,\n",
" 2366, 2369, 2372, 2375, 2430, 2432, 2433, 2435, 2436, 2438,\n",
" 2439, 2441, 2442, 2444, 2445, 2447, 2448, 2450, 2451, 2453,\n",
" 2454, 2456, 2457, 2459, 2460, 2462, 2463, 2465, 2466, 2468,\n",
" 2469, 2471, 2501, 2504, 2507, 2510, 2513, 2516, 2519, 2522,\n",
" 2525, 2528, 2531, 2534, 2537, 2540, 2543, 2546, 2549, 2552,\n",
" 2555, 2558, 2561, 2564, 2567, 2613, 2615, 2616, 2618, 2619,\n",
" 2621, 2622, 2624, 2625, 2627, 2628, 2630, 2631, 2633, 2634,\n",
" 2636, 2637, 2639, 2640, 2642, 2643, 2645, 2646, 2648, 2649,\n",
" 2651, 2652, 2654, 2655, 2657, 2658, 2660, 2693, 2696, 2699,\n",
" 2702, 2705, 2708, 2711, 2714, 2717, 2720, 2723, 2726, 2729,\n",
" 2732, 2735, 2738, 2741, 2744, 2747, 2750, 2753, 2756, 2759,\n",
" 2796, 2798, 2799, 2801, 2802, 2804, 2805, 2807, 2808, 2810,\n",
" 2811, 2813, 2814, 2816, 2817, 2819, 2820, 2822, 2823, 2825,\n",
" 2826, 2828, 2829, 2831, 2832, 2834, 2835, 2837, 2838, 2840,\n",
" 2841, 2843, 2844, 2846, 2847, 2849, 2976, 2978, 2979, 2981,\n",
" 2982, 2984, 2985, 2987, 2988, 2990, 2991, 2993, 2994, 2996,\n",
" 2997, 2999, 3000, 3002, 3003, 3005, 3006, 3008, 3009, 3011,\n",
" 3012, 3014, 3015, 3017, 3018, 3020, 3021, 3023, 3024, 3026,\n",
" 3027, 3029, 3030, 3032, 3033, 3035, 3036, 3038, 3159, 3161,\n",
" 3162, 3164, 3165, 3167, 3168, 3170, 3171, 3173, 3174, 3176,\n",
" 3177, 3179, 3180, 3182, 3183, 3185, 3186, 3188, 3189, 3191,\n",
" 3192, 3194, 3195, 3197, 3198, 3200, 3201, 3203, 3204, 3206,\n",
" 3207, 3209, 3210, 3212, 3213, 3215, 3216, 3218, 3219, 3221,\n",
" 3222, 3224, 3225, 3227, 3342, 3344, 3345, 3347, 3348, 3350,\n",
" 3351, 3353, 3354, 3356, 3357, 3359, 3360, 3362, 3363, 3365,\n",
" 3366, 3368, 3369, 3371, 3372, 3374, 3375, 3377, 3378, 3380,\n",
" 3381, 3383, 3384, 3386, 3387, 3389, 3390, 3392, 3393, 3395,\n",
" 3396, 3398, 3399, 3401, 3402, 3404, 3405, 3407, 3408, 3410,\n",
" 3411, 3413, 3414, 3416, 3522, 3524, 3525, 3527, 3528, 3530,\n",
" 3531, 3533, 3534, 3536, 3537, 3539, 3540, 3542, 3543, 3545,\n",
" 3546, 3548, 3549, 3551, 3552, 3554, 3555, 3557, 3558, 3560,\n",
" 3561, 3563, 3564, 3566, 3567, 3569, 3570, 3572, 3573, 3575,\n",
" 3576, 3578, 3579, 3581, 3582, 3584, 3585, 3587, 3588, 3590,\n",
" 3591, 3593, 3594, 3596, 3597, 3599, 3600, 3602, 3603, 3605,\n",
" 3652, 3655, 3658, 3661, 3664, 3667, 3670, 3673, 3676, 3679,\n",
" 3682, 3685, 3688, 3691, 3694, 3697, 3705, 3707, 3708, 3710,\n",
" 3711, 3713, 3714, 3716, 3717, 3719, 3720, 3722, 3723, 3725,\n",
" 3726, 3728, 3729, 3731, 3732, 3734, 3735, 3737, 3738, 3740,\n",
" 3741, 3743, 3744, 3746, 3747, 3749, 3750, 3752, 3753, 3755,\n",
" 3756, 3758, 3759, 3761, 3762, 3764, 3765, 3767, 3768, 3770,\n",
" 3771, 3773, 3774, 3776, 3777, 3779, 3780, 3782, 3783, 3785,\n",
" 3786, 3788, 3789, 3791, 3792, 3794, 3844, 3847, 3850, 3853,\n",
" 3856, 3859, 3862, 3865, 3868, 3871, 3874, 3877, 3880, 3883,\n",
" 3886, 3889, 3897, 3899, 3900, 3902, 3903, 3905, 3906, 3908,\n",
" 3909, 3911, 3912, 3914, 3915, 3917, 3918, 3920, 3921, 3923,\n",
" 3924, 3926, 3927, 3929, 3930, 3932, 3933, 3935, 3936, 3938,\n",
" 3939, 3941, 3942, 3944, 3945, 3947, 3948, 3950, 3951, 3953,\n",
" 3954, 3956, 3957, 3959, 3960, 3962, 3963, 3965, 3966, 3968,\n",
" 3969, 3971, 3972, 3974, 3975, 3977, 3978, 3980, 3981, 3983,\n",
" 3984, 3986, 4036, 4039, 4042, 4045, 4048, 4051, 4054, 4057,\n",
" 4060, 4063, 4066, 4069, 4072, 4075, 4078, 4081, 4098, 4100,\n",
" 4101, 4103, 4104, 4106, 4107, 4109, 4110, 4112, 4113, 4115,\n",
" 4116, 4118, 4119, 4121, 4122, 4124, 4125, 4127, 4128, 4130,\n",
" 4131, 4133, 4134, 4136, 4137, 4139, 4140, 4142, 4143, 4145,\n",
" 4146, 4148, 4149, 4151, 4152, 4154, 4155, 4157, 4158, 4160,\n",
" 4161, 4163, 4164, 4166, 4167, 4169, 4170, 4172, 4173, 4175,\n",
" 4176, 4178, 4179, 4181, 4228, 4231, 4234, 4237, 4240, 4243,\n",
" 4246, 4249, 4252, 4255, 4258, 4261, 4264, 4267, 4270, 4273,\n",
" 4299, 4301, 4302, 4304, 4305, 4307, 4308, 4310, 4311, 4313,\n",
" 4314, 4316, 4317, 4319, 4320, 4322, 4323, 4325, 4326, 4328,\n",
" 4329, 4331, 4332, 4334, 4335, 4337, 4338, 4340, 4341, 4343,\n",
" 4344, 4346, 4347, 4349, 4350, 4352, 4353, 4355, 4356, 4358,\n",
" 4359, 4361, 4362, 4364, 4365, 4367, 4368, 4370, 4371, 4373,\n",
" 4374, 4376, 4420, 4423, 4426, 4429, 4432, 4435, 4438, 4441,\n",
" 4444, 4447, 4450, 4453, 4456, 4459, 4462, 4465, 4503, 4505,\n",
" 4506, 4508, 4509, 4511, 4512, 4514, 4515, 4517, 4518, 4520,\n",
" 4521, 4523, 4524, 4526, 4527, 4529, 4530, 4532, 4533, 4535,\n",
" 4536, 4538, 4539, 4541, 4542, 4544, 4545, 4547, 4548, 4550,\n",
" 4551, 4553, 4554, 4556, 4557, 4559, 4560, 4562, 4563, 4565,\n",
" 4566, 4568, 4569, 4571, 4612, 4615, 4618, 4621, 4624, 4627,\n",
" 4630, 4633, 4636, 4639, 4642, 4645, 4648, 4651, 4654, 4657,\n",
" 4704, 4706, 4707, 4709, 4710, 4712, 4713, 4715, 4716, 4718,\n",
" 4719, 4721, 4722, 4724, 4725, 4727, 4728, 4730, 4731, 4733,\n",
" 4734, 4736, 4737, 4739, 4740, 4742, 4743, 4745, 4746, 4748,\n",
" 4749, 4751, 4752, 4754, 4755, 4757, 4758, 4760, 4761, 4763,\n",
" 4764, 4766, 4804, 4807, 4810, 4813, 4816, 4819, 4822, 4825,\n",
" 4828, 4831, 4834, 4837, 4840, 4843, 4846, 4849, 4908, 4910,\n",
" 4911, 4913, 4914, 4916, 4917, 4919, 4920, 4922, 4923, 4925,\n",
" 4926, 4928, 4929, 4931, 4932, 4934, 4935, 4937, 4938, 4940,\n",
" 4941, 4943, 4944, 4946, 4947, 4949, 4950, 4952, 4953, 4955,\n",
" 4956, 4958, 4959, 4961, 4996, 4999, 5002, 5005, 5008, 5011,\n",
" 5014, 5017, 5020, 5023, 5026, 5029, 5032, 5035, 5038, 5041,\n",
" 5109, 5111, 5112, 5114, 5115, 5117, 5118, 5120, 5121, 5123,\n",
" 5124, 5126, 5127, 5129, 5130, 5132, 5133, 5135, 5136, 5138,\n",
" 5139, 5141, 5142, 5144, 5145, 5147, 5148, 5150, 5151, 5153,\n",
" 5154, 5156, 5188, 5191, 5194, 5197, 5200, 5203, 5206, 5209,\n",
" 5212, 5215, 5218, 5221, 5224, 5227, 5230, 5233, 5310, 5312,\n",
" 5313, 5315, 5316, 5318, 5319, 5321, 5322, 5324, 5325, 5327,\n",
" 5328, 5330, 5331, 5333, 5334, 5336, 5337, 5339, 5340, 5342,\n",
" 5343, 5345, 5346, 5348, 5349, 5351, 5380, 5383, 5386, 5389,\n",
" 5392, 5395, 5398, 5401, 5404, 5407, 5410, 5413, 5416, 5419,\n",
" 5422, 5425, 5511, 5513, 5514, 5516, 5517, 5519, 5520, 5522,\n",
" 5523, 5525, 5526, 5528, 5529, 5531, 5532, 5534, 5535, 5537,\n",
" 5538, 5540, 5541, 5543, 5544, 5546, 5572, 5575, 5578, 5581,\n",
" 5584, 5587, 5590, 5593, 5596, 5599, 5602, 5605, 5608, 5611,\n",
" 5614, 5617, 5712, 5714, 5715, 5717, 5718, 5720, 5721, 5723,\n",
" 5724, 5726, 5727, 5729, 5730, 5732, 5733, 5735, 5736, 5738,\n",
" 5739, 5741, 5764, 5767, 5770, 5773, 5776, 5779, 5782, 5785,\n",
" 5788, 5791, 5794, 5797, 5800, 5803, 5806, 5809, 5916, 5918,\n",
" 5919, 5921, 5922, 5924, 5925, 5927, 5928, 5930, 5931, 5933,\n",
" 5934, 5936, 5956, 5959, 5962, 5965, 5968, 5971, 5974, 5977,\n",
" 5980, 5983, 5986, 5989, 5992, 5995, 5998, 6001, 6117, 6119,\n",
" 6120, 6122, 6123, 6125, 6126, 6128, 6129, 6131, 6148, 6151,\n",
" 6154, 6157, 6160, 6163, 6166, 6169, 6172, 6175, 6178, 6181,\n",
" 6184, 6187, 6190, 6193, 6318, 6320, 6321, 6323, 6324, 6326,\n",
" 6803, 6806, 6809, 6812, 6815, 6818, 6821, 6824, 6827, 6830,\n",
" 6833, 6836, 6839, 6842, 6845, 6848, 6851, 6854, 6857, 6860,\n",
" 6863, 6866, 6915, 6918, 6921, 6924, 6927, 6930, 6933, 6936,\n",
" 6939, 6942, 6945, 6948, 6951, 6954, 6957, 6960, 6963, 6966,\n",
" 6969, 6995, 6998, 7001, 7004, 7007, 7010, 7013, 7016, 7019,\n",
" 7022, 7025, 7028, 7031, 7034, 7037, 7040, 7043, 7046, 7049,\n",
" 7052, 7055, 7058, 7110, 7113, 7116, 7119, 7122, 7125, 7128,\n",
" 7131, 7134, 7137, 7140, 7143, 7146, 7149, 7152, 7155, 7158,\n",
" 7161, 7187, 7190, 7193, 7196, 7199, 7202, 7205, 7208, 7211,\n",
" 7214, 7217, 7220, 7223, 7226, 7229, 7232, 7235, 7238, 7241,\n",
" 7244, 7247, 7250, 7305, 7308, 7311, 7314, 7317, 7320, 7323,\n",
" 7326, 7329, 7332, 7335, 7338, 7341, 7344, 7347, 7350, 7353,\n",
" 7379, 7382, 7385, 7388, 7391, 7394, 7397, 7400, 7403, 7406,\n",
" 7409, 7412, 7415, 7418, 7421, 7424, 7427, 7430, 7433, 7436,\n",
" 7439, 7442, 7500, 7503, 7506, 7509, 7512, 7515, 7518, 7521,\n",
" 7524, 7527, 7530, 7533, 7536, 7539, 7542, 7545, 7571, 7574,\n",
" 7577, 7580, 7583, 7586, 7589, 7592, 7595, 7598, 7601, 7604,\n",
" 7607, 7610, 7613, 7616, 7619, 7622, 7625, 7628, 7631, 7634,\n",
" 7695, 7698, 7701, 7704, 7707, 7710, 7713, 7716, 7719, 7722,\n",
" 7725, 7728, 7731, 7734, 7737, 7763, 7766, 7769, 7772, 7775,\n",
" 7778, 7781, 7784, 7787, 7790, 7793, 7796, 7799, 7802, 7805,\n",
" 7808, 7811, 7814, 7817, 7820, 7823, 7826, 7890, 7893, 7896,\n",
" 7899, 7902, 7905, 7908, 7911, 7914, 7917, 7920, 7923, 7926,\n",
" 7929, 7955, 7958, 7961, 7964, 7967, 7970, 7973, 7976, 7979,\n",
" 7982, 7985, 7988, 7991, 7994, 7997, 8000, 8003, 8006, 8009,\n",
" 8012, 8015, 8018, 8085, 8088, 8091, 8094, 8097, 8100, 8103,\n",
" 8106, 8109, 8112, 8115, 8118, 8121, 8147, 8150, 8153, 8156,\n",
" 8159, 8162, 8165, 8168, 8171, 8174, 8177, 8180, 8183, 8186,\n",
" 8189, 8192, 8195, 8198, 8201, 8204, 8207, 8210, 8280, 8283,\n",
" 8286, 8289, 8292, 8295, 8298, 8301, 8304, 8307, 8310, 8313,\n",
" 8339, 8342, 8345, 8348, 8351, 8354, 8357, 8360, 8363, 8366,\n",
" 8369, 8372, 8375, 8378, 8381, 8384, 8387, 8390, 8393, 8396,\n",
" 8399, 8402, 8475, 8478, 8481, 8484, 8487, 8490, 8493, 8496,\n",
" 8499, 8502, 8505, 8531, 8534, 8537, 8540, 8543, 8546, 8549,\n",
" 8552, 8555, 8558, 8561, 8564, 8567, 8570, 8573, 8576, 8579,\n",
" 8582, 8585, 8588, 8591, 8594, 8670, 8673, 8676, 8679, 8682,\n",
" 8685, 8688, 8691, 8694, 8697, 8723, 8726, 8729, 8732, 8735,\n",
" 8738, 8741, 8744, 8747, 8750, 8753, 8756, 8759, 8762, 8765,\n",
" 8768, 8771, 8774, 8777, 8780, 8783, 8786, 8865, 8868, 8871,\n",
" 8874, 8877, 8880, 8883, 8886, 8889, 8915, 8918, 8921, 8924,\n",
" 8927, 8930, 8933, 8936, 8939, 8942, 8945, 8948, 8951, 8954,\n",
" 8957, 8960, 8963, 8966, 8969, 8972, 8975, 8978, 9060, 9063,\n",
" 9066, 9069, 9072, 9075, 9078, 9081, 9107, 9110, 9113, 9116,\n",
" 9119, 9122, 9125, 9128, 9131, 9134, 9137, 9140, 9143, 9146,\n",
" 9149, 9152, 9155, 9158, 9161, 9164, 9167, 9170, 9255, 9258,\n",
" 9261, 9264, 9267, 9270, 9273, 9299, 9302, 9305, 9308, 9311,\n",
" 9314, 9317, 9320, 9323, 9326, 9329, 9332, 9335, 9338, 9341,\n",
" 9344, 9347, 9350, 9353, 9356, 9359, 9362, 9450, 9453, 9456,\n",
" 9459, 9462, 9465, 9645, 9648, 9651, 9654, 9657, 9840, 9843,\n",
" 9846, 9849, 10035, 10038, 10041, 10230, 10233, 10425, 10641, 10642,\n",
" 10643, 10644, 10645, 10646, 10647, 10648, 10649, 10650, 10651, 10652,\n",
" 10653, 10654, 10655, 10824, 10825, 10826, 10827, 10828, 10829, 10830,\n",
" 10831, 10832, 10833, 10834, 10835, 10836, 10837, 10838, 10839, 10840,\n",
" 10841, 10842, 10843, 10844, 10845, 10846, 10847, 10848, 10849, 10850,\n",
" 10851, 10852, 10853, 10854, 10855, 10856, 11007, 11008, 11009, 11010,\n",
" 11011, 11012, 11013, 11014, 11015, 11016, 11017, 11018, 11019, 11020,\n",
" 11021, 11022, 11023, 11024, 11025, 11026, 11027, 11028, 11029, 11030,\n",
" 11031, 11032, 11033, 11034, 11035, 11036, 11037, 11038, 11039, 11040,\n",
" 11041, 11042, 11043, 11044, 11045, 11046, 11047, 11048, 11049, 11050,\n",
" 11051, 11052, 11053, 11054, 11055, 11056, 11057, 11058, 11059, 11060,\n",
" 11190, 11191, 11192, 11193, 11194, 11195, 11196, 11197, 11198, 11199,\n",
" 11200, 11201, 11202, 11203, 11204, 11205, 11206, 11207, 11208, 11209,\n",
" 11210, 11211, 11212, 11213, 11214, 11215, 11216, 11217, 11218, 11219,\n",
" 11220, 11221, 11222, 11223, 11224, 11225, 11226, 11227, 11228, 11229,\n",
" 11230, 11231, 11232, 11233, 11234, 11235, 11236, 11237, 11238, 11239,\n",
" 11240, 11241, 11242, 11243, 11244, 11245, 11246, 11247, 11248, 11249,\n",
" 11250, 11251, 11252, 11253, 11254, 11255, 11256, 11257, 11258, 11259,\n",
" 11260, 11261, 11370, 11371, 11372, 11373, 11374, 11375, 11376, 11377,\n",
" 11378, 11379, 11380, 11381, 11382, 11383, 11384, 11385, 11386, 11387,\n",
" 11388, 11389, 11390, 11391, 11392, 11393, 11394, 11395, 11396, 11397,\n",
" 11398, 11399, 11400, 11401, 11402, 11403, 11404, 11405, 11406, 11407,\n",
" 11408, 11409, 11410, 11411, 11412, 11413, 11414, 11415, 11416, 11417,\n",
" 11418, 11419, 11420, 11421, 11422, 11423, 11424, 11425, 11426, 11427,\n",
" 11428, 11429, 11430, 11431, 11432, 11433, 11434, 11435, 11436, 11437,\n",
" 11438, 11439, 11440, 11441, 11442, 11443, 11444, 11445, 11446, 11447,\n",
" 11448, 11449, 11450, 11451, 11452, 11453, 11454, 11455, 11456, 11457,\n",
" 11458, 11459, 11460, 11461, 11462, 11553, 11554, 11555, 11556, 11557,\n",
" 11558, 11559, 11560, 11561, 11562, 11563, 11564, 11565, 11566, 11567,\n",
" 11568, 11569, 11570, 11571, 11572, 11573, 11574, 11575, 11576, 11577,\n",
" 11578, 11579, 11580, 11581, 11582, 11583, 11584, 11585, 11586, 11587,\n",
" 11588, 11589, 11590, 11591, 11592, 11593, 11594, 11595, 11596, 11597,\n",
" 11598, 11599, 11600, 11601, 11602, 11603, 11604, 11605, 11606, 11607,\n",
" 11608, 11609, 11610, 11611, 11612, 11613, 11614, 11615, 11616, 11617,\n",
" 11618, 11619, 11620, 11621, 11622, 11623, 11624, 11625, 11626, 11627,\n",
" 11628, 11629, 11630, 11631, 11632, 11633, 11634, 11635, 11636, 11637,\n",
" 11638, 11639, 11640, 11641, 11642, 11643, 11644, 11645, 11646, 11647,\n",
" 11648, 11649, 11650, 11651, 11652, 11653, 11654, 11655, 11656, 11657,\n",
" 11658, 11659, 11660, 11661, 11662, 11663, 11736, 11737, 11738, 11739,\n",
" 11740, 11741, 11742, 11743, 11744, 11745, 11746, 11747, 11748, 11749,\n",
" 11750, 11751, 11752, 11753, 11754, 11755, 11756, 11757, 11758, 11759,\n",
" 11760, 11761, 11762, 11763, 11764, 11765, 11766, 11767, 11768, 11769,\n",
" 11770, 11771, 11772, 11773, 11774, 11775, 11776, 11777, 11778, 11779,\n",
" 11780, 11781, 11782, 11783, 11784, 11785, 11786, 11787, 11788, 11789,\n",
" 11790, 11791, 11792, 11793, 11794, 11795, 11796, 11797, 11798, 11799,\n",
" 11800, 11801, 11802, 11803, 11804, 11805, 11806, 11807, 11808, 11809,\n",
" 11810, 11811, 11812, 11813, 11814, 11815, 11816, 11817, 11818, 11819,\n",
" 11820, 11821, 11822, 11823, 11824, 11825, 11826, 11827, 11828, 11829,\n",
" 11830, 11831, 11832, 11833, 11834, 11835, 11836, 11837, 11838, 11839,\n",
" 11840, 11841, 11842, 11843, 11844, 11845, 11846, 11847, 11848, 11849,\n",
" 11850, 11851, 11852, 11853, 11854, 11855, 11856, 11857, 11858, 11859,\n",
" 11860, 11861, 11862, 11863, 11864, 11919, 11920, 11921, 11922, 11923,\n",
" 11924, 11925, 11926, 11927, 11928, 11929, 11930, 11931, 11932, 11933,\n",
" 11934, 11935, 11936, 11937, 11938, 11939, 11940, 11941, 11942, 11943,\n",
" 11944, 11945, 11946, 11947, 11948, 11949, 11950, 11951, 11952, 11953,\n",
" 11954, 11955, 11956, 11957, 11958, 11959, 11960, 11961, 11962, 11963,\n",
" 11964, 11965, 11966, 11967, 11968, 11969, 11970, 11971, 11972, 11973,\n",
" 11974, 11975, 11976, 11977, 11978, 11979, 11980, 11981, 11982, 11983,\n",
" 11984, 11985, 11986, 11987, 11988, 11989, 11990, 11991, 11992, 11993,\n",
" 11994, 11995, 11996, 11997, 11998, 11999, 12000, 12001, 12002, 12003,\n",
" 12004, 12005, 12006, 12007, 12008, 12009, 12010, 12011, 12012, 12013,\n",
" 12014, 12015, 12016, 12017, 12018, 12019, 12020, 12021, 12022, 12023,\n",
" 12024, 12025, 12026, 12027, 12028, 12029, 12030, 12031, 12032, 12033,\n",
" 12034, 12035, 12036, 12037, 12038, 12039, 12040, 12041, 12042, 12043,\n",
" 12044, 12045, 12046, 12047, 12048, 12049, 12050, 12051, 12052, 12053,\n",
" 12054, 12055, 12056, 12057, 12058, 12059, 12060, 12061, 12062, 12063,\n",
" 12064, 12065, 12066, 12067, 12068, 12105, 12106, 12107, 12108, 12109,\n",
" 12110, 12111, 12112, 12113, 12114, 12115, 12116, 12117, 12118, 12119,\n",
" 12120, 12121, 12122, 12123, 12124, 12125, 12126, 12127, 12128, 12129,\n",
" 12130, 12131, 12132, 12133, 12134, 12135, 12136, 12137, 12138, 12139,\n",
" 12140, 12141, 12142, 12143, 12144, 12145, 12146, 12147, 12148, 12149,\n",
" 12150, 12151, 12152, 12153, 12154, 12155, 12156, 12157, 12158, 12159,\n",
" 12160, 12161, 12162, 12163, 12164, 12165, 12166, 12167, 12168, 12169,\n",
" 12170, 12171, 12172, 12173, 12174, 12175, 12176, 12177, 12178, 12179,\n",
" 12180, 12181, 12182, 12183, 12184, 12185, 12186, 12187, 12188, 12189,\n",
" 12190, 12191, 12192, 12193, 12194, 12195, 12196, 12197, 12198, 12199,\n",
" 12200, 12201, 12202, 12203, 12204, 12205, 12206, 12207, 12208, 12209,\n",
" 12210, 12211, 12212, 12213, 12214, 12215, 12216, 12217, 12218, 12219,\n",
" 12220, 12221, 12222, 12223, 12224, 12225, 12226, 12227, 12228, 12229,\n",
" 12230, 12231, 12232, 12233, 12234, 12235, 12236, 12237, 12238, 12239,\n",
" 12240, 12241, 12242, 12243, 12244, 12245, 12246, 12247, 12248, 12249,\n",
" 12250, 12251, 12252, 12253, 12254, 12255, 12256, 12257, 12258, 12259,\n",
" 12260, 12261, 12262, 12263, 12264, 12265, 12266,], dtype=int)\n",
"\n",
" if OUTPUT_CHANNELS == 1:\n",
" filt = np.asarray([[[[1, 0, -1],\n",
" [2, 0, -2],\n",
" [1, 0, -1]],\n",
" [[1, 2, 1],\n",
" [0, 0, 0],\n",
" [-1, -2, -1]],\n",
" [[-1, -1, -1],\n",
" [-1, 8, -1],\n",
" [-1, -1, -1]]]])\n",
" elif OUTPUT_CHANNELS == 2:\n",
" filt = np.asarray([[[[1, 0, -1],\n",
" [2, 0, -2],\n",
" [1, 0, -1]],\n",
" [[1, 2, 1],\n",
" [0, 0, 0],\n",
" [-1, -2, -1]],\n",
" [[-1, -1, -1],\n",
" [-1, 8, -1],\n",
" [-1, -1, -1]]],\n",
" [[[0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111]],\n",
" [[0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111]],\n",
" [[0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111],\n",
" [0.1111, 0.1111, 0.1111]]]])\n",
" else:\n",
" assert False\n",
"else:\n",
" assert False"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### OpenCV test"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 1152x288 with 3 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Turn spike indices into image\n",
"# **NOTE** image is RGB\n",
"image = np.zeros(INPUT_SIZE * INPUT_SIZE * INPUT_CHANNELS)\n",
"image[spike_indices] = 1\n",
"image = np.reshape(image, (INPUT_SIZE, INPUT_SIZE, INPUT_CHANNELS))\n",
"\n",
"# Use OpenCV to calculate convolution\n",
"# **NOTE** OpenCV does valid padding\n",
"filter_out = [[cv2.filter2D(image[:,:,i], cv2.CV_64F, filt[o,i]) for i in range(INPUT_CHANNELS)]\n",
" for o in range(OUTPUT_CHANNELS)]\n",
"\n",
"# Show results\n",
"fig, axes = plt.subplots(OUTPUT_CHANNELS, 2 + INPUT_CHANNELS, figsize=(16,4))\n",
"for o in range(OUTPUT_CHANNELS):\n",
" axes_row = axes[o] if OUTPUT_CHANNELS > 1 else axes\n",
" axes_row[0].set_title(\"image\")\n",
" axes_row[0].imshow(image if INPUT_CHANNELS > 1 else image[:,:,0]);\n",
"\n",
" for i in range(INPUT_CHANNELS):\n",
" axes_row[i + 1].set_title(\"input channel %u\" % i)\n",
" axes_row[i + 1].imshow(filter_out[o][i], vmin=-10, vmax=10)\n",
"\n",
" axes_row[-1].set_title(\"filter output\")\n",
" axes_row[-1].imshow(np.sum(filter_out[o], axis=0), vmin=-10, vmax=10)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Toeplitz approach"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 1152x144 with 3 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 1152x1152 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Zero pad filter to output size\n",
"zero_pad_filt = np.pad(filt, ((0, 0), (0, 0), (OUTPUT_SIZE - filt.shape[2], 0), (0, OUTPUT_SIZE - filt.shape[3])), \n",
" \"constant\", constant_values=0.0)\n",
"# Flip rows\n",
"zero_pad_filt = np.flip(zero_pad_filt, axis=2)\n",
"\n",
"\n",
"# Loop through output channels\n",
"doubly_blocked_channels = []\n",
"for o in range(zero_pad_filt.shape[0]):\n",
" doubly_blocked_channels.append([])\n",
" # Loop through input channels\n",
" for i in range(zero_pad_filt.shape[1]):\n",
" # Build list of toeplitz matrices from rows\n",
" f_matrices = []\n",
" for j in range(zero_pad_filt.shape[2]):\n",
" toeplitz_col = zero_pad_filt[o,i,j,:]\n",
" toeplitz_row = np.concatenate(((toeplitz_col[0],), np.zeros(INPUT_SIZE - 1)))\n",
" f_matrices.append(toeplitz(toeplitz_col, toeplitz_row))\n",
"\n",
" # doubly blocked toeplitz indices: \n",
" # this matrix defines which toeplitz matrix from toeplitz_list goes to which part of the doubly blocked\n",
" block_toeplitz_col = list(range(1, zero_pad_filt.shape[2] + 1))\n",
" block_toeplitz_row = np.concatenate(((block_toeplitz_col[0],), np.zeros(INPUT_SIZE - 1, dtype=int)))\n",
" block_indices = toeplitz(block_toeplitz_col, block_toeplitz_row)\n",
"\n",
" ## create doubly blocked matrix with zero values\n",
" toeplitz_shape = f_matrices[0].shape # shape of one toeplitz matrix\n",
"\n",
" doubly_blocked = np.zeros((toeplitz_shape[0] * block_indices.shape[0], \n",
" toeplitz_shape[1] * block_indices.shape[1]))\n",
"\n",
" # tile toeplitz matrices for each row in the doubly blocked matrix\n",
" for j in range(block_indices.shape[0]):\n",
" for k in range(block_indices.shape[1]):\n",
" start_j = j * toeplitz_shape[0]\n",
" start_k = k * toeplitz_shape[1]\n",
" end_j = start_j + toeplitz_shape[0]\n",
" end_k = start_k + toeplitz_shape[1]\n",
" doubly_blocked[start_j:end_j, start_k:end_k] = f_matrices[block_indices[j,k] - 1]\n",
"\n",
" # If this is the first input and output channel\n",
" if i == 0 and o == 0:\n",
" # Show some example toeplitz matrices\n",
" fig, axes = plt.subplots(1, 3, figsize=(16,2), sharey=True)\n",
" axes[0].imshow(f_matrices[0])\n",
" axes[0].set_title(\"Channel 0 (F0)\")\n",
" axes[1].imshow(f_matrices[1])\n",
" axes[1].set_title(\"Channel 0 (F1)\")\n",
" axes[2].imshow(f_matrices[2])\n",
" axes[2].set_title(\"Channel 0 (F2)\")\n",
"\n",
" # Show complete, double-blocked matrix\n",
" fig, axis = plt.subplots(figsize=(16,16))\n",
" axis.imshow(doubly_blocked)\n",
" axis.set_title(\"Channel 0 (Doubly-blocked)\");\n",
"\n",
" # Add double-blocked channel matrix to list\n",
" doubly_blocked_channels[-1].append(doubly_blocked)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Standard matrix multiply by Toeplitz\n",
"I suspect the difference in sign is due to cross-correlation vs convolution"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# Multiply each doubly-blocked channel matrix by appropriate image channel\n",
"dense_result = [[doubly_blocked_channels[o][i].dot(image[:,:,i].flatten()) for i in range(INPUT_CHANNELS)] \n",
" for o in range(OUTPUT_CHANNELS)]\n",
"# Sum across input channels\n",
"dense_result = np.sum(dense_result, axis=1)\n",
"\n",
"# Plot output channels\n",
"fig, axes = plt.subplots(OUTPUT_CHANNELS)\n",
"for o in range(OUTPUT_CHANNELS):\n",
" ax = axes[o] if OUTPUT_CHANNELS > 1 else axes\n",
" ax.imshow(np.reshape(dense_result[o], (OUTPUT_SIZE, OUTPUT_SIZE)), vmin=-10, vmax=10)\n",
" ax.set_title(\"Output %u\" % o);"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sparse, spiking approach\n",
"We're not actually multiplying - just summing weights from rows where there's spikes"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"sparse_spike_output = np.zeros((OUTPUT_CHANNELS, OUTPUT_SIZE * OUTPUT_SIZE))\n",
"\n",
"# Loop through spikes\n",
"for pre in spike_indices:\n",
" # Split pre into row, column and channel\n",
" pre_row = (pre // INPUT_CHANNELS) // INPUT_SIZE\n",
" pre_col = (pre // INPUT_CHANNELS) % INPUT_SIZE\n",
" pre_chan = pre % INPUT_CHANNELS\n",
" \n",
" # Loop through output channels\n",
" for o in range(OUTPUT_CHANNELS):\n",
" # Determine which column of blocks contains pre\n",
" # **NOTE** that the columns of the Toeplitz matrix are indexed rows\n",
" # Rotate row of zero-padded filter corresponding to each block and concatenate together\n",
" col_test = np.concatenate([np.pad(zero_pad_filt[o, pre_chan, max(-1, i - pre_row)], \n",
" (pre_col, 0))[:OUTPUT_SIZE]\n",
" for i in range(OUTPUT_SIZE)])\n",
" assert np.array_equal(doubly_blocked_channels[o][pre_chan][:,pre // INPUT_CHANNELS], col_test)\n",
"\n",
" # Add to output\n",
" sparse_spike_output[o] += col_test\n",
"\n",
"square_sparse_spike_output = np.reshape(sparse_spike_output, (OUTPUT_CHANNELS, OUTPUT_SIZE, OUTPUT_SIZE))\n",
"\n",
"fig, axes = plt.subplots(OUTPUT_CHANNELS)\n",
"for o in range(OUTPUT_CHANNELS):\n",
" ax = axes[o] if OUTPUT_CHANNELS > 1 else axes\n",
" ax.imshow(square_sparse_spike_output[o], vmin=-10, vmax=10)\n",
" ax.set_title(\"Output %u\" % o);\n",
"\n",
"assert np.allclose(dense_result, sparse_spike_output)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sparser, spiking approach\n",
"There's no point in using the zero-padded filters - we can ignore zeroed rows and copy non-added columns into correct place rather than rotating"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"sparser_spike_output = np.zeros((OUTPUT_CHANNELS, OUTPUT_SIZE * OUTPUT_SIZE))\n",
"\n",
"# Loop through spikes\n",
"for pre in spike_indices:\n",
" # Split pre into row, column and channel\n",
" pre_row = (pre // INPUT_CHANNELS) // INPUT_SIZE\n",
" pre_col = (pre // INPUT_CHANNELS) % INPUT_SIZE\n",
" pre_chan = pre % INPUT_CHANNELS\n",
" \n",
" # Get length of filter row to apply here\n",
" row_len = min(filt.shape[3], OUTPUT_SIZE - pre_col)\n",
" \n",
" for o in range(OUTPUT_CHANNELS):\n",
" # Loop through filter rows\n",
" for i in range(pre_row, min(OUTPUT_SIZE, pre_row + filt.shape[2])):\n",
" # Extract row of filter\n",
" # **NOTE** from the POV of connectivity matrices, the columns of the Toeplitz matrix are the rows\n",
" filter_row_idx = filt.shape[2] - (i - pre_row) - 1\n",
" filter_row = filt[o, pre_chan, filter_row_idx]\n",
"\n",
" # Place it into correct slice of output\n",
" start_out = (i * OUTPUT_SIZE) + pre_col\n",
" end_out = start_out + row_len\n",
" sparser_spike_output[o,start_out:end_out] += filter_row[:row_len]\n",
"\n",
"square_sparser_spike_output = np.reshape(sparser_spike_output, (OUTPUT_CHANNELS, OUTPUT_SIZE, OUTPUT_SIZE))\n",
"\n",
"fig, axes = plt.subplots(OUTPUT_CHANNELS)\n",
"for o in range(OUTPUT_CHANNELS):\n",
" ax = axes[o] if OUTPUT_CHANNELS > 1 else axes\n",
" ax.imshow(square_sparser_spike_output[o], vmin=-10, vmax=10)\n",
" ax.set_title(\"Output %u\" % o);\n",
"\n",
"assert np.allclose(dense_result, sparser_spike_output)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Sparser, spiking approach rearranged for parallel implementation\n",
"If we re-arrange the loops slightly we're closer to something that could be efficiently postsynaptically parallelised"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"sparser_parallel_spike_output = np.zeros((OUTPUT_CHANNELS, OUTPUT_SIZE * OUTPUT_SIZE))\n",
"\n",
"# Parallelise across filter dimensions\n",
"for post_channel in range(filt.shape[0]):\n",
" for post_row in range(filt.shape[2]):\n",
" for post_col in range(filt.shape[3]):\n",
" # Extract vector of filter channels used by all spikes \n",
" filter_channels = filt[post_channel,:,filt.shape[2] - post_row - 1,post_col]\n",
"\n",
" # Loop through spikes\n",
" for pre in spike_indices:\n",
" # Split pre into row, column and channel\n",
" pre_row = (pre // INPUT_CHANNELS) // INPUT_SIZE\n",
" pre_col = (pre // INPUT_CHANNELS) % INPUT_SIZE\n",
" pre_chan = pre % INPUT_CHANNELS\n",
"\n",
" # If we haven't gone off edge of output\n",
" i = pre_row + post_row\n",
" if i < OUTPUT_SIZE and post_col < (OUTPUT_SIZE - pre_col):\n",
" start_out = (i * OUTPUT_SIZE) + pre_col\n",
"\n",
" # Update output (coalesced reading of filter row and no collisions on atomic add)\n",
" sparser_parallel_spike_output[post_channel,start_out + post_col] += filter_channels[pre_chan]\n",
"\n",
"square_sparser_parallel_spike_output = np.reshape(sparser_parallel_spike_output, (OUTPUT_CHANNELS, OUTPUT_SIZE, OUTPUT_SIZE))\n",
"\n",
"fig, axes = plt.subplots(OUTPUT_CHANNELS)\n",
"for o in range(OUTPUT_CHANNELS):\n",
" ax = axes[o] if OUTPUT_CHANNELS > 1 else axes\n",
" ax.imshow(square_sparser_parallel_spike_output[o], vmin=-10, vmax=10)\n",
" ax.set_title(\"Output %u\" % o);\n",
"\n",
"assert np.allclose(dense_result, sparser_parallel_spike_output)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"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.6.8"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment