Python go faster

In [1]:
import numpy as np
import numba as nb
In [2]:
%%html
<style>

.CodeMirror {
    width: 100vw;
}

.container {
    width: 99% !important;
}

.rendered_html {
  font-size:0.8em;
}
.rendered_html table, .rendered_html th, .rendered_html tr, .rendered_html td {
     font-size: 100%;
}

</style>

Python ist interpretiert

  • Interaktive Datenanalyse
  • Sehr flexible Sprache, wenig Sorgen um Datentypen etc.
  • Code wird erst zur Laufzeit interpretiert, der Interpreter braucht Zeit dafür

=> Manchmal zu langsam

Performance besser machen

  • Erst Messen
  • Dann Schneller machen, was langsam ist
In [3]:
to_square = list(range(10000))
to_square
Out[3]:
[0,
 1,
 2,
 3,
 4,
 5,
 6,
 7,
 8,
 9,
 10,
 11,
 12,
 13,
 14,
 15,
 16,
 17,
 18,
 19,
 20,
 21,
 22,
 23,
 24,
 25,
 26,
 27,
 28,
 29,
 30,
 31,
 32,
 33,
 34,
 35,
 36,
 37,
 38,
 39,
 40,
 41,
 42,
 43,
 44,
 45,
 46,
 47,
 48,
 49,
 50,
 51,
 52,
 53,
 54,
 55,
 56,
 57,
 58,
 59,
 60,
 61,
 62,
 63,
 64,
 65,
 66,
 67,
 68,
 69,
 70,
 71,
 72,
 73,
 74,
 75,
 76,
 77,
 78,
 79,
 80,
 81,
 82,
 83,
 84,
 85,
 86,
 87,
 88,
 89,
 90,
 91,
 92,
 93,
 94,
 95,
 96,
 97,
 98,
 99,
 100,
 101,
 102,
 103,
 104,
 105,
 106,
 107,
 108,
 109,
 110,
 111,
 112,
 113,
 114,
 115,
 116,
 117,
 118,
 119,
 120,
 121,
 122,
 123,
 124,
 125,
 126,
 127,
 128,
 129,
 130,
 131,
 132,
 133,
 134,
 135,
 136,
 137,
 138,
 139,
 140,
 141,
 142,
 143,
 144,
 145,
 146,
 147,
 148,
 149,
 150,
 151,
 152,
 153,
 154,
 155,
 156,
 157,
 158,
 159,
 160,
 161,
 162,
 163,
 164,
 165,
 166,
 167,
 168,
 169,
 170,
 171,
 172,
 173,
 174,
 175,
 176,
 177,
 178,
 179,
 180,
 181,
 182,
 183,
 184,
 185,
 186,
 187,
 188,
 189,
 190,
 191,
 192,
 193,
 194,
 195,
 196,
 197,
 198,
 199,
 200,
 201,
 202,
 203,
 204,
 205,
 206,
 207,
 208,
 209,
 210,
 211,
 212,
 213,
 214,
 215,
 216,
 217,
 218,
 219,
 220,
 221,
 222,
 223,
 224,
 225,
 226,
 227,
 228,
 229,
 230,
 231,
 232,
 233,
 234,
 235,
 236,
 237,
 238,
 239,
 240,
 241,
 242,
 243,
 244,
 245,
 246,
 247,
 248,
 249,
 250,
 251,
 252,
 253,
 254,
 255,
 256,
 257,
 258,
 259,
 260,
 261,
 262,
 263,
 264,
 265,
 266,
 267,
 268,
 269,
 270,
 271,
 272,
 273,
 274,
 275,
 276,
 277,
 278,
 279,
 280,
 281,
 282,
 283,
 284,
 285,
 286,
 287,
 288,
 289,
 290,
 291,
 292,
 293,
 294,
 295,
 296,
 297,
 298,
 299,
 300,
 301,
 302,
 303,
 304,
 305,
 306,
 307,
 308,
 309,
 310,
 311,
 312,
 313,
 314,
 315,
 316,
 317,
 318,
 319,
 320,
 321,
 322,
 323,
 324,
 325,
 326,
 327,
 328,
 329,
 330,
 331,
 332,
 333,
 334,
 335,
 336,
 337,
 338,
 339,
 340,
 341,
 342,
 343,
 344,
 345,
 346,
 347,
 348,
 349,
 350,
 351,
 352,
 353,
 354,
 355,
 356,
 357,
 358,
 359,
 360,
 361,
 362,
 363,
 364,
 365,
 366,
 367,
 368,
 369,
 370,
 371,
 372,
 373,
 374,
 375,
 376,
 377,
 378,
 379,
 380,
 381,
 382,
 383,
 384,
 385,
 386,
 387,
 388,
 389,
 390,
 391,
 392,
 393,
 394,
 395,
 396,
 397,
 398,
 399,
 400,
 401,
 402,
 403,
 404,
 405,
 406,
 407,
 408,
 409,
 410,
 411,
 412,
 413,
 414,
 415,
 416,
 417,
 418,
 419,
 420,
 421,
 422,
 423,
 424,
 425,
 426,
 427,
 428,
 429,
 430,
 431,
 432,
 433,
 434,
 435,
 436,
 437,
 438,
 439,
 440,
 441,
 442,
 443,
 444,
 445,
 446,
 447,
 448,
 449,
 450,
 451,
 452,
 453,
 454,
 455,
 456,
 457,
 458,
 459,
 460,
 461,
 462,
 463,
 464,
 465,
 466,
 467,
 468,
 469,
 470,
 471,
 472,
 473,
 474,
 475,
 476,
 477,
 478,
 479,
 480,
 481,
 482,
 483,
 484,
 485,
 486,
 487,
 488,
 489,
 490,
 491,
 492,
 493,
 494,
 495,
 496,
 497,
 498,
 499,
 500,
 501,
 502,
 503,
 504,
 505,
 506,
 507,
 508,
 509,
 510,
 511,
 512,
 513,
 514,
 515,
 516,
 517,
 518,
 519,
 520,
 521,
 522,
 523,
 524,
 525,
 526,
 527,
 528,
 529,
 530,
 531,
 532,
 533,
 534,
 535,
 536,
 537,
 538,
 539,
 540,
 541,
 542,
 543,
 544,
 545,
 546,
 547,
 548,
 549,
 550,
 551,
 552,
 553,
 554,
 555,
 556,
 557,
 558,
 559,
 560,
 561,
 562,
 563,
 564,
 565,
 566,
 567,
 568,
 569,
 570,
 571,
 572,
 573,
 574,
 575,
 576,
 577,
 578,
 579,
 580,
 581,
 582,
 583,
 584,
 585,
 586,
 587,
 588,
 589,
 590,
 591,
 592,
 593,
 594,
 595,
 596,
 597,
 598,
 599,
 600,
 601,
 602,
 603,
 604,
 605,
 606,
 607,
 608,
 609,
 610,
 611,
 612,
 613,
 614,
 615,
 616,
 617,
 618,
 619,
 620,
 621,
 622,
 623,
 624,
 625,
 626,
 627,
 628,
 629,
 630,
 631,
 632,
 633,
 634,
 635,
 636,
 637,
 638,
 639,
 640,
 641,
 642,
 643,
 644,
 645,
 646,
 647,
 648,
 649,
 650,
 651,
 652,
 653,
 654,
 655,
 656,
 657,
 658,
 659,
 660,
 661,
 662,
 663,
 664,
 665,
 666,
 667,
 668,
 669,
 670,
 671,
 672,
 673,
 674,
 675,
 676,
 677,
 678,
 679,
 680,
 681,
 682,
 683,
 684,
 685,
 686,
 687,
 688,
 689,
 690,
 691,
 692,
 693,
 694,
 695,
 696,
 697,
 698,
 699,
 700,
 701,
 702,
 703,
 704,
 705,
 706,
 707,
 708,
 709,
 710,
 711,
 712,
 713,
 714,
 715,
 716,
 717,
 718,
 719,
 720,
 721,
 722,
 723,
 724,
 725,
 726,
 727,
 728,
 729,
 730,
 731,
 732,
 733,
 734,
 735,
 736,
 737,
 738,
 739,
 740,
 741,
 742,
 743,
 744,
 745,
 746,
 747,
 748,
 749,
 750,
 751,
 752,
 753,
 754,
 755,
 756,
 757,
 758,
 759,
 760,
 761,
 762,
 763,
 764,
 765,
 766,
 767,
 768,
 769,
 770,
 771,
 772,
 773,
 774,
 775,
 776,
 777,
 778,
 779,
 780,
 781,
 782,
 783,
 784,
 785,
 786,
 787,
 788,
 789,
 790,
 791,
 792,
 793,
 794,
 795,
 796,
 797,
 798,
 799,
 800,
 801,
 802,
 803,
 804,
 805,
 806,
 807,
 808,
 809,
 810,
 811,
 812,
 813,
 814,
 815,
 816,
 817,
 818,
 819,
 820,
 821,
 822,
 823,
 824,
 825,
 826,
 827,
 828,
 829,
 830,
 831,
 832,
 833,
 834,
 835,
 836,
 837,
 838,
 839,
 840,
 841,
 842,
 843,
 844,
 845,
 846,
 847,
 848,
 849,
 850,
 851,
 852,
 853,
 854,
 855,
 856,
 857,
 858,
 859,
 860,
 861,
 862,
 863,
 864,
 865,
 866,
 867,
 868,
 869,
 870,
 871,
 872,
 873,
 874,
 875,
 876,
 877,
 878,
 879,
 880,
 881,
 882,
 883,
 884,
 885,
 886,
 887,
 888,
 889,
 890,
 891,
 892,
 893,
 894,
 895,
 896,
 897,
 898,
 899,
 900,
 901,
 902,
 903,
 904,
 905,
 906,
 907,
 908,
 909,
 910,
 911,
 912,
 913,
 914,
 915,
 916,
 917,
 918,
 919,
 920,
 921,
 922,
 923,
 924,
 925,
 926,
 927,
 928,
 929,
 930,
 931,
 932,
 933,
 934,
 935,
 936,
 937,
 938,
 939,
 940,
 941,
 942,
 943,
 944,
 945,
 946,
 947,
 948,
 949,
 950,
 951,
 952,
 953,
 954,
 955,
 956,
 957,
 958,
 959,
 960,
 961,
 962,
 963,
 964,
 965,
 966,
 967,
 968,
 969,
 970,
 971,
 972,
 973,
 974,
 975,
 976,
 977,
 978,
 979,
 980,
 981,
 982,
 983,
 984,
 985,
 986,
 987,
 988,
 989,
 990,
 991,
 992,
 993,
 994,
 995,
 996,
 997,
 998,
 999,
 ...]
