text:
#== # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# Description
#
#   Coefficients for the IGRF v12 to be used in the function `igrf12`.
#
#   This values were obtained from the official website [1].
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
#
# References
#
#   [1] https://www.ngdc.noaa.gov/IAGA/vmod/igrf12coeffs.txt
#
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ==#

const G_igrf12 = [
# deg  ord   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF     DGRF      DGRF      DGRF     IGRF      SV
#   n    m 1900.0 1905.0 1910.0 1915.0 1920.0 1925.0 1930.0 1935.0 1940.0 1945.0 1950.0 1955.0 1960.0 1965.0 1970.0 1975.0 1980.0 1985.0 1990.0 1995.0   2000.0    2005.0    2010.0   2015.0 2015-20
    1    0 -31543 -31464 -31354 -31212 -31060 -30926 -30805 -30715 -30654 -30594 -30554 -30500 -30421 -30334 -30220 -30100 -29992 -29873 -29775 -29692 -29619.4 -29554.63 -29496.57 -29442.0    10.3
    1    1  -2298  -2298  -2297  -2306  -2317  -2318  -2316  -2306  -2292  -2285  -2250  -2215  -2169  -2119  -2068  -2013  -1956  -1905  -1848  -1784  -1728.2  -1669.05  -1586.42  -1501.0    18.1
    2    0   -677   -728   -769   -802   -839   -893   -951  -1018  -1106  -1244  -1341  -1440  -1555  -1662  -1781  -1902  -1997  -2072  -2131  -2200  -2267.7  -2337.24  -2396.06  -2445.1    -8.7
    2    1   2905   2928   2948   2956   2959   2969   2980   2984   2981   2990   2998   3003   3002   2997   3000   3010   3027   3044   3059   3070   3068.4   3047.69   3026.34   3012.9    -3.3
    2    2    924   1041   1176   1309   1407   1471   1517   1550   1566   1578   1576   1581   1590   1594   1611   1632   1663   1687   1686   1681   1670.9   1657.76   1668.17   1676.7     2.1
    3    0   1022   1037   1058   1084   1111   1140   1172   1206   1240   1282   1297   1302   1302   1297   1287   1276   1281   1296   1314   1335   1339.6   1336.30   1339.85   1350.7     3.4
    3    1  -1469  -1494  -1524  -1559  -1600  -1645  -1692  -1740  -1790  -1834  -1889  -1944  -1992  -2038  -2091  -2144  -2180  -2208  -2239  -2267  -2288.0  -2305.83  -2326.54  -2352.3    -5.5
    3    2   1256   1239   1223   1212   1205   1202   1205   1215   1232   1255   1274   1288   1289   1292   1278   1260   1251   1247   1248   1249   1252.1   1246.39   1232.10   1225.6    -0.7
    3    3    572    635    705    778    839    881    907    918    916    913    896    882    878    856    838    830    833    829    802    759    714.5    672.51    633.73    582.0   -10.1
    4    0    876    880    884    887    889    891    896    903    914    944    954    958    957    957    952    946    938    936    939    940    932.3    920.55    912.66    907.6    -0.7
    4    1    628    643    660    678    695    711    727    744    762    776    792    796    800    804    800    791    782    780    780    780    786.8    797.96    808.97    813.7     0.2
    4    2    660    653    644    631    616    601    584    565    550    544    528    510    504    479    461    438    398    361    325    290    250.0    210.65    166.58    120.4    -9.1
    4    3   -361   -380   -400   -416   -424   -426   -422   -415   -405   -421   -408   -397   -394   -390   -395   -405   -419   -424   -423   -418   -403.0   -379.86   -356.83   -334.9     4.1
    4    4    134    146    160    178    199    217    234    249    265    304    303    290    269    252    234    216    199    170    141    122    111.3    100.00     89.40     70.4    -4.3
    5    0   -184   -192   -201   -211   -221   -230   -237   -241   -241   -253   -240   -229   -222   -219   -216   -218   -218   -214   -214   -214   -218.8   -227.00   -230.87   -232.6    -0.2
    5    1    328    328    327    327    326    326    327    329    334    346    349    360    362    358    359    356    357    355    353    352    351.4    354.41    357.29    360.1     0.5
    5    2    264    259    253    245    236    226    218    211    208    194    211    230    242    254    262    264    261    253    245    235    222.3    208.95    200.26    192.4    -1.3
    5    3      5     -1     -9    -16    -23    -28    -32    -33    -33    -20    -20    -23    -26    -31    -42    -59    -74    -93   -109   -118   -130.4   -136.54   -141.05   -140.9    -0.1
    5    4    -86    -93   -102   -111   -119   -125   -131   -136   -141   -142   -147   -152   -156   -157   -160   -159   -162   -164   -165   -166   -168.6   -168.05   -163.17   -157.5     1.4
    5    5    -16    -26    -38    -51    -62    -69    -74    -76    -76    -82    -76    -69    -63    -62    -56    -49    -48    -46    -36    -17    -12.9    -13.55     -8.03      4.1     3.9
    6    0     63     62     62     61     61     61     60     59     57     59     54     47     46     45     43     45     48     53     61     68     72.3     73.60     72.78     70.0    -0.3
    6    1     61     60     58     57     55     54     53     53     54     57     57     57     58     61     64     66     66     65     65     67     68.2     69.56     68.69     67.7    -0.1
    6    2    -11    -11    -11    -10    -10     -9     -9     -8     -7      6      4      3      1      8     15     28     42     51     59     68     74.2     76.74     75.92     72.7    -0.7
    6    3   -217   -221   -224   -228   -233   -238   -242   -246   -249   -246   -247   -247   -237   -228   -212   -198   -192   -185   -178   -170   -160.9   -151.34   -141.40   -129.9     2.1
    6    4    -58    -57    -54    -51    -46    -40    -32    -25    -18    -25    -16     -8     -1      4      2      1      4      4      3     -1     -5.9    -14.58    -22.83    -28.9    -1.2
    6    5     59     57     54     49     44     39     32     25     18     21     12      7     -2      1      3      6     14     16     18     19     16.9     14.58     13.10     13.2     0.3
    6    6    -90    -92    -95    -98   -101   -103   -104   -106   -107   -104   -105   -107   -113   -111   -112   -111   -108   -102    -96    -93    -90.4    -86.36    -78.09    -70.9     1.6
    7    0     70     70     71     72     73     73     74     74     74     70     65     65     67     75     72     71     72     74     77     77     79.0     79.88     80.44     81.6     0.3
    7    1    -55    -54    -54    -54    -54    -54    -54    -53    -53    -40    -55    -56    -56    -57    -57    -56    -59    -62    -64    -72    -74.0    -74.46    -75.00    -76.1    -0.2
    7    2      0      0      1      2      2      3      4      4      4      0      2      2      5      4      1      1      2      3      2      1      0.0     -1.65     -4.55     -6.8    -0.5
    7    3     34     33     32     31     29     27     25     23     20      0      1     10     15     13     14     16     21     24     26     28     33.3     38.73     45.24     51.8     1.3
    7    4    -41    -41    -40    -38    -37    -35    -34    -33    -31    -29    -40    -32    -32    -26    -22    -14    -12     -6     -1      5      9.1     12.30     14.00     15.0     0.1
    7    5    -21    -20    -19    -18    -16    -14    -12    -11     -9    -10     -7    -11     -7     -6     -2      0      1      4      5      4      6.9      9.37     10.46      9.4    -0.6
    7    6     18     18     18     19     19     19     18     18     17     15      5      9     17     13     13     12     11     10      9      8      7.3      5.42      1.64     -2.8    -0.8
    7    7      6      6      6      6      6      6      6      6      5     29     19     18      8      1     -2     -5     -2      0      0     -2     -1.2      1.94      4.92      6.8     0.2
    8    0     11     11     11     11     11     11     11     11     11     13     22     11     15     13     14     14     18     21     23     25     24.4     24.80     24.41     24.2     0.2
    8    1      8      8      8      8      7      7      7      7      7      7     15      9      6      5      6      6      6      6      5      6      6.6      7.62      8.21      8.8     0.0
    8    2     -4     -4     -4     -4     -3     -3     -3     -3     -3     -8     -4     -6     -4     -4     -2     -1      0      0     -1     -6     -9.2    -11.73    -14.50    -16.9    -0.6
    8    3     -9     -9     -9     -9     -9     -9     -9     -9    -10     -5     -1    -14    -11    -14    -13    -12    -11    -11    -10     -9     -7.9     -6.88     -5.59     -3.2     0.5
    8    4      1      1      1      2      2      2      2      1      1      9     11      6      2      0     -3     -8     -7     -9    -12    -14    -16.6    -18.11    -19.34    -20.6    -0.2
    8    5      2      2      2      3      4      4      5      6      6      7     15     10     10      8      5      4      4      4      3      9      9.1     10.17     11.61     13.4     0.4
    8    6     -9     -8     -8     -8     -7     -7     -6     -6     -5    -10    -13     -7     -5     -1      0      0      3      4      4      6      7.0      9.36     10.85     11.7     0.1
    8    7      5      5      5      6      6      7      8      8      9      7      5      6     10     11     11     10      6      4      2     -5     -7.9    -11.25    -14.05    -15.9    -0.4
    8    8      8      8      8      8      8      8      8      7      7      2     -1      9      8      4      3      1     -1     -4     -6     -7     -7.0     -4.87     -3.54     -2.0     0.3
    9    0      8      8      8      8      8      8      8      8      8      5      3      4      4      8      8      7      5      5      4      4      5.0      5.58      5.50      5.4     0.0
    9    1     10     10     10     10     10     10     10     10     10    -21     -7      9      6     10     10     10     10     10      9      9      9.4      9.76      9.45      8.8     0.0
    9    2      1      1      1      1      1      1      1      1      1      1     -1     -4      0      2      2      2      1      1      1      3      3.0      3.58      3.45      3.1     0.0
    9    3    -11    -11    -11    -11    -11    -11    -12    -12    -12    -11    -25     -5     -9    -13    -12    -12    -12    -12    -12    -10     -8.4     -6.94     -5.27     -3.3     0.0
    9    4     12     12     12     12     12     12     12     11     11      3     10      2      1     10     10     10      9      9      9      8      6.3      5.01      3.13      0.7     0.0
    9    5      1      1      1      1      1      1      1      1      1     16      5      4      4     -1     -1     -1     -3     -3     -4     -8     -8.9    -10.76    -12.38    -13.3     0.0
    9    6     -2     -2     -2     -2     -2     -2     -2     -2     -2     -3     -5      1     -1     -1      0     -1     -1     -1     -2     -1     -1.5     -1.25     -0.76     -0.1     0.0
    9    7      2      2      2      2      2      2      3      3      3     -4     -2      2     -2      5      3      4      7      7      7     10      9.3      8.76      8.43      8.7     0.0
    9    8     -1      0      0      0      0      0      0      0      1     -3      3      2      3      1      1      1      2      1      1     -2     -4.3     -6.66     -8.42     -9.1     0.0
    9    9     -1     -1     -1     -1     -1     -1     -2     -2     -2     -4      8      5     -1     -2     -1     -2     -5     -5     -6     -8     -8.2     -9.22    -10.08    -10.5     0.0
   10    0     -3     -3     -3     -3     -3     -3     -3     -3     -3     -3     -8     -3      1     -2     -3     -3     -4     -4     -3     -3     -2.6     -2.17     -1.94     -1.9     0.0
   10    1     -4     -4     -4     -4     -4     -4     -4     -4     -4     11      4     -5     -3     -3     -3     -3     -4     -4     -4     -6     -6.0     -6.12     -6.24     -6.3     0.0
   10    2      2      2      2      2      2      2      2      2      2      1     -1     -1      4      2      2      2      2      3      2      2      1.7      1.42      0.89      0.1     0.0
   10    3     -5     -5     -5     -5     -5     -5     -5     -5     -5      2     13      2      0     -5     -5     -5     -5     -5     -5     -4     -3.1     -2.35     -1.07      0.5     0.0
   10    4     -2     -2     -2     -2     -2     -2     -2     -2     -2     -5     -4     -3     -1     -2     -1     -2     -2     -2     -2     -1     -0.5     -0.15     -0.16     -0.5     0.0
   10    5      6      6      6      6      6      6      6      6      6     -1      4      7      4      4      6      5      5      5      4      4      3.7      3.06      2.45      1.8     0.0
   10    6      4      4      4      4      4      4      4      4      4      8     12      4      6      4      4      4      3      3      3      2      1.0      0.29     -0.33     -0.7     0.0
   10    7      0      0      0      0      0      0      0      0      0     -1      3     -2      1      0      1      1      1      1      1      2      2.0      2.06      2.13      2.1     0.0
   10    8      2      2      2      1      1      1      1      2      2     -3      2      6     -1      2      0      0      2      2      3      5      4.2      3.77      3.09      2.4     0.0
   10    9      2      2      2      2      3      3      3      3      3      5     10     -2      2      2      3      3      3      3      3      1      0.3     -0.21     -1.03     -1.8     0.0
   10   10      0      0      0      0      0      0      0      0      0     -2      3      0      0      0     -1     -1      0      0      0      0     -1.1     -2.09     -2.80     -3.6     0.0
   11    0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      2.7      2.95      3.05      3.1     0.0
   11    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -1.7     -1.60     -1.48     -1.5     0.0
   11    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -1.9     -1.88     -2.03     -2.3     0.0
   11    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.5      1.44      1.65      2.0     0.0
   11    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.1     -0.31     -0.51     -0.8     0.0
   11    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.1      0.29      0.54      0.6     0.0
   11    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.7     -0.79     -0.79     -0.7     0.0
   11    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.7      0.53      0.37      0.2     0.0
   11    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.7      1.80      1.79      1.7     0.0
   11    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.1      0.16      0.12     -0.2     0.0
   11   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.2      0.96      0.75      0.4     0.0
   11   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      4.0      3.99      3.75      3.5     0.0
   12    0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -2.2     -2.15     -2.12     -1.9     0.0
   12    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.3     -0.29     -0.21     -0.2     0.0
   12    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.2      0.21      0.30      0.4     0.0
   12    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.9      0.89      1.04      1.2     0.0
   12    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.2     -0.38     -0.63     -0.8     0.0
   12    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.9      0.96      0.95      0.9     0.0
   12    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.5     -0.30     -0.11      0.1     0.0
   12    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.46      0.52      0.5     0.0
   12    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.3     -0.35     -0.39     -0.3     0.0
   12    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.36     -0.37     -0.4     0.0
   12   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.1      0.08      0.21      0.2     0.0
   12   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.2     -0.49     -0.77     -0.9     0.0
   12   12      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.08      0.04      0.0     0.0
   13    0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.2     -0.16     -0.09      0.0     0.0
   13    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -0.88     -0.89     -0.9     0.0
   13    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.30      0.31      0.4     0.0
   13    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.1      0.28      0.42      0.5     0.0
   13    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.43     -0.45     -0.5     0.0
   13    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.3      1.18      1.08      1.0     0.0
   13    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.37     -0.31     -0.2     0.0
   13    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.7      0.75      0.78      0.8     0.0
   13    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.26     -0.18     -0.1     0.0
   13    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.35      0.38      0.3     0.0
   13   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.1     -0.05      0.02      0.1     0.0
   13   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.4      0.41      0.42      0.5     0.0
   13   12      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.0     -0.10     -0.26     -0.4     0.0
   13   13      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.1     -0.18     -0.26     -0.3     0.0
]

