text:
module RPO
using ..AGFFileReader: Glass, GlassID, AGF
export EKPC, H_ZLAF55_MOLD, BSM16C_MOLD, IG6, D_LAK6_MOLD, N_LAF2_MOLD, S_NPH1_MOLD, IG5, H_ZLAF53_MOLD, D_LAK70_MOLD, H_ZLAF52_MOLD, S_LAL12_MOLD, E_FDS1_MOLD, D_LAK70, IG2, L_TIM28_MOLD, SF57_MOLD, IG4, D_ZLAF52A_MOLD, H_ZLAF56_MOLD, S_LAH60_MOLD, K_CSK120_MOLD, N_SK5_MOLD, K_VC79_MOLD, N_BK7_MOLD, S_LAL18_MOLD, H_LAK54_MOLD, N_FK51_MOLD, P_SK57_MOLD, L_LAM60_MOLD, S_LAL13_MOLD, TAF3_MOLD, D_K59_MOLD, TAC4_MOLD, VC78, K_VC89_MOLD, FDS9_MOLD, N_FK5_MOLD, TAF1_MOLD, VC78_MOLD, H_ZLAF50B_MOLD, BACD14_MOLD, N_LAK22_MOLD

const EKPC = Glass(GlassID(AGF, 1728), 1, 2.1665838, 0.11325275, 0.25033244, -0.085983038, 0.015632264, -0.0010525329, 0.0, 0.0, 0.0, 0.0, 0.334, 2.325, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 2, -1.0, [(0.334, 1.0, 25.0), (0.35, 1.0, 25.0), (0.365, 1.0, 25.0), (0.37, 1.0, 25.0), (0.38, 1.0, 25.0), (0.39, 1.0, 25.0), (0.4, 1.0, 25.0), (0.42, 1.0, 25.0), (0.46, 1.0, 25.0), (0.5, 1.0, 25.0), (0.66, 1.0, 25.0), (1.06, 1.0, 25.0), (1.529, 1.0, 25.0), (2.325, 1.0, 25.0)], 1.585936, -1.0, -1.0, 0, 30.119218, 0, 0.0, 0)
const H_ZLAF55_MOLD = Glass(GlassID(AGF, 1729), 1, 3.25484318, -0.0128524549, 0.0333590798, -6.78562065e-5, 0.000111853849, -4.03704375e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0082, -1.0, -1.0, 6.6, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.01, 10.0), (0.34, 0.19, 10.0), (0.35, 0.47, 10.0), (0.36, 0.68, 10.0), (0.37, 0.8, 10.0), (0.38, 0.88, 10.0), (0.39, 0.915, 10.0), (0.4, 0.939, 10.0), (0.42, 0.963, 10.0), (0.44, 0.974, 10.0), (0.46, 0.981, 10.0), (0.48, 0.986, 10.0), (0.5, 0.989, 10.0), (0.55, 0.993, 10.0), (0.6, 0.994, 10.0), (0.65, 0.995, 10.0), (0.7, 0.995, 10.0), (0.8, 0.0, 10.0), (0.85, 0.0, 10.0), (0.9, 0.0, 10.0), (0.95, 0.0, 10.0), (1.0, 0.0, 10.0), (1.06, 0.0, 10.0), (1.2, 0.0, 10.0), (1.4, 0.0, 10.0), (1.6, 0.0, 10.0), (1.8, 0.0, 10.0), (2.0, 0.0, 10.0), (2.2, 0.0, 10.0), (2.4, 0.0, 10.0)], 1.83, -1.0, -1.0, 0, 42.726836, 0, 4.95, 0)
const BSM16C_MOLD = Glass(GlassID(AGF, 1730), 1, 2.56787068, -0.01138582621, 0.01387681972, 0.0005015765279, -3.592774947e-5, 1.983667247e-6, 0.0, 0.0, 0.0, 0.0, 0.299999999, 2.4, 2.256e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, -0.0014, 3.2, 3.0, 6.3, -1.0, 0, 52.2, [(0.3, 0.1, 10.0), (0.31, 0.24, 10.0), (0.32, 0.42, 10.0), (0.33, 0.6, 10.0), (0.34, 0.74, 10.0), (0.35, 0.85, 10.0), (0.36, 0.912, 10.0), (0.37, 0.948, 10.0), (0.38, 0.968, 10.0), (0.39, 0.979, 10.0), (0.4, 0.986, 10.0), (0.42, 0.992, 10.0), (0.44, 0.993, 10.0), (0.46, 0.995, 10.0), (0.48, 0.996, 10.0), (0.5, 0.997, 10.0), (0.55, 0.998, 10.0), (0.6, 0.998, 10.0), (0.65, 0.998, 10.0), (0.7, 0.998, 10.0), (0.8, 0.0, 10.0), (0.9, 0.0, 10.0), (1.0, 0.0, 10.0), (1.2, 0.0, 10.0), (1.4, 0.0, 10.0), (1.6, 0.0, 10.0), (1.8, 0.0, 10.0), (2.0, 0.0, 10.0), (2.2, 0.0, 10.0), (2.4, 0.0, 10.0)], 1.61481, -1.0, -1.0, 0, 59.71032, 0, 3.57, 5)
const IG6 = Glass(GlassID(AGF, 1731), 1, 7.74508077, -0.000557064219, 3.2517883, -78.7663982, 988.437047, -4179.30731, 0.0, 0.0, 0.0, 0.0, 3.0, 12.0, 3.39e-5, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 20.7, -1.0, 0, -1.0, [], 1.0, -1.0, -1.0, 0, 0.0, 0, 4.63, 0)
const D_LAK6_MOLD = Glass(GlassID(AGF, 1732), 1, 2.80532992, -0.0177972005, 0.0169077957, 0.000786545091, -2.23253554e-5, -5.36623399e-8, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 0, -1.0, [], 1.689442, -1.0, -1.0, 0, 52.830176, 0, 1.0, 0)
const N_LAF2_MOLD = Glass(GlassID(AGF, 1733), 2, 1.79419393, 0.0102626245, 0.155056926, 0.044352647, 1.09019471, 100.731467, 0.0, 0.0, 0.0, 0.0, 0.35, 2.5, -3.64e-6, 9.2e-9, -6.0e-12, 6.43e-7, 6.11e-10, 0.22, 20.0, -0.0027, 2.2, 3.5, 8.06, 2.0, 0, 52.2, [(0.35, 0.025, 25.0), (0.365, 0.31, 25.0), (0.37, 0.43, 25.0), (0.38, 0.63, 25.0), (0.39, 0.76, 25.0), (0.4, 0.84, 25.0), (0.405, 0.865, 25.0), (0.42, 0.915, 25.0), (0.436, 0.94, 25.0), (0.46, 0.962, 25.0), (0.5, 0.983, 25.0), (0.546, 0.994, 25.0), (0.58, 0.993, 25.0), (0.62, 0.992, 25.0), (0.66, 0.993, 25.0), (0.7, 0.996, 25.0), (1.06, 0.997, 25.0), (1.53, 0.99, 25.0), (1.97, 0.93, 25.0), (2.325, 0.69, 25.0), (2.5, 0.4, 25.0)], 1.738772, 1.0, 3.0, 0, 44.536828, 0, 4.295, 2)
const S_NPH1_MOLD = Glass(GlassID(AGF, 1734), 2, 1.72039395, 0.0137918186, 0.35905958, 0.0669088725, 1.95245396, 136.641902, 0.0, 0.0, 0.0, 0.0, 0.3, 2.4, -2.275e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, 0.0261, 1.0, 10.5, 8.3, -1.0, 0, 1.0, [(0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.0, 10.0), (0.35, 0.0, 10.0), (0.36, 0.0, 10.0), (0.37, 0.0, 10.0), (0.38, 0.14, 10.0), (0.39, 0.53, 10.0), (0.4, 0.77, 10.0), (0.42, 0.917, 10.0), (0.44, 0.952, 10.0), (0.46, 0.967, 10.0), (0.48, 0.975, 10.0), (0.5, 0.982, 10.0), (0.55, 0.992, 10.0), (0.6, 0.994, 10.0), (0.65, 0.995, 10.0), (0.7, 0.996, 10.0), (0.8, 0.997, 10.0), (0.9, 0.997, 10.0), (1.0, 0.996, 10.0), (1.2, 0.997, 10.0), (1.4, 0.994, 10.0), (1.6, 0.992, 10.0), (1.8, 0.984, 10.0), (2.0, 0.973, 10.0), (2.2, 0.934, 10.0), (2.4, 0.88, 10.0)], 1.797892, -1.0, -1.0, 0, 22.463062, 0, 3.29, 4)
const IG5 = Glass(GlassID(AGF, 1735), 1, 6.92709255, -0.00120658749, -3.58858859, 103.314022, -1124.75323, 4295.46144, 0.0, 0.0, 0.0, 0.0, 3.0, 12.0, 8.2e-5, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 14.0, -1.0, 0, -1.0, [], 1.0, -1.0, -1.0, 0, 0.0, 0, 4.66, 0)
const H_ZLAF53_MOLD = Glass(GlassID(AGF, 1736), 1, 3.24453775, -0.0153351622, 0.0330644118, 0.0014056192, -5.51574923e-5, 7.11912475e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0039, -1.0, -1.0, 6.3, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.02, 10.0), (0.35, 0.17, 10.0), (0.36, 0.41, 10.0), (0.37, 0.61, 10.0), (0.38, 0.75, 10.0), (0.39, 0.84, 10.0), (0.4, 0.89, 10.0), (0.42, 0.942, 10.0), (0.44, 0.96, 10.0), (0.46, 0.972, 10.0), (0.48, 0.98, 10.0), (0.5, 0.987, 10.0), (0.55, 0.994, 10.0), (0.6, 0.995, 10.0), (0.65, 0.995, 10.0), (0.7, 0.996, 10.0), (0.8, 0.997, 10.0), (0.85, 0.998, 10.0), (0.9, 0.998, 10.0), (0.95, 0.998, 10.0), (1.0, 0.998, 10.0), (1.06, 0.998, 10.0), (1.2, 0.998, 10.0), (1.4, 0.997, 10.0), (1.6, 0.984, 10.0), (1.8, 0.976, 10.0), (2.0, 0.958, 10.0), (2.2, 0.903, 10.0), (2.4, 0.72, 10.0)], 1.8292, -1.0, -1.0, 0, 36.952953, 0, 4.55, 0)
const D_LAK70_MOLD = Glass(GlassID(AGF, 1737), 1, 2.6962639, 0.00638424925, 0.0324462812, -0.00344923153, 0.000451981089, -2.02364943e-5, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 2, -1.0, [], 1.665254, -1.0, -1.0, 0, 55.135587, 0, 1.0, 0)
const H_ZLAF52_MOLD = Glass(GlassID(AGF, 1738), 1, 3.15651187, -0.0148252255, 0.0294604452, 0.000981264712, -2.29185364e-5, 3.79523742e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0055, -1.0, -1.0, 6.2, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.06, 10.0), (0.35, 0.28, 10.0), (0.36, 0.52, 10.0), (0.37, 0.7, 10.0), (0.38, 0.81, 10.0), (0.39, 0.88, 10.0), (0.4, 0.923, 10.0), (0.42, 0.958, 10.0), (0.44, 0.971, 10.0), (0.46, 0.98, 10.0), (0.48, 0.986, 10.0), (0.5, 0.991, 10.0), (0.55, 0.995, 10.0), (0.6, 0.995, 10.0), (0.65, 0.996, 10.0), (0.7, 0.997, 10.0), (0.8, 0.997, 10.0), (0.85, 0.998, 10.0), (0.9, 0.998, 10.0), (0.95, 0.998, 10.0), (1.0, 0.998, 10.0), (1.06, 0.998, 10.0), (1.2, 0.996, 10.0), (1.4, 0.99, 10.0), (1.6, 0.98, 10.0), (1.8, 0.956, 10.0), (2.0, 0.922, 10.0), (2.2, 0.81, 10.0), (2.4, 0.56, 10.0)], 1.801298, -1.0, -1.0, 0, 40.704676, 0, 4.47, 0)
const S_LAL12_MOLD = Glass(GlassID(AGF, 1739), 2, 0.609918184, 0.000533113491, 1.13827825, 0.015815259, 1.20182489, 107.73823, 0.0, 0.0, 0.0, 0.0, 0.3, 2.4, -7.683e-7, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, -0.0047, 4.2, 2.5, 7.2, -1.0, 0, 53.0, [(0.3, 0.29, 10.0), (0.31, 0.45, 10.0), (0.32, 0.61, 10.0), (0.33, 0.73, 10.0), (0.34, 0.83, 10.0), (0.35, 0.89, 10.0), (0.36, 0.938, 10.0), (0.37, 0.962, 10.0), (0.38, 0.976, 10.0), (0.39, 0.984, 10.0), (0.4, 0.988, 10.0), (0.42, 0.992, 10.0), (0.44, 0.994, 10.0), (0.46, 0.995, 10.0), (0.48, 0.997, 10.0), (0.5, 0.998, 10.0), (0.55, 0.999, 10.0), (0.6, 0.998, 10.0), (0.65, 0.998, 10.0), (0.7, 0.998, 10.0), (0.8, 0.999, 10.0), (0.9, 0.997, 10.0), (1.0, 0.996, 10.0), (1.2, 0.996, 10.0), (1.4, 0.991, 10.0), (1.6, 0.991, 10.0), (1.8, 0.981, 10.0), (2.0, 0.963, 10.0), (2.2, 0.901, 10.0), (2.4, 0.73, 10.0)], 1.673298, -1.0, -1.0, 0, 54.966722, 0, 4.01, 1)
const E_FDS1_MOLD = Glass(GlassID(AGF, 1740), 1, 3.46650745, -0.0202617699, 0.0533843287, 0.00629834765, -0.000572117101, 7.34747837e-5, 0.0, 0.0, 0.0, 0.0, 0.25, 1.55, -7.0623e-7, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0282, -1.0, 11.1, 6.3, 1.0, 0, 1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.0, 10.0), (0.35, 0.0, 10.0), (0.36, 0.0, 10.0), (0.37, 0.0, 10.0), (0.38, 0.01, 10.0), (0.39, 0.13, 10.0), (0.4, 0.4, 10.0), (0.42, 0.78, 10.0), (0.44, 0.88, 10.0), (0.46, 0.92, 10.0), (0.48, 0.95, 10.0), (0.5, 0.958, 10.0), (0.55, 0.977, 10.0), (0.6, 0.988, 10.0), (0.65, 0.991, 10.0), (0.7, 0.995, 10.0), (0.75, 0.0, 10.0), (0.8, 0.0, 10.0), (0.9, 0.0, 10.0), (1.0, 0.0, 10.0), (1.06, 0.0, 10.0), (1.1, 0.0, 10.0), (1.3, 0.0, 10.0), (1.55, 0.0, 10.0)], 1.912658, -1.0, 2.0, 0, 20.647419, 0, 3.94, 0)
const D_LAK70 = Glass(GlassID(AGF, 1741), 1, 2.70892374, 0.00639831933, 0.0325213777, -0.00345719463, 0.000453015557, -2.02829394e-5, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 2, -1.0, [], 1.669104, -1.0, -1.0, 0, 55.454671, 0, 1.0, 0)
const IG2 = Glass(GlassID(AGF, 1742), 1, 6.37933507, -0.00111513063, -4.78062765, 144.905769, -1731.6457, 7119.30411, 0.0, 0.0, 0.0, 0.0, 3.0, 12.0, 5.72e-5, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 12.1, -1.0, 0, -1.0, [], 1.0, -1.0, -1.0, 0, 0.0, 0, 4.41, 0)
const L_TIM28_MOLD = Glass(GlassID(AGF, 1743), 2, 1.56554809, 0.0126346935, 0.176885637, 0.0603406048, 1.14661648, 116.334311, 0.0, 0.0, 0.0, 0.0, 0.35, 2.4, -1.86e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, 0.0074, 1999.0, 3.0, 10.1, 1.0, 3, 1.0, [(0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.0, 10.0), (0.35, 0.0, 10.0), (0.36, 0.16, 10.0), (0.37, 0.57, 10.0), (0.38, 0.8, 10.0), (0.39, 0.89, 10.0), (0.4, 0.929, 10.0), (0.42, 0.964, 10.0), (0.44, 0.974, 10.0), (0.46, 0.98, 10.0), (0.48, 0.984, 10.0), (0.5, 0.989, 10.0), (0.55, 0.997, 10.0), (0.6, 0.996, 10.0), (0.65, 0.0, 10.0), (0.7, 0.0, 10.0), (0.8, 0.0, 10.0), (0.9, 0.0, 10.0), (1.0, 0.0, 10.0), (1.2, 0.0, 10.0), (1.4, 0.0, 10.0), (1.6, 0.0, 10.0), (1.8, 0.0, 10.0), (2.0, 0.0, 10.0), (2.2, 0.0, 10.0), (2.4, 0.0, 10.0)], 1.68403, -1.0, -1.0, 0, 30.856565, 0, 2.88, 3)
const SF57_MOLD = Glass(GlassID(AGF, 1744), 1, 3.240155287, -0.009571992651, 0.04883185889, 0.003148947643, -0.0001774970599, 2.889640871e-5, 0.0, 0.0, 0.0, 0.0, 0.369999999, 2.5, 7.26e-6, 1.88e-8, -5.14e-11, 1.96e-6, 1.79e-9, 0.276, 20.0, 0.0123, 4.3, 2.5, 8.3, 2.0, 0, 52.3, [(0.37, 0.01, 25.0), (0.38, 0.198, 25.0), (0.39, 0.45, 25.0), (0.4, 0.66, 25.0), (0.405, 0.73, 25.0), (0.42, 0.86, 25.0), (0.436, 0.93, 25.0), (0.46, 0.968, 25.0), (0.5, 0.986, 25.0), (0.546, 0.994, 25.0), (0.58, 0.994, 25.0), (0.62, 0.994, 25.0), (0.66, 0.994, 25.0), (0.7, 0.996, 25.0), (1.06, 0.997, 25.0), (1.53, 0.991, 25.0), (1.97, 0.93, 25.0), (2.325, 0.79, 25.0), (2.5, 0.75, 25.0)], 1.84457, 2.3, 5.0, 0, 23.7525, 0, 5.51, 3)
const IG4 = Glass(GlassID(AGF, 1745), 1, 6.91189161, -0.000787956404, -4.22296071, 142.900646, -1812.32748, 7766.33028, 0.0, 0.0, 0.0, 0.0, 3.0, 12.0, 3.24e-5, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 20.4, -1.0, 0, -1.0, [], 1.0, -1.0, -1.0, 0, 0.0, 0, 4.47, 0)
const D_ZLAF52A_MOLD = Glass(GlassID(AGF, 1746), 1, 3.18012111, -0.0305336243, 0.0150556955, 0.00519177551, -0.000615002878, 3.57892588e-5, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 0, -1.0, [], 1.801201, -1.0, -1.0, 0, 40.631273, 0, 1.0, 0)
const H_ZLAF56_MOLD = Glass(GlassID(AGF, 1747), 1, 3.13237288, -0.0132119823, 0.0339851496, 0.00184155673, -0.000107740182, 1.29364847e-5, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0007, -1.0, -1.0, 7.5, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.0, 10.0), (0.35, 0.01, 10.0), (0.36, 0.17, 10.0), (0.37, 0.48, 10.0), (0.38, 0.68, 10.0), (0.39, 0.79, 10.0), (0.4, 0.852, 10.0), (0.42, 0.912, 10.0), (0.44, 0.937, 10.0), (0.46, 0.951, 10.0), (0.48, 0.962, 10.0), (0.5, 0.971, 10.0), (0.55, 0.984, 10.0), (0.6, 0.987, 10.0), (0.65, 0.989, 10.0), (0.7, 0.991, 10.0), (0.8, 0.992, 10.0), (0.85, 0.997, 10.0), (0.9, 0.997, 10.0), (0.95, 0.998, 10.0), (1.0, 0.998, 10.0), (1.06, 0.998, 10.0), (1.2, 0.998, 10.0), (1.4, 0.997, 10.0), (1.6, 0.995, 10.0), (1.8, 0.989, 10.0), (2.0, 0.975, 10.0), (2.2, 0.939, 10.0), (2.4, 0.849, 10.0)], 1.799999, -1.0, -1.0, 0, 33.017644, 0, 3.69, 0)
const S_LAH60_MOLD = Glass(GlassID(AGF, 1748), 2, 1.08334791, 2.38405685e-11, 1.1529996, 0.0294633109, 2.47494795, 170.254264, 0.0, 0.0, 0.0, 0.0, 0.365, 2.325, -3.93e-7, 1.2e-8, -3.29e-11, 8.13e-7, 1.17e-9, 0.284, 25.0, 0.012962, 1.0, 5.0, 5.6, -1.0, 2, 4.2, [(0.24, 0.0, 10.0), (0.25, 0.0, 10.0), (0.26, 0.0, 10.0), (0.27, 0.0, 10.0), (0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.0, 10.0), (0.33, 0.0, 10.0), (0.34, 0.03, 10.0), (0.35, 0.27, 10.0), (0.36, 0.54, 10.0), (0.37, 0.72, 10.0), (0.38, 0.83, 10.0), (0.39, 0.88, 10.0), (0.4, 0.924, 10.0), (0.42, 0.957, 10.0), (0.44, 0.972, 10.0), (0.46, 0.98, 10.0), (0.48, 0.986, 10.0), (0.5, 0.99, 10.0), (0.55, 0.996, 10.0), (0.6, 0.997, 10.0), (0.65, 0.997, 10.0), (0.7, 0.998, 10.0), (0.8, 0.999, 10.0), (0.9, 0.998, 10.0), (1.0, 0.997, 10.0), (1.2, 0.996, 10.0), (1.4, 0.993, 10.0), (1.6, 0.992, 10.0), (1.8, 0.984, 10.0), (2.0, 0.964, 10.0), (2.2, 0.906, 10.0), (2.4, 0.72, 10.0)], 1.827266, 3.0, -1.0, 0, 36.787075, 0, 4.43, 1)
const K_CSK120_MOLD = Glass(GlassID(AGF, 1749), 1, 2.462205306, -0.007402005673, 0.01806043171, -0.001017272649, 0.0001624358258, -7.641622271e-6, 0.0, 0.0, 0.0, 0.0, 0.269999999, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0059, -1.0, -1.0, 0.0, 2.0, 0, 4.0, [(0.27, 0.0, 10.0), (0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.079, 10.0), (0.32, 0.386, 10.0), (0.33, 0.679, 10.0), (0.34, 0.843, 10.0), (0.35, 0.923, 10.0), (0.36, 0.963, 10.0), (0.37, 0.972, 10.0), (0.38, 0.99, 10.0), (0.39, 0.998, 10.0), (0.4, 0.998, 10.0), (0.42, 0.998, 10.0), (0.44, 0.998, 10.0), (0.46, 0.998, 10.0), (0.48, 0.998, 10.0), (0.5, 0.998, 10.0), (0.55, 0.998, 10.0), (0.6, 0.998, 10.0), (0.7, 0.998, 10.0), (0.8, 0.998, 10.0), (1.06, 0.998, 10.0), (1.5, 0.994, 10.0), (2.0, 0.988, 10.0)], 1.5833, -1.0, -1.0, 0, 59.191064, 0, 3.0, 0)
const N_SK5_MOLD = Glass(GlassID(AGF, 1750), 2, 0.982325914, 0.00533315206, 0.488744522, 0.0173212991, 0.984484296, 98.3938446, 0.0, 0.0, 0.0, 0.0, 0.3, 2.5, 3.5e-6, 1.22e-8, 6.38e-11, 2.46e-7, -3.34e-11, 0.278, 20.0, -0.0007, 1.3, 1.5, 5.5, 3.0, 0, 4.4, [(0.3, 0.02, 25.0), (0.31, 0.1, 25.0), (0.32, 0.27, 25.0), (0.334, 0.58, 25.0), (0.35, 0.82, 25.0), (0.365, 0.93, 25.0), (0.37, 0.94, 25.0), (0.38, 0.96, 25.0), (0.39, 0.971, 25.0), (0.4, 0.981, 25.0), (0.405, 0.983, 25.0), (0.42, 0.986, 25.0), (0.436, 0.987, 25.0), (0.46, 0.989, 25.0), (0.5, 0.994, 25.0), (0.546, 0.996, 25.0), (0.58, 0.995, 25.0), (0.62, 0.993, 25.0), (0.66, 0.994, 25.0), (0.7, 0.995, 25.0), (1.06, 0.997, 25.0), (1.53, 0.98, 25.0), (1.97, 0.91, 25.0), (2.325, 0.64, 25.0), (2.5, 0.38, 25.0)], 1.58393, 2.0, 1.0, 0, 60.726008, 0, 3.3, 2)
const K_VC79_MOLD = Glass(GlassID(AGF, 1751), 1, 2.534883491, -0.01093481644, 0.01483039411, 0.0003095841104, -9.025669048e-6, 6.707866289e-7, 0.0, 0.0, 0.0, 0.0, 0.269999999, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0076, -1.0, -1.0, 0.0, 2.0, 0, 4.0, [(0.27, 0.022, 10.0), (0.28, 0.103, 10.0), (0.29, 0.26, 10.0), (0.3, 0.378, 10.0), (0.31, 0.669, 10.0), (0.32, 0.799, 10.0), (0.33, 0.891, 10.0), (0.34, 0.939, 10.0), (0.35, 0.964, 10.0), (0.36, 0.978, 10.0), (0.37, 0.982, 10.0), (0.38, 0.985, 10.0), (0.39, 0.985, 10.0), (0.4, 0.985, 10.0), (0.42, 0.985, 10.0), (0.44, 0.988, 10.0), (0.46, 0.99, 10.0), (0.48, 0.991, 10.0), (0.5, 0.992, 10.0), (0.55, 0.994, 10.0), (0.6, 0.994, 10.0), (0.7, 0.997, 10.0), (0.8, 0.997, 10.0), (1.06, 0.998, 10.0), (1.5, 0.998, 10.0), (2.0, 0.997, 10.0)], 1.605145, -1.0, -1.0, 0, 57.304584, 0, 3.09, 0)
const N_BK7_MOLD = Glass(GlassID(AGF, 1752), 2, 0.780178416, 0.0133285338, 0.478659702, 0.000830413318, 1.04547946, 107.124175, 0.0, 0.0, 0.0, 0.0, 0.3, 2.5, 1.86e-6, 1.31e-8, -1.37e-11, 4.34e-7, 6.27e-10, 0.17, 20.0, -0.0009, 2.3, 1.0, 7.1, 2.0, 0, 1.0, [(0.3, 0.05, 25.0), (0.31, 0.25, 25.0), (0.32, 0.52, 25.0), (0.334, 0.78, 25.0), (0.35, 0.92, 25.0), (0.365, 0.971, 25.0), (0.37, 0.977, 25.0), (0.38, 0.983, 25.0), (0.39, 0.989, 25.0), (0.4, 0.992, 25.0), (0.405, 0.993, 25.0), (0.42, 0.993, 25.0), (0.436, 0.992, 25.0), (0.46, 0.993, 25.0), (0.5, 0.994, 25.0), (0.546, 0.996, 25.0), (0.58, 0.995, 25.0), (0.62, 0.994, 25.0), (0.66, 0.994, 25.0), (0.7, 0.996, 25.0), (1.06, 0.997, 25.0), (1.53, 0.98, 25.0), (1.97, 0.84, 25.0), (2.325, 0.56, 25.0), (2.5, 0.36, 25.0)], 1.512595, 2.0, 0.0, 0, 63.648436, 0, 2.51, 1)
const S_LAL18_MOLD = Glass(GlassID(AGF, 1753), 2, 0.66506272, 0.00101735308, 1.24938061, 0.0157988109, 1.31025811, 91.274655, 0.0, 0.0, 0.0, 0.0, 0.3, 2.4, 4.566e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, -0.0086, 2.0, 7.5, 5.9, -1.0, 0, 51.2, [(0.3, 0.3, 10.0), (0.31, 0.32, 10.0), (0.32, 0.55, 10.0), (0.33, 0.68, 10.0), (0.34, 0.78, 10.0), (0.35, 0.86, 10.0), (0.36, 0.912, 10.0), (0.37, 0.946, 10.0), (0.38, 0.967, 10.0), (0.39, 0.978, 10.0), (0.4, 0.984, 10.0), (0.42, 0.991, 10.0), (0.44, 0.994, 10.0), (0.46, 0.996, 10.0), (0.48, 0.997, 10.0), (0.5, 0.998, 10.0), (0.55, 0.999, 10.0), (0.6, 0.998, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.8, 0.998, 10.0), (0.9, 0.998, 10.0), (1.0, 0.997, 10.0), (1.2, 0.996, 10.0), (1.4, 0.991, 10.0), (1.6, 0.991, 10.0), (1.8, 0.982, 10.0), (2.0, 0.956, 10.0), (2.2, 0.87, 10.0), (2.4, 0.6, 10.0)], 1.723761, -1.0, -1.0, 0, 54.273851, 0, 4.18, 1)
const H_LAK54_MOLD = Glass(GlassID(AGF, 1754), 1, 2.9277611, -0.0147660748, 0.0206867604, 0.000708735021, -4.16441993e-5, 2.58153901e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.692, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0098, -1.0, -1.0, 5.4, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.04, 10.0), (0.3, 0.12, 10.0), (0.31, 0.24, 10.0), (0.32, 0.39, 10.0), (0.33, 0.53, 10.0), (0.34, 0.67, 10.0), (0.35, 0.78, 10.0), (0.36, 0.853, 10.0), (0.37, 0.905, 10.0), (0.38, 0.938, 10.0), (0.39, 0.957, 10.0), (0.4, 0.969, 10.0), (0.42, 0.979, 10.0), (0.44, 0.984, 10.0), (0.46, 0.987, 10.0), (0.48, 0.99, 10.0), (0.5, 0.992, 10.0), (0.55, 0.994, 10.0), (0.6, 0.994, 10.0), (0.65, 0.994, 10.0), (0.7, 0.995, 10.0), (0.8, 0.996, 10.0), (0.85, 0.997, 10.0), (0.9, 0.998, 10.0), (0.95, 0.998, 10.0), (1.0, 0.998, 10.0), (1.06, 0.998, 10.0), (1.2, 0.998, 10.0), (1.4, 0.998, 10.0), (1.6, 0.997, 10.0), (1.8, 0.985, 10.0), (2.0, 0.962, 10.0), (2.2, 0.899, 10.0), (2.4, 0.65, 10.0)], 1.728497, -1.0, -1.0, 0, 51.102214, 0, 4.01, 0)
const N_FK51_MOLD = Glass(GlassID(AGF, 1755), 2, 0.402845603, 0.000358331487, 0.779722736, 0.00992579562, 0.953460338, 177.526238, 0.0, 0.0, 0.0, 0.0, 0.29, 2.5, -1.83e-5, -7.89e-9, -1.63e-12, 3.74e-7, 3.46e-10, 0.15, 20.0, 0.0342, 4.3, 18.0, 13.3, 2.0, 3, 52.3, [(0.29, 0.01, 25.0), (0.3, 0.035, 25.0), (0.31, 0.12, 25.0), (0.32, 0.3, 25.0), (0.334, 0.63, 25.0), (0.35, 0.875, 25.0), (0.365, 0.963, 25.0), (0.37, 0.976, 25.0), (0.38, 0.988, 25.0), (0.39, 0.992, 25.0), (0.4, 0.993, 25.0), (0.405, 0.993, 25.0), (0.42, 0.992, 25.0), (0.436, 0.992, 25.0), (0.46, 0.993, 25.0), (0.5, 0.996, 25.0), (0.546, 0.997, 25.0), (0.58, 0.997, 25.0), (0.62, 0.996, 25.0), (0.66, 0.995, 25.0), (0.7, 0.995, 25.0), (1.06, 0.994, 25.0), (1.53, 0.98, 25.0), (1.97, 0.94, 25.0), (2.325, 0.84, 25.0), (2.5, 0.75, 25.0)], 1.484658, 2.2, 0.0, 0, 84.146056, 0, 3.66, 4)
const P_SK57_MOLD = Glass(GlassID(AGF, 1756), 1, 2.473063668, -0.01117810562, 0.01209876935, 0.0007748745456, -7.12908019e-5, 3.290007747e-6, 0.0, 0.0, 0.0, 0.0, 0.31, 2.5, 2.6e-6, 9.4e-9, -2.3e-11, 4.9e-7, 5.96e-10, 0.178, 20.0, -0.0024, 3.0, -1.0, 7.23, 4.0, 0, 52.3, [(0.31, 0.0, 25.0), (0.32, 0.16, 25.0), (0.334, 0.61, 25.0), (0.35, 0.87, 25.0), (0.365, 0.95, 25.0), (0.37, 0.96, 25.0), (0.38, 0.973, 25.0), (0.39, 0.98, 25.0), (0.4, 0.984, 25.0), (0.405, 0.985, 25.0), (0.42, 0.987, 25.0), (0.436, 0.989, 25.0), (0.46, 0.991, 25.0), (0.5, 0.995, 25.0), (0.546, 0.997, 25.0), (0.58, 0.997, 25.0), (0.62, 0.997, 25.0), (0.66, 0.997, 25.0), (0.7, 0.997, 25.0), (1.06, 0.997, 25.0), (1.53, 0.978, 25.0), (1.97, 0.89, 25.0), (2.325, 0.63, 25.0), (2.5, 0.4, 25.0)], 1.584061, 2.0, 3.0, 0, 58.956575, 0, 3.012, 3)
const L_LAM60_MOLD = Glass(GlassID(AGF, 1757), 2, 1.108755708, 0.01936029572, 0.8475056475, 0.002000002086, 1.354896422, 106.7885088, 0.0, 0.0, 0.0, 0.0, 0.309999999, 2.4, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, -0.0088, 2.0, 19.5, 7.4, -1.0, 0, 51.2, [(0.24, 0.0, 10.0), (0.25, 0.0, 10.0), (0.26, 0.0, 10.0), (0.27, 0.0, 10.0), (0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.09, 10.0), (0.32, 0.33, 10.0), (0.33, 0.56, 10.0), (0.34, 0.72, 10.0), (0.35, 0.83, 10.0), (0.36, 0.9, 10.0), (0.37, 0.94, 10.0), (0.38, 0.97, 10.0), (0.39, 0.977, 10.0), (0.4, 0.983, 10.0), (0.42, 0.988, 10.0), (0.44, 0.991, 10.0), (0.46, 0.993, 10.0), (0.48, 0.996, 10.0), (0.5, 0.997, 10.0), (0.55, 0.998, 10.0), (0.6, 0.998, 10.0), (0.65, 0.998, 10.0), (0.7, 0.999, 10.0), (0.8, 0.999, 10.0), (0.9, 0.999, 10.0), (1.0, 0.999, 10.0), (1.2, 0.999, 10.0), (1.4, 0.998, 10.0), (1.6, 0.997, 10.0), (1.8, 0.991, 10.0), (2.0, 0.974, 10.0), (2.2, 0.936, 10.0), (2.4, 0.75, 10.0)], 1.738585, 4.0, -1.0, 0, 48.990757, 0, 4.2, 4)
const S_LAL13_MOLD = Glass(GlassID(AGF, 1758), 2, 1.15067264, 0.0167483199, 0.646991168, 0.000278647233, 1.32830643, 102.511518, 0.0, 0.0, 0.0, 0.0, 0.3, 2.4, 7.171e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 25.0, -0.0081, 3.0, 3.0, 5.7, -1.0, 0, 52.0, [(0.3, 0.03, 10.0), (0.31, 0.08, 10.0), (0.32, 0.19, 10.0), (0.33, 0.34, 10.0), (0.34, 0.52, 10.0), (0.35, 0.68, 10.0), (0.36, 0.8, 10.0), (0.37, 0.88, 10.0), (0.38, 0.932, 10.0), (0.39, 0.958, 10.0), (0.4, 0.972, 10.0), (0.42, 0.986, 10.0), (0.44, 0.99, 10.0), (0.46, 0.993, 10.0), (0.48, 0.995, 10.0), (0.5, 0.996, 10.0), (0.55, 0.997, 10.0), (0.6, 0.995, 10.0), (0.65, 0.995, 10.0), (0.7, 0.996, 10.0), (0.8, 0.997, 10.0), (0.9, 0.996, 10.0), (1.0, 0.995, 10.0), (1.2, 0.995, 10.0), (1.4, 0.99, 10.0), (1.6, 0.99, 10.0), (1.8, 0.981, 10.0), (2.0, 0.958, 10.0), (2.2, 0.88, 10.0), (2.4, 0.66, 10.0)], 1.688895, -1.0, -1.0, 0, 52.855414, 0, 3.6, 1)
const TAF3_MOLD = Glass(GlassID(AGF, 1759), 1, 3.15871089, -0.0140753606, 0.0287918139, 3.34879169e-5, 8.0245017e-5, -2.88900113e-6, 0.0, 0.0, 0.0, 0.0, 0.25, 1.55, 3.8238e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0067, -1.0, 16.3, 6.3, 1.0, 0, 3.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.01, 10.0), (0.31, 0.05, 10.0), (0.32, 0.12, 10.0), (0.33, 0.25, 10.0), (0.34, 0.41, 10.0), (0.35, 0.51, 10.0), (0.36, 0.71, 10.0), (0.37, 0.82, 10.0), (0.38, 0.89, 10.0), (0.39, 0.93, 10.0), (0.4, 0.953, 10.0), (0.42, 0.97, 10.0), (0.44, 0.979, 10.0), (0.46, 0.987, 10.0), (0.48, 0.996, 10.0), (0.5, 0.996, 10.0), (0.55, 0.999, 10.0), (0.6, 0.999, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.75, 0.999, 10.0), (0.8, 0.999, 10.0), (0.9, 0.999, 10.0), (1.0, 0.998, 10.0), (1.06, 0.999, 10.0), (1.1, 0.998, 10.0), (1.3, 0.996, 10.0), (1.55, 0.997, 10.0)], 1.7998, -1.0, 2.0, 0, 46.24814, 0, 4.65, 0)
const D_K59_MOLD = Glass(GlassID(AGF, 1760), 1, 2.26619651, -0.0100434033, 0.00963297006, 0.000714825442, -0.000102309298, 6.58788276e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 7.5, -1.0, 0, -1.0, [], 1.514796, -1.0, -1.0, 0, 63.09874, 0, 2.41, 0)
const TAC4_MOLD = Glass(GlassID(AGF, 1761), 1, 2.9254352, -0.0132275531, 0.0234911825, -0.000163595621, 9.21331502e-5, -4.84866833e-6, 0.0, 0.0, 0.0, 0.0, 0.25, 1.55, 9.2955e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0064, -1.0, 8.1, 5.2, 1.0, 1, 4.0, [(0.28, 0.0, 10.0), (0.29, 0.01, 10.0), (0.3, 0.05, 10.0), (0.31, 0.13, 10.0), (0.32, 0.26, 10.0), (0.33, 0.41, 10.0), (0.34, 0.57, 10.0), (0.35, 0.71, 10.0), (0.36, 0.82, 10.0), (0.37, 0.891, 10.0), (0.38, 0.934, 10.0), (0.39, 0.959, 10.0), (0.4, 0.972, 10.0), (0.42, 0.985, 10.0), (0.44, 0.988, 10.0), (0.46, 0.994, 10.0), (0.48, 0.997, 10.0), (0.5, 0.999, 10.0), (0.55, 0.999, 10.0), (0.6, 0.999, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.75, 0.999, 10.0), (0.8, 0.999, 10.0), (0.9, 0.999, 10.0), (1.0, 0.999, 10.0), (1.06, 0.999, 10.0), (1.1, 0.999, 10.0), (1.3, 0.999, 10.0), (1.55, 0.991, 10.0)], 1.728999, -1.0, 3.0, 0, 50.70639, 0, 4.06, 0)
const VC78 = Glass(GlassID(AGF, 1762), 1, 2.735136, -0.01182207, 0.01827911, 0.0001798584, 1.677301e-5, -5.307061e-7, 0.0, 0.0, 0.0, 0.0, 0.27, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0088, -1.0, -1.0, 0.0, 2.0, 2, 4.0, [(0.27, 0.032, 10.0), (0.28, 0.111, 10.0), (0.29, 0.232, 10.0), (0.3, 0.279, 10.0), (0.31, 0.552, 10.0), (0.32, 0.71, 10.0), (0.33, 0.826, 10.0), (0.34, 0.898, 10.0), (0.35, 0.943, 10.0), (0.36, 0.967, 10.0), (0.37, 0.982, 10.0), (0.38, 0.985, 10.0), (0.39, 0.988, 10.0), (0.4, 0.99, 10.0), (0.42, 0.99, 10.0), (0.44, 0.991, 10.0), (0.46, 0.994, 10.0), (0.48, 0.995, 10.0), (0.5, 0.995, 10.0), (0.55, 0.995, 10.0), (0.6, 0.997, 10.0), (0.7, 0.998, 10.0), (0.8, 0.998, 10.0), (1.06, 0.998, 10.0), (1.5, 0.998, 10.0), (2.0, 0.995, 10.0)], 1.669096, -1.0, -1.0, 0, 55.418322, 0, 3.44, 0)
const K_VC89_MOLD = Glass(GlassID(AGF, 1763), 1, 3.156483328, -0.008569421184, 0.03656210778, -0.0008804961946, 0.0002065655345, -7.019901337e-6, 0.0, 0.0, 0.0, 0.0, 0.269999999, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 0, -1.0, [], 1.804597, -1.0, -1.0, 0, 40.712764, 0, 1.0, 0)
const FDS9_MOLD = Glass(GlassID(AGF, 1764), 1, 3.25298133, -0.01489599, 0.0413434, 0.00540956, -0.000490511259, 4.51034874e-5, 0.0, 0.0, 0.0, 0.0, 0.46, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.0, -1.0, -1.0, 0.0, -1.0, 2, -1.0, [(0.334, 1.0, 25.0), (0.35, 1.0, 25.0), (0.365, 1.0, 25.0), (0.37, 1.0, 25.0), (0.38, 1.0, 25.0), (0.39, 1.0, 25.0), (0.4, 1.0, 25.0), (0.42, 1.0, 25.0), (0.46, 1.0, 25.0), (0.5, 1.0, 25.0), (0.66, 1.0, 25.0), (1.06, 1.0, 25.0), (1.529, 1.0, 25.0), (2.325, 1.0, 25.0)], 1.845058, -1.0, -1.0, 0, 23.781322, 0, 1.0, 0)
const N_FK5_MOLD = Glass(GlassID(AGF, 1765), 2, 0.339383535, 0.0150237221, 0.839911284, 0.00482102014, 0.909090481, 97.8824387, 0.0, 0.0, 0.0, 0.0, 0.3, 2.5, -7.24e-6, 1.58e-8, -9.51e-12, 3.51e-7, 4.61e-10, 0.156, 20.0, 0.0036, 2.3, 2.0, 9.2, 2.0, 0, 4.0, [(0.27, 0.0, 25.0), (0.28, 0.11, 25.0), (0.29, 0.4, 25.0), (0.3, 0.7, 25.0), (0.31, 0.86, 25.0), (0.32, 0.93, 25.0), (0.334, 0.972, 25.0), (0.35, 0.987, 25.0), (0.365, 0.992, 25.0), (0.37, 0.992, 25.0), (0.38, 0.99, 25.0), (0.39, 0.994, 25.0), (0.4, 0.994, 25.0), (0.405, 0.994, 25.0), (0.42, 0.993, 25.0), (0.436, 0.993, 25.0), (0.46, 0.993, 25.0), (0.5, 0.993, 25.0), (0.546, 0.994, 25.0), (0.58, 0.994, 25.0), (0.62, 0.993, 25.0), (0.66, 0.994, 25.0), (0.7, 0.996, 25.0), (1.06, 0.998, 25.0), (1.53, 0.965, 25.0), (1.97, 0.93, 25.0), (2.325, 0.63, 25.0), (2.5, 0.38, 25.0)], 1.48439, 2.0, 1.0, 0, 69.958041, 0, 2.45, 1)
const TAF1_MOLD = Glass(GlassID(AGF, 1766), 1, 3.05438324, -0.0154525436, 0.0235532812, 0.0006611972, -2.8277377e-5, 2.20316121e-6, 0.0, 0.0, 0.0, 0.0, 0.25, 1.55, 5.4401e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0086, -1.0, 11.6, 5.9, 1.0, 0, 3.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.07, 10.0), (0.32, 0.22, 10.0), (0.33, 0.4, 10.0), (0.34, 0.56, 10.0), (0.35, 0.7, 10.0), (0.36, 0.81, 10.0), (0.37, 0.88, 10.0), (0.38, 0.92, 10.0), (0.39, 0.95, 10.0), (0.4, 0.968, 10.0), (0.42, 0.982, 10.0), (0.44, 0.99, 10.0), (0.46, 0.996, 10.0), (0.48, 0.997, 10.0), (0.5, 0.999, 10.0), (0.55, 0.999, 10.0), (0.6, 0.999, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.75, 0.998, 10.0), (0.8, 0.996, 10.0), (0.9, 0.999, 10.0), (1.0, 0.999, 10.0), (1.06, 0.999, 10.0), (1.1, 0.998, 10.0), (1.3, 0.999, 10.0), (1.55, 0.992, 10.0)], 1.767, -1.0, 2.0, 0, 49.270913, 0, 4.28, 0)
const VC78_MOLD = Glass(GlassID(AGF, 1767), 1, 2.72315491, -0.011795786, 0.0182393739, 0.000179456538, 1.67443241e-5, -5.29694392e-7, 0.0, 0.0, 0.0, 0.0, 0.2, 1.135, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0088, -1.0, -1.0, 0.0, 2.0, 2, 4.0, [(0.27, 0.032, 10.0), (0.28, 0.111, 10.0), (0.29, 0.232, 10.0), (0.3, 0.279, 10.0), (0.31, 0.552, 10.0), (0.32, 0.71, 10.0), (0.33, 0.826, 10.0), (0.34, 0.898, 10.0), (0.35, 0.943, 10.0), (0.36, 0.967, 10.0), (0.37, 0.982, 10.0), (0.38, 0.985, 10.0), (0.39, 0.988, 10.0), (0.4, 0.99, 10.0), (0.42, 0.99, 10.0), (0.44, 0.991, 10.0), (0.46, 0.994, 10.0), (0.48, 0.995, 10.0), (0.5, 0.995, 10.0), (0.55, 0.995, 10.0), (0.6, 0.997, 10.0), (0.7, 0.998, 10.0), (0.8, 0.998, 10.0), (1.06, 0.998, 10.0), (1.5, 0.998, 10.0), (2.0, 0.995, 10.0), (0.6, 0.999, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.75, 0.999, 10.0), (0.8, 0.999, 10.0), (0.9, 0.999, 10.0), (1.0, 0.999, 10.0), (1.06, 0.998, 10.0), (1.1, 0.998, 10.0), (1.3, 0.998, 10.0), (1.55, 0.993, 10.0)], 1.66547, -1.0, -1.0, 0, 55.117971, 0, 3.44, 0)
const H_ZLAF50B_MOLD = Glass(GlassID(AGF, 1768), 1, 3.15783794, -0.0153043586, 0.0266112335, 0.000705929142, -1.54365564e-5, 1.94771335e-6, 0.0, 0.0, 0.0, 0.0, 0.365, 1.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, -0.0093, -1.0, -1.0, 6.3, -1.0, 0, -1.0, [(0.28, 0.0, 10.0), (0.29, 0.0, 10.0), (0.3, 0.0, 10.0), (0.31, 0.0, 10.0), (0.32, 0.04, 10.0), (0.33, 0.14, 10.0), (0.34, 0.29, 10.0), (0.35, 0.46, 10.0), (0.36, 0.61, 10.0), (0.37, 0.74, 10.0), (0.38, 0.831, 10.0), (0.39, 0.888, 10.0), (0.4, 0.923, 10.0), (0.42, 0.956, 10.0), (0.44, 0.969, 10.0), (0.46, 0.976, 10.0), (0.48, 0.982, 10.0), (0.5, 0.986, 10.0), (0.55, 0.99, 10.0), (0.6, 0.992, 10.0), (0.65, 0.992, 10.0), (0.7, 0.994, 10.0), (0.8, 0.995, 10.0), (0.85, 0.997, 10.0), (0.9, 0.998, 10.0), (0.95, 0.998, 10.0), (1.0, 0.998, 10.0), (1.06, 0.998, 10.0), (1.2, 0.998, 10.0), (1.4, 0.998, 10.0), (1.6, 0.998, 10.0), (1.8, 0.997, 10.0), (2.0, 0.974, 10.0), (2.2, 0.926, 10.0), (2.4, 0.7, 10.0)], 1.7987, -1.0, -1.0, 0, 46.268881, 0, 4.72, 0)
const BACD14_MOLD = Glass(GlassID(AGF, 1769), 1, 2.51890371, -0.0118689364, 0.0122214182, 0.000789633586, -7.71764413e-5, 3.98293393e-6, 0.0, 0.0, 0.0, 0.0, 0.25, 1.55, 1.2212e-6, 0.0, 0.0, 0.0, 0.0, 0.0, 20.0, 0.002, -1.0, 2.7, 6.0, 3.0, 0, 4.0, [(0.28, 0.0, 10.0), (0.29, 0.01, 10.0), (0.3, 0.05, 10.0), (0.31, 0.17, 10.0), (0.32, 0.35, 10.0), (0.33, 0.56, 10.0), (0.34, 0.74, 10.0), (0.35, 0.85, 10.0), (0.36, 0.915, 10.0), (0.37, 0.952, 10.0), (0.38, 0.973, 10.0), (0.39, 0.985, 10.0), (0.4, 0.989, 10.0), (0.42, 0.992, 10.0), (0.44, 0.993, 10.0), (0.46, 0.994, 10.0), (0.48, 0.996, 10.0), (0.5, 0.999, 10.0), (0.55, 0.999, 10.0), (0.6, 0.999, 10.0), (0.65, 0.999, 10.0), (0.7, 0.999, 10.0), (0.75, 0.999, 10.0), (0.8, 0.999, 10.0), (0.9, 0.999, 10.0), (1.0, 0.999, 10.0), (1.06, 0.998, 10.0), (1.1, 0.998, 10.0), (1.3, 0.998, 10.0), (1.55, 0.993, 10.0)], 1.598511, -1.0, 5.0, 0, 60.231575, 0, 3.43, 0)
const N_LAK22_MOLD = Glass(GlassID(AGF, 1770), 2, 0.629412843, 0.00132678736, 1.03372876, 0.0158399692, 1.0775735, 104.339117, 0.0, 0.0, 0.0, 0.0, 0.31, 2.5, 1.36e-6, 1.49e-8, -1.29e-11, 3.41e-7, 2.09e-10, 0.262, 20.0, -0.0031, 2.3, 3.5, 6.6, 2.0, 0, 51.2, [(0.31, 0.02, 25.0), (0.32, 0.1, 25.0), (0.334, 0.35, 25.0), (0.35, 0.655, 25.0), (0.365, 0.84, 25.0), (0.37, 0.873, 25.0), (0.38, 0.92, 25.0), (0.39, 0.95, 25.0), (0.4, 0.964, 25.0), (0.405, 0.968, 25.0), (0.42, 0.973, 25.0), (0.436, 0.975, 25.0), (0.46, 0.98, 25.0), (0.5, 0.988, 25.0), (0.546, 0.993, 25.0), (0.58, 0.993, 25.0), (0.62, 0.991, 25.0), (0.66, 0.992, 25.0), (0.7, 0.994, 25.0), (1.06, 0.994, 25.0), (1.53, 0.978, 25.0), (1.97, 0.9, 25.0), (2.325, 0.62, 25.0), (2.5, 0.37, 25.0)], 1.646725, 1.0, 2.0, 0, 55.510774, 0, 3.768, 3)
end # module