In [4]:
def pure_python_square(a):
    result = []
    for x in a:
        result.append(x**2)
    return result

%timeit pure_python_square(to_square)
2.23 ms ± 36 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
In [5]:
def numpy_square(a):
    return np.array(a)**2

%timeit numpy_square(to_square)
401 µs ± 803 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [6]:
def already_numpy_square(a):
    return a**2

array_to_square = np.array(to_square)

%timeit already_numpy_square(array_to_square)
4.25 µs ± 22.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
In [7]:
@nb.jit(nopython=True, fastmath=True)
def numba_square(a):
    return a**2

%timeit numba_square(array_to_square)
The slowest run took 6.19 times longer than the fastest. This could mean that an intermediate result is being cached.
9.35 µs ± 6.86 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
In [8]:
@nb.jit(nopython=True, fastmath=True)
def numba_square(a):
    return a**2

numba_square(array_to_square)
%timeit numba_square(array_to_square)
3.65 µs ± 59 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
method timing
pure python 9 ms
numpy 2.8 ms
numpy, prior setup 40.6 µs
numba 50 µs (??)
numba, prior setup 25 µs

Wie?

  • In python: Jeder Befehl x**2 muss interpretiert werden
  • In numpy: Einmal a**2 interpretiert, danach nur noch rechnen
  • In numba: Einmal für einen Datentyp kompiliert, danach bei jedem Aufruf nur noch rechnen => minimaler Overhead
  • Viele Algorithmen sind eine Abfolge von einfachen Operationen