const H_igrf12 = [
# deg  ord   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   IGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF   DGRF     DGRF      DGRF      DGRF     IGRF      SV
#   n    m 1900.0 1905.0 1910.0 1915.0 1920.0 1925.0 1930.0 1935.0 1940.0 1945.0 1950.0 1955.0 1960.0 1965.0 1970.0 1975.0 1980.0 1985.0 1990.0 1995.0   2000.0    2005.0    2010.0   2015.0 2015-20
    1    1   5922   5909   5898   5875   5845   5817   5808   5812   5821   5810   5815   5820   5791   5776   5737   5675   5604   5500   5406   5306   5186.1   5077.99   4944.26   4797.1   -26.6
    2    1  -1061  -1086  -1128  -1191  -1259  -1334  -1424  -1520  -1614  -1702  -1810  -1898  -1967  -2016  -2047  -2067  -2129  -2197  -2279  -2366  -2481.6  -2594.50  -2708.54  -2845.6   -27.4
    2    2   1121   1065   1000    917    823    728    644    586    528    477    381    291    206    114     25    -68   -200   -306   -373   -413   -458.0   -515.43   -575.73   -641.9   -14.1
    3    1   -330   -357   -389   -421   -445   -462   -480   -494   -499   -499   -476   -462   -414   -404   -366   -333   -336   -310   -284   -262   -227.6   -198.86   -160.40   -115.3     8.2
    3    2      3     34     62     84    103    119    133    146    163    186    206    216    224    240    251    262    271    284    293    302    293.4    269.72    251.75    244.9    -0.4
    3    3    523    480    425    360    293    229    166    101     43    -11    -46    -83   -130   -165   -196   -223   -252   -297   -352   -427   -491.1   -524.72   -537.03   -538.4     1.8
    4    1    195    203    211    218    220    216    205    188    169    144    136    133    135    148    167    191    212    232    247    262    272.6    282.07    286.48    283.3    -1.3
    4    2    -69    -77    -90   -109   -134   -163   -195   -226   -252   -276   -278   -274   -278   -269   -266   -265   -257   -249   -240   -236   -231.9   -225.23   -211.03   -188.7     5.3
    4    3   -210   -201   -189   -173   -153   -130   -109    -90    -72    -55    -37    -23      3     13     26     39     53     69     84     97    119.8    145.15    164.46    180.9     2.9
    4    4    -75    -65    -55    -51    -57    -70    -90   -114   -141   -178   -210   -230   -255   -269   -279   -288   -297   -297   -299   -306   -303.8   -305.36   -309.72   -329.5    -5.2
    5    1   -210   -193   -172   -148   -122    -96    -72    -51    -33    -12      3     15     16     19     26     31     46     47     46     46     43.8     42.72     44.58     47.3     0.6
    5    2     53     56     57     58     58     58     60     64     71     95    103    110    125    128    139    148    150    150    154    165    171.9    180.25    189.01    197.0     1.7
    5    3    -33    -32    -33    -34    -38    -44    -53    -64    -75    -67    -87    -98   -117   -126   -139   -152   -151   -154   -153   -143   -133.1   -123.45   -118.06   -119.3    -1.2
    5    4   -124   -125   -126   -126   -125   -122   -118   -115   -113   -119   -122   -121   -114    -97    -91    -83    -78    -75    -69    -55    -39.3    -19.57     -0.01     16.0     3.4
    5    5      3     11     21     32     43     51     58     64     69     82     80     78     81     81     83     88     92     95     97    107    106.3    103.85    101.04    100.2     0.0
    6    1     -9     -7     -5     -2      0      3      4      4      4      6     -1     -9    -10    -11    -12    -13    -15    -16    -16    -17    -17.4    -20.33    -20.90    -20.8     0.0
    6    2     83     86     89     93     96     99    102    104    105    100     99     96     99    100    100     99     93     88     82     72     63.7     54.75     44.18     33.2    -2.1
    6    3      2      4      5      8     11     14     19     25     33     16     33     48     60     68     72     75     71     69     69     67     65.1     63.63     61.54     58.9    -0.7
    6    4    -35    -32    -29    -26    -22    -18    -16    -15    -15     -9    -12    -16    -20    -32    -37    -41    -43    -48    -52    -58    -61.2    -63.53    -66.26    -66.7     0.2
    6    5     36     32     28     23     18     13      8      4      0    -16    -12    -12    -11     -8     -6     -4     -2     -1      1      1      0.7      0.24      3.02      7.3     0.9
    6    6    -69    -67    -65    -62    -57    -52    -46    -40    -33    -39    -30    -24    -17     -7      1     11     17     21     24     36     43.8     50.94     55.40     62.6     1.0
    7    1    -45    -46    -47    -48    -49    -50    -51    -52    -52    -45    -35    -50    -55    -61    -70    -77    -82    -83    -80    -69    -64.6    -61.14    -57.80    -54.1     0.8
    7    2    -13    -14    -14    -14    -14    -14    -15    -17    -18    -18    -17    -24    -28    -27    -27    -26    -27    -27    -26    -25    -24.2    -22.57    -21.20    -19.5     0.4
    7    3    -10    -11    -12    -12    -13    -14    -14    -14    -14      2      0     -4     -6     -2     -4     -5     -5     -2      0      4      6.2      6.82      6.54      5.7    -0.2
    7    4     -1      0      1      2      4      5      6      7      7      6     10      8      7      6      8     10     16     20     21     24     24.0     25.35     24.96     24.4    -0.3
    7    5     28     28     28     28     28     29     29     29     29     28     36     28     23     26     23     22     18     17     17     17     14.8     10.93      7.03      3.4    -0.6
    7    6    -12    -12    -13    -15    -16    -17    -18    -19    -20    -17    -18    -20    -18    -23    -23    -23    -23    -23    -23    -24    -25.4    -26.32    -27.61    -27.4     0.1
    7    7    -22    -22    -22    -22    -22    -21    -20    -19    -19    -22    -16    -18    -17    -12    -11    -12    -10     -7     -4     -6     -5.8     -4.64     -3.28     -2.2    -0.2
    8    1      8      8      8      8      8      8      8      8      8     12      5     10     11      7      7      6      7      8     10     11     11.9     11.20     10.84     10.1    -0.3
    8    2    -14    -15    -15    -15    -15    -15    -15    -15    -14    -21    -22    -15    -14    -12    -15    -16    -18    -19    -19    -21    -21.5    -20.88    -20.03    -18.3     0.3
    8    3      7      7      6      6      6      6      5      5      5    -12      0      5      7      9      6      4      4      5      6      8      8.5      9.83     11.83     13.3     0.1
    8    4    -13    -13    -13    -13    -14    -14    -14    -15    -15     -7    -21    -23    -18    -16    -17    -19    -22    -23    -22    -23    -21.5    -19.71    -17.41    -14.6     0.5
    8    5      5      5      5      5      5      5      5      5      5      2     -8      3      4      4      6      6      9     11     12     15     15.5     16.22     16.71     16.2    -0.2
    8    6     16     16     16     16     17     17     18     18     19     18     17     23     23     24     21     18     16     14     12     11      8.9      7.61      6.96      5.7    -0.3
    8    7     -5     -5     -5     -5     -5     -5     -5     -5     -5      3     -4     -4      1     -3     -6    -10    -13    -15    -16    -16    -14.9    -12.76    -10.74     -9.1     0.3
    8    8    -18    -18    -18    -18    -19    -19    -19    -19    -19    -11    -17    -13    -20    -17    -16    -17    -15    -11    -10     -4     -2.1     -0.06      1.64      2.1     0.0
    9    1    -20    -20    -20    -20    -20    -20    -20    -20    -21    -27    -24    -11    -18    -22    -21    -21    -21    -21    -20    -20    -19.7    -20.11    -20.54    -21.6     0.0
    9    2     14     14     14     14     14     14     14     15     15     17     19     12     12     15     16     16     16     15     15     15     13.4     12.69     11.51     10.8     0.0
    9    3      5      5      5      5      5      5      5      5      5     29     12      7      2      7      6      7      9      9     11     12     12.5     12.67     12.75     11.8     0.0
    9    4     -3     -3     -3     -3     -3     -3     -3     -3     -3     -9      2      6      0     -4     -4     -4     -5     -6     -7     -6     -6.2     -6.72     -7.14     -6.8     0.0
    9    5     -2     -2     -2     -2     -2     -2     -2     -3     -3      4      2     -2     -3     -5     -5     -5     -6     -6     -7     -8     -8.4     -8.16     -7.42     -6.9     0.0
    9    6      8      8      8      8      9      9      9      9      9      9      8     10      9     10     10     10      9      9      9      8      8.4      8.10      7.97      7.8     0.0
    9    7     10     10     10     10     10     10     10     11     11      6      8      7      8     10     11     11     10      9      8      5      3.8      2.92      2.14      1.0     0.0
    9    8     -2     -2     -2     -2     -2     -2     -2     -2     -2      1    -11     -6      0     -4     -2     -3     -6     -7     -7     -8     -8.2     -7.73     -6.08     -4.0     0.0
    9    9      2      2      2      2      2      2      2      2      2      8     -7      5      5      1      1      1      2      2      2      3      4.8      6.01      7.01      8.4     0.0
   10    1      2      2      2      2      2      2      2      2      2      5     13     -4      4      2      1      1      1      1      2      1      1.7      2.19      2.73      3.2     0.0
   10    2      1      1      1      1      1      1      1      1      1      1     -2      0      1      1      1      1      0      0      1      0      0.0      0.10     -0.10     -0.4     0.0
   10    3      2      2      2      2      2      2      2      2      2    -20    -10     -8      0      2      3      3      3      3      3      4      4.0      4.46      4.71      4.6     0.0
   10    4      6      6      6      6      6      6      6      6      6     -1      2     -2      2      6      4      4      6      6      6      5      4.9      4.76      4.44      4.4     0.0
   10    5     -4     -4     -4     -4     -4     -4     -4     -4     -4     -6     -3     -4     -5     -4     -4     -4     -4     -4     -4     -5     -5.9     -6.58     -7.22     -7.9     0.0
   10    6      0      0      0      0      0      0      0      0      0      6      6      1      1      0      0     -1      0      0      0     -1     -1.2     -1.01     -0.96     -0.6     0.0
   10    7     -2     -2     -2     -2     -2     -2     -2     -1     -1     -4     -3     -3     -1     -2     -1     -1     -1     -1     -2     -2     -2.9     -3.47     -3.95     -4.2     0.0
   10    8      4      4      4      4      4      4      4      4      4     -2      6      7      6      3      3      3      4      4      3      1      0.2     -0.86     -1.99     -2.8     0.0
   10    9      0      0      0      0      0      0      0      0      0      0     11     -1      0      0      1      1      0      0     -1     -2     -2.2     -2.31     -1.97     -1.2     0.0
   10   10     -6     -6     -6     -6     -6     -6     -6     -6     -6     -2      8     -3     -7     -6     -4     -5     -6     -6     -6     -7     -7.4     -7.93     -8.31     -8.7     0.0
   11    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.1      0.26      0.13     -0.1     0.0
   11    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.3      1.44      1.67      2.0     0.0
   11    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -0.77     -0.66     -0.7     0.0
   11    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -2.6     -2.27     -1.76     -1.1     0.0
   11    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.9      0.90      0.85      0.8     0.0
   11    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.7     -0.58     -0.39     -0.2     0.0
   11    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -2.8     -2.69     -2.51     -2.2     0.0
   11    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -1.08     -1.27     -1.4     0.0
   11    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -1.2     -1.58     -2.11     -2.5     0.0
   11   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -1.9     -1.90     -1.94     -2.0     0.0
   11   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -1.39     -1.86     -2.4     0.0
   12    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.55     -0.87     -1.1     0.0
   12    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.23      0.27      0.4     0.0
   12    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      2.5      2.38      2.13      1.9     0.0
   12    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -2.6     -2.63     -2.49     -2.2     0.0
   12    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.7      0.61      0.49      0.3     0.0
   12    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.40      0.59      0.7     0.0
   12    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.0      0.01      0.00     -0.1     0.0
   12    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.0      0.02      0.13      0.3     0.0
   12    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.28      0.27      0.2     0.0
   12   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -0.87     -0.86     -0.9     0.0
   12   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.34     -0.23     -0.1     0.0
   12   12      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.8      0.88      0.87      0.7     0.0
   13    1      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -0.76     -0.87     -0.9     0.0
   13    2      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.2      0.33      0.30      0.4     0.0
   13    3      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      1.8      1.72      1.66      1.6     0.0
   13    4      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.4     -0.54     -0.59     -0.5     0.0
   13    5      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -1.0     -1.07     -1.14     -1.2     0.0
   13    6      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.1     -0.04     -0.07     -0.1     0.0
   13    7      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.7      0.63      0.54      0.4     0.0
   13    8      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.21      0.10     -0.1     0.0
   13    9      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.6      0.53      0.49      0.4     0.0
   13   10      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0.3      0.38      0.44      0.5     0.0
   13   11      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.2     -0.22     -0.25     -0.3     0.0
   13   12      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.5     -0.57     -0.53     -0.4     0.0
   13   13      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0      0     -0.9     -0.82     -0.79     -0.8     0.0
]