max_stars_repo_name: rambunctiousapple/GlassCat

max_issues_repo_name: rambunctiousapple/GlassCat

max_forks_repo_name: rambunctiousapple/GlassCat


text:
using SafeTestsets
using Test

@safetestset "primefield" begin
    include("base/primefield.jl")
end
@safetestset "simplex" begin
    include("base/simplex.jl")
end
@safetestset "chainelement" begin
    include("base/chainelement.jl")
end
@safetestset "chain" begin
    include("base/chain.jl")
end
@safetestset "plotting" begin
    include("base/plotting.jl")
end

@safetestset "reducedmatrix" begin
    include("computation/reducedmatrix.jl")
end
@safetestset "zerodimensional" begin
    include("computation/zerodimensional.jl")
end

@safetestset "rips" begin
    include("filtrations/rips.jl")
end
@safetestset "cubical" begin
    include("filtrations/cubical.jl")
end
@safetestset "custom" begin
    include("filtrations/custom.jl")
end
@safetestset "alpha" begin
    include("filtrations/alpha.jl")
end
@safetestset "edgecollapse" begin
    include("filtrations/edgecollapse.jl")
end
@safetestset "new filtrations" begin
    include("filtrations/newfiltrations.jl")
end

@safetestset "cycles" begin
    include("extra/cycles.jl")