In [9]:
from uncertainties import ufloat as uf
to_square_uncertain = [uf(x, 1) for x in to_square]
to_square_uncertain
Out[9]:
[0.0+/-1.0,
 1.0+/-1.0,
 2.0+/-1.0,
 3.0+/-1.0,
 4.0+/-1.0,
 5.0+/-1.0,
 6.0+/-1.0,
 7.0+/-1.0,
 8.0+/-1.0,
 9.0+/-1.0,
 10.0+/-1.0,
 11.0+/-1.0,
 12.0+/-1.0,
 13.0+/-1.0,
 14.0+/-1.0,
 15.0+/-1.0,
 16.0+/-1.0,
 17.0+/-1.0,
 18.0+/-1.0,
 19.0+/-1.0,
 20.0+/-1.0,
 21.0+/-1.0,
 22.0+/-1.0,
 23.0+/-1.0,
 24.0+/-1.0,
 25.0+/-1.0,
 26.0+/-1.0,
 27.0+/-1.0,
 28.0+/-1.0,
 29.0+/-1.0,
 30.0+/-1.0,
 31.0+/-1.0,
 32.0+/-1.0,
 33.0+/-1.0,
 34.0+/-1.0,
 35.0+/-1.0,
 36.0+/-1.0,
 37.0+/-1.0,
 38.0+/-1.0,
 39.0+/-1.0,
 40.0+/-1.0,
 41.0+/-1.0,
 42.0+/-1.0,
 43.0+/-1.0,
 44.0+/-1.0,
 45.0+/-1.0,
 46.0+/-1.0,
 47.0+/-1.0,
 48.0+/-1.0,
 49.0+/-1.0,
 50.0+/-1.0,
 51.0+/-1.0,
 52.0+/-1.0,
 53.0+/-1.0,
 54.0+/-1.0,
 55.0+/-1.0,
 56.0+/-1.0,
 57.0+/-1.0,
 58.0+/-1.0,
 59.0+/-1.0,
 60.0+/-1.0,
 61.0+/-1.0,
 62.0+/-1.0,
 63.0+/-1.0,
 64.0+/-1.0,
 65.0+/-1.0,
 66.0+/-1.0,
 67.0+/-1.0,
 68.0+/-1.0,
 69.0+/-1.0,
 70.0+/-1.0,
 71.0+/-1.0,
 72.0+/-1.0,
 73.0+/-1.0,
 74.0+/-1.0,
 75.0+/-1.0,
 76.0+/-1.0,
 77.0+/-1.0,
 78.0+/-1.0,
 79.0+/-1.0,
 80.0+/-1.0,
 81.0+/-1.0,
 82.0+/-1.0,
 83.0+/-1.0,
 84.0+/-1.0,
 85.0+/-1.0,
 86.0+/-1.0,
 87.0+/-1.0,
 88.0+/-1.0,
 89.0+/-1.0,
 90.0+/-1.0,
 91.0+/-1.0,
 92.0+/-1.0,
 93.0+/-1.0,
 94.0+/-1.0,
 95.0+/-1.0,
 96.0+/-1.0,
 97.0+/-1.0,
 98.0+/-1.0,
 99.0+/-1.0,
 100.0+/-1.0,
 101.0+/-1.0,
 102.0+/-1.0,
 103.0+/-1.0,
 104.0+/-1.0,
 105.0+/-1.0,
 106.0+/-1.0,
 107.0+/-1.0,
 108.0+/-1.0,
 109.0+/-1.0,
 110.0+/-1.0,
 111.0+/-1.0,
 112.0+/-1.0,
 113.0+/-1.0,
 114.0+/-1.0,
 115.0+/-1.0,
 116.0+/-1.0,
 117.0+/-1.0,
 118.0+/-1.0,
 119.0+/-1.0,
 120.0+/-1.0,
 121.0+/-1.0,
 122.0+/-1.0,
 123.0+/-1.0,
 124.0+/-1.0,
 125.0+/-1.0,
 126.0+/-1.0,
 127.0+/-1.0,
 128.0+/-1.0,
 129.0+/-1.0,
 130.0+/-1.0,
 131.0+/-1.0,
 132.0+/-1.0,
 133.0+/-1.0,
 134.0+/-1.0,
 135.0+/-1.0,
 136.0+/-1.0,
 137.0+/-1.0,
 138.0+/-1.0,
 139.0+/-1.0,
 140.0+/-1.0,
 141.0+/-1.0,
 142.0+/-1.0,
 143.0+/-1.0,
 144.0+/-1.0,
 145.0+/-1.0,
 146.0+/-1.0,
 147.0+/-1.0,
 148.0+/-1.0,
 149.0+/-1.0,
 150.0+/-1.0,
 151.0+/-1.0,
 152.0+/-1.0,
 153.0+/-1.0,
 154.0+/-1.0,
 155.0+/-1.0,
 156.0+/-1.0,
 157.0+/-1.0,
 158.0+/-1.0,
 159.0+/-1.0,
 160.0+/-1.0,
 161.0+/-1.0,
 162.0+/-1.0,
 163.0+/-1.0,
 164.0+/-1.0,
 165.0+/-1.0,
 166.0+/-1.0,
 167.0+/-1.0,
 168.0+/-1.0,
 169.0+/-1.0,
 170.0+/-1.0,
 171.0+/-1.0,
 172.0+/-1.0,
 173.0+/-1.0,
 174.0+/-1.0,
 175.0+/-1.0,
 176.0+/-1.0,
 177.0+/-1.0,
 178.0+/-1.0,
 179.0+/-1.0,
 180.0+/-1.0,
 181.0+/-1.0,
 182.0+/-1.0,
 183.0+/-1.0,
 184.0+/-1.0,
 185.0+/-1.0,
 186.0+/-1.0,
 187.0+/-1.0,
 188.0+/-1.0,
 189.0+/-1.0,
 190.0+/-1.0,
 191.0+/-1.0,
 192.0+/-1.0,
 193.0+/-1.0,
 194.0+/-1.0,
 195.0+/-1.0,
 196.0+/-1.0,
 197.0+/-1.0,
 198.0+/-1.0,
 199.0+/-1.0,
 200.0+/-1.0,
 201.0+/-1.0,
 202.0+/-1.0,
 203.0+/-1.0,
 204.0+/-1.0,
 205.0+/-1.0,
 206.0+/-1.0,
 207.0+/-1.0,
 208.0+/-1.0,
 209.0+/-1.0,
 210.0+/-1.0,
 211.0+/-1.0,
 212.0+/-1.0,
 213.0+/-1.0,
 214.0+/-1.0,
 215.0+/-1.0,
 216.0+/-1.0,
 217.0+/-1.0,
 218.0+/-1.0,
 219.0+/-1.0,
 220.0+/-1.0,
 221.0+/-1.0,
 222.0+/-1.0,
 223.0+/-1.0,
 224.0+/-1.0,
 225.0+/-1.0,
 226.0+/-1.0,
 227.0+/-1.0,
 228.0+/-1.0,
 229.0+/-1.0,
 230.0+/-1.0,
 231.0+/-1.0,
 232.0+/-1.0,
 233.0+/-1.0,
 234.0+/-1.0,
 235.0+/-1.0,
 236.0+/-1.0,
 237.0+/-1.0,
 238.0+/-1.0,
 239.0+/-1.0,
 240.0+/-1.0,
 241.0+/-1.0,
 242.0+/-1.0,
 243.0+/-1.0,
 244.0+/-1.0,
 245.0+/-1.0,
 246.0+/-1.0,
 247.0+/-1.0,
 248.0+/-1.0,
 249.0+/-1.0,
 250.0+/-1.0,
 251.0+/-1.0,
 252.0+/-1.0,
 253.0+/-1.0,
 254.0+/-1.0,
 255.0+/-1.0,
 256.0+/-1.0,
 257.0+/-1.0,
 258.0+/-1.0,
 259.0+/-1.0,
 260.0+/-1.0,
 261.0+/-1.0,
 262.0+/-1.0,
 263.0+/-1.0,
 264.0+/-1.0,
 265.0+/-1.0,
 266.0+/-1.0,
 267.0+/-1.0,
 268.0+/-1.0,
 269.0+/-1.0,
 270.0+/-1.0,
 271.0+/-1.0,
 272.0+/-1.0,
 273.0+/-1.0,
 274.0+/-1.0,
 275.0+/-1.0,
 276.0+/-1.0,
 277.0+/-1.0,
 278.0+/-1.0,
 279.0+/-1.0,
 280.0+/-1.0,
 281.0+/-1.0,
 282.0+/-1.0,
 283.0+/-1.0,
 284.0+/-1.0,
 285.0+/-1.0,
 286.0+/-1.0,
 287.0+/-1.0,
 288.0+/-1.0,
 289.0+/-1.0,
 290.0+/-1.0,
 291.0+/-1.0,
 292.0+/-1.0,
 293.0+/-1.0,
 294.0+/-1.0,
 295.0+/-1.0,
 296.0+/-1.0,
 297.0+/-1.0,
 298.0+/-1.0,
 299.0+/-1.0,
 300.0+/-1.0,
 301.0+/-1.0,
 302.0+/-1.0,
 303.0+/-1.0,
 304.0+/-1.0,
 305.0+/-1.0,
 306.0+/-1.0,
 307.0+/-1.0,
 308.0+/-1.0,
 309.0+/-1.0,
 310.0+/-1.0,
 311.0+/-1.0,
 312.0+/-1.0,
 313.0+/-1.0,
 314.0+/-1.0,
 315.0+/-1.0,
 316.0+/-1.0,
 317.0+/-1.0,
 318.0+/-1.0,
 319.0+/-1.0,
 320.0+/-1.0,
 321.0+/-1.0,
 322.0+/-1.0,
 323.0+/-1.0,
 324.0+/-1.0,
 325.0+/-1.0,
 326.0+/-1.0,
 327.0+/-1.0,
 328.0+/-1.0,
 329.0+/-1.0,
 330.0+/-1.0,
 331.0+/-1.0,
 332.0+/-1.0,
 333.0+/-1.0,
 334.0+/-1.0,
 335.0+/-1.0,
 336.0+/-1.0,
 337.0+/-1.0,
 338.0+/-1.0,
 339.0+/-1.0,
 340.0+/-1.0,
 341.0+/-1.0,
 342.0+/-1.0,
 343.0+/-1.0,
 344.0+/-1.0,
 345.0+/-1.0,
 346.0+/-1.0,
 347.0+/-1.0,
 348.0+/-1.0,
 349.0+/-1.0,
 350.0+/-1.0,
 351.0+/-1.0,
 352.0+/-1.0,
 353.0+/-1.0,
 354.0+/-1.0,
 355.0+/-1.0,
 356.0+/-1.0,
 357.0+/-1.0,
 358.0+/-1.0,
 359.0+/-1.0,
 360.0+/-1.0,
 361.0+/-1.0,
 362.0+/-1.0,
 363.0+/-1.0,
 364.0+/-1.0,
 365.0+/-1.0,
 366.0+/-1.0,
 367.0+/-1.0,
 368.0+/-1.0,
 369.0+/-1.0,
 370.0+/-1.0,
 371.0+/-1.0,
 372.0+/-1.0,
 373.0+/-1.0,
 374.0+/-1.0,
 375.0+/-1.0,
 376.0+/-1.0,
 377.0+/-1.0,
 378.0+/-1.0,
 379.0+/-1.0,
 380.0+/-1.0,
 381.0+/-1.0,
 382.0+/-1.0,
 383.0+/-1.0,
 384.0+/-1.0,
 385.0+/-1.0,
 386.0+/-1.0,
 387.0+/-1.0,
 388.0+/-1.0,
 389.0+/-1.0,
 390.0+/-1.0,
 391.0+/-1.0,
 392.0+/-1.0,
 393.0+/-1.0,
 394.0+/-1.0,
 395.0+/-1.0,
 396.0+/-1.0,
 397.0+/-1.0,
 398.0+/-1.0,
 399.0+/-1.0,
 400.0+/-1.0,
 401.0+/-1.0,
 402.0+/-1.0,
 403.0+/-1.0,
 404.0+/-1.0,
 405.0+/-1.0,
 406.0+/-1.0,
 407.0+/-1.0,
 408.0+/-1.0,
 409.0+/-1.0,
 410.0+/-1.0,
 411.0+/-1.0,
 412.0+/-1.0,
 413.0+/-1.0,
 414.0+/-1.0,
 415.0+/-1.0,
 416.0+/-1.0,
 417.0+/-1.0,
 418.0+/-1.0,
 419.0+/-1.0,
 420.0+/-1.0,
 421.0+/-1.0,
 422.0+/-1.0,
 423.0+/-1.0,
 424.0+/-1.0,
 425.0+/-1.0,
 426.0+/-1.0,
 427.0+/-1.0,
 428.0+/-1.0,
 429.0+/-1.0,
 430.0+/-1.0,
 431.0+/-1.0,
 432.0+/-1.0,
 433.0+/-1.0,
 434.0+/-1.0,
 435.0+/-1.0,
 436.0+/-1.0,
 437.0+/-1.0,
 438.0+/-1.0,
 439.0+/-1.0,
 440.0+/-1.0,
 441.0+/-1.0,
 442.0+/-1.0,
 443.0+/-1.0,
 444.0+/-1.0,
 445.0+/-1.0,
 446.0+/-1.0,
 447.0+/-1.0,
 448.0+/-1.0,
 449.0+/-1.0,
 450.0+/-1.0,
 451.0+/-1.0,
 452.0+/-1.0,
 453.0+/-1.0,
 454.0+/-1.0,
 455.0+/-1.0,
 456.0+/-1.0,
 457.0+/-1.0,
 458.0+/-1.0,
 459.0+/-1.0,
 460.0+/-1.0,
 461.0+/-1.0,
 462.0+/-1.0,
 463.0+/-1.0,
 464.0+/-1.0,
 465.0+/-1.0,
 466.0+/-1.0,
 467.0+/-1.0,
 468.0+/-1.0,
 469.0+/-1.0,
 470.0+/-1.0,
 471.0+/-1.0,
 472.0+/-1.0,
 473.0+/-1.0,
 474.0+/-1.0,
 475.0+/-1.0,
 476.0+/-1.0,
 477.0+/-1.0,
 478.0+/-1.0,
 479.0+/-1.0,
 480.0+/-1.0,
 481.0+/-1.0,
 482.0+/-1.0,
 483.0+/-1.0,
 484.0+/-1.0,
 485.0+/-1.0,
 486.0+/-1.0,
 487.0+/-1.0,
 488.0+/-1.0,
 489.0+/-1.0,
 490.0+/-1.0,
 491.0+/-1.0,
 492.0+/-1.0,
 493.0+/-1.0,
 494.0+/-1.0,
 495.0+/-1.0,
 496.0+/-1.0,
 497.0+/-1.0,
 498.0+/-1.0,
 499.0+/-1.0,
 500.0+/-1.0,
 501.0+/-1.0,
 502.0+/-1.0,
 503.0+/-1.0,
 504.0+/-1.0,
 505.0+/-1.0,
 506.0+/-1.0,
 507.0+/-1.0,
 508.0+/-1.0,
 509.0+/-1.0,
 510.0+/-1.0,
 511.0+/-1.0,
 512.0+/-1.0,
 513.0+/-1.0,
 514.0+/-1.0,
 515.0+/-1.0,
 516.0+/-1.0,
 517.0+/-1.0,
 518.0+/-1.0,
 519.0+/-1.0,
 520.0+/-1.0,
 521.0+/-1.0,
 522.0+/-1.0,
 523.0+/-1.0,
 524.0+/-1.0,
 525.0+/-1.0,
 526.0+/-1.0,
 527.0+/-1.0,
 528.0+/-1.0,
 529.0+/-1.0,
 530.0+/-1.0,
 531.0+/-1.0,
 532.0+/-1.0,
 533.0+/-1.0,
 534.0+/-1.0,
 535.0+/-1.0,
 536.0+/-1.0,
 537.0+/-1.0,
 538.0+/-1.0,
 539.0+/-1.0,
 540.0+/-1.0,
 541.0+/-1.0,
 542.0+/-1.0,
 543.0+/-1.0,
 544.0+/-1.0,
 545.0+/-1.0,
 546.0+/-1.0,
 547.0+/-1.0,
 548.0+/-1.0,
 549.0+/-1.0,
 550.0+/-1.0,
 551.0+/-1.0,
 552.0+/-1.0,
 553.0+/-1.0,
 554.0+/-1.0,
 555.0+/-1.0,
 556.0+/-1.0,
 557.0+/-1.0,
 558.0+/-1.0,
 559.0+/-1.0,
 560.0+/-1.0,
 561.0+/-1.0,
 562.0+/-1.0,
 563.0+/-1.0,
 564.0+/-1.0,
 565.0+/-1.0,
 566.0+/-1.0,
 567.0+/-1.0,
 568.0+/-1.0,
 569.0+/-1.0,
 570.0+/-1.0,
 571.0+/-1.0,
 572.0+/-1.0,
 573.0+/-1.0,
 574.0+/-1.0,
 575.0+/-1.0,
 576.0+/-1.0,
 577.0+/-1.0,
 578.0+/-1.0,
 579.0+/-1.0,
 580.0+/-1.0,
 581.0+/-1.0,
 582.0+/-1.0,
 583.0+/-1.0,
 584.0+/-1.0,
 585.0+/-1.0,
 586.0+/-1.0,
 587.0+/-1.0,
 588.0+/-1.0,
 589.0+/-1.0,
 590.0+/-1.0,
 591.0+/-1.0,
 592.0+/-1.0,
 593.0+/-1.0,
 594.0+/-1.0,
 595.0+/-1.0,
 596.0+/-1.0,
 597.0+/-1.0,
 598.0+/-1.0,
 599.0+/-1.0,
 600.0+/-1.0,
 601.0+/-1.0,
 602.0+/-1.0,
 603.0+/-1.0,
 604.0+/-1.0,
 605.0+/-1.0,
 606.0+/-1.0,
 607.0+/-1.0,
 608.0+/-1.0,
 609.0+/-1.0,
 610.0+/-1.0,
 611.0+/-1.0,
 612.0+/-1.0,
 613.0+/-1.0,
 614.0+/-1.0,
 615.0+/-1.0,
 616.0+/-1.0,
 617.0+/-1.0,
 618.0+/-1.0,
 619.0+/-1.0,
 620.0+/-1.0,
 621.0+/-1.0,
 622.0+/-1.0,
 623.0+/-1.0,
 624.0+/-1.0,
 625.0+/-1.0,
 626.0+/-1.0,
 627.0+/-1.0,
 628.0+/-1.0,
 629.0+/-1.0,
 630.0+/-1.0,
 631.0+/-1.0,
 632.0+/-1.0,
 633.0+/-1.0,
 634.0+/-1.0,
 635.0+/-1.0,
 636.0+/-1.0,
 637.0+/-1.0,
 638.0+/-1.0,
 639.0+/-1.0,
 640.0+/-1.0,
 641.0+/-1.0,
 642.0+/-1.0,
 643.0+/-1.0,
 644.0+/-1.0,
 645.0+/-1.0,
 646.0+/-1.0,
 647.0+/-1.0,
 648.0+/-1.0,
 649.0+/-1.0,
 650.0+/-1.0,
 651.0+/-1.0,
 652.0+/-1.0,
 653.0+/-1.0,
 654.0+/-1.0,
 655.0+/-1.0,
 656.0+/-1.0,
 657.0+/-1.0,
 658.0+/-1.0,
 659.0+/-1.0,
 660.0+/-1.0,
 661.0+/-1.0,
 662.0+/-1.0,
 663.0+/-1.0,
 664.0+/-1.0,
 665.0+/-1.0,
 666.0+/-1.0,
 667.0+/-1.0,
 668.0+/-1.0,
 669.0+/-1.0,
 670.0+/-1.0,
 671.0+/-1.0,
 672.0+/-1.0,
 673.0+/-1.0,
 674.0+/-1.0,
 675.0+/-1.0,
 676.0+/-1.0,
 677.0+/-1.0,
 678.0+/-1.0,
 679.0+/-1.0,
 680.0+/-1.0,
 681.0+/-1.0,
 682.0+/-1.0,
 683.0+/-1.0,
 684.0+/-1.0,
 685.0+/-1.0,
 686.0+/-1.0,
 687.0+/-1.0,
 688.0+/-1.0,
 689.0+/-1.0,
 690.0+/-1.0,
 691.0+/-1.0,
 692.0+/-1.0,
 693.0+/-1.0,
 694.0+/-1.0,
 695.0+/-1.0,
 696.0+/-1.0,
 697.0+/-1.0,
 698.0+/-1.0,
 699.0+/-1.0,
 700.0+/-1.0,
 701.0+/-1.0,
 702.0+/-1.0,
 703.0+/-1.0,
 704.0+/-1.0,
 705.0+/-1.0,
 706.0+/-1.0,
 707.0+/-1.0,
 708.0+/-1.0,
 709.0+/-1.0,
 710.0+/-1.0,
 711.0+/-1.0,
 712.0+/-1.0,
 713.0+/-1.0,
 714.0+/-1.0,
 715.0+/-1.0,
 716.0+/-1.0,
 717.0+/-1.0,
 718.0+/-1.0,
 719.0+/-1.0,
 720.0+/-1.0,
 721.0+/-1.0,
 722.0+/-1.0,
 723.0+/-1.0,
 724.0+/-1.0,
 725.0+/-1.0,
 726.0+/-1.0,
 727.0+/-1.0,
 728.0+/-1.0,
 729.0+/-1.0,
 730.0+/-1.0,
 731.0+/-1.0,
 732.0+/-1.0,
 733.0+/-1.0,
 734.0+/-1.0,
 735.0+/-1.0,
 736.0+/-1.0,
 737.0+/-1.0,
 738.0+/-1.0,
 739.0+/-1.0,
 740.0+/-1.0,
 741.0+/-1.0,
 742.0+/-1.0,
 743.0+/-1.0,
 744.0+/-1.0,
 745.0+/-1.0,
 746.0+/-1.0,
 747.0+/-1.0,
 748.0+/-1.0,
 749.0+/-1.0,
 750.0+/-1.0,
 751.0+/-1.0,
 752.0+/-1.0,
 753.0+/-1.0,
 754.0+/-1.0,
 755.0+/-1.0,
 756.0+/-1.0,
 757.0+/-1.0,
 758.0+/-1.0,
 759.0+/-1.0,
 760.0+/-1.0,
 761.0+/-1.0,
 762.0+/-1.0,
 763.0+/-1.0,
 764.0+/-1.0,
 765.0+/-1.0,
 766.0+/-1.0,
 767.0+/-1.0,
 768.0+/-1.0,
 769.0+/-1.0,
 770.0+/-1.0,
 771.0+/-1.0,
 772.0+/-1.0,
 773.0+/-1.0,
 774.0+/-1.0,
 775.0+/-1.0,
 776.0+/-1.0,
 777.0+/-1.0,
 778.0+/-1.0,
 779.0+/-1.0,
 780.0+/-1.0,
 781.0+/-1.0,
 782.0+/-1.0,
 783.0+/-1.0,
 784.0+/-1.0,
 785.0+/-1.0,
 786.0+/-1.0,
 787.0+/-1.0,
 788.0+/-1.0,
 789.0+/-1.0,
 790.0+/-1.0,
 791.0+/-1.0,
 792.0+/-1.0,
 793.0+/-1.0,
 794.0+/-1.0,
 795.0+/-1.0,
 796.0+/-1.0,
 797.0+/-1.0,
 798.0+/-1.0,
 799.0+/-1.0,
 800.0+/-1.0,
 801.0+/-1.0,
 802.0+/-1.0,
 803.0+/-1.0,
 804.0+/-1.0,
 805.0+/-1.0,
 806.0+/-1.0,
 807.0+/-1.0,
 808.0+/-1.0,
 809.0+/-1.0,
 810.0+/-1.0,
 811.0+/-1.0,
 812.0+/-1.0,
 813.0+/-1.0,
 814.0+/-1.0,
 815.0+/-1.0,
 816.0+/-1.0,
 817.0+/-1.0,
 818.0+/-1.0,
 819.0+/-1.0,
 820.0+/-1.0,
 821.0+/-1.0,
 822.0+/-1.0,
 823.0+/-1.0,
 824.0+/-1.0,
 825.0+/-1.0,
 826.0+/-1.0,
 827.0+/-1.0,
 828.0+/-1.0,
 829.0+/-1.0,
 830.0+/-1.0,
 831.0+/-1.0,
 832.0+/-1.0,
 833.0+/-1.0,
 834.0+/-1.0,
 835.0+/-1.0,
 836.0+/-1.0,
 837.0+/-1.0,
 838.0+/-1.0,
 839.0+/-1.0,
 840.0+/-1.0,
 841.0+/-1.0,
 842.0+/-1.0,
 843.0+/-1.0,
 844.0+/-1.0,
 845.0+/-1.0,
 846.0+/-1.0,
 847.0+/-1.0,
 848.0+/-1.0,
 849.0+/-1.0,
 850.0+/-1.0,
 851.0+/-1.0,
 852.0+/-1.0,
 853.0+/-1.0,
 854.0+/-1.0,
 855.0+/-1.0,
 856.0+/-1.0,
 857.0+/-1.0,
 858.0+/-1.0,
 859.0+/-1.0,
 860.0+/-1.0,
 861.0+/-1.0,
 862.0+/-1.0,
 863.0+/-1.0,
 864.0+/-1.0,
 865.0+/-1.0,
 866.0+/-1.0,
 867.0+/-1.0,
 868.0+/-1.0,
 869.0+/-1.0,
 870.0+/-1.0,
 871.0+/-1.0,
 872.0+/-1.0,
 873.0+/-1.0,
 874.0+/-1.0,
 875.0+/-1.0,
 876.0+/-1.0,
 877.0+/-1.0,
 878.0+/-1.0,
 879.0+/-1.0,
 880.0+/-1.0,
 881.0+/-1.0,
 882.0+/-1.0,
 883.0+/-1.0,
 884.0+/-1.0,
 885.0+/-1.0,
 886.0+/-1.0,
 887.0+/-1.0,
 888.0+/-1.0,
 889.0+/-1.0,
 890.0+/-1.0,
 891.0+/-1.0,
 892.0+/-1.0,
 893.0+/-1.0,
 894.0+/-1.0,
 895.0+/-1.0,
 896.0+/-1.0,
 897.0+/-1.0,
 898.0+/-1.0,
 899.0+/-1.0,
 900.0+/-1.0,
 901.0+/-1.0,
 902.0+/-1.0,
 903.0+/-1.0,
 904.0+/-1.0,
 905.0+/-1.0,
 906.0+/-1.0,
 907.0+/-1.0,
 908.0+/-1.0,
 909.0+/-1.0,
 910.0+/-1.0,
 911.0+/-1.0,
 912.0+/-1.0,
 913.0+/-1.0,
 914.0+/-1.0,
 915.0+/-1.0,
 916.0+/-1.0,
 917.0+/-1.0,
 918.0+/-1.0,
 919.0+/-1.0,
 920.0+/-1.0,
 921.0+/-1.0,
 922.0+/-1.0,
 923.0+/-1.0,
 924.0+/-1.0,
 925.0+/-1.0,
 926.0+/-1.0,
 927.0+/-1.0,
 928.0+/-1.0,
 929.0+/-1.0,
 930.0+/-1.0,
 931.0+/-1.0,
 932.0+/-1.0,
 933.0+/-1.0,
 934.0+/-1.0,
 935.0+/-1.0,
 936.0+/-1.0,
 937.0+/-1.0,
 938.0+/-1.0,
 939.0+/-1.0,
 940.0+/-1.0,
 941.0+/-1.0,
 942.0+/-1.0,
 943.0+/-1.0,
 944.0+/-1.0,
 945.0+/-1.0,
 946.0+/-1.0,
 947.0+/-1.0,
 948.0+/-1.0,
 949.0+/-1.0,
 950.0+/-1.0,
 951.0+/-1.0,
 952.0+/-1.0,
 953.0+/-1.0,
 954.0+/-1.0,
 955.0+/-1.0,
 956.0+/-1.0,
 957.0+/-1.0,
 958.0+/-1.0,
 959.0+/-1.0,
 960.0+/-1.0,
 961.0+/-1.0,
 962.0+/-1.0,
 963.0+/-1.0,
 964.0+/-1.0,
 965.0+/-1.0,
 966.0+/-1.0,
 967.0+/-1.0,
 968.0+/-1.0,
 969.0+/-1.0,
 970.0+/-1.0,
 971.0+/-1.0,
 972.0+/-1.0,
 973.0+/-1.0,
 974.0+/-1.0,
 975.0+/-1.0,
 976.0+/-1.0,
 977.0+/-1.0,
 978.0+/-1.0,
 979.0+/-1.0,
 980.0+/-1.0,
 981.0+/-1.0,
 982.0+/-1.0,
 983.0+/-1.0,
 984.0+/-1.0,
 985.0+/-1.0,
 986.0+/-1.0,
 987.0+/-1.0,
 988.0+/-1.0,
 989.0+/-1.0,
 990.0+/-1.0,
 991.0+/-1.0,
 992.0+/-1.0,
 993.0+/-1.0,
 994.0+/-1.0,
 995.0+/-1.0,
 996.0+/-1.0,
 997.0+/-1.0,
 998.0+/-1.0,
 999.0+/-1.0,
 ...]