text:
using PMDPs

function super_simple_pp()
    T = 3
    P = SA[ PMDPs.Product(SA[true], T),]
    C₀ = SA[1,]
    D = BernoulliScheme(T, [0.1])
    β = DiscreteNonParametric([10.], [1.])
    B = [β,]
    A = [0., 5., 10., 15.]
    objective = :revenue

    pp = PMDPs.PMDPProblem(P, C₀, D, B, A, objective)
end

function simple_pp()
    P = SA[ PMDPs.Product(SA[true, false], 6), # 1
            PMDPs.Product(SA[false, true], 8), # 2
            PMDPs.Product(SA[true, true], 6)]  # 3
    C₀ = SA[3,3]
    D = BernoulliScheme(8, [0.1, 0.1, 0.1])
    β₁ = DiscreteNonParametric([10.], [1.])
    β₂ = DiscreteNonParametric([10.,15.], [0.5, 0.5])
    B = [β₁, β₁, β₂]
    A = [0., 5., 10., 15.]
    objective = :revenue

    pp = PMDPs.PMDPProblem(P, C₀, D, B, A, objective)
end

function simple_short_trace(pp::PMDPs.PMDPProblem)
    SimHistory([
        (s = PMDPs.State(pp.c₀, 1, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 3, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 5, 2), info = (b=10.,))
    ], 1., nothing, nothing)
end

function simple_exhaust_capacity_trace(pp::PMDPs.PMDPProblem)
    SimHistory([
        (s = PMDPs.State(pp.c₀, 1, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 2, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 3, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 4, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 5, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 6, 3), info = (b=15.,)),
        # (s = PMDPs.State(pp.c₀, 7, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 8, 2), info = (b=10.,))
    ], 1., nothing, nothing)
end

function simple_trace_different_utility_revenue_optim_allocs(pp::PMDPs.PMDPProblem)
    SimHistory([
        # (s = PMDPs.State(pp.c₀, 1, 1), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 2, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 3, 3), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 4, 2), info = (b=10.,)),
        # (s = PMDPs.State(pp.c₀, 5, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 6, 3), info = (b=10.,)),
        # (s = PMDPs.State(pp.c₀, 7, 2), info = (b=10.,)),
        (s = PMDPs.State(pp.c₀, 8, 2), info = (b=10.,))
    ], 1., nothing, nothing)
end

function empty_trace(pp::PMDPs.PMDPProblem)
    empty_trace = SimHistory([
        (s=PMDPs.State(pp.c₀, 1, length(pp.P)+1), info = (b=PMDPs.EMPTY_PRODUCT_USER_BUDGET,)),
        ], 1., nothing, nothing)
end

ext: jl


text:
module Cointegration

using LinearAlgebra
using SparseArrays
using Printf
using Statistics
using Random

using Distributions

import Base: convert, copy, show
import LinearAlgebra: eigen, eigvals, syrk_wrapper!
import StatsBase: loglikelihood, residuals
import Distributions: estimate
import ProgressMeter: Progress, next!

export β, τ, ρ, δ, VAR, bootstrap, civecmI1, civecmI2, civecmI2alt, companion, estimate, lrtest,
    normalitytest, ranktest, restrict, setrank, simulate
# From StatsBase
export residuals

include("auxiliary.jl")
include("abstract.jl")
include("I1.jl")
include("I2ParuoloRahbek.jl")
include("VAR.jl")
# include("I2MosconiParuolo.jl")
include("I2Givens.jl")

end


text:
mutable struct Snailfish
    left::Union{Int, Snailfish}
    right::Union{Int, Snailfish}
    direction::Union{Nothing, Symbol}
    parent::Union{Nothing, Snailfish}

    function Snailfish(v::Vector; direction=nothing)
        s = new(
            typeof(v[1]) === Int ? v[1] : Snailfish(v[1]; direction=:left),
            typeof(v[2]) === Int ? v[2] : Snailfish(v[2]; direction=:right),
            direction,
            nothing
        )
        (typeof(s.left) === Snailfish) && (s.left.parent = s)
        (typeof(s.right) === Snailfish) && (s.right.parent = s)
        s
    end

    Snailfish(left, right, direction, parent) = new(left, right, direction, parent)
end

function Base.:+(s1::Snailfish, s2::Snailfish)
    s = Snailfish(deepcopy(s1), deepcopy(s2), nothing, nothing)
    s.left.parent = s
    s.left.direction = :left

    s.right.parent = s
    s.right.direction = :right

    reduce!(s)
    s
end

function reduce!(s::Snailfish)
    change = true
    while change
        change = explode!(s) || split!(s)
    end
    s
end

explode!(::Int; direction, depth) = false

function explode!(s::Snailfish; direction=nothing, depth=0)
    if depth < 4
        return explode!(s.left; direction=:left, depth=depth+1) || explode!(s.right; direction=:right, depth=depth+1)
    else
        bump_neighbour(s, :left, s.left)
        bump_neighbour(s, :right, s.right)

        setproperty!(s.parent, direction, 0)
        return true
    end
end

function bump_neighbour(s::Snailfish, direction, value)
    opposite_dir = direction == :left ? :right : :left
    if s.direction == direction
        while s.direction == direction
            s = s.parent
        end
    end
    if s.direction !== nothing
        s = s.parent
        if typeof(getproperty(s, direction)) === Snailfish
            s = getproperty(s, direction)

            while typeof(getproperty(s, opposite_dir)) === Snailfish
                s = getproperty(s, opposite_dir)
            end
            setproperty!(s, opposite_dir, getproperty(s, opposite_dir) + value)
        else
            setproperty!(s, direction, getproperty(s, direction) + value)
        end
    end