end
@safetestset "circularcoordinates" begin
    include("extra/circularcoordinates.jl")
end
@safetestset "mlj" begin
    include("extra/mlj.jl")
end

@safetestset "aqua" begin
    include("aqua.jl")
end
@safetestset "doctests" begin
    include("doctests.jl")
end

ext: jl


text:
# Use baremodule to shave off a few KB from the serialized `.ji` file
baremodule CMake_jll
using Base
using Base: UUID
import JLLWrappers

JLLWrappers.@generate_main_file_header("CMake")
JLLWrappers.@generate_main_file("CMake", UUID("3f4e10e2-61f2-5801-8945-23b9d642d0e6"))
end  # module CMake_jll


text:
# ............................................ FITS private sector ................................................................

using Dates

# ........................................... cast filename into a FITSname object .................................

"""
    cast_FITS_name(filename::String)

Decompose the FITS filename 'filnam.fits' into its name, prefix, numerator and extension.
#### Examples:
```
strExample = "T23.01.fits"
f = cast_FITS_name(strExample)
FITS_name("T23.01", "T23.", "01", ".fits")

f.name, f.prefix, f.numerator, f.extension
("T23.01", "T23.", "01", ".fits")
```
"""
function cast_FITS_name(str::String)

    Base.length(Base.strip(str)) == 0 && error("FitsError: filename required")

    ne = Base.findlast('.',str)                                     # ne: first digit of extension
    nl = Base.length(str)                                           # ne: length of file name including extension

    hasextension = ne == nothing ? false : true

    if hasextension
        strNam = str[1:ne-1]
        strExt = Base.rstrip(str[ne:nl])
        strExt = Base.Unicode.lowercase(strExt)
        isfits = strExt == ".fits" ? true : false
        n = Base.Unicode.isdigit(str[ne-1]) ? ne-1 : nothing        # n: last digit of numerator (if existent)
    else
        isfits = false
        n = Base.Unicode.isdigit(str[nl]) ? nl : nothing            # n: last digit of numerator (if existent)
    end

    isfits || error("FitsError: '$str': incorrect filename (lacks mandatory '.fits' extension)")

    if n != nothing
        strNum = ""
        while Base.Unicode.isdigit(str[n])
            strNum = str[n] * strNum
            n -= 1
        end
        strPre = str[1:n]
    else
        strPre = strNam
        strNum = " "
    end

    return FITS_name(strNam,strPre,strNum,strExt)