In [10]:
x = to_square_uncertain[3]
x**2
Out[10]:
9.0+/-6.0
In [11]:
f = x**2 + uf(2, 1)
f.derivatives
Out[11]:
defaultdict(None, {2.0+/-1.0: 1.0, 3.0+/-1.0: 6.0})
In [12]:
%timeit pure_python_square(to_square)
%timeit pure_python_square(to_square_uncertain)
2.21 ms ± 10.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
43.2 ms ± 110 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [13]:
%timeit already_numpy_square(array_to_square)
array_to_square_uncertain = np.array(to_square_uncertain)
%timeit already_numpy_square(array_to_square_uncertain)
4.42 µs ± 23.3 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
43.2 ms ± 341 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [14]:
%timeit numba_square(array_to_square)
%timeit numba_square(array_to_square_uncertain)
3.41 µs ± 47.5 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
---------------------------------------------------------------------------
TypingError                               Traceback (most recent call last)
<ipython-input-14-b7098004b707> in <module>
      1 get_ipython().run_line_magic('timeit', 'numba_square(array_to_square)')
----> 2 get_ipython().run_line_magic('timeit', 'numba_square(array_to_square_uncertain)')

~/.local/lib/python3.6/site-packages/IPython/core/interactiveshell.py in run_line_magic(self, magic_name, line, _stack_depth)
   2285                 kwargs['local_ns'] = sys._getframe(stack_depth).f_locals
   2286             with self.builtin_trap:
-> 2287                 result = fn(*args,**kwargs)
   2288             return result
   2289 

<decorator-gen-61> in timeit(self, line, cell, local_ns)

~/.local/lib/python3.6/site-packages/IPython/core/magic.py in <lambda>(f, *a, **k)
    185     # but it's overkill for just that one bit of state.
    186     def magic_deco(arg):
--> 187         call = lambda f, *a, **k: f(*a, **k)
    188 
    189         if callable(arg):

~/.local/lib/python3.6/site-packages/IPython/core/magics/execution.py in timeit(self, line, cell, local_ns)
   1104             for index in range(0, 10):
   1105                 number = 10 ** index
-> 1106                 time_number = timer.timeit(number)
   1107                 if time_number >= 0.2:
   1108                     break

~/.local/lib/python3.6/site-packages/IPython/core/magics/execution.py in timeit(self, number)
    158         gc.disable()
    159         try:
--> 160             timing = self.inner(it, self.timer)
    161         finally:
    162             if gcold:

<magic-timeit> in inner(_it, _timer)

~/.local/lib/python3.6/site-packages/numba/dispatcher.py in _compile_for_args(self, *args, **kws)
    346                 e.patch_message(msg)
    347 
--> 348             error_rewrite(e, 'typing')
    349         except errors.UnsupportedError as e:
    350             # Something unsupported is present in the user code, add help info