end

function split!(s::Snailfish)
    for dir in (:left, :right)
        if typeof(getproperty(s, dir)) === Snailfish
            split!(getproperty(s, dir)) && return true
        elseif getproperty(s, dir) > 9
            setproperty!(s, dir, Snailfish(
                getproperty(s, dir) ÷ 2,
                getproperty(s, dir) - (getproperty(s, dir) ÷ 2),
                dir,
                s
            ))
            return true
        end
    end
    false
end

magnitude(v::Int) = v
magnitude(s::Snailfish) = 3 * magnitude(s.left) + 2 * magnitude(s.right)

function parse_line(l)
    v = eval(Meta.parse(l))
    Snailfish(v)
end

const data = parse_line.(readlines())

# Part One
reduce(+, data) |> magnitude |> println

# Part Two
[
    data[i] + data[j]
    for i in eachindex(data), j in eachindex(data)
    if i != j
] .|> magnitude |> maximum |> println

max_stars_repo_name: pLOPeGG/JuliaOfCode

max_issues_repo_name: pLOPeGG/JuliaOfCode

max_forks_repo_name: pLOPeGG/JuliaOfCode


text:
using PICDataStructures, Test
using PICDataStructures: dimensionality, unitname, unwrapdata
using Unitful
using RecursiveArrayTools: recursive_bottom_eltype

@testset "Scalar field interface" begin
    grids =
        SparseAxisGrid(1:0.1:2),
        SparseAxisGrid(1:0.01:2, 1:0.01:2),
        SparseAxisGrid(1:0.005:2, 1:0.01:2, 1:0.01:2),
        SparseAxisGrid(1u"m":0.1u"m":2.0u"m"),
        SparseAxisGrid(1u"m":0.01u"m":2u"m", 1u"m":0.01u"m":2u"m"),
        SparseAxisGrid(1u"m":0.005u"m":2u"m", 1u"m":0.01u"m":2u"m", 1u"m":0.01u"m":2u"m")

    fields = [
        scalarfield(x->inv(x...), grids[1], name="1D"),
        scalarfield(grids[2], name="2D") do (x,y)
            1 / √(x^2 + y^2)
        end,
        scalarfield(grids[3], name="3D") do (x,y,z)
            1 / √(x^2 + y^2 + z^2)
        end,
        scalarfield(grids[4], name="1D") do (x,)
            1u"V" / x
        end,
        scalarfield(grids[5], name="2D") do (x,y)
            1u"V" / √(x^2 + y^2)
        end,
        scalarfield(grids[6], name="3D") do (x,y,z)
            1u"V" / √(x^2 + y^2 + z^2)
        end
    ]

    @testset "$(dimensionality(f))D ($(unitname(f)))" for (grid,f) in zip(grids,fields)
        @test f isa ScalarField
        @test getdomain(f) == grid

        T = typeof(f)
        N = dimensionality(f)
        @test isconcretetype(T)

        @testset "Traits" begin
            @test scalarness(T) === ScalarQuantity()
            @test domain_discretization(T) === LatticeGrid{N}()
            @test domain_type(T) <: SparseAxisGrid
        end

        @testset "Indexing" begin
            @test size(f) == size(grid)
            𝟙 = oneunit(recursive_bottom_eltype(f))
            @test f[begin] == f[1] == 𝟙 / √N
            @test f[end] == 𝟙 / √(4*N)
        end
        @testset "Iteration" begin
            @test [fd for fd in f] == collect(f)
        end
        @testset "Broadcasting" begin
            f2 = f .* 2
            @test typeof(f) == typeof(f2)
            @test getdomain(f2) == getdomain(f)
            @test 2f[1] == f2[1]
            @test nameof(f) == nameof(f2)
        end

        @testset "Downsampling" begin
            if N == 3
                f_small = downsample(f, 51, 26, 26)
                @test size(f_small) == (51, 26, 26)
                f_small = downsample(f)
                # in case the downsampling size is too close
                # to the target one, we will get the same size
                @test size(f_small) == size(f)
                f_small = downsample(f, 50)
                @test all(size(f_small) .≤ 51)
            elseif N == 2
                f_small = downsample(f, 51, 51)
                @test size(f_small) == (51, 51)
                f_small = downsample(f)
                @test all(size(f_small) .≤ 160)
            else
                f_small = downsample(f, 3)
                @test size(f_small) == (3,)
            end
            @test nameof(f) == nameof(f_small) == "$(N)D"
        end
    end

    @testset "Sclicing" begin
        @testset "2D" begin
            N = 2
            fi = fields[2]
            grid = grids[2]
            f_extra = scalarfield(grid) do (x,y)
                0.5x - grid.x[1]
            end
            f = fi + f_extra

            f_slice = selectdim(f, :x, grid.x[1])
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            @test f[1] == f_slice[1]
            @test f[1,:] == f_slice

            mid = (grid.y[end] + grid.y[begin])/2
            f_slice = selectdim(f, :y, mid)
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            l = length(grid.y)
            @test f[:,l÷2+1] == f_slice

            f_slice = selectdim(f, :y, grid.y[1])
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            @test f[:,1] == f_slice

            @test nameof(f) == nameof(f_slice) == "2D"
        end
        @testset "3D" begin
            N = 3
            fi = fields[3]
            grid = grids[3]
            f_extra = scalarfield(grid) do (x,y)
                0.3x - grid.x[1]
            end
            f = fi + f_extra

            f_slice = selectdim(f, :x, grid.x[1])
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            @test f[1] == f_slice[1]
            @test f[1,:,:] == f_slice

            mid = (grid.y[end] + grid.y[begin])/2
            f_slice = selectdim(f, :y, mid)
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            l = length(grid.y)
            @test f[:,l÷2+1,:] == f_slice

            f_slice = selectdim(f, :z, grid.y[1])
            @test ndims(f_slice) == N - 1
            @test dimensionality(f_slice) == N - 1
            @test f[:,:,1] == f_slice

            @test nameof(f) == nameof(f_slice) == "3D"
        end
        @testset "getindex slice" begin
            f = fields[3]
            N = 3

            f_slice = f[x=1]
            @test ndims(f_slice) == N - 1
        end
    end

    @testset "Unit handling" begin
        @test ustrip(fields[4]) == fields[1]
        @test ustrip(fields[5]) == fields[2]
        @test ustrip(fields[6]) == fields[3]

        @test fields[1] .* u"V/m" == fields[4]
        @test fields[2] .* u"V/m" == fields[5]
        @test fields[3] .* u"V/m" == fields[6]

        @test ustrip(u"V/m", fields[4]) == fields[1]
        @test ustrip(u"V/m", fields[5]) == fields[2]
        @test ustrip(u"V/m", fields[6]) == fields[3]

        @test ustrip(u"V/m", u"m", fields[4]) == fields[1]
        @test ustrip(u"V/m", u"m", fields[5]) == fields[2]
        @test ustrip(u"V/m", u"m", fields[6]) == fields[3]

        @test ustrip(fields[1]) == fields[1]
        @test nameof(ustrip(fields[1])) == "1D"

        @test nameof(ustrip(u"V/m", fields[4])) == "1D"
        @test nameof(ustrip(u"V/m", u"m", fields[4])) == "1D"
    end
end

@testset "Scalar variable interface" begin
    grids = [
        ParticlePositions(collect.((0:0.1:1,0:0.1:1))...),
        ParticlePositions(collect.(((0:0.1:1).*u"m",(0:0.1:1).*u"m"))...),
        ParticlePositions(collect.((0:0.1:1,0:0.1:1,0:0.1:1))...),
        ParticlePositions(collect.(((0:0.1:1).*u"m",(0:0.1:1).*u"m",(0:0.1:1).*u"m"))...),
    ]
    vars = [
        scalarvariable(grids[1], name="2D") do (x,y)
            x^2 + y^2
        end,
        scalarvariable(grids[2], name="2D") do (x,y)
            x^2 + y^2
        end,
        scalarvariable(grids[3], name="3D") do (x,y,z)
            x^2 + y^2 + z^2
        end,
        scalarvariable(grids[4], name="3D") do (x,y,z)
            x^2 + y^2 + z^2
        end,
    ]

    @testset "$(dimensionality(v))D ($(unitname(v)))" for (grid,v) in zip(grids,vars)
        @test v isa ScalarVariable
        @test getdomain(v) == grid
        @test ndims(v) == 1

        T = typeof(v)
        N = dimensionality(v)
        @test isconcretetype(T)

        @testset "Traits" begin
            @test scalarness(T) === ScalarQuantity()
            @test domain_discretization(T) === ParticleGrid()
            @test domain_type(T) <: ParticlePositions
        end

        @testset "Indexing" begin
            @test size(v) == size(grid)
            @test iszero(v[1])
            @test v[1] isa Number
        end
        @testset "Iteration" begin
            @test [fd for fd in v] == collect(v)
        end
        @testset "Broadcasting" begin
            v2 = v .* 2
            @test typeof(v) == typeof(v2)
            @test v2.grid == getdomain(v)
            @test 2v[end] == v2[end]
            @test nameof(v2) == nameof(v)
        end

        @testset "Downsampling" begin
            v_small = downsample(v, 4)
            @test size(v_small) == (4,)
            v_small = downsample(v)
            @test all(size(v_small) .≤ size(v))
            @test nameof(v) == nameof(v_small)
        end
    end

    @testset "Sclicing" begin
        @testset "2D" begin
            v = vars[1]
            v_slice = selectdim(v, :x, 0.0, ϵ=0.1)
            @test dimensionality(v_slice) == 1
            @test size(v_slice) == size(getdomain(v_slice))
            @test length(v_slice) == 2
            @test v_slice ≈ [0.0, 0.02]
            @test nameof(v) == nameof(v_slice) == "2D"
        end
        @testset "3D" begin
            v = vars[3]
            v_slice = selectdim(v, :x, 0.0, ϵ=0.1)
            @test dimensionality(v_slice) == 2
            @test size(v_slice) == size(getdomain(v_slice))
            @test length(v_slice) == 2
            @test v_slice ≈ [0.0, 0.03]
            @test nameof(v) == nameof(v_slice) == "3D"
        end
    end

    @testset "Unit handling" begin
        v = vars[1]
        v_u = vars[2]

        @test all(ustrip(v_u) .≈ v)
        @test all(v .* 1u"m^2" .≈ v_u)
        @test nameof(ustrip(v_u)) == nameof(v)
    end
end


text:
# This file is a part of AstroLib.jl. License is MIT "Expat".

# dpdt gives the time rate of change of the mean orbital quantities
# dpdt elements taken from https://ssd.jpl.nasa.gov/txt/p_elem_t1.txt
const dpd = @SMatrix [ 0.00000037  0.00001906 -0.00594749 -0.12534081  0.16047689 149472.67411175;
                       0.00000390 -0.00004107 -0.00078890 -0.27769418  0.00268329  58517.81538729;
                       0.00000562 -0.00004392 -0.01294668  0.0         0.32327364  35999.37244981;
                       0.00001847  0.00007882 -0.00813131 -0.29257343  0.44441088  19140.30268499;
                      -0.00011607 -0.00013253 -0.00183714  0.20469106  0.21252668   3034.74612775;
                      -0.00125060 -0.00050991  0.00193609 -0.28867794 -0.41897216   1222.49362201;
                      -0.00196176 -0.00004397 -0.00242939  0.04240589  0.40805281    428.48202785;
                       0.00026291  0.00005105  0.00035372 -0.00508664 -0.32241464    218.45945325;
                      -0.00031596  0.00005170  0.00004818 -0.01183482 -0.04062942    145.20780515]