end

# ........................................... cast records into a FITS_header object .................................

function _cast_header(records::Array{String,1}, hduindex::Int)

    records = _rm_blanks(records)         # remove blank records to collect header records data (key, val, comment)
    nrec = length(records)                # number of keys in header with given hduindex

    keys = [Base.strip(records[i][1:8]) for i=1:nrec]
    vals = [records[i][9:10] ≠ "= " ? records[i][11:31] : _fits_parse(records[i][11:31]) for i=1:nrec]
    coms = [records[i][34:80] for i=1:nrec]
    dict = [keys[i] => vals[i] for i=1:nrec]
    maps = [keys[i] => i for i=1:nrec]

    return FITS_header(hduindex,records,keys,vals,coms,Dict(dict),Dict(maps))

end

# .................................. cast data into FITS_data objects ....................................

function _cast_data(hduindex::Int, hdutype::String, data)

    return FITS_data(hduindex, hdutype, data)

end

function _fits_bzero(E::DataType)

    return E ∉ [Int8, UInt16, UInt32, UInt64, UInt128] ? 0.0 : E == Int8 ? -128 : 2^(8E.size-1)

end

function _fits_eltype(nbits::Int, bzero::Number)

    E = nbits ==   8 ? UInt8 :
        nbits ==  16 ? Int16 :
        nbits ==  32 ? Int32 :
        nbits ==  64 ? Int64 : Int64

    E = nbits == -32 ? Float32 :
        nbits == -64 ? Float64 : E

    E = bzero == 0.0 ? E : E == UInt8 ? Int8 :
                           E == Int16 ? UInt16 :
                           E == Int32 ? UInt32 :
                           E == Int64 ? UInt64 : E

    return E