~/.local/lib/python3.6/site-packages/numba/dispatcher.py in error_rewrite(e, issue_type)
    313                 raise e
    314             else:
--> 315                 reraise(type(e), e, None)
    316 
    317         argtypes = []

~/.local/lib/python3.6/site-packages/numba/six.py in reraise(tp, value, tb)
    656             value = tp()
    657         if value.__traceback__ is not tb:
--> 658             raise value.with_traceback(tb)
    659         raise value
    660 

TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Internal error at <numba.typeinfer.ArgConstraint object at 0x7fdbeb1d5160>:
--%<----------------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/errors.py", line 599, in new_error_context
    yield
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/typeinfer.py", line 199, in __call__
    assert ty.is_precise()
AssertionError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/typeinfer.py", line 142, in propagate
    constraint(typeinfer)
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/typeinfer.py", line 200, in __call__
    typeinfer.add_type(self.dst, ty, loc=self.loc)
  File "/home/mpfluege/.local/miniconda3/envs/pitchwalk/lib/python3.6/contextlib.py", line 99, in __exit__
    self.gen.throw(type, value, traceback)
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/errors.py", line 607, in new_error_context
    six.reraise(type(newerr), newerr, tb)
  File "/home/mpfluege/.local/lib/python3.6/site-packages/numba/six.py", line 659, in reraise
    raise value