const record = Dict(1=>"mercury", 2=>"venus", 3=>"earth", 4=>"mars", 5=>"jupiter",
                  6=>"saturn", 7=>"uranus", 8=>"neptune", 9=>"pluto")

function _helio(jd::T, num::Integer, radians::Bool) where {T<:AbstractFloat}

    if num<1 || num>9
        error("Input should be an integer in the range 1:9 denoting planet number")
    end
    t = (jd - J2000) / JULIANCENTURY
    body = record[num]
    dpdt = dpd .* t
    a = planets[body].axis/AU + dpdt[num, 1]
    eccen = planets[body].ecc + dpdt[num, 2]
    n = deg2rad(0.9856076686 / (a * sqrt(a) ))
    inc = deg2rad(planets[body].inc + dpdt[num, 3])
    along = deg2rad(planets[body].asc_long + dpdt[num, 4])
    plong = deg2rad(planets[body].per_long + dpdt[num, 5])
    mlong = deg2rad(planets[body].mean_long + dpdt[num, 6])
    m = mlong - plong
    E = kepler_solver(m, eccen)
    nu = trueanom(E, eccen)
    hrad = a * (1 - eccen * cos(E))
    hlong = mod2pi(nu + plong)
    hlat = asin(sin(hlong - along) * sin(inc))
    if !radians
        return hrad, rad2deg(hlong), rad2deg(hlat)
    end
    return hrad, hlong, hlat
end

"""
    helio(jd, list[, radians=true]) -> hrad, hlong, hlat

### Purpose ###

Compute heliocentric coordinates for the planets.

### Explanation ###

The mean orbital elements for epoch J2000 are used. These are derived
from a 250 yr least squares fit of the DE 200 planetary ephemeris to a
Keplerian orbit where each element is allowed to vary linearly with
time. Useful mainly for dates between 1800 and 2050, this solution fits the
terrestrial planet orbits to ~25'' or better, but achieves only ~600''
for Saturn.

### Arguments ###

* `jd`: julian date, scalar or vector
* `num`: integer denoting planet number, scalar or vector
  1 = Mercury, 2 = Venus, ... 9 = Pluto
* `radians`(optional): if this keyword is set to
  `true`, than the longitude and latitude output are in radians rather than degrees.

### Output ###

* `hrad`: the heliocentric radii, in astronomical units.
* `hlong`: the heliocentric (ecliptic) longitudes, in degrees.
* `hlat`: the heliocentric latitudes in degrees.

### Example ###

(1) Find heliocentric position of Venus on August 23, 2000

```jldoctest
julia> using AstroLib

julia> helio(jdcnv(2000,08,23,0), 2)
(0.7213758288364316, 198.39093251916148, 2.887355631705488)
```

(2) Find the current heliocentric positions of all the planets

```jldoctest
julia> using AstroLib

julia> helio.([jdcnv(1900)], 1:9)
9-element Array{Tuple{Float64,Float64,Float64},1}:
 (0.4207394142180803, 202.60972662618906, 3.0503005607270532)
 (0.7274605731764012, 344.5381482401048, -3.3924346961624785)
 (0.9832446886519147, 101.54969268801035, 0.012669354526696368)
 (1.4212659241051142, 287.8531100442217, -1.5754626002228043)
 (5.386813769590955, 235.91306092135062, 0.9131692817310215)
 (10.054339927304339, 268.04069870870387, 1.0851704598594278)
 (18.984683376211326, 250.0555468087738, 0.05297087029604253)
 (29.87722677219009, 87.07244903504716, -1.245060583142733)
 (46.9647515992327, 75.94692594417324, -9.576681044165511)
```
### Notes ###

This program is based on the two-body model and thus neglects
interactions between the planets.

The coordinates are given for equinox 2000 and *not* the equinox
of the supplied date.

Code of this function is based on IDL Astronomy User's Library.
"""
helio(jd::Real, num::Integer, radians::Bool=false) =
    _helio(float(jd), num, radians)

function helio(jd::AbstractVector{P}, num::AbstractVector{<:Real},
               radians::Bool = false) where {P<:Real}
    @assert length(jd) == length(num) "jd and num vectors should
                                       be of the same length"
    typejd = float(P)
    hrad_out = similar(jd,  typejd)
    hlong_out = similar(jd,  typejd)
    hlat_out = similar(jd,  typejd)
    for i in eachindex(jd)
        hrad_out[i], hlong_out[i], hlat_out[i] =
        helio(jd[i], num[i], radians)
    end
    return hrad_out, hlong_out, hlat_out
end


text:
"""
    defaultFiles(s, pids)

Make a good set of filenames for saving a dataset.
"""
function defaultFiles(s, pids)
    return [String(s) * "-$i.slice" for i in eachindex(pids)]
end

"""
    distributed_export(sym::Symbol, pids, files=defaultFiles(sym,pids))

Export the content of symbol `sym` by each worker specified by `pids` to a
corresponding filename in `files`.
"""
function distributed_export(sym::Symbol, pids, files = defaultFiles(sym, pids))
    distributed_foreach(
        files,
        (fn) -> Base.eval(Main, :(
            begin
                open(f -> $serialize(f, $sym), $fn, "w")
                nothing
            end
        )),
        pids,
    )
    nothing
end

"""
    distributed_export(dInfo::LoadedDataInfo, files=defaultFiles(dInfo.val, dInfo.workers))

Overloaded functionality for `LoadedDataInfo`.
"""
function distributed_export(
    dInfo::LoadedDataInfo,
    files = defaultFiles(dInfo.val, dInfo.workers),
)
    distributed_export(dInfo.val, dInfo.workers, files)
end

"""
    distributed_import(sym::Symbol, pids, files=defaultFiles(sym,pids))

Import the content of symbol `sym` by each worker specified by `pids` from the
corresponding filename in `files`.
"""
function distributed_import(sym::Symbol, pids, files = defaultFiles(sym, pids))
    distributed_foreach(
        files,
        (fn) -> Base.eval(Main, :(
            begin
                $sym = open($deserialize, $fn)
                nothing
            end
        )),
        pids,
    )
    return LoadedDataInfo(sym, pids)
end

"""
    distributed_import(dInfo::LoadedDataInfo, files=defaultFiles(dInfo.val, dInfo.workers))

Overloaded functionality for `LoadedDataInfo`.
"""
function distributed_import(
    dInfo::LoadedDataInfo,
    files = defaultFiles(dInfo.val, dInfo.workers),
)
    distributed_import(dInfo.val, dInfo.workers, files)
end

"""
    distributed_unlink(sym::Symbol, pids, files=defaultFiles(sym,pids))

Remove the files created by `distributed_export` with the same parameters.
"""
function distributed_unlink(sym::Symbol, pids, files = defaultFiles(sym, pids))
    distributed_foreach(files, (fn) -> rm(fn), pids)
    nothing
end

"""
    distributed_unlink(dInfo::LoadedDataInfo, files=defaultFiles(dInfo.val, dInfo.workers))

Overloaded functionality for `LoadedDataInfo`.
"""
function distributed_unlink(
    dInfo::LoadedDataInfo,
    files = defaultFiles(dInfo.val, dInfo.workers),
)
    distributed_unlink(dInfo.val, dInfo.workers, files)
end


text:
module BenchSort

using BenchmarkTools
using Random: Random, shuffle
using ThreadsX

Random.seed!(1234)

n = 100_000
datasets = [
    # (label, setup)
    ("I64 (wide)", rand(Int64, n)),
    ("I64 (narrow)", rand(0:9, n)),
    ("F64 (wide)", rand(Float64, n)),
    ("F64 (narrow)", rand(0:0.1:0.9, n)),
    ("sorted", [1:n;]),
    ("reversed", [reverse(1:n);]),
]

suite = BenchmarkGroup()

for (label, xs) in datasets
    s = suite[label] = BenchmarkGroup()
    for algname in [:MergeSort, :QuickSort, :StableQuickSort]
        alg = getproperty(ThreadsX, algname)
        s["ThreadsX.$algname"] =
            @benchmarkable(ThreadsX.sort!(xs; alg = $alg), setup = (xs = copy($xs)))
    end
    s["Base"] = @benchmarkable(sort!(xs), setup = (xs = copy($xs)))
end

end  # module
BenchSort.suite


text:
export PlaneWave

Base.@kwdef struct PlaneWave{ND}
    k̂::NTuple{ND,Real}
    ê::NTuple{3, Real}
    a::Number = 1.0
end

function (sim::Simulation)(::typeof(setsrc!),pw::PlaneWave, reg::Function = (x -> true), gridtype::GridType= p̂)
sim(setsrc!,x̂,x -> pw.a * exp(-im * dot(pw.k̂, x)) * pw.ê[1],reg,gridtype)
sim(setsrc!,ŷ,x -> pw.a * exp(-im * dot(pw.k̂, x)) * pw.ê[2],reg,gridtype)
sim(setsrc!,ẑ,x -> pw.a * exp(-im * dot(pw.k̂, x)) * pw.ê[3],reg,gridtype)
end
########################################################


text:
using DiffEqFlux, Flux
""" CTRNN0 implements a continuous time recurrent neural net
    with no hidden layers:
        dxdt = -x/τ + σ(Ax + Bu + μ) + ν

    Available types:
        * CTRNN0Elman               dxdt = -x/τ + σ(Ax + Bu + μ) + ν
        * CTRNN0Canonical           dxdt = -x/τ + σ(Ax + Bu + μ) - σ(μ)
        * CTRNN0Zero                dxdt = -x/τ + σ(Ax + Bu)
"""
abstract type CTRNN0 <: Ode end

""" dxdt = -x/τ + σ(Ax + Bu + μ) + ν
    CTRNN0Elman """
struct CTRNN0Elman{F,FU,F2} <: CTRNN0
    state_dim::Int
    input_dim::Int
    paramsum::Int
    index_dict::Dict{String,UnitRange{Int}}
    σ::F
    σ_u::FU
    initial_params::F2
    function CTRNN0Elman(
        state_dim::Integer,
        input_dim::Integer;
        σ = tanh,
        initW = Flux.glorot_uniform,
        initb = Flux.zeros,
        σ_u = identity,
    )
        # compute indices
        i = 1
        index_dict = Dict{String,UnitRange{Int}}()
        index_dict["logτ"] = i:i
        i += 1
        index_dict["A"] = i:i+state_dim*state_dim-1
        i += state_dim * state_dim
        index_dict["B"] = i:i+input_dim*state_dim-1
        i += input_dim * state_dim
        index_dict["μ"] = i:i+state_dim-1
        i += state_dim
        index_dict["ν"] = i:i+state_dim-1
        i += state_dim

        # initialize initial parameters
        initial_params() = vcat(
            Flux.zeros(1),
            vec(initW(state_dim, state_dim)),
            vec(initW(state_dim, input_dim)),
            vec(initb(state_dim)),
            vec(initb(state_dim)),
        )

        new{typeof(σ),typeof(σ_u),typeof(initial_params)}(
            state_dim,
            input_dim,
            i - 1,
            index_dict,
            σ,
            σ_u,
            initial_params,
        )
    end