end

function _fits_new_records(key::String, val::Any, com::String)

    k = _format_recordkey(key)
    v = _format_recordvalue(val)
    c = _format_recordcomment(com,val)

    records = length(v * c) > 67 ? _format_recordslongstring(k, v, c) : [(k * "= " * v * " / " * c)]

    return records

end

function _fits_obsolete_records(h::FITS_header, recordindex::Int)

    n = recordindex

    if typeof(h.values[n]) <: AbstractString
       while (h.comments[n][end-1:end] == "&'") | (h.keys[n+1] == "CONTINUE")
          n += 1
       end
    end

    records = [h.records[i] for i=recordindex:n]

    return records

end

function _fits_parse(str::String) # routine

    T = Float32
    s = Base.strip(str)
    c = Base.collect(s)
    l = Base.length(s)

    Base.length(s) == 0 && return 0

    d = [Base.Unicode.isdigit(c[i]) for i ∈ Base.eachindex(c)]  # d: digits
    p = [Base.Unicode.ispunct(c[i]) for i ∈ Base.eachindex(c)]  # p: punctuation

    s[1] == '\'' && return str
    s[1] == '-'  && (d[1] = true) && (p[1] = false)     # change leading sign into digit (for type parsing only)
    s[1] == '+'  && (d[1] = true) && (p[1] = false)     # change leading sign into digit (for type parsing only)

    a = p .== d                                         # a: other non-digit or punctuation characters

    ia = [i for i ∈ Base.eachindex(a) if a[i]==1]       # ia: indices of nonzero elements of a
    ip = [i for i ∈ Base.eachindex(p) if p[i]==1]       # ip: indices of nonzero elements of p

    sd = Base.sum(d)                                    # sd: number of digits
    sp = Base.sum(p)                                    # sd: number of punctuation characters
    sa = Base.sum(a)                                    # sa: number of other non-digit or punctuation characters

    E = ['E','D','e','p']

    sd == l && return Base.parse(Int,s)
    sa >= 2 && return str
    sp >= 3 && return str
    sa == 1 && s == "T" && return true
    sa == 1 && s == "F" && return false
    sa == 0 && sp == 1 && s[ip[1]] == '.' && return Base.parse(T,s)
    sp == 0 && sa == 1 && s[ia[1]] ∈ E && return Base.parse(T,s)
    sp == 1 && s[ip[1]] == '-' && s[ip[1]-1] ∈ E && return Base.parse(T,s)
    sp == 1 && s[ip[1]] == '.' && s[ia[1]] ∈ E && ip[1] < ia[1]  && return Base.parse(T,s)
    sp == 2 && s[ip[1]] == '.' && s[ip[2]] == '-' && s[ip[2]-1] ∈ E && ip[1] < ia[1]  &&  return Base.parse(T,s)

    return error("FitsError: $str: parsing error")

end

function _format_key(key::String)::String

    key = Base.Unicode.uppercase(Base.strip(key))

    length(key) > 8 && error("FitsError: '$key': length exceeds 8 characters (FITS standard)")

    return key

end

function _format_recordcomment(com::String,val::Any)::String

    strErr = "FitsWarning: record truncated at 80 characters (FITS standard)"

    c = strip(com)
    v = _format_recordvalue(val)
    T = typeof(val)

    (T <: DateTime) | (T <: Real) ? (length(v * c) > 67 ? (c = c[1:67-length(v)]; println(strErr)) : 0) : 0

    return length(c) > 47 ? com : rpad(c,67-length(v))

end

function _format_recordkey(key::String)

    return rpad(key,8)

end

function _format_recordslongstring(key::String, val::AbstractString, com::String)

    lcom = length(com)
    last = lcom > 0 ? "&'" : "'"
    lval = length(val)

    records = [(key * "= " * val)]

    if  lval < 70
        records[1] = rpad(records[1][1:end-1] * last,80)
    elseif (lval == 70)
        chr = records[1][end-1]
        records[1] = records[1][1:end-2] * last
        push!(records,rpad(("CONTINUE  '" * chr * last),80))
    elseif lval > 70
         val = val[1:end-1]
        lval = length(val)
        nrec = (length(val)-68)÷67 + 1
        nrec > 1 ? [push!(records,("CONTINUE  '" * val[68i+2-i:68(i+1)-i] * "&'")) for i=1:nrec-1] : 0
         val = val[68(nrec)+2-nrec:end]; lval = length(val)
        (lcom == 0) & (lval == 1) ? (records[end] = records[end][1:end-2] * val * "'"; lval  =0) : 0
        lval > 0 ? push!(records,rpad(("CONTINUE  '" * val * last),80)) : 0
    end

    if lcom <= 65
        push!(records, rpad("CONTINUE  '' / " * com,80))
    else
        ncom = lcom÷64 + 1
        ncom > 1 ? [push!(records,"CONTINUE  '&' / " * com[64i+1:64(i+1)]) for i=0:ncom-2] : 0
        push!(records,rpad("CONTINUE  '' / " * com[64(ncom-1)+1:end],80))
    end

    return records

end

function _format_recordvalue(val::Any)

    typeof(val) <: AbstractChar && error("FitsError: '$val': invalid record value (not 'numeric', 'date' or 'single quote delimited string')")
    typeof(val) <: AbstractString ? (length(val) > 1 ? true : error("FitsError: string value not delimited by single quotes")) : 0

    typeof(val) <: AbstractString && return _format_recordvalue_charstring(val)
    typeof(val) <: DateTime && return _format_recordvalue_datetime(val)
    typeof(val) <: Real   && return _format_recordvalue_numeric(val)

    return error("FitsError: '$val' invalid record value type")

end

function _format_recordvalue_charstring(val::AbstractString)

    isascii(val) || error("FitsError: string not standard ASCII")

    isasciiprintable = !convert(Bool,sum(.!(31 .< Int.(collect(val)) .< 127)))

    isasciiprintable || error("FitsError: string not printable (not restricted to ASCII range 32-126)")

    v = (strip(val))

    (v[1] == '\'') & (v[end] == '\'') || error("FitsError: string value not delimited by single quotes")

    recordvalue = length(v) == 10 ? rpad(v,20) : length(v) < 21 ? rpad(v[1:end-1],19) * "'" : val

    return recordvalue

end

function _format_recordvalue_datetime(val::Dates.DateTime)

    return "'" * string(val) * "'"

end

function _format_recordvalue_numeric(val::Real)

    val = typeof(val) != Bool ? string(val) : val == true ? "T" : "F"

    return lpad(val,20)

end

function _hdu_count(o::IO)

    h = _header_pointers(o::IO)                 # h: start-of-header pointers

    return length(h)                            # number of HDUs

end

function _isavailable(filename::String, protect::Bool)

     return (!Base.Filesystem.isfile(filename) | !protect)

end

function _rm_blanks(records::Array{String,1})               # remove blank records

    record_B = repeat(' ',length(records[1]))

    return [records[i] for i ∈ findall(records .≠ record_B)]

end

function _validate_FITS_name(filename::String)

    return cast_FITS_name(filename)

end


text:
using Test, TransferEntropy

x, y, z = rand(100), rand(100), rand(100)

###########################################
# Set `dim` and infer `k`, `l` and `m`.
###########################################
tol =  1e-12
# Only with time series
@test all(transferentropy(x, y, z) .>= 0)
@test all(transferentropy(x, y, z, dim = 5) .>= 0 - tol)
@test_throws ArgumentError transferentropy(x, y, z, dim = 3)

# Only with time series
@test transferentropy(x, y, z, RectangularBinning(10)) >=  0 - tol
@test all(transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4]) .>=  0 - tol)
@test all(transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], dim = 4) .>=  0 - tol)
@test all(transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], dim = 5) .>=  0 - tol)

@test_throws ArgumentError transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], dim = 2)

###########################################
# Infer `dim` from `k`, `l` and `m`.
###########################################

# Only with time series
@test all(transferentropy(x, y, z, 1, 1, 1, 1) .>= 0 - tol)
@test all(transferentropy(x, y, z, 1, 2, 1, 1) .>= 0 - tol)
@test_throws ArgumentError transferentropy(x, y, z, 1, 1, 0, 1)

# Only with time series
@test transferentropy(x, y, z, RectangularBinning(10), 1, 1, 1, 1) >= 0 - tol
@test all(transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], 1, 1, 1, 1) .>= 0 - tol)
@test all(transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], 1, 2, 1, 1) .>= 0 - tol)

@test_throws ArgumentError transferentropy(x, y, z, [RectangularBinning(x) for x in 2:4], 1, 0, 1, 1)


text:
# Tests for partial information decomposition function

# Test partial information decomposition for AND gate
arr_and = [arr1[i] >= 0.5 && arr2[i] >= 0.5 ? 1.0 : 0.0 for i in 1:length(arr1)]
pid = get_partial_information_decomposition(arr1, arr2, arr_and)
@test pid["redundancy"] ≈ 0.3 atol = 0.1
@test pid["unique_1"] ≈ 0 atol = 0.1
@test pid["unique_2"] ≈ 0 atol = 0.1
@test pid["synergy"] ≈ 0.5 atol = 0.1
println("Partial information decomposition with AND gate passed.")

pid = get_partial_information_decomposition(arr1, arr2, arr_and, all_orientations = true)
@test pid["z"]["redundancy"] ≈ 0.3 atol = 0.1
@test pid["z"]["unique_1"] ≈ 0 atol = 0.1
@test pid["z"]["unique_2"] ≈ 0 atol = 0.1
@test pid["z"]["synergy"] ≈ 0.5 atol = 0.1
println("Partial information decomposition with AND gate (all orientations) passed.")

# Test redundancy for AND gate
redundancy = get_redundancy(arr1, arr2, arr_and)
@test redundancy ≈ 0.3 atol = 0.1
println("Redundancy with AND gate passed.")