numba.errors.InternalError: 
[1] During: typing of argument at <ipython-input-8-d829abb038a8> (3)
--%<----------------------------------------------------------------------------


File "<ipython-input-8-d829abb038a8>", line 3:
def numba_square(a):
    return a**2
    ^

This error may have been caused by the following argument(s):
- argument 0: Unsupported array dtype: object

This is not usually a problem with Numba itself but instead often caused by
the use of unsupported features or an issue in resolving types.

To see Python/NumPy features supported by the latest release of Numba visit:
http://numba.pydata.org/numba-doc/dev/reference/pysupported.html
and
http://numba.pydata.org/numba-doc/dev/reference/numpysupported.html

For more information about typing errors and how to debug them visit:
http://numba.pydata.org/numba-doc/latest/user/troubleshoot.html#my-code-doesn-t-compile

If you think your code should work with Numba, please report the error message
and traceback, along with a minimal reproducer at:
https://github.com/numba/numba/issues/new
In [15]:
@nb.jit(nopython=True, fastmath=True)
def numba_square_uncertain(a):
    result = np.empty_like(a)
    for i in range(len(a)):
        nom_val, std_dev = a[i]
        sq_nom_val = nom_val**2
        sq_std_dev = 2 * nom_val * std_dev
        result[i] = sq_nom_val, sq_std_dev
    return result