end

function unpack_params(f::CTRNN0Elman, p)
    logτ = view(p, f.index_dict["logτ"])
    A = reshape(view(p, f.index_dict["A"]), f.state_dim, f.state_dim)
    B = reshape(view(p, f.index_dict["B"]), f.state_dim, f.input_dim)
    μ = view(p, f.index_dict["μ"])
    ν = view(p, f.index_dict["ν"])
    return logτ, A, B, μ, ν
end

function (f::CTRNN0Elman)(xu, p)
    x, u = extract_inputs(f, xu)
    logτ, A, B, μ, ν = unpack_params(f, p)
    return -x .* exp.(-logτ) .+ (f.σ.((A * x .+ B * f.σ_u.(u)) .+ μ) .+ ν)
end

""" dxdt = -x/τ + σ(Ax + Bu + μ) - σ(μ)
    CTRNN0Canonical """
struct CTRNN0Canonical{F,FU,F2} <: CTRNN0
    state_dim::Int
    input_dim::Int
    paramsum::Int
    index_dict::Dict{String,UnitRange{Int}}
    σ::F
    σ_u::FU
    initial_params::F2
    function CTRNN0Canonical(
        state_dim::Integer,
        input_dim::Integer;
        σ = tanh,
        initW = Flux.glorot_uniform,
        initb = Flux.zeros,
        σ_u = identity,
    )
        # compute indices
        i = 1
        index_dict = Dict{String,UnitRange{Int}}()
        index_dict["logτ"] = i:i
        i += 1
        index_dict["A"] = i:i+state_dim*state_dim-1
        i += state_dim * state_dim
        index_dict["B"] = i:i+input_dim*state_dim-1
        i += input_dim * state_dim
        index_dict["μ"] = i:i+state_dim-1
        i += state_dim

        # initialize initial parameters
        initial_params() = vcat(
            Flux.zeros(1),
            vec(initW(state_dim, state_dim)),
            vec(initW(state_dim, input_dim)),
            vec(initb(state_dim)),
        )

        new{typeof(σ),typeof(σ_u),typeof(initial_params)}(
            state_dim,
            input_dim,
            i - 1,
            index_dict,
            σ,
            σ_u,
            initial_params,
        )
    end
end

function unpack_params(f::CTRNN0Canonical, p)
    logτ = view(p, f.index_dict["logτ"])
    A = reshape(view(p, f.index_dict["A"]), f.state_dim, f.state_dim)
    B = reshape(view(p, f.index_dict["B"]), f.state_dim, f.input_dim)
    μ = view(p, f.index_dict["μ"])
    ν = -f.σ.(μ)
    return logτ, A, B, μ, ν
end

function (f::CTRNN0Canonical)(xu, p)
    x, u = extract_inputs(f, xu)
    logτ = view(p, f.index_dict["logτ"])
    A = reshape(view(p, f.index_dict["A"]), f.state_dim, f.state_dim)
    B = reshape(view(p, f.index_dict["B"]), f.state_dim, f.input_dim)
    μ = view(p, f.index_dict["μ"])
    # return -x.*exp.(-logτ) .+ f.σ.(A*x .+ B*f.σ_u.(u) .+ μ) .- f.σ.(μ)
    return -(x .* exp.(-logτ) .+ f.σ.(μ)) .+ f.σ.((A * x .+ B * f.σ_u.(u)) .+ μ)
end

""" dxdt = -x/τ + σ(Ax + Bu)
    CTRNN0Zero """
struct CTRNN0Zero{F,FU,F2} <: CTRNN0
    state_dim::Int
    input_dim::Int
    paramsum::Int
    index_dict::Dict{String,UnitRange{Int}}
    σ::F
    σ_u::FU
    initial_params::F2
    function CTRNN0Zero(
        state_dim::Integer,
        input_dim::Integer;
        σ = tanh,
        initW = Flux.glorot_uniform,
        σ_u = identity,
    )
        # compute indices
        i = 1
        index_dict = Dict{String,UnitRange{Int}}()
        index_dict["logτ"] = i:i
        i += 1
        index_dict["A"] = i:i+state_dim*state_dim-1
        i += state_dim * state_dim
        index_dict["B"] = i:i+input_dim*state_dim-1
        i += input_dim * state_dim

        # initialize initial parameters
        initial_params() = vcat(
            Flux.zeros(1),
            vec(initW(state_dim, state_dim)),
            vec(initW(state_dim, input_dim)),
        )

        new{typeof(σ),typeof(σ_u),typeof(initial_params)}(
            state_dim,
            input_dim,
            i - 1,
            index_dict,
            σ,
            σ_u,
            initial_params,
        )
    end
end

function unpack_params(f::CTRNN0Zero, p)
    logτ = view(p, f.index_dict["logτ"])
    A = reshape(view(p, f.index_dict["A"]), f.state_dim, f.state_dim)
    B = reshape(view(p, f.index_dict["B"]), f.state_dim, f.input_dim)
    μ = zeros(f.state_dim)
    ν = zeros(f.state_dim)
    return logτ, A, B, μ, ν
end

function (f::CTRNN0Zero)(xu, p)
    x, u = extract_inputs(f, xu)
    logτ = view(p, f.index_dict["logτ"])
    A = reshape(view(p, f.index_dict["A"]), f.state_dim, f.state_dim)
    B = reshape(view(p, f.index_dict["B"]), f.state_dim, f.input_dim)
    return -x .* exp.(-logτ) .+ f.σ.(A * x .+ B * f.σ_u.(u))
end

max_stars_repo_name: syanga/ISSNeuralODE

max_issues_repo_name: syanga/ISSNeuralODE

max_forks_repo_name: syanga/ISSNeuralODE


text:
"""
    cleanSC(E[;maxiter=50,ϕ=0.5,stopn=10,peak_removal=false,trust_region=nothing])

CLEAN-SC algorithm for source identification and quantification optionally setting maximum iterations `maxiter` (default 50), and loop gain `ϕ` (default 0.5). Additionally, a stopping criterion `max_peak[i] > max_peak[i-stopn]` can be set with parameter `stopn`. Subtraction of peak sources in the dirty map is supported by `peak_removal=true/false` to remove peak sources outside `trust_region` with limits given as `[xmin,xmax,ymin,ymax]` e.g. `trust_region=[-0.75;1.5;-1.0;1.0]`.

References:
-	Sijtsma, P. (2007). CLEAN based on spatial source coherence. International Journal of Aeroacoustics, 6(4), 357–374.

With inspiration from https://github.com/acoular/acoular/blob/66cba3cffb3bc72602c869f99347be76798f4ac1/acoular/fbeamform.py#L1496
"""
function cleanSC(E;maxiter=50,ϕ=0.5,stopn=10,peak_removal=false,trust_region=nothing)
    @unpack CSM_s,steeringvec,M,N,Nf,fn = E
    x = zeros(N,Nf)

    if peak_removal
        xi = findall((E.rx.>=trust_region[1]) .& (E.rx.<=trust_region[2]))
        yi = findall((E.ry.>=trust_region[3]) .& (E.ry.<=trust_region[4]))
        trust_indices = LinearIndices((E.Nx,E.Ny))[xi,yi]
    else
        trust_indices = LinearIndices((E.Nx,E.Ny))
    end

    @views @inbounds for j = 1:Nf
        _cleanSC!(x[:,j],steeringvec.arr[:,:,j],CSM_s.arr[:,:,j],maxiter,ϕ,stopn,peak_removal,trust_indices)
    end
    return FreqArray(x,E.fn)
end