redundancy = get_redundancy(arr1, arr2, arr_and, all_orientations = true)[1]
@test redundancy ≈ 0.3 atol = 0.1
println("Redundancy with AND gate (all orientations) passed.")

# Test unique information for AND gate
mutual_information = get_mutual_information(arr1, arr_and)
@test apply_unique_information_formula(mutual_information, redundancy) ≈ 0 atol = 0.1
println("Unique information with AND gate passed.")

# Test synergy for AND gate
interaction_information = get_interaction_information(arr1, arr2, arr_and)
@test apply_synergy_formula(interaction_information, redundancy) ≈ 0.5 atol = 0.1
println("Synergy with AND gate passed.")


text:
module FeatureTransform

using ..ImageMorphology: SplitAxis, SplitAxes
using ..ImageCore

export feature_transform, distance_transform

"""
    feature_transform(img::AbstractArray{Bool, N};
                      weights=nothing, nthreads=Threads.nthreads()) -> F

Compute the feature transform of a binary image `I`, finding the
closest "feature" (positions where `I` is `true`) for each location in
`I`.  Specifically, `F[i]` is a `CartesianIndex` encoding the position
closest to `i` for which `I[F[i]]` is `true`.  In cases where two or
more features in `I` have the same distance from `i`, an arbitrary
feature is chosen. If `I` has no `true` values, then all locations are
mapped to an index where each coordinate is `typemin(Int)`.

Optionally specify the weight `w` assigned to each coordinate.  For
example, if `I` corresponds to an image where voxels are anisotropic,
`w` could be the voxel spacing along each coordinate axis. The default
value of `nothing` is equivalent to `w=(1,1,...)`.

See also: [`distance_transform`](@ref).

# Citation

'A Linear Time Algorithm for Computing Exact Euclidean Distance
Transforms of Binary Images in Arbitrary Dimensions' [Maurer et al.,
2003] (DOI: 10.1109/TPAMI.2003.1177156)
"""
function feature_transform(img::AbstractArray{<:Union{Bool,AbstractGray{Bool}},N};
                           weights::Union{Nothing,NTuple{N}}=nothing,
                           nthreads::Int = length(img) < 1000 ? 1 : Threads.nthreads()) where N
    nthreads > 0 || error("the number of threads must be positive, got $nthreads")
    N == 0 && return reshape([CartesianIndex()])
    # Allocate the output
    F = similar(img, CartesianIndex{N})
    axsimg = axes(img)
    # To allocate temporary storage for voronoift!, compute one
    # element (so we have the proper type)
    fi = first(CartesianIndices(axsimg))
    drft = DistRFT(fi, weights, (), Base.tail(fi.I))
    if nthreads == 1 || N == 1
        tmp = typeof(drft)[]
        computeft!(F, img, axsimg, CartesianIndex(), weights, tmp)
        # Finish the last dimension (for multithreading, we avoid doing it in computeft!)
        finishft!(F, img, axsimg, CartesianIndex(), weights, tmp)
    else
        tmps = [typeof(drft)[] for _ = 1:nthreads] # temporary storage (one per thread)
        saxs = SplitAxes(axsimg, nthreads - 0.2)   # give main thread less work since it also schedules the others
        tasks = [Threads.@spawn computeft!(F, img, saxs[i], CartesianIndex(), weights, tmps[i]) for i = 2:nthreads]
        computeft!(F, img, saxs[1], CartesianIndex(), weights, tmps[1])
        foreach(wait, tasks)
        # Finish the last dimension
        saxs1 = SplitAxes(axsimg[1:N-1], nthreads - 0.2)
        tasks = [Threads.@spawn finishft!(F, img, (saxs1[i]..., axsimg[end]), CartesianIndex(), weights, tmps[i]) for i = 2:nthreads]
        finishft!(F, img, (saxs1[1]..., axsimg[end]), CartesianIndex(), weights, tmps[1])
        foreach(wait, tasks)
    end
    return F
end

"""
    distance_transform(F::AbstractArray{CartesianIndex}, [w=nothing]) -> D

Compute the distance transform of `F`, where each element `F[i]`
represents a "target" or "feature" location assigned to `i`.
Specifically, `D[i]` is the distance between `i` and `F[i]`.
Optionally specify the weight `w` assigned to each coordinate; the
default value of `nothing` is equivalent to `w=(1,1,...)`.

See also: [`feature_transform`](@ref).
"""
function distance_transform(F::AbstractArray{CartesianIndex{N},N}, w::Union{Nothing,NTuple{N}}=nothing) where N
    # To allocate the proper output type, compute the distance for one element
    R = CartesianIndices(axes(F))
    dst = wnorm2(zero(eltype(R)), w)
    D = similar(F, typeof(sqrt(dst)))

    ∅ = nullindex(F)
    @inbounds for i in R
        fi = F[i]
        D[i] = fi == ∅ ? Inf : sqrt(wnorm2(fi - i, w))
    end

    D
end

# This recursive implementation computes the feature transform, other than for finishing the
# work along the final axis (axis `N` for an `N` dimensional array).
# Omission of the final axis makes it easy to implement multithreading.
# You can finish the final axis with a call to `finishft!` with `jpost = CartesianIndex()`.
function computeft!(F, img, axsimg, jpost::CartesianIndex{K}, pixelspacing, tmp) where K
    # tmp is workspace for voronoift!
    ∅ = nullindex(F)                             # sentinel position
    if K == ndims(img)-1                           # innermost loop (d=1 case, line 1)
        # Fig. 2, lines 2-8
        @inbounds @simd for i1 in axes(img, 1)
            F[i1, jpost] = gray(img[i1, jpost]) ? CartesianIndex(i1, jpost) : ∅
        end
    else                                         # recursively handle trailing dimensions
        # Fig. 2, lines 10-12
        for i1 in axsimg[ndims(img) - K]
            computeft!(F, img, axsimg, CartesianIndex(i1, jpost), pixelspacing, tmp)
        end
    end
    K == 0 && return F                           # defer the final axis, where threads will be split across next-to-last axis
    return finishft!(F, img, axsimg, jpost, pixelspacing, tmp)
end

function finishft!(F, img, axsimg, jpost, pixelspacing, tmp)
    # Fig. 2, lines 14-20
    axespre = truncatet(axsimg, jpost)          # first N-K-1 axes (these are "finished" within each K+1-dimensional slice)
    for jpre in CartesianIndices(axespre)
        voronoift!(F, img, jpre, jpost, pixelspacing, tmp)     # finish axis N-K in K-dimensional slice `jpost`
    end
    return F
end

function voronoift!(F, img, jpre, jpost, pixelspacing, tmp)
    d = length(jpre)+1   # axis to work along
    ∅ = nullindex(F)
    empty!(tmp)
    for i in axes(img, d)
        # Fig 3, lines 3-13
        xi = CartesianIndex(jpre, i, jpost)
        @inbounds fi = F[xi]
        if fi != ∅
            fidist = DistRFT(fi, pixelspacing, jpre, jpost)
            if length(tmp) < 2
                push!(tmp, fidist)
            else
                @inbounds while length(tmp) >= 2 && removeft(tmp[end-1], tmp[end], fidist)
                    pop!(tmp)
                end
                push!(tmp, fidist)
            end
        end
    end
    nS = length(tmp)
    nS == 0 && return F
    # Fig 3, lines 18-24
    l = 1
    @inbounds fthis = tmp[l].fi
    for i in axes(img, d)
        xi = CartesianIndex(jpre, i, jpost)
        d2this = wnorm2(xi-fthis, pixelspacing)
        while l < nS
            @inbounds fnext = tmp[l+1].fi
            d2next = wnorm2(xi-fnext, pixelspacing)
            if d2this > d2next
                d2this, fthis = d2next, fnext
                l += 1
            else
                break
            end
        end
        @inbounds F[xi] = fthis
    end
    F
end

## Utilities

# Stores a feature location and its distance from the hyperplane Rd
struct DistRFT{N,T}
    fi::CartesianIndex{N}
    dist2::T
    d::Int  # the coordinate in dimension d
end

"""
    DistRFT(fi::CartesianIndex, w, jpre, jpost)

Bundles a feature `fi` together with its distance from the line Rd,
where Rd is specified by `(jpre..., :, jpost...)`. `w` is the
weighting applied to each coordinate, and must be `nothing` or be a
tuple with the same number of coordiantes as `fi`.

"""
function DistRFT(fi::CartesianIndex, w, jpre::CartesianIndex, jpost::CartesianIndex)
    d2pre, ipost, wpost = dist2pre(fi.I, w, jpre.I)
    d2post = wnorm2(CartesianIndex(ipost) - jpost, wpost)
    @inbounds fid = fi[length(jpre)+1]
    DistRFT(fi, d2pre + d2post, fid)
end
DistRFT(fi::CartesianIndex, w, jpre::Tuple, jpost::Tuple) =
    DistRFT(fi, w, CartesianIndex(jpre), CartesianIndex(jpost))

@inline function removeft(u, v, w)
    a, b, c = v.d-u.d, w.d-v.d, w.d-u.d
    c*v.dist2 - b*u.dist2 - a*w.dist2 > a*b*c
end

"""
    truncatet(inds, j::CartesianIndex{K})

Discard the last `K+1` elements of the tuple `inds`.
"""
truncatet(inds, j::CartesianIndex) = _truncatet((), inds, j)
_truncatet(out, inds::NTuple{N}, j::CartesianIndex{N}) where {N} = Base.front(out)
@inline _truncatet(out, inds, j) = _truncatet((out..., inds[1]), Base.tail(inds), j)

if VERSION < v"1.1"
    nullindex(A::AbstractArray{T,N}) where {T,N} = typemin(Int)*one(CartesianIndex{N})
else
    # This is the proper implementation
    nullindex(A::AbstractArray{T,N}) where {T,N} = typemin(Int)*oneunit(CartesianIndex{N})
end

"""
    wnorm2(x::CartesianIndex, w)

Compute `∑ (w[i]*x[i])^2`.  Specifying `nothing` for `w` is equivalent to `w = (1,1,...)`.
"""
wnorm2(x::CartesianIndex, w) = _wnorm2(0, x.I, w)
_wnorm2(s, ::Tuple{}, ::Nothing)    = s
_wnorm2(s, ::Tuple{}, ::Tuple{}) = s
@inline _wnorm2(s, x, w::Nothing) = _wnorm2(s + sqr(x[1]), Base.tail(x), w)
@inline _wnorm2(s, x, w) = _wnorm2(s + sqr(w[1]*x[1]), Base.tail(x), Base.tail(w))

"""
    dist2pre(x, w, jpre) -> s, xpost, wpost

`s` is equivalent to `wnorm2(x[1:length(jpre)]-jpre, w)`. `xpost` and
`wpost` contain the trailing indices of `x` and `w` (skipping the
element `length(jpre)+1`).
"""
dist2pre(x::Tuple, w, jpre) = _dist2pre(0, x, w, jpre)
_dist2pre(s, x, w::Nothing, ::Tuple{}) = s, Base.tail(x), w
_dist2pre(s, x, w,       ::Tuple{}) = s, Base.tail(x), Base.tail(w)
@inline _dist2pre(s, x, w::Nothing, jpre) = _dist2pre(s + sqr(x[1]-jpre[1]), Base.tail(x), w, Base.tail(jpre))
@inline _dist2pre(s, x, w, jpre) = _dist2pre(s + sqr(w[1]*(x[1]-jpre[1])), Base.tail(x), Base.tail(w), Base.tail(jpre))

@inline sqr(x) = x*x

end # module


text:
module REPLMode

#   This file is part of VerTeX.jl. It is licensed under the MIT license
#   Copyright (C) 2019 Michael Reed

# This file is adapted from Julia. License is MIT: https://julialang.org/license

using Markdown
using UUIDs, Pkg

import REPL
import REPL: LineEdit, REPLCompletions

using Pkg.Types, Pkg.Operations #, Pkg.Display

vtxerror(msg::String...) = throw(PkgError(join(msg)))

#########################
# Specification Structs #
#########################

#import Pkg.REPLMode: OptionSpec, OptionSpecs, ArgSpec, CommandSpec, CommandSpecs, SuperSpecs, QString, unwrap, Option, wrap_option, is_opt, parse_option, Statement, lex, tokenize, core_parse, parse, APIOptions, Command, enforce_option, MiniREPL

#---------#
# Options #
#---------#
const OptionDeclaration = Vector{Pair{Symbol,Any}}

#----------#
# Commands #
#----------#
@enum(CommandKind, CMD_HELP, CMD_VIM, CMD_PDF, CMD_STATUS, CMD_DICT,
                 CMD_RANGER, CMD_PREVIEW, CMD_SEARCH, CMD_CD, CMD_CDPKG,
                 CMD_GRAPH)
#=@enum(CommandKind, CMD_HELP, CMD_RM, CMD_ADD, CMD_DEVELOP, CMD_UP,
                   CMD_STATUS, CMD_TEST, CMD_GC, CMD_BUILD, CMD_PIN,
                   CMD_FREE, CMD_GENERATE, CMD_RESOLVE, CMD_PRECOMPILE,
                   CMD_INSTANTIATE, CMD_ACTIVATE, CMD_PREVIEW,
                   CMD_REGISTRY_ADD, CMD_REGISTRY_RM, CMD_REGISTRY_UP, CMD_REGISTRY_STATUS
                   )=#
const CommandDeclaration = Vector{Pair{Symbol,Any}}

include("specs.jl")