numba_compatible_to_square_uncertain = np.array([[u.nominal_value, u.std_dev]
                                                 for u in to_square_uncertain])
numba_square_uncertain(numba_compatible_to_square_uncertain)
%timeit numba_square_uncertain(numba_compatible_to_square_uncertain)
242 µs ± 681 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)

squaring uncertainties

method timing
pure python 760 ms
numpy, prior setup 760 ms
numba, prior setup )-:
numba, custom algorithm 320 µs

Fazit

  • Gleiche Mathematik, unterschiedliche Parameter => hoher Overhead für Interpretation
  • Overhead kann reduziert werden mit Hilfe von numpy und numba
  • numpy ist sehr praktisch, nützt häufig schon viel und integriert volle python-Funktionen, dann aber langsam
  • numba ist noch schneller, hat nicht alle features
  • mit für das Problem optimierten Algorithmen + numba ist sehr viel rauszuholen

Alternativen

  • In C(++) schreiben, an python andocken (ctypes, swig, etc.): Man muss C(++) schreiben
  • Cython: In einem python-Dialekt schreiben, explizit kompilieren, anbinden
  • Pypy: Alternativer python-Interpreter, nicht immer kompatibel, häufig schneller als normales Python
  • Für Mathematik ist keine Alternative schneller als numba.
In [16]:
@nb.jit(nopython=True, fastmath=True, parallel=True)
def numba_square_uncertain_parallel(a):
    result = np.empty_like(a)
    for i in range(len(a)):
        nom_val, std_dev = a[i]
        sq_nom_val = nom_val**2
        sq_std_dev = 2 * nom_val * std_dev
        result[i] = sq_nom_val, sq_std_dev
    return result

numba_square_uncertain_parallel(numba_compatible_to_square_uncertain)

%timeit numba_square_uncertain(numba_compatible_to_square_uncertain)
%timeit numba_square_uncertain_parallel(numba_compatible_to_square_uncertain)
242 µs ± 466 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)
242 µs ± 1.14 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)