function _cleanSC!(x,st,csm,maxiter,ϕ,stopn,peak_removal,trust_indices)
    M,N = size(st)
    g = similar(st[:,1])
    h = similar(g)
    h_old = similar(h)
    H = similar(csm)
    max_val = zeros(maxiter)
    dirtyMap = zeros(N)
    for i in 1:maxiter
        AeroAcoustics.bf_col!(dirtyMap,st,csm)
        # Numerical issue with Amiet correction can cause NaNs
        if isempty(filter(!isnan,dirtyMap))
            @goto stop
        else
            dirtyMap[ isnan.(dirtyMap)] .= -Inf
            max_val[i],max_idx = findmax(dirtyMap)
        end
        g .= st[:,max_idx]
        h .= g
        for _ in 1:20
            h_old .= h
            H .= h*h'
            H .= diagm(diag(H))
            h .= (csm*g/max_val[i] + H*g) ./sqrt.(1 .+ mydot(g',H,g))
        end
        Pmax = zeros(N)
        Pmax[max_idx] = 1

        if peak_removal
            if max_idx ∈ trust_indices
                x .+= ϕ*max_val[i]*Pmax
                csm -= ϕ*max_val[i]*(h*h')
            else
                csm -= max_val[i]*(h*h')
            end
        else
            x .+= ϕ*max_val[i]*Pmax
            csm -= ϕ*max_val[i]*(h*h')
        end

        csm[Diagonal(ones(Bool,M))] .= 0
        if (i > stopn) && (max_val[i] > max_val[i-stopn])
            @goto stop
        end
    end
    @label stop
    return nothing
end


text:
using STREAMBenchmark
using Test, Statistics
using CpuId: cachesize

Base.Threads.nthreads() > 1 || (@warn Running test suite with only a single thread!)

function with_avxt(f)
    @eval STREAMBenchmark.avxt() = true
    f()
    @eval STREAMBenchmark.avxt() = false
end

use_less_memory = true
@show use_less_memory

@testset "STREAMBenchmark.jl" begin
    @testset "Benchmarks" begin
        @test STREAMBenchmark.default_vector_length() >= 4*cachesize()[end] / sizeof(Float64)

        use_less_memory && (STREAMBenchmark.default_vector_length() = 10)
        @show STREAMBenchmark.default_vector_length()

        # memory_bandwidth
        @test keys(memory_bandwidth()) == (:median, :minimum, :maximum)
        @test 1000 < memory_bandwidth().median < 500_000
        @test 1000 < memory_bandwidth(multithreading=false).median < 500_000
        with_avxt() do
            @test 1000 < memory_bandwidth().median < 500_000
        end

        # TODO: add verbose=true test
        @test memory_bandwidth().median > memory_bandwidth(write_allocate=false).median

        # benchmark
        let nt = benchmark()
            @test keys(nt) == (:single, :multi)
            @test keys(nt.single) == (:median, :minimum, :maximum)
            @test keys(nt.multi) == (:median, :minimum, :maximum)
        end
        # vector_length_dependence
        let d = STREAMBenchmark.vector_length_dependence()
            @test typeof(d) == Dict{Int64, Float64}
            @test length(d) == 4
            @test maximum(abs.(diff(collect(values(d))))) / median(values(d)) < 0.2
        end
        let d = STREAMBenchmark.vector_length_dependence(n=2)
            @test length(d) == 2
        end
    end

    @testset "Kernels" begin
        A = [1.0,2.0,3.0,4.0,5.0]
        B = [0.8450044149444245, 0.2991196515689396, 0.5449487174110352, 0.06376462113406589, 0.817610835138292]
        C = [42.0,42.0,42.0,42.0,42.0]
        s = 13

        STREAMBenchmark.copy(C, A)
        @test C == A
        STREAMBenchmark.copy_threaded(C, A)
        @test C == A
        STREAMBenchmark.scale(B,C,s)
        @test B ≈ s .* C
        STREAMBenchmark.scale_threaded(B,C,s)
        @test B ≈ s .* C
        STREAMBenchmark.add(C,A,B)
        @test C ≈ A .+ B
        STREAMBenchmark.add_threaded(C,A,B)
        @test C ≈ A .+ B
        STREAMBenchmark.triad(A,B,C,s)
        @test A ≈ B .+ s .* C
        STREAMBenchmark.triad_threaded(A,B,C,s)
        @test A ≈ B .+ s .* C

        # @avxt threading
        with_avxt() do
           STREAMBenchmark.copy_threaded(C, A)
           @test C == A
           STREAMBenchmark.scale_threaded(B,C,s)
           @test B ≈ s .* C
           STREAMBenchmark.add_threaded(C,A,B)
           @test C ≈ A .+ B
           STREAMBenchmark.triad_threaded(A,B,C,s)
           @test A ≈ B .+ s .* C
        end
    end

    @testset "Original C STREAM Benchmark" begin
        mktempdir() do tmpdir
            cd(tmpdir) do
                STREAMBenchmark.download_original_STREAM()
                @test isdir("stream")
                isdir("stream") && cd("stream") do
                    @test isfile("stream.c")
                    @test isfile("mysecond.c")
                end

                try
                    STREAMBenchmark.compile_original_STREAM()
                    @test isfile("stream/stream")
                catch e
                    @warn "Compilation of original C STREAM benchmark failed."
                    println(e)
                end
                @test_throws ErrorException STREAMBenchmark.compile_original_STREAM(compiler=:carsten)
            end
        end

        mktempdir() do tmpdir
            cd(tmpdir) do
                @test_logs (:warn,"Couldn't find source code \"stream/stream.c\". Have you run STREAMBenchmark.download_original_STREAM()?") STREAMBenchmark.compile_original_STREAM()
                @test_logs (:warn,"Couldn't find executable \"stream/stream\". Have you run STREAMBenchmark.compile_original_STREAM()?") STREAMBenchmark.execute_original_STREAM()
            end
        end
    end
end


text:
const Triplet{T} = NamedTuple{(:i, :j, :k), Tuple{T, T, T}} where T <: Integer

"""
    function Triplet([S::Type{U},] t::NTuple{3,T}) where {U <: Integer, T <: Integer}

Create a Triplet.

A Triplet always has the names (or keys) (:i, :j, :k), and it is assumed that for an embedding X and pairwise distances D[i,j],
D[i,j] < D[i,k] (so i is assumed or annotated to be closer to j than k).

The underlying struct for a Triplet is a NamedTuple with names = (:i, :j, :k).

---
Other constructors:
 - function Triplet(S::Type{U}, t::NTuple{3,T}) where {U <: Integer, T <: Integer}
 - function Triplet(t::Vector{T}) where T <: Integer
 - function Triplet(S::DataType, t::Vector{T}) where T <: Integer
 - function Triplet(i::Int, j::Int, k::Int)
 - function Triplet(S::DataType, i::Int, j::Int, k::Int)
"""
Triplet(t::NTuple{3,T}) where T <: Integer = Triplet{T}((i = t[1], j = t[2], k = t[3]))

function Triplet(S::Type{U}, t::NTuple{3,T}) where {U <: Integer, T <: Integer}
    S <: Integer || throw(ArgumentError("S must be a subtype of Integer"))
    Triplet{S}(NTuple{3,S}(t))
end

function Triplet(t::Vector{T}) where T <: Integer
    length(t) == 3 || throw(ArgumentError("Triplet must be of length 3"))
    Triplet{T}(NTuple{3,T}(t))
end

function Triplet(S::Type{U}, t::Vector{T}) where {U <: Integer, T <: Integer}
    length(t) == 3 || throw(ArgumentError("Triplet must be of length 3"))
    Triplet{S}(NTuple{3,S}(t))
end

function Triplet(i::T, j::T, k::T) where T <: Integer
    Triplet{T}((i,j,k))
end

function Triplet(S::Type{U}, i::T, j::T, k::T) where {U <: Integer, T <: Integer}
    Triplet{S}((i,j,k))
end

function Base.show(io::IO, ::Type{Triplet})
    print(io, "Triplet")
end

function Base.show(io::IO, t::Triplet)
    n = nfields(t)
    for i = 1:n
        # if field types aren't concrete, show full type
        if typeof(getfield(t, i)) !== fieldtype(typeof(t), i)
            show(io, typeof(t))
            print(io, "(")
            show(io, Tuple(t))
            print(io, ")")
            return
        end
    end

    typeinfo = get(io, :typeinfo, Any)
    print(io, "Triplet{$(eltype(t))}(")
    for i = 1:n
        print(io, fieldname(typeof(t),i), " = ")
        show(IOContext(io, :typeinfo =>
                       t isa typeinfo <: NamedTuple ? fieldtype(typeinfo, i) : Any),
             getfield(t, i))
        if n == 1
            print(io, ",")
        elseif i < n
            print(io, ", ")
        end
    end
    print(io, ")")
end

const Triplets{T} = Vector{Triplet{T}} where T <: Integer

function Base.show(io::IO, ::Type{Triplets})
    print(io, "Triplets")
end

"""
    Triplets(X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where T <: Real

Generate a set of triplets from X (matrix or embedding).

X is assumed to be an d × n AbstractMatrix, so it can be:
  - A d × n AbstractMatrix
  - A d × n TripletEmbeddings.Embedding

Parameters:
 - f::Function corresponds to the noise function when generating triplets (x -> 1 implies probability of success is 1)
 - shuffle::Bool is a flag deciding whether the triplets are returned shuffled or not (default is false)

This method will optimize the type used for each Triplet (between Int16 and Int64).
---
    Triplets(triplets::Vector{Triplet{(:i, :j, :k), Tuple{T, T, T}}}) where T <: Integer

Function to generate Triplets from a Vector{Triplet}. To be used only with Stochastic Gradient Descent (SGD).

"""
function Triplets(X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where T <: Real
    0 < percentage ≤ 100 || throw(ArgumentError("Percentage of triplets must be in the interval (0, 100]"))
    # if percentage < 100
    #     @warn "Shuffling to have all items represented"
    #     shuffle = true
    # end
    triplets = label(X, f, shuffle)[1:floor(Int, end * percentage / 100)]
    checktriplets(triplets) || throw(AssertionError("Triplets do not contain all items."))
    return triplets
end

function Triplets(S::Type{U}, X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where {U <: Integer, T <: Real}
    0 < percentage ≤ 100 || throw(ArgumentError("Percentage of triplets must be in the interval (0, 100]"))
    # if percentage < 100
    #     @warn "Shuffling to have all items represented"
    #     shuffle = true
    # end
    triplets = label(X, f, shuffle, S)[1:floor(Int, end * percentage / 100)]
    checktriplets(triplets) || throw(AssertionError("Triplets do not contain all items."))
    return triplets
end

function Triplets(X::AbstractVector{S}; f::Function = x -> 1, shuffle::Bool = false) where S <: Real
    length(X) > 1 || throw(AssertionError("Number of elements in X must be > 1"))
    Triplets(reshape(X, 1, length(X)); f = f, shuffle = shuffle)
end

"""
    checktriplets(triplets::Triplets)

Checks whether triplets contains all elements from 1:n, where n is the maximum
value found in triplets.
"""
function checktriplets(triplets::Triplets{T}) where T <: Integer
    # Transform triplets into Matrix{Int32} and call respective function
    return checktriplets(getindex.(triplets, [1 2 3]))
end

function checktriplets(triplets::Matrix{T}) where T <: Integer
    return sort(unique(triplets)) == 1:maximum(triplets)
end

@doc raw"""
    label(X::Matrix{T}, f::Function) where T <: Real

Compute the triplets from X. X is assumed to be d × n,
so that each item of the embedding is a vector (column).

f is a function modeling the probabilities of success/failure,
assuming that these probabilities are modeled through a Bernoulli
random variable:

```math
y_{ijk} = \cases{
    -1 \quad \text{w.p.} & f(D_{ij}^* - D_{ik}^*) \\
    +1 \quad \text{w.p.} & 1- f(D_{ij}^* - D_{ik}^*)
}
```
"""
function label(X::AbstractMatrix{T}, f::Function, shuffle::Bool, S::Type{U}) where {T <: Real, U <: Integer}
    maximum(X) ≠ minimum(X) || throw(ArgumentError("Embedding is constant, no triplets to compute."))
    sum(isnan.(X)) == 0 || throw(DomainError("Embedding X has NaNs values."))

    d, n = size(X)
    D = pairwise(SqEuclidean(), X, dims=2)

    triplets = Vector{Triplet{S}}(undef, n*binomial(n-1, 2))
    counter = 0

    for k = 1:n, j = 1:k-1, i = 1:n
        if i != j && i != k

            # Random noise distributes Bernoulli, with p = f(abs(D[i,j] - D[i,k]))
            # If f(x) = p (constant), then the noise is independent of the distance between pairs
            @inbounds mistake = f(abs(D[i,j] - D[i,k])) <= 1 - rand()

            if D[i,j] < D[i,k]
                counter +=1
                if !mistake
                    @inbounds triplets[counter] = Triplet(S, i, j, k)
                else
                    @inbounds triplets[counter] = Triplet(S, i, k, j)
                end
            elseif D[i,j] > D[i,k]
                counter += 1
                if !mistake
                    @inbounds triplets[counter] = Triplet(S, i, k, j)
                else
                    @inbounds triplets[counter] = Triplet(S, i, j, k)
                end
            end
        end
    end

    return shuffle ? Random.shuffle(triplets[1:counter]) : triplets[1:counter]

end

function label(X::AbstractMatrix{T}, f::Function, shuffle::Bool) where T <: Real
    d, n = size(X)
    label(X, f, shuffle, tripletstype(n))
end

function tripletstype(n::Int)
    S = if typemax(Int16) > n
        Int16
    elseif typemax(UInt16) > n
        UInt16
    elseif typemax(Int32) > n
        Int32
    elseif typemax(UInt32) > n
        UInt32
    else
        Int64
    end
    return S
end

"""
    sampletriplet([rng], n)

Draw a triplet of distinct integers between 1 and `n` without replacement.

Optionally specify a random number generator `rng` as the first argument
(defaults to `Random.GLOBAL_RNG`).

This function return a NTuple{3,Int}, _not_ a Triplet{T}.

"""
function sampletriplet(rng::AbstractRNG, n::Int)
    i = rand(rng, 1:n)
    j = rand(rng, 1:n-1)
    k = rand(rng, 1:n)

    return (i, i == j ? n : j, (k == i || k == j) ? rand(rng, (1:n)[Not(i,j)]) : k)
end

sampletriplet(n::Int) = sampletriplet(Random.GLOBAL_RNG, n)

"""
    sampletriplets([rng], n, number_of_triplets)

Draw `number_of_triplets` triplets of distinct integers between 1 and `n` without replacement.

Optionally specify a random number generator `rng` as the first argument
(defaults to `Random.GLOBAL_RNG`).

This function returns a Vector{NTuple{3,Int}}, _not_ a Vector{Triplet{T}}.

"""
function sampletriplets(rng::AbstractRNG, n::Int, number_of_triplets::Int)
    S = tripletstype(number_of_triplets)
    triplets = [sampletriplet(n) for _ in 1:number_of_triplets]
    return triplets
end

sampletriplets(n::Int, number_of_triplets::Int) = sampletriplets(Random.GLOBAL_RNG, n, number_of_triplets)

########################
### Labeled Triplets ###
########################

const LabeledTriplet{T} = NamedTuple{(:i, :j, :k, :y), Tuple{T, T, T, T}} where T <: Integer

@doc raw"""
    function LabeledTriplet([S::Type{U},] t::NTuple{4,T}) where {U <: Integer, T <: Integer}

Create a Labeled Triplet.

A Labeled Triplet always has the names (or keys) (:i, :j, :k. :y). For an embedding X with pairwise distances D[i,j],
y ∈ {-1,+1} denotes whether D[i,j] < D[i,k] (y = -1) or D[i,j] > D[i,k] (y = +1), according to:

    ```math
    \begin{equation}
        y_t =
        \begin{cases}
          -1, &\text{w.p. }\quad f(D^*_{ij} - D^*_{ik})\\
          +1, &\text{w.p. }\quad 1 - f(D^*_{ij} - D^*_{ik}).
        \end{cases}
    \end{equation}
    ```

The underlying struct for a Triplet is a NamedTuple with names = (:i, :j, :k).

---
Other constructors:
 - function LabeledTriplet(S::Type{U}, t::NTuple{4,T}) where {U <: Integer, T <: Integer}
 - function LabeledTriplet(t::Vector{T}) where T <: Integer
 - function LabeledTriplet(S::DataType, t::Vector{T}) where T <: Integer
 - function LabeledTriplet(i::Int, j::Int, k::Int, y::Int)
 - function LabeledTriplet(S::DataType, i::Int, j::Int, k::Int, y::Int)
"""
LabeledTriplet(t::NTuple{4,T}) where T <: Integer = LabeledTriplet{eltype(t)}((i = t[1], j = t[2], k = t[3], y = t[4]))

function LabeledTriplet(S::Type{U}, t::NTuple{4,T}) where {U <: Integer, T <: Integer}
    S <: Integer || throw(ArgumentError("S must be a subtype of Integer"))
    LabeledTriplet{S}(NTuple{4,S}(t))
end

function LabeledTriplet(t::Vector{T}) where T <: Integer
    length(t) == 4 || throw(ArgumentError("LabeledTriplet must be of length 4"))
    @assert t[end] in [-1,1] || throw(ArgumentError("Label y (last value of argument) must be either -1 or +1."))
    LabeledTriplet{T}(NTuple{4,T}(t))
end

function LabeledTriplet(S::Type{U}, t::Vector{T}) where {U <: Integer, T <: Integer}
    length(t) == 4 || throw(ArgumentError("LabeledTriplet must be of length 4"))
    @assert t[end] in [-1,1] || throw(ArgumentError("Label y (last value of argument) must be either -1 or +1."))
    LabeledTriplet{S}(NTuple{4,S}(t))
end

function LabeledTriplet(i::T, j::T, k::T, y::T) where T <: Integer
    @assert y in [-1,1] || throw(ArgumentError("Label y must be either -1 or +1."))
    LabeledTriplet{eltype(i)}((i,j,k,y))
end

function LabeledTriplet(S::Type{U}, i::T, j::T, k::T, y::T) where {U <: Integer, T <: Integer}
    @assert y in [-1,1] || throw(ArgumentError("Label y must be either -1 or +1."))
    LabeledTriplet{S}((i,j,k,y))
end

function Base.show(io::IO, ::Type{LabeledTriplet})
    print(io, "LabeledTriplet")
end

function Base.show(io::IO, t::LabeledTriplet)
    n = nfields(t)
    for i = 1:n
        # if field types aren't concrete, show full type
        if typeof(getfield(t, i)) !== fieldtype(typeof(t), i)
            show(io, typeof(t))
            print(io, "(")
            show(io, Tuple(t))
            print(io, ")")
            return
        end
    end

    typeinfo = get(io, :typeinfo, Any)
    print(io, "LabeledTriplet{$(eltype(t))}(")
    for i = 1:n
        print(io, fieldname(typeof(t),i), " = ")
        show(IOContext(io, :typeinfo =>
                       t isa typeinfo <: NamedTuple ? fieldtype(typeinfo, i) : Any),
             getfield(t, i))
        if n == 1
            print(io, ",")
        elseif i < n
            print(io, ", ")
        end
    end
    print(io, ")")
end

const LabeledTriplets{T} = Vector{LabeledTriplet{T}} where T <: Integer

function Base.show(io::IO, ::Type{LabeledTriplets{T}}) where T
    print(io, "LabeledTriplets{$(T)}")
end

"""
    LabeledTriplets(X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where T <: Real

Generate a set of labeled triplets from X (matrix or embedding).

X is assumed to be an d × n AbstractMatrix, so it can be:
  - A d × n AbstractMatrix
  - A d × n TripletEmbeddings.Embedding

Parameters:
 - f::Function corresponds to the noise function when generating triplets (x -> 1 implies probability of success is 1)
 - shuffle::Bool is a flag deciding whether the triplets are returned shuffled or not (default is false)

This method will optimize the type used for each Triplet (between Int16 and Int64).
---
    Triplets(triplets::Vector{Triplet{(:i, :j, :k), Tuple{T, T, T}}}) where T <: Integer

Function to generate Triplets from a Vector{Triplet}. To be used only with Stochastic Gradient Descent (SGD).

"""
function LabeledTriplets(X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where T <: Real
    0 < percentage ≤ 100 || throw(ArgumentError("Percentage of triplets must be in the interval (0, 100]"))
    # if percentage < 100
    #     @warn "Shuffling to have all items represented"
    #     shuffle = true
    # end
    triplets = label(LabeledTriplet, X, f, shuffle)[1:floor(Int, end * percentage / 100)]
    checktriplets(triplets) || throw(AssertionError("Triplets do not contain all items."))
    return triplets
end

function LabeledTriplets(S::Type{U}, X::AbstractMatrix{T}; f::Function = x -> 1, shuffle::Bool = false, percentage::Real = 100) where {U <: Integer, T <: Real}
    0 < percentage ≤ 100 || throw(ArgumentError("Percentage of triplets must be in the interval (0, 100]"))
    # if percentage < 100
    #     @warn "Shuffling to have all items represented"
    #     shuffle = true
    # end
    triplets = label(LabeledTriplet, X, f, shuffle, S)[1:floor(Int, end * percentage / 100)]
    checktriplets(triplets) || throw(AssertionError("Triplets do not contain all items."))
    return triplets
end

function LabeledTriplets(X::AbstractVector{S}; f::Function = x -> 1, shuffle::Bool = false) where S <: Real
    length(X) > 1 || throw(AssertionError("Number of elements in X must be > 1"))
    LabeledTriplets(reshape(X, 1, length(X)); f = f, shuffle = shuffle)
end

"""
    checktriplets(triplets::LabeledTriplets)

Checks whether triplets contains all elements from 1:n, where n is the maximum
value found in triplets.
"""
function checktriplets(triplets::LabeledTriplets{T}) where T <: Integer
    # Transform triplets into Matrix{Int32} and call respective function
    return checktriplets(getindex.(triplets, [1 2 3]))
end

@doc raw"""
    label(X::Matrix{T}, f::Function) where T <: Real

Compute the triplets from X. X is assumed to be d × n,
so that each item of the embedding is a vector (column).

f is a function modeling the probabilities of success/failure,
assuming that these probabilities are modeled through a Bernoulli
random variable:

```math
y_{ijk} = \cases{
    -1 \quad \text{w.p.} & f(D_{ij}^* - D_{ik}^*) \\
    +1 \quad \text{w.p.} & 1- f(D_{ij}^* - D_{ik}^*)
}
```
"""
function label(::Type{LabeledTriplet}, X::AbstractMatrix{T}, f::Function, shuffle::Bool, U::Type{V}) where {T <: Real, V <: Integer}
    maximum(X) ≠ minimum(X) || throw(DomainError("Embedding is constant, no triplets to compute."))
    sum(isnan.(X)) == 0 || throw(DomainError("Embedding X has NaNs values."))

    d, n = size(X)
    D = pairwise(SqEuclidean(), X, dims=2)

    triplets = Vector{LabeledTriplet{U}}(undef, n*binomial(n-1, 2))
    counter = 0

    for k = 1:n, j = 1:k-1, i = 1:n
        if i != j && i != k

            # Random noise distributes Bernoulli, with p = f(abs(D[i,j] - D[i,k]))
            # If f(x) = p (constant), then the noise is independent of the distance between pairs
            @inbounds mistake = f(abs(D[i,j] - D[i,k])) <= 1 - rand()

            if D[i,j] < D[i,k]
                counter +=1
                @inbounds triplets[counter] = LabeledTriplet{U}((i, j, k, !mistake ? -1 : +1))
            elseif D[i,j] > D[i,k]
                counter += 1
                @inbounds triplets[counter] = LabeledTriplet{U}((i, j, k, !mistake ? +1 : -1))
            end
        end
    end

    return shuffle ? Random.shuffle(triplets[1:counter]) : triplets[1:counter]

end

function label(::Type{LabeledTriplet}, X::AbstractMatrix{T}, f::Function, shuffle::Bool) where T <: Real
    d, n = size(X)
    label(LabeledTriplet, X, f, shuffle, tripletstype(n))
end


text:
"""
    function have_ss_connected(g::Graph, vertices::Vector{Int})

Checks whetever subgraph induced by `vertices` in `g` has stationary state.
Assumes `vertices` generates connected subgraph.
"""
function have_ss_connected(g::Graph, vertices::Vector{Int})
  ind_g, order = induced_subgraph(g, vertices)

  if length(vertices) == 1
    return false
  elseif length(vertices) == 2 #TODO remove after fixing bug in LightGraphs
    return degree(g, vertices[1]) == degree(g, vertices[2])
  end

  if is_bipartite(ind_g)
    bmap = bipartite_map(ind_g)
    v1 = find(x->x == 1, bmap)
    v2 = find(x->x == 2, bmap)
    return sum(degree(g, order[v1])) == sum(degree(g, order[v2]))
  else
    return true
  end
end

"""
    function have_ss_connected(g::Graph, vertices::Vector{Int})

Checks whetever all connected subgraphs induced by `vertices` in `g` have
stationary state.
"""
function have_ss(g::Graph, vertices::Vector{Int})

  subgraph, order = induced_subgraph(g, vertices)
  components = [order[vs] for vs=connected_components(subgraph)]
  all(have_ss_connected(g, vs) for vs=components)
end

max_stars_repo_name: QuantumWalks/ExceptionalConfiguration

max_issues_repo_name: QuantumWalks/ExceptionalConfiguration

max_forks_repo_name: QuantumWalks/ExceptionalConfiguration


text:
function decode_pass(pass::AbstractString)::Tuple
    row = parse(Int, map(c -> c =='B' ? '1' : '0', pass[1:7]); base = 2)
    seat = parse(Int, map(c -> c =='R' ? '1' : '0', pass[8:10]); base = 2)
    return (row, seat)
end

seat_id((row, seat)) = 8row + seat

@assert decode_pass("FBFBBFFRLR") == (44, 5)
@assert seat_id((44, 5)) == 357

seats = readlines("day05.in") .|> decode_pass .|> seat_id |> sort!
println("Q1: ", last(seats))
println("Q2: ", seats[findfirst(==(2), diff(seats))] + 1)

max_stars_repo_name: dhanak/competitive-coding

max_issues_repo_name: dhanak/competitive-coding

max_forks_repo_name: dhanak/competitive-coding