#############
# Execution #
#############
function do_cmd(repl::REPL.AbstractREPL, input::String; do_rethrow=false)
    try
        statements = parse(input)
        commands   = map(Command, statements)
        for command in commands
            do_cmd!(command, repl)
        end
    catch err
        do_rethrow && rethrow()
        if err isa PkgError || err isa ResolverError
            Base.display_error(repl.t.err_stream, ErrorException(sprint(showerror, err)), Ptr{Nothing}[])
        else
            Base.display_error(repl.t.err_stream, err, Base.catch_backtrace())
        end
    end
end

function do_cmd!(command::Command, repl)
    context = Dict{Symbol,Any}(:preview => command.preview)

    # REPL specific commands
    command.spec.kind == CMD_HELP && return Base.invokelatest(do_help!, command, repl)

    # API commands
    # TODO is invokelatest still needed?
    if applicable(command.spec.handler, context, command.arguments, command.options)
        Base.invokelatest(command.spec.handler, context, command.arguments, command.options)
    else
        Base.invokelatest(command.spec.handler, command.arguments, command.options)
    end
end

function parse_command(words::Vector{QString})
    statement, word = core_parse(words; only_cmd=true)
    if statement.super === nothing && statement.spec === nothing
        vtxerror("invalid input: `$word` is not a command")
    end
    return statement.spec === nothing ?  statement.super : statement.spec
end

function do_help!(command::Command, repl::REPL.AbstractREPL)
    disp = REPL.REPLDisplay(repl)
    if isempty(command.arguments)
        Base.display(disp, help)
        return
    end
    help_md = md""

    cmd = parse_command(command.arguments)
    if cmd isa String
        # gather all helps for super spec `cmd`
        all_specs = sort!(unique(values(super_specs[cmd]));
                          by=(spec->spec.canonical_name))
        for spec in all_specs
            isempty(help_md.content) || push!(help_md.content, md"---")
            push!(help_md.content, spec.help)
        end
    elseif cmd isa CommandSpec
        push!(help_md.content, cmd.help)
    end
    !isempty(command.arguments) && @warn "More than one command specified, only rendering help for first"
    Base.display(disp, help_md)
end

raw(a) = [x.raw for x ∈ a]

do_vim!(a,b) = texedit(raw(a)...)

do_pdf!(a,b) = pdf(load(raw(a)...))

do_status!(a,b) = display_manifest(raw(a)...)

do_dict!(a,b) = display_dictionary()

function do_ranger!(a,b)
    dir = joinpath(homedir(),".julia","config","vtx")
    repo = expanduser(getdepot()[length(a)<1 ? "julia" : a[1].raw])
    run(`ranger $repo --choosefile=$dir`)
    try
        texedit(read(`cat $dir`,String))
        run(`rm $dir`)
    catch
    end
end

do_preview!(a,b) = preview_vertex(load(raw(a)...))

do_search!(a,b) = preview_vertex.(searchvtx([:search],raw(a)))

function do_cd!(a,b)
    if length(a)<1
        dir = joinpath(homedir(),".julia","config","cd")
        run(`ranger $(pwd()) --choosedir=$dir`)
        cd(read(`cat $dir`,String))
    else
        cd(joinpath(expanduser(getdepot()[a[1].raw])))
    end
    println(pwd())
end

do_cdpkg!(a,b) = (cdpkg(a[1].raw); println(pwd()))

function do_graph!(a,b)
    path = joinpath("/tmp","vtx-data.pdf")
    drawgraph(path)
    zathura(path)
end

######################
# REPL mode creation #
######################

# Provide a string macro pkg"cmd" that can be used in the same way
# as the REPLMode `pkg> cmd`. Useful for testing and in environments
# where we do not have a REPL, e.g. IJulia.

const minirepl = Ref{MiniREPL}()

__init__() = minirepl[] = MiniREPL()

macro vtx_str(str::String)
    :($(do_cmd)(minirepl[], $str; do_rethrow=true))
end

vtxstr(str::String) = do_cmd(minirepl[], str; do_rethrow=true)

struct VtxCompletionProvider <: LineEdit.CompletionProvider end

function LineEdit.complete_line(c::VtxCompletionProvider, s)
    partial = REPL.beforecursor(s.input_buffer)
    full = LineEdit.input_string(s)
    ret, range, should_complete = completions(full, lastindex(partial))
    return ret, partial[range], should_complete
end

prev_project_file = nothing
prev_project_timestamp = nothing
prev_prefix = ""

function promptf()
    #=global prev_project_timestamp, prev_prefix, prev_project_file
    project_file = try
        Types.find_project_file()
    catch
        nothing
    end=#
    prefix = ""
    #=if project_file !== nothing
        if prev_project_file == project_file && prev_project_timestamp == mtime(project_file)
            prefix = prev_prefix
        else
            project = try
                Types.read_project(project_file)
            catch
                nothing
            end
            if project !== nothing
                projname = project.name
                name = projname !== nothing ? projname : basename(dirname(project_file))
                prefix = string("(", name, ") ")
                prev_prefix = prefix
                prev_project_timestamp = mtime(project_file)
                prev_project_file = project_file
            end
        end
    end=#
    return prefix * "vtx> "
end

# Set up the repl Pkg REPLMode
function create_mode(repl, main)
    vtx_mode = LineEdit.Prompt(promptf;
        prompt_prefix = repl.options.hascolor ? Base.text_colors[:white] : "",
        prompt_suffix = "",
        complete = VtxCompletionProvider(),
        sticky = true)

    vtx_mode.repl = repl
    hp = main.hist
    hp.mode_mapping[:pkg] = vtx_mode
    vtx_mode.hist = hp

    search_prompt, skeymap = LineEdit.setup_search_keymap(hp)
    prefix_prompt, prefix_keymap = LineEdit.setup_prefix_keymap(hp, vtx_mode)

    vtx_mode.on_done = (s, buf, ok) -> begin
        ok || return REPL.transition(s, :abort)
        input = String(take!(buf))
        REPL.reset(repl)
        do_cmd(repl, input)
        REPL.prepare_next(repl)
        REPL.reset_state(s)
        s.current_mode.sticky || REPL.transition(s, main)
    end

    mk = REPL.mode_keymap(main)

    shell_mode = nothing
    for mode in Base.active_repl.interface.modes
        if mode isa LineEdit.Prompt
            mode.prompt == "shell> " && (shell_mode = mode)
        end
    end

    repl_keymap = Dict()
    if shell_mode != nothing
        repl_keymap[';'] = function (s,o...)
            if isempty(s) || position(LineEdit.buffer(s)) == 0
                buf = copy(LineEdit.buffer(s))
                LineEdit.transition(s, shell_mode) do
                    LineEdit.state(s, shell_mode).input_buffer = buf
                end
            else
                LineEdit.edit_insert(s, ';')
            end
        end
    end

    b = Dict{Any,Any}[
        skeymap, repl_keymap, mk, prefix_keymap, LineEdit.history_keymap,
        LineEdit.default_keymap, LineEdit.escape_defaults
    ]
    vtx_mode.keymap_dict = LineEdit.keymap(b)
    return vtx_mode
end

function repl_init(repl)
    main_mode = repl.interface.modes[1]
    vtx_mode = create_mode(repl, main_mode)
    push!(repl.interface.modes, vtx_mode)
    keymap = Dict{Any,Any}(
        ',' => function (s,args...)
            if isempty(s) || position(LineEdit.buffer(s)) == 0
                buf = copy(LineEdit.buffer(s))
                LineEdit.transition(s, vtx_mode) do
                    LineEdit.state(s, vtx_mode).input_buffer = buf
                end
            else
                LineEdit.edit_insert(s, ',')
            end
        end
    )
    main_mode.keymap_dict = LineEdit.keymap_merge(main_mode.keymap_dict, keymap)
    return
end

########
# SPEC #
########
include("completions.jl")
include("args.jl")
include("cmd.jl")
super_specs = SuperSpecs(command_declarations)

########
# HELP #
########
function canonical_names()
    # add "package" commands
    xs = [(spec.canonical_name => spec) for spec in unique(values(super_specs["package"]))]
    sort!(xs, by=first)
    # add other super commands, e.g. "registry"
    for (super, specs) in super_specs
        super != "package" || continue # skip "package"
        temp = [(join([super, spec.canonical_name], " ") => spec) for spec in unique(values(specs))]
        append!(xs, sort!(temp, by=first))
    end
    return xs
end

function gen_help()
    help = md"""
**Welcome to the VerTeX REPL-mode**. To return to the `julia>` prompt, either press
backspace when the input line is empty or press Ctrl+C.
**Synopsis**
    vtx> cmd [opts] [args]
Multiple commands can be given on the same line by interleaving a `;` between the commands.
**Commands**
"""
    for (command, spec) in canonical_names()
        push!(help.content, Markdown.parse("`$command`: $(spec.description)"))
    end
    return help
end

const help = gen_help()

end #module


text:
# Stuff We need to maintain compatibility with the matlab api

## BasisFamily stuff

# needed for the `convert(::Basis, ::Dict)` method below
Base.convert(::Type{BasisFamily}, s::Symbol) =
    s == :spli ? Spline() :
    s == :cheb ? Cheb() :
    s == :lin  ? Lin() :
    error("Unknown basis type")

old_name(::Lin) = :lin
old_name(::Cheb) = :cheb
old_name(::Spline) = :spli

## BasisParams stuff

# needed for the `convert(::Basis, ::Dict)` method below
Base.convert(::Type{BasisParams}, p::Vector{Any}) =
    length(p) == 3 && isa(p[1], Number) ? ChebParams(p...) :
    length(p) == 3 ? SplineParams(p...) :
    length(p) == 2 ? LinParams(p...) :
    error("Unknown parameter type")

old_name(::LinParams) = :lin
old_name(::ChebParams) = :cheb
old_name(::SplineParams) = :spli

old_params(p::LinParams) = Any[p.breaks, p.evennum]
old_params(p::ChebParams) = Any[p.n, p.a, p.b]
old_params(p::SplineParams) = Any[p.breaks, p.evennum, p.k]

## Basis stuff

# convert old API to new API
function Base.convert(::Type{Basis}, b::Dict{Symbol, Any})
    btype = map(x->convert(BasisFamily, x), b[:basetype])
    param = BasisParams[convert(BasisParams, x) for x in b[:params]]
    Basis(param...)
end

# convert new API to old API
function revert(b::Basis)
    B = Dict{Symbol, Any}()
    B[:d] = ndims(b)
    the_nodes = nodes.(b.params)
    B[:n] = [length(vec) for vec in the_nodes]
    B[:a] = [minimum(vec) for vec in the_nodes]
    B[:b] = [maximum(vec) for vec in the_nodes]
    B[:basetype] = Symbol[old_name(bt) for bt in b.params]
    B[:params] = Any[old_params(p) for p in b.params]
    B
end

# add method to funbasex that creates a BasisStructure
function funbasex(basis::Basis, x=nodes(basis)[1], order=0,
                  bformat::BasisMatrices.ABSR=Direct())
    BasisMatrix(Nothing, basis, bformat, x, order)
end

funbase(basis::Basis, x=nodes(basis)[1], order=fill(0, 1, ndims(basis))) =
    funbasex(basis, x, order, Expanded()).vals[1]


text:
import GSL.deriv_central
using Base.Test

# verify derivatives of f by finite differences for functions of
# numeric vectors that return a tuple (value, derivient).
function test_deriv(f::Function, x::FloatingPoint, claimed_deriv::FloatingPoint)
    numeric_deriv, abs_err = deriv_central(f, x, 1e-3)
    info("deriv expected $numeric_deriv; got $(claimed_deriv) [tol: $abs_err]")
    obs_err = abs(numeric_deriv - claimed_deriv)
    @test obs_err < 1e-11 || abs_err < 1e-4 || abs_err / abs(numeric_deriv) < 1e-4
    @test_approx_eq_eps numeric_deriv claimed_deriv 10abs_err
end

# test the test
test_deriv( (x)->x^2, 4., 8. )


text:
using ScenTrees
using Test
using Statistics: std
using CSV, DataFrames, XLSX

@testset "ScenTrees.jl" begin
    @testset "A sample of a Scenario Tree 1D" begin
        x = Tree([1,3,3,3,3],1)
        @test typeof(x) == Tree
        @test length(x.parent) == 121
        @test length(x.state) == length(x.probability) == length(x.parent) == 121
        @test sum(x.probability) ≈ 41.0
        @test length(x.children) == 41
    end
    @testset "A sample of a Scenario Tree 2D" begin
        y = Tree([1,3,3,3,3],2)
        @test typeof(y) == Tree
        @test length(y.parent) == 121
        @test length(y.probability) == length(y.parent) == 121
        @test length(y.state) == length(y.parent)*2 == 242
        @test sum(y.probability) ≈ 41.0
        @test length(y.children) == 41
    end
    @testset "ScenTrees.jl - Tree Approximation 1D" begin
        paths = [GaussianSamplePath1D,RunningMaximum1D]
        trees = [Tree([1,2,2,2]),Tree([1,3,3,3])]
        samplesize = 100000
        pNorm = 2
        rWasserstein = 2

        for path in paths
            for newtree in trees
                TreeApproximation!(newtree,path,samplesize,pNorm,rWasserstein)
                @test length(newtree.parent) == length(newtree.state)
                @test length(newtree.parent) == length(newtree.probability)
                @test length(stage(newtree)) == length(newtree.parent)
                @test height(newtree) == maximum(stage(newtree))
                @test round(sum(leaves(newtree)[3]),digits=1) == 1.0   #sum of unconditional probabilities of the leaves
            end
        end
    end
    @testset "ScenTrees.jl - Tree Approximation 2D" begin
        twoD= TreeApproximation!(Tree([1,3,3,3],2),GaussianSamplePath2D,100000,2,2)
        @test size(twoD.state,2) == 2
        @test size(twoD.state,1) == length(twoD.parent) == length(twoD.probability)
    end

    @testset "ScenTree.jl - Lattice Approximation" begin
        tstLat = LatticeApproximation([1,2,3,4],GaussianSamplePath1D,500000)
        @test length(tstLat.state) == length(tstLat.probability)
        @test round.(sum.(tstLat.probability), digits = 1)  == [1.0, 1.0, 1.0, 1.0] #sum of probs at every stage
    end
    @testset "ScenTrees.jl - Test Example Data" begin
        data = CSV.read("data5.csv")
        gsData = Matrix(data)
        df = DataFrame(XLSX.readtable("Mappe1.xlsx", "Sheet1")...)
        df1 = Matrix(df)
        df1 = convert(Array{Float64,2},df1)
        df2 = DataFrame(XLSX.readtable("Mappe1.xlsx", "Sheet2")...)
        df22 = Matrix(df2)
        df22 = convert(Array{Float64,2},df22)
        RandomWalkData = CSV.read("RandomDataWalk.csv")
        RWData = Matrix(RandomWalkData)

        @test size(gsData) ==(100,10)
        @test size(df1) == (1000,7)
        @test size(df22) == (1000,4)
        @test size(RWData) == (1000,5)

        sd1 = zeros(5)
        sd2 = zeros(7)

        for t = 1:size(RWData,2)
            sd1[t] = std(RWData[:,t])
        end

        for t = 1:size(df1,2)
            sd2[t] = std(df1[:,t])
        end
        @test (sd1 .< 5) == Bool[true, true, true, true, true]
        @test (sd2 .< 10) == Bool[true, true, true, true, true, true, true]
    #end
#     @testset "ScenTrees.jl - Test Kernel trajectory creation" begin
#         a = KernelScenarios(gsData)
#         b = KernelScenarios(df1)
#         c = KernelScenarios(df22)
#         d = KernelScenarios(RWData)
#         @test length(a()) == length(gsData,2)
#         @test length(b()) == length(df1,2)
#         @test length(c()) == length(df22,2)
#         @test length(d()) == length(RWData,2)
#     end
    #@testset "ScenTrees.jl - Test Kernel Lattice creation" begin
        LatFromKernel = LatticeApproximation([1,3,4,5,6],KernelScenarios(RWData),100000)
        @test round.(sum.(LatFromKernel.probability),digits=1) == [1.0, 1.0, 1.0, 1.0, 1.0]
        @test length(LatFromKernel.state) == length(LatFromKernel.probability)
    end
end


text:
"""
    function integratorHeun_(p, platform)

Adapter for the Heun integration step method as described in [Stochastic Improved Euler](https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_method_(SDE)) integrator in Îto prescription.

```math
K₁ = f(x(t),t)*Δt + g(x(t),t)(ΔW-S Δt^{1/2} )
```
```math
K₂ = f(x(t)+K₁,t+Δt)*Δt + g(x(t)+K₁,t+Δt)(ΔW+SΔt^{1/2} )
```
```math
x(t+Δt) = x(t) + (K₁+K₂)/2
```
where ``S`` is a random variable chosen to be ±1 with probability 1/2 and
``ΔW`` is a Wiener process with step proportional to ``Δt^{1/2}``.

The algorithm can be reduced to six kernels invocations performing the following actions:
 - Clean the interaction parameters array
 - Compute interaction parameters at original position v₀  (if there are interaction parameters)
 - Compute K₂ and intermediate v₁
 - Clean the interaction parameters array
 - Compute interaction parameters at intermediate position vᵢₙₜ  (if there are interaction parameters)
 - Compute K₂ parameters and final position v₁
"""
function addIntegratorHeun_!(p::Program_, platform::String)

    if  "Equation" in keys(p.agent.declaredUpdates)

        code = p.agent.declaredUpdates["Equation"]

        #Create first interaction parameter kernel if there is any interaction parameter updated
        if "UpdateInteraction" in keys(p.agent.declaredUpdates)

            k1 = loop_[p.neighbors](p,p.agent.declaredUpdates["UpdateInteraction"],platform)
            k1 = vectorize_(p.agent,k1,p,interaction=true)
            k1 = wrapInFunction_(:interactionStep1_,k1)
            push!(p.declareF.args,k1)

        end

        #Create first integration step kernel
        #Make the substitution dW -> (dW-S) and count number of calls to dW
        m1 = [i for i in split(string(gensym("dW")),"#") if i != ""]
        codeK1 = gensym_ids(postwalk(x->@capture(x,dW) ? :($(gensym("dW"))) : x, code))
        codeK1 = postwalk(x->@capture(x,v_) && (split(string(v),"_")[1] == "dW") ? :(dW[ic1_,$(Meta.parse(split(string(v),"_")[2]))]) : x, codeK1)
        codeK1 = postwalk(x->@capture(x,dW[ic1_,pos_]) ? :(dW[ic1_,$pos]-S_[ic1_,$pos]) : x, codeK1)
        m2 = [i for i in split(string(gensym("dW")),"#") if i != ""]
        m = Meta.parse(m2[2])-Meta.parse(m1[2])-1

        for (i,j) in enumerate(p.agent.declaredSymbols["Local"])
            if j in keys(p.update["Variables"])
                ii = p.update["Local"][j]
                ki = p.update["Variables"][j]
                codeK1 = postwalk(x -> @capture(x,g_(s_)) && g == DIFFSYMBOL && s == j ? :(K₁_[ic1_,$ki]) : x, codeK1)
                #Saves intermediate step vᵢₙₜ in final pos localVCopy
                push!(codeK1.args,:(localVCopy[ic1_,$ii] = localV[ic1_,$i] + K₁_[ic1_,$ki]))
            end
        end
        codeK1 = vectorize_(p.agent,codeK1,p)
        if inexpr(codeK1,:dW) #Add initialisation is necessary
            for i in 1:m
                pushfirst!(codeK1.args,:(dW[ic1_,$i] = Uniform(0,1)*sqrt(dt)))
                pushfirst!(codeK1.args,:(S_[ic1_,$i] = 2*(round(rand())- .5)*sqrt(dt)))
            end
        end
        k2 = simpleFirstLoopWrapInFunction_(platform,:integrationStep1_,codeK1) #First function declaration
        push!(p.declareF.args,k2)
        push!(p.declareVar.args,:(K₁_ = copy(zeros(Float64,nMax,$(length(p.update["Variables"]))))))
        push!(p.args,:K₁_ )

        #Create second interaction parameter kernel using localVCopy if there is any
        if "UpdateInteraction" in keys(p.agent.declaredUpdates)

            k3 = loop_(p,p.agent,space,p.agent.declaredUpdates["UpdateInteraction"],platform)
            for (i,j) in enumerate(p.agent.declaredSymbols["Local"])
                codeK1 = postwalk(x -> @capture(x,$j) ? :(localVCopy[ic1_,$ii]) : x, k3)
            end
            k3 = vectorize_(p.agent,k3,p,interaction=true)
            k3 = wrapInFunction_(:interactionStep2_,k3)
            push!(p.declareF.args,k3)

        end

        #Create second integration step kernel
        codeK2 = gensym_ids(postwalk(x->@capture(x,dW) ? :($(gensym("dW"))) : x, code))
        codeK2 = postwalk(x->@capture(x,v_) && (split(string(v),"_")[1] == "dW") ? :(dW[ic1_,$(Meta.parse(split(string(v),"_")[2]))]) : x, codeK2)
        codeK2 = postwalk(x->@capture(x,dW[ic1_,pos_]) ? :(dW[ic1_,$pos]+S_[ic1_,$pos]) : x, codeK2)
        for (i,j) in enumerate(p.agent.declaredSymbols["Local"])
            if j in keys(p.update["Variables"])
                ii = p.update["Local"][j]
                ki = p.update["Variables"][j]
                codeK2 = postwalk(x -> @capture(x,g_(s_)) && g == DIFFSYMBOL && s == j ? :(K₁[ic1_,$ii]) : x, codeK2) #Save second point in first vector, saves an additional declaration
                codeK2 = postwalk(x -> @capture(x,s_) && s == j ? :((localVCopy_[ic1_,$ki])) : x, codeK2)
                codeK2 = postwalk(x -> @capture(x,t) ? :(t+dt) : x, codeK2)

                #Add old pos, K2 (stored in final pos for now) and K1 to final pos
                push!(codeK2.args,:(localVCopy[ic1_,$ii] = (localVCopy[ic1_,$ii] + localV[ic1_,$i] + K₁_[ic1_,$ki])/2))
            end
        end
        codeK2 = vectorize_(p.agent,codeK2,p)
        k4 = simpleFirstLoopWrapInFunction_(platform,:integrationStep2_,codeK2)
        push!(p.declareF.args,k4)

        #Create a function that puts all kernels together
        if inexpr(codeK1,:dW)
            push!(p.declareVar.args, #declare random variables for Stochastic integration
                :(begin
                    dW = zeros(Float64,nMax,$m)
                    S_ = zeros(Float64,nMax,$m)
                end)
            )

            push!(p.args,:dW,:S_)
        end
        if "UpdateInteraction" in keys(p.agent.declaredUpdates)
            addInteraction1 = [:(@platformAdapt cleanInteraction_!(ARGS_);@platformAdapt interactionStep1_(ARGS_))]
            addInteraction2 = [:(@platformAdapt cleanInteraction_!(ARGS_);@platformAdapt interactionStep2_(ARGS_))]
            push!(p.execInit.args, :(@platformAdapt cleanInteraction_!(ARGS_); @platformAdapt interactionStep1_(ARGS_)))
        else
            addInteraction1 = []
            addInteraction2 = []
        end
        push!(p.declareF.args,
            :(begin
                function integrationStep_!(ARGS_)
                    $(addInteraction1...)
                    @platformAdapt integrationStep1_(ARGS_)
                    $(addInteraction2...)
                    @platformAdapt integrationStep1_(ARGS_)

                    return
                end
            end)
        )

        #Add integration step to the main function
        push!(p.execInit.args,:(integrationStep_!(ARGS_)))
        push!(p.execInloop.args,:(integrationStep_!(ARGS_)))

    end

    return
end


text:
# This file is a part of Julia. License is MIT: https://julialang.org/license

abstract type AbstractSparseArray{Tv,Ti,N} <: AbstractArray{Tv,N} end

const AbstractSparseVector{Tv,Ti} = AbstractSparseArray{Tv,Ti,1}
const AbstractSparseMatrix{Tv,Ti} = AbstractSparseArray{Tv,Ti,2}

"""
    issparse(S)

Returns `true` if `S` is sparse, and `false` otherwise.
"""
issparse(A::AbstractArray) = false
issparse(S::AbstractSparseArray) = true

issparse(S::Symmetric{<:Any,<:AbstractSparseMatrix}) = true
issparse(S::Hermitian{<:Any,<:AbstractSparseMatrix}) = true
issparse(S::LowerTriangular{<:Any,<:AbstractSparseMatrix}) = true
issparse(S::LinAlg.UnitLowerTriangular{<:Any,<:AbstractSparseMatrix}) = true
issparse(S::UpperTriangular{<:Any,<:AbstractSparseMatrix}) = true
issparse(S::LinAlg.UnitUpperTriangular{<:Any,<:AbstractSparseMatrix}) = true

indtype(S::AbstractSparseArray{<:Any,Ti}) where {Ti} = Ti

max_stars_repo_name: caodi/julia

max_issues_repo_name: caodi/julia

max_forks_repo_name: caodi/julia


text:
@testset "Guaranteed Ellipse Fit" begin
    @info "Test: Guaranteed Ellipse Fit"

    @testset "Convergence on noiseless data" begin
        𝛏 = [10, 5, 25, 25, π/4]
        geo_to_alg = GeometricToAlgebraic()
        𝛉₀ = geo_to_alg(𝛏)
        𝛉₀ = 𝛉₀ / norm(𝛉₀)
        α₁ = 0
        α₂ = 2*π
        N = 25
        observations = sample_points_on_ellipse(𝛏..., N, α₁, α₂)
        𝛉₁ = fit_ellipse(observations, GuaranteedEllipseFit(𝛉₀))
        𝐫 = GuaranteedEllipseFitting.vector_valued_objective(observations, 𝛉₁)
        @test 𝛉₀ ≈ 𝛉₁
        @test isapprox(dot(𝐫, 𝐫), 0.0, atol= 1e-10)
    end

    @testset "Numerical" begin
        truth = SVector(3.96548501597781e-06,
                        -5.0179230231193e-07,
                        1.88176818319181e-05,
                        -0.00182736162233016,
                        -0.00930825073431271,
                         0.999955007411677)
        truth_geo = SVector(314.346509735058,
                            144.209111864029,
                            246.264470570879,
                            250.610687177739,
                            0.0168864414911359)

        𝛉₀ = fit_ellipse(data, DirectEllipseFit())
        𝛉₁ = fit_ellipse(data, GuaranteedEllipseFit(𝛉₀))
        alg_to_geo = AlgebraicToGeometric()
        𝛈 = alg_to_geo(𝛉₁)
        @test isapprox(norm(𝛉₁ - truth) , 0.0, atol= 1e-8)
        @test isapprox(norm(𝛈 - truth_geo) , 0.0, atol= 1e-4)
    end

end