From cbedde965096c6244bc6230e1dd2cd58b3f4615d Mon Sep 17 00:00:00 2001 From: igerber Date: Sat, 21 Mar 2026 10:10:13 -0400 Subject: [PATCH 1/5] Add EDID validation tests against Chen, Sant'Anna & Xie (2025) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Validate the EfficientDiD estimator against published results from the paper's Table 6 (HRS empirical application) and Tables 4/5 patterns (Compustat MC simulations). HRS replication: point estimates match within 0.1-1.3% for all targets except ATT(9,10) which is a near-zero noisy estimate (90 ± 641). The CS cross-validation matches to <$1 on all ATT(g,t), confirming data loading correctness. Fixture is a 656-individual subset of the Dobkin et al. (2018) publicly available replication kit. MC simulations validate unbiasedness, RMSE dominance over CS, efficiency gains increasing with serial correlation, ~95% coverage, and SE calibration across rho values. Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 3 + tests/data/hrs_edid_validation.csv | 2625 ++++++++++++++++++++++++ tests/test_efficient_did_validation.py | 421 ++++ 3 files changed, 3049 insertions(+) create mode 100644 tests/data/hrs_edid_validation.csv create mode 100644 tests/test_efficient_did_validation.py diff --git a/.gitignore b/.gitignore index 1e39833d..5dc1bcd7 100644 --- a/.gitignore +++ b/.gitignore @@ -90,3 +90,6 @@ papers/ # Local analysis notebooks (not committed) analysis/ + +# Replication data (local only, not for distribution) +replication_data/ diff --git a/tests/data/hrs_edid_validation.csv b/tests/data/hrs_edid_validation.csv new file mode 100644 index 00000000..197f2ee6 --- /dev/null +++ b/tests/data/hrs_edid_validation.csv @@ -0,0 +1,2625 @@ +unit,time,outcome,first_treat +12549040,7,5498.679387799289,10.0 +12549040,8,1326.9255014306798,10.0 +12549040,9,979.418461917745,10.0 +12549040,10,6532.907324946035,10.0 +13390021,7,3672.8630659817645,8.0 +13390021,8,41504.0,8.0 +13390021,9,1130.0982252897059,8.0 +13390021,10,1174.1925274366604,8.0 +14167040,7,581.7135723000019,10.0 +14167040,8,1748.0,10.0 +14167040,9,2773.4493945651534,10.0 +14167040,10,1237.9084010184947,10.0 +14247040,7,1884.1999832709919,9.0 +14247040,8,6150.0,9.0 +14247040,9,3173.692516021924,9.0 +14247040,10,973.9426390366098,9.0 +16468040,7,1050.9059061624123,8.0 +16468040,8,5400.0,8.0 +16468040,9,47.087426053737744,8.0 +16468040,10,45.511338272738776,8.0 +17027040,7,488.2997139744542,10.0 +17027040,8,585.0,10.0 +17027040,9,1111.2632548682109,10.0 +17027040,10,728.1814123638204,10.0 +17134011,7,74.30647821350391,10.0 +17134011,8,0.0,10.0 +17134011,9,73.45638464383089,10.0 +17134011,10,0.0,10.0 +18435042,7,4118.701935262788,9.0 +18435042,8,4320.0,9.0 +18435042,9,7486.9007425443015,9.0 +18435042,10,6895.390574476021,9.0 +19786020,7,99.78298502956238,inf +19786020,8,0.0,inf +19786020,9,188.34970421495098,inf +19786020,10,600.7496652001519,inf +20634040,7,636.912670401462,8.0 +20634040,8,5012.0,8.0 +20634040,9,847.5736689672794,8.0 +20634040,10,3185.7936790917142,8.0 +21242040,7,0.0,8.0 +21242040,8,4320.0,8.0 +21242040,9,2154.720616219039,8.0 +21242040,10,68.26700740910816,8.0 +21416011,7,212.304223467154,9.0 +21416011,8,420.0,9.0 +21416011,9,10194.427740634223,9.0 +21416011,10,8273.96129798391,9.0 +21721030,7,0.0,10.0 +21721030,8,0.0,10.0 +21721030,9,47.087426053737744,10.0 +21721030,10,0.0,10.0 +22492030,7,496.2201901297637,9.0 +22492030,8,240.0,9.0 +22492030,9,135.61178703476472,9.0 +22492030,10,327.68163556371917,9.0 +23752011,7,106.152111733577,10.0 +23752011,8,0.0,10.0 +23752011,9,0.0,10.0 +23752011,10,447.75263470623514,10.0 +24741011,7,509.5301363211696,10.0 +24741011,8,360.0,10.0 +24741011,9,941.7485210747549,10.0 +24741011,10,6067.943705538899,10.0 +30176040,7,496.7918829131404,9.0 +30176040,8,3500.0,9.0 +30176040,9,1327.8654147154043,9.0 +30176040,10,182.0453530909551,9.0 +31059030,7,530.760558667885,8.0 +31059030,8,0.0,8.0 +31059030,9,9332.727843850822,8.0 +31059030,10,364.0907061819102,8.0 +34026040,7,636.912670401462,10.0 +34026040,8,220.0,10.0 +34026040,9,1737.5260213829229,10.0 +34026040,10,1583.7945718913093,10.0 +34319040,7,808.8790914098568,8.0 +34319040,8,4575.0,8.0 +34319040,9,1205.4381069756862,8.0 +34319040,10,928.431300763871,8.0 +36495041,7,743.0647821350391,8.0 +36495041,8,14200.0,8.0 +36495041,9,1883.4970421495098,8.0 +36495041,10,1110.476653854826,8.0 +37055040,7,1125.2123843759161,8.0 +37055040,8,1650.0,8.0 +37055040,9,565.0491126448529,8.0 +37055040,10,1001.249442000253,8.0 +37217040,7,1953.1988558978169,9.0 +37217040,8,2300.0,9.0 +37217040,9,6780.589351738236,9.0 +37217040,10,9120.721168966009,9.0 +38525040,7,387.4552078275561,10.0 +38525040,8,1260.0,10.0 +38525040,9,2100.0992019967034,10.0 +38525040,10,1438.1582894185453,10.0 +44211040,7,0.0,8.0 +44211040,8,30.0,8.0 +44211040,9,0.0,8.0 +44211040,10,519.3930562592327,8.0 +44748030,7,3311.9458860876025,9.0 +44748030,8,1620.0,9.0 +44748030,9,12242.730773971814,9.0 +44748030,10,1374.442415836711,9.0 +45397040,7,1602.8968871770128,9.0 +45397040,8,1340.0,9.0 +45397040,9,2966.507841385478,9.0 +45397040,10,3223.818969884893,9.0 +47344030,7,2653.802793339425,10.0 +47344030,8,3000.0,10.0 +47344030,9,2071.8467463644606,10.0 +47344030,10,2442.938374957219,10.0 +48612040,7,286.61070168065794,9.0 +48612040,8,200.0,9.0 +48612040,9,4897.092309588726,9.0 +48612040,10,2730.6802963643263,9.0 +48621030,7,4543.310382197096,8.0 +48621030,8,3640.0,8.0 +48621030,9,2335.536332265392,8.0 +48621030,10,8256.558583982976,8.0 +48624040,7,1762.1250547773782,10.0 +48624040,8,926.0,10.0 +48624040,9,1233.690562607929,10.0 +48624040,10,1947.8852780732195,10.0 +50825042,7,743.0647821350391,inf +50825042,8,350.0,inf +50825042,9,108.30107992359682,inf +50825042,10,107.46063232949643,inf +52295030,7,3396.867575474464,10.0 +52295030,8,1060.0,10.0 +52295030,9,866.4086393887745,10.0 +52295030,10,0.0,10.0 +52436030,7,8025.099647058421,8.0 +52436030,8,7890.0,8.0 +52436030,9,5518.6463334980635,8.0 +52436030,10,906.2513326454199,8.0 +53889040,7,1152.8119334266462,10.0 +53889040,8,490.0,10.0 +53889040,9,832.5056926300833,10.0 +53889040,10,782.7950182911069,10.0 +55185041,7,48522.13027341805,9.0 +55185041,8,4760.0,9.0 +55185041,9,5490.393877865821,9.0 +55185041,10,4059.6113739282987,9.0 +56117031,7,424.608446934308,9.0 +56117031,8,300.0,9.0 +56117031,9,1977.6718942569853,9.0 +56117031,10,364.0907061819102,9.0 +56138040,7,4219.546441409686,10.0 +56138040,8,1336.6110890323635,10.0 +56138040,9,4661.655179320037,10.0 +56138040,10,2793.976440566907,10.0 +58609031,7,3305.576759383588,8.0 +58609031,8,5960.0,8.0 +58609031,9,5820.005860241985,8.0 +58609031,10,3386.043567491765,8.0 +72327040,7,5477.448965452573,8.0 +72327040,8,1250.0,8.0 +72327040,9,1954.1281812301165,8.0 +72327040,10,482.420185691031,8.0 +72950040,7,3672.8630659817645,10.0 +72950040,8,5070.0,10.0 +72950040,9,1676.3123675130637,10.0 +72950040,10,15410.139139149349,10.0 +73763011,7,1433.0535084032895,10.0 +73763011,8,1820.0,10.0 +73763011,9,1422.0402668228799,10.0 +73763011,10,400.4997768001012,10.0 +76382040,7,1730.279421257305,8.0 +76382040,8,1970.0,8.0 +76382040,9,1582.1375154055881,8.0 +76382040,10,2038.9079546186972,8.0 +76577011,7,0.0,9.0 +76577011,8,0.0,9.0 +76577011,9,0.0,9.0 +76577011,10,0.0,9.0 +77364012,7,1323.2538403460364,8.0 +77364012,8,0.0,8.0 +77364012,9,0.0,8.0 +77364012,10,429.84252931798574,8.0 +79039040,7,3396.867575474464,10.0 +79039040,8,1200.0,10.0 +79039040,9,2166.021598471936,10.0 +79039040,10,9739.426390366098,10.0 +79882040,7,1337.5166078430702,8.0 +79882040,8,2000.0,8.0 +79882040,9,135.61178703476472,8.0 +79882040,10,1333.482211391246,8.0 +80535040,7,1520.0982400248226,8.0 +80535040,8,1162.2705122020552,8.0 +80535040,9,3623.848309095657,8.0 +80535040,10,1201.4993304003037,8.0 +83640030,7,1231.3644961094933,10.0 +83640030,8,1220.0,10.0 +83640030,9,271.22357406952943,10.0 +83640030,10,4278.065797637445,10.0 +84317030,7,382.14760224087723,10.0 +84317030,8,435.0,10.0 +84317030,9,904.0785802317647,10.0 +84317030,10,2883.5269675081545,10.0 +84687011,7,6708.813461562067,10.0 +84687011,8,1820.0,10.0 +84687011,9,1685.7298527238113,10.0 +84687011,10,609.8519328546996,10.0 +86123040,7,2038.1205452846784,9.0 +86123040,8,10200.0,9.0 +86123040,9,4237.868344836397,9.0 +86123040,10,546.1360592728653,9.0 +86769030,7,520.1453474945273,9.0 +86769030,8,2815.0,9.0 +86769030,9,13937.878111906373,9.0 +86769030,10,1826.8307496014393,9.0 +110096010,7,0.0,8.0 +110096010,8,18.0,8.0 +110096010,9,0.0,8.0 +110096010,10,0.0,8.0 +111082010,7,2229.194346405117,8.0 +111082010,8,6170.0,8.0 +111082010,9,3126.6050899681863,8.0 +111082010,10,2785.293902291613,8.0 +111939010,7,10509.059061624124,8.0 +111939010,8,2200.0,8.0 +111939010,9,3766.9940842990195,8.0 +111939010,10,2384.7941254915117,8.0 +112575020,7,3524.2501095547564,8.0 +112575020,8,31800.0,8.0 +112575020,9,18139.38200828279,8.0 +112575020,10,24895.046489666674,8.0 +112752020,7,1571.0512536569397,8.0 +112752020,8,2439.0,8.0 +112752020,9,117.71856513434436,8.0 +112752020,10,1468.6286418364512,8.0 +113083010,7,881.0625273886891,9.0 +113083010,8,1260.0,9.0 +113083010,9,10777.370075179495,9.0 +113083010,10,4369.088474182922,9.0 +113097020,7,4331.0061587299415,9.0 +113097020,8,2560.0,9.0 +113097020,9,94.17485210747549,9.0 +113097020,10,0.0,9.0 +113613020,7,530.760558667885,9.0 +113613020,8,970.0,9.0 +113613020,9,1139.5157105004535,9.0 +113613020,10,1729.4308543640734,9.0 +113619010,7,1326.9013966697125,8.0 +113619010,8,685.0,8.0 +113619010,9,612.1365386985907,8.0 +113619010,10,671.6289520593527,8.0 +113874020,7,520.1453474945273,9.0 +113874020,8,20.0,9.0 +113874020,9,517.9616865911152,9.0 +113874020,10,2594.14628154611,9.0 +113932020,7,3057.180817927018,9.0 +113932020,8,1554.0,9.0 +113932020,9,2169.7885925562355,9.0 +113932020,10,1354.417426996706,9.0 +114031010,7,1273.825340802924,8.0 +114031010,8,76383.59066879368,8.0 +114031010,9,809.9037281242893,8.0 +114031010,10,1656.6127131276914,8.0 +114117010,7,1634.7425206970859,8.0 +114117010,8,3000.0,8.0 +114117010,9,2825.2455632242645,8.0 +114117010,10,3549.8843852736245,8.0 +114254020,7,37.153239106751954,8.0 +114254020,8,3600.0,8.0 +114254020,9,583.884083066348,8.0 +114254020,10,45.511338272738776,8.0 +115355010,7,1061.52111733577,8.0 +115355010,8,3420.0,8.0 +115355010,9,1012.3796601553615,8.0 +115355010,10,0.0,8.0 +116287020,7,1592.281676003655,8.0 +116287020,8,2220.0,8.0 +116287020,9,0.0,8.0 +116287020,10,6781.189402638078,8.0 +116768010,7,114.64428067226316,8.0 +116768010,8,35644.25445346742,8.0 +116768010,9,1582.1375154055881,8.0 +116768010,10,2184.544237091461,8.0 +117144021,7,461.76168604106,8.0 +117144021,8,1920.0,8.0 +117144021,9,6460.394854572819,8.0 +117144021,10,555.238326927413,8.0 +117310010,7,1178.2884402427048,8.0 +117310010,8,2620.0,8.0 +117310010,9,4110.732294491305,8.0 +117310010,10,5916.4739754560405,8.0 +118324010,7,7642.952044817544,8.0 +118324010,8,0.0,8.0 +118324010,9,4520.392901158823,8.0 +118324010,10,2894.521114146186,8.0 +119380010,7,0.0,8.0 +119380010,8,0.0,8.0 +119380010,9,0.0,8.0 +119380010,10,436.9088474182922,8.0 +119953010,7,4458.388692810234,8.0 +119953010,8,4300.0,8.0 +119953010,9,322.0779942075662,8.0 +119953010,10,1711.226319054978,8.0 +120075020,7,2834.261383286506,10.0 +120075020,8,7312.618639271264,10.0 +120075020,9,5462.141422233579,10.0 +120075020,10,20389.07954618697,10.0 +121006020,7,1299.3018476189825,8.0 +121006020,8,855.0,8.0 +121006020,9,491.59272800102207,8.0 +121006020,10,174.7635389673169,8.0 +121324020,7,0.0,8.0 +121324020,8,290.0,8.0 +121324020,9,103.59233731822304,8.0 +121324020,10,77.36927506365592,8.0 +121620010,7,0.0,8.0 +121620010,8,0.0,8.0 +121620010,9,5367.966570126103,8.0 +121620010,10,1274.3174716366857,8.0 +122305011,7,3609.1717989416184,8.0 +122305011,8,6550.0,8.0 +122305011,9,2994.7602970177204,8.0 +122305011,10,3531.679849964529,8.0 +122305021,7,0.0,inf +122305021,8,0.0,inf +122305021,9,0.0,inf +122305021,10,0.0,inf +122425020,7,3184.56335200731,9.0 +122425020,8,2580.0,9.0 +122425020,9,1600.9724858270833,9.0 +122425020,10,491.52245334557875,9.0 +122629020,7,1082.7515396824854,9.0 +122629020,8,760.0,9.0 +122629020,9,3032.430237860711,9.0 +122629020,10,782.7950182911069,9.0 +123278010,7,1273.825340802924,9.0 +123278010,8,1340.0,9.0 +123278010,9,3917.67384767098,9.0 +123278010,10,1084.9903044220923,9.0 +124479010,7,0.0,8.0 +124479010,8,0.0,8.0 +124479010,9,282.52455632242646,8.0 +124479010,10,0.0,8.0 +124543020,7,4118.701935262788,9.0 +124543020,8,4800.0,9.0 +124543020,9,5170.199380700405,9.0 +124543020,10,4369.088474182922,9.0 +124573020,7,2993.4895508868717,8.0 +124573020,8,2200.0,8.0 +124573020,9,3465.634557555098,8.0 +124573020,10,17276.10400833164,8.0 +124590020,7,615.6822480547467,8.0 +124590020,8,2050.0,8.0 +124590020,9,2015.3418350999755,8.0 +124590020,10,2757.9870993279696,8.0 +124709010,7,1953.1988558978169,8.0 +124709010,8,3070.0,8.0 +124709010,9,1422.0402668228799,8.0 +124709010,10,1711.226319054978,8.0 +125388010,7,393.8243345315707,8.0 +125388010,8,2700.0,8.0 +125388010,9,1059.4670862090993,8.0 +125388010,10,1092.2721185457306,8.0 +125396010,7,0.0,8.0 +125396010,8,1640.0,8.0 +125396010,9,226.01964505794118,8.0 +125396010,10,0.0,8.0 +131926010,7,5413.757698412427,8.0 +131926010,8,5440.0,8.0 +131926010,9,1525.632604141103,8.0 +131926010,10,2730.6802963643263,8.0 +132153020,7,1609.2660138810274,8.0 +132153020,8,2132.0,8.0 +132153020,9,3925.2078358395784,8.0 +132153020,10,5373.031616474822,8.0 +132849020,7,833.2940771085795,inf +132849020,8,1020.0,inf +132849020,9,734.5638464383088,inf +132849020,10,546.1360592728653,inf +133851010,7,5010.379673824835,8.0 +133851010,8,3170.0,8.0 +133851010,9,9885.378227924091,8.0 +133851010,10,9921.471743457052,8.0 +135936011,7,636.912670401462,8.0 +135936011,8,990.0,8.0 +135936011,9,536.7966570126104,8.0 +135936011,10,828.3063565638457,8.0 +137015020,7,212.304223467154,9.0 +137015020,8,290.5676280505138,9.0 +137015020,9,1120.6807400789583,9.0 +137015020,10,491.52245334557875,9.0 +137890020,7,79.61408380018275,9.0 +137890020,8,40.0,9.0 +137890020,9,0.0,9.0 +137890020,10,4642.156503819355,9.0 +138721020,7,1422.4382972299318,10.0 +138721020,8,2480.0,10.0 +138721020,9,376.69940842990195,10.0 +138721020,10,4150.634050473776,10.0 +139506010,7,4415.927848116803,8.0 +139506010,8,8626.0,8.0 +139506010,9,13222.14923588956,8.0 +139506010,10,6717.473529056243,8.0 +139756010,7,254.7650681605848,8.0 +139756010,8,35500.0,8.0 +139756010,9,1808.1571604635294,8.0 +139756010,10,1875.0671368368376,8.0 +139834020,7,2186.733501711686,9.0 +139834020,8,2000.0,9.0 +139834020,9,6027.190534878431,9.0 +139834020,10,1911.4762074550285,9.0 +140192010,7,2759.954905073002,8.0 +140192010,8,4980.0,8.0 +140192010,9,3814.0815103527575,8.0 +140192010,10,2366.5895901824165,8.0 +140382010,7,1379.977452536501,9.0 +140382010,8,200.0,9.0 +140382010,9,291.942041533174,9.0 +140382010,10,1467.285545913098,9.0 +140397020,7,16103.27534998363,8.0 +140397020,8,13600.0,8.0 +140397020,9,3837.6252233796263,8.0 +140397020,10,3754.6854075009487,8.0 +140411020,7,127.3825340802924,10.0 +140411020,8,2200.0,10.0 +140411020,9,0.0,10.0 +140411020,10,37501.34273673675,10.0 +140589020,7,1401.2078748832164,10.0 +140589020,8,2660.0,10.0 +140589020,9,489.7092309588725,10.0 +140589020,10,1199.9770610127102,10.0 +144434020,7,541.3757698412427,8.0 +144434020,8,210.0,8.0 +144434020,9,423.7868344836397,8.0 +144434020,10,71.64042155299762,8.0 +145220020,7,3481.7892648613256,9.0 +145220020,8,2650.0,9.0 +145220020,9,5838.84083066348,9.0 +145220020,10,895.6631372074991,9.0 +147421020,7,5010.379673824835,8.0 +147421020,8,4400.0,8.0 +147421020,9,2636.895859009314,8.0 +147421020,10,27778.57345717483,8.0 +148569011,7,1143.2582433706243,10.0 +148569011,8,1260.0,10.0 +148569011,9,640.3889943308334,10.0 +148569011,10,1012.1721631857104,10.0 +148613020,7,4373.467003423372,10.0 +148613020,8,3800.0,10.0 +148613020,9,5556.316274341054,10.0 +148613020,10,8902.017766147705,10.0 +149550020,7,106.152111733577,9.0 +149550020,8,600.0,9.0 +149550020,9,8268.552015036348,9.0 +149550020,10,913.4153748007196,9.0 +150186010,7,4819.305872704396,8.0 +150186010,8,4500.0,8.0 +150186010,9,4049.518640621446,8.0 +150186010,10,8149.09795165348,8.0 +150393020,7,148.61295642700782,8.0 +150393020,8,1420.0,8.0 +150393020,9,4219.033374414902,8.0 +150393020,10,837.4086242183935,8.0 +152265020,7,4718.461366557498,10.0 +152265020,8,1630.0,10.0 +152265020,9,3616.314320927059,10.0 +152265020,10,7361.053314570506,10.0 +152777010,7,785.5256268284699,8.0 +152777010,8,2420.0,8.0 +152777010,9,612.1365386985907,8.0 +152777010,10,1552.846861865847,8.0 +153372010,7,4299.160525209869,8.0 +153372010,8,2324.5410244041104,8.0 +153372010,9,2222.5265097364218,8.0 +153372010,10,5695.413513463311,8.0 +153741020,7,106.152111733577,10.0 +153741020,8,0.0,10.0 +153741020,9,0.0,10.0 +153741020,10,10434.839639173546,10.0 +154374010,7,288.73374391532946,8.0 +154374010,8,1720.0,8.0 +154374010,9,31718.090189797746,8.0 +154374010,10,1347.1356128730677,8.0 +155507020,7,34287.13208994537,8.0 +155507020,8,3950.0,8.0 +155507020,9,1450.2927224551227,8.0 +155507020,10,3304.123158600835,8.0 +156701010,7,3721.6514259732276,8.0 +156701010,8,19440.0,8.0 +156701010,9,27310.707111167892,8.0 +156701010,10,6107.345937393047,8.0 +157235020,7,530.760558667885,inf +157235020,8,3980.0,inf +157235020,9,0.0,inf +157235020,10,0.0,inf +157592010,7,1586.9740704169762,8.0 +157592010,8,400.0,8.0 +157592010,9,11592.924294430233,8.0 +157592010,10,709.9768770547249,8.0 +157738010,7,2069.9661788047515,8.0 +157738010,8,2230.0,8.0 +157738010,9,678.0589351738236,8.0 +157738010,10,7146.132049911513,8.0 +157907010,7,6202.752376622046,8.0 +157907010,8,10300.0,8.0 +157907010,9,0.0,8.0 +157907010,10,0.0,8.0 +158116020,7,77066.43311857691,8.0 +158116020,8,5580.0,8.0 +158116020,9,13372.82899926152,8.0 +158116020,10,6043.905722619709,8.0 +160674010,7,583.8366145346736,8.0 +160674010,8,1320.0,8.0 +160674010,9,3653.984261770049,8.0 +160674010,10,6917.723417456294,8.0 +160674020,7,605.067036881389,9.0 +160674020,8,860.0,9.0 +160674020,9,2184.8565688934314,9.0 +160674020,10,2257.362378327843,9.0 +165823020,7,2547.650681605848,8.0 +165823020,8,339.9641248191012,8.0 +165823020,9,188.34970421495098,8.0 +165823020,10,1988.021698095684,8.0 +165914020,7,317.39481408339526,inf +165914020,8,1700.0,inf +165914020,9,452.03929011588235,inf +165914020,10,0.0,inf +172013020,7,647.5278815748197,8.0 +172013020,8,1020.0,8.0 +172013020,9,423.7868344836397,8.0 +172013020,10,7491.166279692802,8.0 +172611020,7,0.0,8.0 +172611020,8,7200.0,8.0 +172611020,9,1582.1375154055881,8.0 +172611020,10,2384.7941254915117,8.0 +173122010,7,1583.7895070649688,8.0 +173122010,8,6292.0,8.0 +173122010,9,1186.6031365541912,8.0 +173122010,10,1256.1129363275902,8.0 +173877020,7,1146.4428067226318,8.0 +173877020,8,720.0,8.0 +173877020,9,1600.9724858270833,8.0 +173877020,10,4878.815462837597,8.0 +174707010,7,2149.5802626049344,9.0 +174707010,8,320.0,9.0 +174707010,9,2825.2455632242645,9.0 +174707010,10,1456.3628247276408,9.0 +176082020,7,2420.268147525556,8.0 +176082020,8,1110.0,8.0 +176082020,9,1280.7779886616668,8.0 +176082020,10,1037.658512618444,8.0 +176787020,7,870.4473162153314,9.0 +176787020,8,240.0,9.0 +176787020,9,574.4665978556005,9.0 +176787020,10,3185.7936790917142,9.0 +177293020,7,3131.4872961405217,inf +177293020,8,5308.0,inf +177293020,9,2274.3226783955333,inf +177293020,10,1297.073140773055,inf +177660020,7,2008.397953999277,9.0 +177660020,8,3720.0,9.0 +177660020,9,3126.6050899681863,9.0 +177660020,10,5579.690072237774,9.0 +179842010,7,1040.2906949890546,8.0 +179842010,8,1190.0,8.0 +179842010,9,75.33988168598039,8.0 +179842010,10,1925.1296089368502,8.0 +179842020,7,658.1430927481774,inf +179842020,8,1460.0,inf +179842020,9,1892.9145273602574,inf +179842020,10,1328.9310775639722,inf +180170020,7,689.9887262682505,9.0 +180170020,8,642.0,9.0 +180170020,9,1747.8852551147452,9.0 +180170020,10,2821.702972909804,9.0 +181464010,7,713.3421908496375,8.0 +181464010,8,1200.0,8.0 +181464010,9,1589.6715035741863,8.0 +181464010,10,25917.363319513224,8.0 +182158020,7,4458.388692810234,8.0 +182158020,8,15480.0,8.0 +182158020,9,6742.919410895245,8.0 +182158020,10,16960.869802672187,8.0 +182785010,7,4776.8450280109655,8.0 +182785010,8,13200.0,8.0 +182785010,9,9888.359471284926,8.0 +182785010,10,6099.42955531245,8.0 +183390020,7,743.0647821350391,9.0 +183390020,8,2340.0,9.0 +183390020,9,1337.282899926152,9.0 +183390020,10,418.70431210919674,9.0 +183414020,7,2791.800538593075,8.0 +183414020,8,1450.0,8.0 +183414020,9,791.0687577027941,8.0 +183414020,10,800.9995536002024,8.0 +184024020,7,2165.5030793649707,9.0 +184024020,8,590.0,9.0 +184024020,9,1487.9626632981128,9.0 +184024020,10,609.8519328546996,9.0 +187522010,7,1698.433787737232,8.0 +187522010,8,2420.0,8.0 +187522010,9,988.8359471284926,8.0 +187522010,10,4232.554459364706,8.0 +187575011,7,305.71808179270175,8.0 +187575011,8,3945.0,8.0 +187575011,9,1130.0982252897059,8.0 +187575011,10,2230.0555753641997,8.0 +204314020,7,3184.56335200731,8.0 +204314020,8,0.0,8.0 +204314020,9,0.0,8.0 +204314020,10,0.0,8.0 +211173020,7,0.0,10.0 +211173020,8,0.0,10.0 +211173020,9,452.03929011588235,10.0 +211173020,10,1820.453530909551,10.0 +500002020,7,743.0647821350391,10.0 +500002020,8,500.0,10.0 +500002020,9,706.3113908060661,10.0 +500002020,10,3185.7936790917142,10.0 +500004020,7,8975.161047073936,8.0 +500004020,8,19500.0,8.0 +500004020,9,2825.2455632242645,8.0 +500004020,10,2238.7631735311757,8.0 +500013020,7,3492.4044760346833,8.0 +500013020,8,6120.0,8.0 +500013020,9,10683.19522307202,8.0 +500013020,10,1361.1680095069548,8.0 +500014010,7,291.9183072673368,9.0 +500014010,8,225.0,9.0 +500014010,9,824.0299559404106,9.0 +500014010,10,1274.3174716366857,9.0 +500014020,7,9129.081609087623,10.0 +500014020,8,7000.0,10.0 +500014020,9,1577.4287728002146,10.0 +500014020,10,14654.650923821886,10.0 +500021010,7,675.1274306255498,8.0 +500021010,8,31120.0,8.0 +500021010,9,555.6316274341054,8.0 +500021010,10,136.53401481821632,8.0 +500022010,7,2117.7346290848614,inf +500022010,8,1960.0,inf +500022010,9,2561.5559773233335,inf +500022010,10,3285.9186232917396,inf +500023010,7,3184.56335200731,8.0 +500023010,8,864.0,8.0 +500023010,9,2636.895859009314,8.0 +500023010,10,2539.5326756188238,8.0 +500034020,7,2016.890122937963,10.0 +500034020,8,3292.0,10.0 +500034020,9,4237.868344836397,10.0 +500034020,10,2337.2687531665474,10.0 +500035020,7,1655.9729430438013,9.0 +500035020,8,3816.0,9.0 +500035020,9,7778.842784077476,9.0 +500035020,10,2621.4530845097534,9.0 +500042020,7,2759.954905073002,inf +500042020,8,6000.0,inf +500042020,9,791.0687577027941,inf +500042020,10,546.1360592728653,inf +500044010,7,12844.405519762817,9.0 +500044010,8,724.0,9.0 +500044010,9,2335.536332265392,9.0 +500044010,10,1835.785802295564,9.0 +500051010,7,562.6061921879581,8.0 +500051010,8,265.0,8.0 +500051010,9,0.0,8.0 +500051010,10,491.52245334557875,8.0 +500051020,7,371.53239106751954,10.0 +500051020,8,100.0,10.0 +500051020,9,998.2534323392402,10.0 +500051020,10,1064.9653155820872,10.0 +500057010,7,6017.763214176481,8.0 +500057010,8,17200.0,8.0 +500057010,9,6629.909588366275,8.0 +500057010,10,0.0,8.0 +500058010,7,1910.738011204386,9.0 +500058010,8,1240.0,9.0 +500058010,9,906.9691004141396,9.0 +500058010,10,3707.391815367627,9.0 +500060010,7,8529.322177792912,9.0 +500060010,8,16040.0,9.0 +500060010,9,847.5736689672794,9.0 +500060010,10,3959.4864297282734,9.0 +500073010,7,2462.7289922189866,8.0 +500073010,8,2390.0,8.0 +500073010,9,226.01964505794118,8.0 +500073010,10,0.0,8.0 +500083010,7,573.2214033613159,9.0 +500083010,8,1565.0,9.0 +500083010,9,588.5928256717218,9.0 +500083010,10,3617.84128842638,9.0 +500088020,7,477.6845028010965,9.0 +500088020,8,940.0,9.0 +500088020,9,3107.770119546691,9.0 +500088020,10,455.1133827273878,9.0 +500097020,7,3089.026451447091,10.0 +500097020,8,2900.0,10.0 +500097020,9,3041.8477230714584,10.0 +500097020,10,7463.859476729159,10.0 +500104010,7,1157.8471103027819,10.0 +500104010,8,1080.0,10.0 +500104010,9,0.0,10.0 +500104010,10,1638.408177818596,10.0 +500112020,7,5647.292344226296,inf +500112020,8,120.0,inf +500112020,9,1808.1571604635294,inf +500112020,10,1956.9875457277674,inf +500122010,7,106.152111733577,inf +500122010,8,100.0,inf +500122010,9,2825.2455632242645,inf +500122010,10,2730.6802963643263,inf +500139010,7,1847.04674416424,8.0 +500139010,8,2190.0,8.0 +500139010,9,1761.0697344097916,8.0 +500139010,10,1943.2464346250606,8.0 +500149020,7,137.9977452536501,inf +500149020,8,80.0,inf +500149020,9,51.79616865911152,inf +500149020,10,304.4717916002399,inf +500152010,7,0.0,10.0 +500152010,8,96.0,10.0 +500152010,9,67.80589351738236,10.0 +500152010,10,0.0,10.0 +500152020,7,63.6912670401462,10.0 +500152020,8,72.64190701262845,10.0 +500152020,9,0.0,10.0 +500152020,10,2905.443835331643,10.0 +500157010,7,4469.003903983592,8.0 +500157010,8,2750.0,8.0 +500157010,9,4143.693492728921,8.0 +500157010,10,5379.440183837723,8.0 +500170010,7,4989.149251478119,8.0 +500170010,8,1000.0,8.0 +500170010,9,630.9715091200858,8.0 +500170010,10,546.1360592728653,8.0 +500172010,7,2611.3419486459943,8.0 +500172010,8,4100.0,8.0 +500172010,9,1836.409616095772,8.0 +500172010,10,4569.338362582973,8.0 +500177010,7,38015.36642672125,9.0 +500177010,8,1135.0,9.0 +500177010,9,11206.807400789583,9.0 +500177010,10,1183.2947950912082,9.0 +500180010,7,5519.909810146004,8.0 +500180010,8,2580.0,8.0 +500180010,9,1487.9626632981128,8.0 +500180010,10,131.07265422548767,8.0 +500189020,7,0.0,8.0 +500189020,8,780.0,8.0 +500189020,9,0.0,8.0 +500189020,10,10558.630479275396,8.0 +500202010,7,3004.1047620602294,inf +500202010,8,2272.0,inf +500202010,9,6210.831496488008,inf +500202010,10,6462.610034728906,inf +500216010,7,2494.5746257390597,8.0 +500216010,8,5100.0,8.0 +500216010,9,1459.71020766587,8.0 +500216010,10,8537.927059965794,8.0 +500225010,7,573.2214033613159,10.0 +500225010,8,55.0,10.0 +500225010,9,2316.701361843897,10.0 +500225010,10,5721.685447648719,10.0 +500227010,7,0.0,8.0 +500227010,8,0.0,8.0 +500227010,9,0.0,8.0 +500227010,10,0.0,8.0 +500236010,7,3249.316140164792,8.0 +500236010,8,5700.0,8.0 +500236010,9,1996.5068646784805,8.0 +500236010,10,3098.448232167147,8.0 +500254010,7,334.37915196076756,8.0 +500254010,8,10280.0,8.0 +500254010,9,508.54420138036767,8.0 +500254010,10,36.409070618191016,8.0 +500269010,7,530.760558667885,8.0 +500269010,8,80.0,8.0 +500269010,9,47.087426053737744,8.0 +500269010,10,0.0,8.0 +500270010,7,509.5301363211696,9.0 +500270010,8,0.0,9.0 +500270010,9,0.0,9.0 +500270010,10,0.0,9.0 +500273020,7,4718.461366557498,8.0 +500273020,8,12772.0,8.0 +500273020,9,1182.8361424698921,8.0 +500273020,10,577.0837692983276,8.0 +500276010,7,4139.932357609503,10.0 +500276010,8,3780.0,10.0 +500276010,9,1589.6715035741863,10.0 +500276010,10,2075.317025236888,10.0 +500278010,7,2038.1205452846784,9.0 +500278010,8,2400.0,9.0 +500278010,9,3107.770119546691,9.0 +500278010,10,2457.6122667278937,9.0 +500291010,7,212.304223467154,9.0 +500291010,8,400.0,9.0 +500291010,9,1346.7003851368995,9.0 +500291010,10,728.1814123638204,9.0 +500292010,7,14946.217332087643,8.0 +500292010,8,22300.0,8.0 +500292010,9,5593.986215184044,8.0 +500292010,10,5133.678957164934,8.0 +500299020,7,233.53464581386942,9.0 +500299020,8,130.0,9.0 +500299020,9,5688.161067291519,9.0 +500299020,10,3094.7710025462366,9.0 +500309010,7,369.40934883284797,9.0 +500309010,8,490.0,9.0 +500309010,9,10547.583436037256,9.0 +500309010,10,892.0222301456799,9.0 +500309020,7,127.3825340802924,8.0 +500309020,8,1718.0,8.0 +500309020,9,2975.9253265962257,8.0 +500309020,10,1729.4308543640734,8.0 +500310010,7,5095.301363211696,10.0 +500310010,8,1560.0,10.0 +500310010,9,1894.7980244024068,10.0 +500310010,10,1587.4354789531285,10.0 +500317020,7,371.53239106751954,8.0 +500317020,8,6170.0,8.0 +500317020,9,1732.817278777549,8.0 +500317020,10,91.02267654547755,8.0 +500318010,7,5572.985866012793,inf +500318010,8,4519.0,inf +500318010,9,4897.092309588726,inf +500318010,10,3504.3730470008854,inf +500329010,7,51218.393911450905,inf +500329010,8,2410.0,inf +500329010,9,2175.4390836826838,inf +500329010,10,2251.9010177351147,inf +500344020,7,1188.9036514160625,8.0 +500344020,8,20500.0,8.0 +500344020,9,421.9033374414902,8.0 +500344020,10,822.844995971117,8.0 +500355010,7,4203.623624649649,8.0 +500355010,8,1560.0,8.0 +500355010,9,1186.6031365541912,8.0 +500355010,10,8192.04088909298,8.0 +500356020,7,18979.997577963568,10.0 +500356020,8,710.0,10.0 +500356020,9,274.9905681538284,10.0 +500356020,10,5865.501276590573,10.0 +500363020,7,5710.9836112664425,inf +500363020,8,1515.0,inf +500363020,9,2434.4199269782416,inf +500363020,10,3404.24810280086,inf +500381010,7,6878.65684033579,8.0 +500381010,8,4552.226172791383,8.0 +500381010,9,4614.567753266299,8.0 +500381010,10,9102.267654547755,8.0 +500383010,7,0.0,9.0 +500383010,8,2300.0,9.0 +500383010,9,188.34970421495098,9.0 +500383010,10,731.8223194256395,9.0 +500384010,7,214.42726570182555,8.0 +500384010,8,120.0,8.0 +500384010,9,0.0,8.0 +500384010,10,0.0,8.0 +500387010,7,1114.5971732025585,8.0 +500387010,8,1200.0,8.0 +500387010,9,0.0,8.0 +500387010,10,2448.509999073346,8.0 +500389010,7,790.8332324151487,8.0 +500389010,8,580.0,8.0 +500389010,9,489.7092309588725,8.0 +500389010,10,709.9768770547249,8.0 +500396010,7,976.5994279489084,10.0 +500396010,8,5100.0,10.0 +500396010,9,7345.638464383088,10.0 +500396010,10,6098.519328546996,10.0 +500408020,7,636.912670401462,10.0 +500408020,8,500.0,10.0 +500408020,9,1252.525533029424,10.0 +500408020,10,13835.446834912587,10.0 +500410020,7,41.35168251081364,9.0 +500410020,8,0.0,9.0 +500410020,9,749.6318227755049,9.0 +500410020,10,1272.497018105776,9.0 +500415010,7,0.0,8.0 +500415010,8,300.0,8.0 +500415010,9,791.0687577027941,8.0 +500415010,10,0.0,8.0 +500416020,7,4734.384183317535,10.0 +500416020,8,3000.0,10.0 +500416020,9,306.06826934929535,10.0 +500416020,10,2457.6122667278937,10.0 +500417010,7,1167.6732290693471,8.0 +500417010,8,100.0,8.0 +500417010,9,536.7966570126104,8.0 +500417010,10,0.0,8.0 +500421010,7,1804.5858994708092,8.0 +500421010,8,6812.0,8.0 +500421010,9,7298.55103832935,8.0 +500421010,10,1383.5446834912586,8.0 +500427010,7,817.3712603485429,9.0 +500427010,8,920.0,9.0 +500427010,9,805.1949855189155,9.0 +500427010,10,1201.4993304003037,9.0 +500427020,7,1053.028948397084,8.0 +500427020,8,1660.0,8.0 +500427020,9,2038.8855481268445,8.0 +500427020,10,3404.24810280086,8.0 +500431010,7,1787.6015615934368,8.0 +500431010,8,1756.0,8.0 +500431010,9,4501.557930737328,8.0 +500431010,10,23356.41880156954,8.0 +500438020,7,3184.56335200731,9.0 +500438020,8,1300.0,9.0 +500438020,9,1177.1856513434436,9.0 +500438020,10,455.1133827273878,9.0 +500441010,7,2908.5678615000097,10.0 +500441010,8,1743.4057683030828,10.0 +500441010,9,1685.7298527238113,10.0 +500441010,10,4187.043121091967,10.0 +500444010,7,1399.084832648545,8.0 +500444010,8,2680.0,8.0 +500444010,9,546.2141422233578,8.0 +500444010,10,709.9768770547249,8.0 +500445010,7,46.70692916277388,10.0 +500445010,8,1320.0,10.0 +500445010,9,0.0,10.0 +500445010,10,218.4544237091461,10.0 +500460010,7,585.9596567693451,9.0 +500460010,8,744.0,9.0 +500460010,9,244.85461547943626,9.0 +500460010,10,899.3040442693182,9.0 +500461010,7,127.3825340802924,8.0 +500461010,8,33000.0,8.0 +500461010,9,0.0,8.0 +500461010,10,21845.44237091461,8.0 +500461020,7,689.9887262682505,10.0 +500461020,8,0.0,10.0 +500461020,9,1059.4670862090993,10.0 +500461020,10,44036.770912702035,10.0 +500467020,7,0.0,10.0 +500467020,8,0.0,10.0 +500467020,9,0.0,10.0 +500467020,10,0.0,10.0 +500475010,7,350.3019687208041,10.0 +500475010,8,150.0,10.0 +500475010,9,0.0,10.0 +500475010,10,6762.984867328982,10.0 +500476010,7,382.14760224087723,8.0 +500476010,8,600.0,8.0 +500476010,9,565.0491126448529,8.0 +500476010,10,0.0,8.0 +500483010,7,7197.113175536521,10.0 +500483010,8,1352.0,10.0 +500483010,9,636.6220002465343,10.0 +500483010,10,5224.701633710411,10.0 +500490010,7,63.6912670401462,9.0 +500490010,8,625.0,9.0 +500490010,9,13667.596286357919,9.0 +500490010,10,1674.817248436787,9.0 +500490020,7,1999.9057850605907,inf +500490020,8,428.0,inf +500490020,9,470.87426053737744,inf +500490020,10,389.5770556146439,inf +500502020,7,1048.782863927741,10.0 +500502020,8,1420.0,10.0 +500502020,9,3570.168643394396,10.0 +500502020,10,5188.29256309222,10.0 +500510010,7,5732.214033613158,9.0 +500510010,8,375.0,9.0 +500510010,9,33157.08192999997,9.0 +500510010,10,1492.7718953458318,9.0 +500512010,7,1358.7470301897856,10.0 +500512010,8,5500.0,10.0 +500512010,9,447.3305475105086,10.0 +500512010,10,8742.728082193118,10.0 +500513010,7,8279.864715219006,8.0 +500513010,8,9800.0,8.0 +500513010,9,1197.9041188070883,8.0 +500513010,10,6425.29073734526,8.0 +500530010,7,0.0,8.0 +500530010,8,1440.0,8.0 +500530010,9,339.0294675869118,8.0 +500530010,10,5570.587804583226,8.0 +500533010,7,68.99887262682505,9.0 +500533010,8,700.0,9.0 +500533010,9,659.2239647523285,9.0 +500533010,10,156.55900365822137,9.0 +500546010,7,4999.764462651477,8.0 +500546010,8,1994.0,8.0 +500546010,9,8287.386985457842,8.0 +500546010,10,20571.124899277926,8.0 +500546020,7,297.22591285401563,9.0 +500546020,8,520.0,9.0 +500546020,9,2726.3619685114154,9.0 +500546020,10,1201.4993304003037,9.0 +500549010,7,2759.954905073002,inf +500549010,8,1800.0,inf +500549010,9,0.0,inf +500549010,10,5461.360592728653,inf +500550010,7,15285.904089635089,9.0 +500550010,8,5800.0,9.0 +500550010,9,17139.82308356054,9.0 +500550010,10,7090.666502892701,9.0 +500555020,7,4479.619115156949,8.0 +500555020,8,5100.0,8.0 +500555020,9,7100.783848903652,8.0 +500555020,10,35316.79849964529,8.0 +500560020,7,5424.372909585785,10.0 +500560020,8,3808.0,10.0 +500560020,9,4435.6355342620955,10.0 +500560020,10,7844.334264689255,10.0 +500561010,7,0.0,8.0 +500561010,8,182.0,8.0 +500561010,9,678.0589351738236,8.0 +500561010,10,1019.4539773093486,8.0 +500563010,7,11294.584688452593,8.0 +500563010,8,2600.0,8.0 +500563010,9,2109.516687207451,8.0 +500563010,10,32587.21765021556,8.0 +500567010,7,2080.581389978109,9.0 +500567010,8,660.0,9.0 +500567010,9,6204.239256840486,9.0 +500567010,10,5390.9417218630715,9.0 +500576020,7,112.52123843759162,9.0 +500576020,8,5386.0,9.0 +500576020,9,1506.7976337196078,9.0 +500576020,10,446.01111507283997,9.0 +500587010,7,1061.52111733577,8.0 +500587010,8,3680.0,8.0 +500587010,9,2636.895859009314,8.0 +500587010,10,9184.188063438685,8.0 +500595020,7,0.0,8.0 +500595020,8,11400.0,8.0 +500595020,9,8212.047103771863,8.0 +500595020,10,477.86905186375714,8.0 +500609010,7,0.0,10.0 +500609010,8,100.0,10.0 +500609010,9,14.126227816121323,10.0 +500609010,10,0.0,10.0 +500611010,7,10.33792062770341,8.0 +500611010,8,0.0,8.0 +500611010,9,47.087426053737744,8.0 +500611010,10,45.511338272738776,8.0 +500619010,7,9022.929497354045,9.0 +500619010,8,950.0,9.0 +500619010,9,1459.71020766587,9.0 +500619010,10,5041.6946667922075,9.0 +500622020,7,1305.6709743229972,9.0 +500622020,8,500.0,9.0 +500622020,9,2071.8467463644606,9.0 +500622020,10,501.48295087098336,9.0 +500633010,7,7165.267542016448,8.0 +500633010,8,2700.0,8.0 +500633010,9,2848.7892762511337,8.0 +500633010,10,6444.40549941981,8.0 +500635010,7,3524.2501095547564,8.0 +500635010,8,4800.0,8.0 +500635010,9,329.61198237616424,8.0 +500635010,10,364.0907061819102,8.0 +500641010,7,0.0,9.0 +500641010,8,77.48470081347035,9.0 +500641010,9,0.0,9.0 +500641010,10,0.0,9.0 +500648020,7,27164.325392622355,10.0 +500648020,8,2086.0,10.0 +500648020,9,3423.255874106734,10.0 +500648020,10,4943.189087156836,10.0 +500654010,7,849.216893868616,10.0 +500654010,8,640.0,10.0 +500654010,9,0.0,10.0 +500654010,10,2202.748772400557,10.0 +500662020,7,1273.825340802924,10.0 +500662020,8,840.0,10.0 +500662020,9,565.0491126448529,10.0 +500662020,10,9088.614253065933,10.0 +500663010,7,3396.867575474464,8.0 +500663010,8,1880.0,8.0 +500663010,9,1506.7976337196078,8.0 +500663010,10,4951.633604073979,8.0 +500674020,7,0.0,9.0 +500674020,8,30.0,9.0 +500674020,9,814.612470729663,9.0 +500674020,10,0.0,9.0 +500681020,7,577.4674878306589,9.0 +500681020,8,836.0,9.0 +500681020,9,6097.821673959038,9.0 +500681020,10,4096.02044454649,9.0 +500684010,7,1273.825340802924,9.0 +500684010,8,2100.0,9.0 +500684010,9,3107.770119546691,9.0 +500684010,10,2284.6691812914864,9.0 +500686010,7,0.0,inf +500686010,8,0.0,inf +500686010,9,0.0,inf +500686010,10,0.0,inf +500698010,7,15.92281676003655,8.0 +500698010,8,480.0,8.0 +500698010,9,3766.9940842990195,8.0 +500698010,10,10777.084902984541,8.0 +500699010,7,8279.864715219006,8.0 +500699010,8,9646.845251277058,8.0 +500699010,9,6686.41449963076,8.0 +500699010,10,1952.2014873191852,8.0 +500700010,7,4522.07995985038,8.0 +500700010,8,4560.0,8.0 +500700010,9,470.87426053737744,8.0 +500700010,10,364.0907061819102,8.0 +500701010,7,477.6845028010965,10.0 +500701010,8,1046.0434609818496,10.0 +500701010,9,2090.681716785956,10.0 +500701010,10,16820.990625604252,10.0 +500702010,7,3120.872084967164,9.0 +500702010,8,2479.5104260310513,9.0 +500702010,9,5650.491126448529,9.0 +500702010,10,5461.360592728653,9.0 +500704010,7,0.0,9.0 +500704010,8,0.0,9.0 +500704010,9,0.0,9.0 +500704010,10,0.0,9.0 +500707010,7,106.152111733577,10.0 +500707010,8,0.0,10.0 +500707010,9,9.417485210747548,10.0 +500707010,10,1310.7265422548767,10.0 +500710020,7,2069.9661788047515,10.0 +500710020,8,500.0,10.0 +500710020,9,207.1846746364461,10.0 +500710020,10,5659.593302686812,10.0 +500711020,7,8200.250631418823,8.0 +500711020,8,5100.0,8.0 +500711020,9,5744.665978556005,8.0 +500711020,10,10566.96217906715,8.0 +500712010,7,4246.08446934308,8.0 +500712010,8,8500.0,8.0 +500712010,9,25294.42352754684,8.0 +500712010,10,8082.813677238406,8.0 +500712020,7,12770.099041549314,8.0 +500712020,8,820.0,8.0 +500712020,9,357.86443800840686,8.0 +500712020,10,709.9768770547249,8.0 +500717010,7,31.8456335200731,10.0 +500717010,8,8800.0,10.0 +500717010,9,4473.305475105086,10.0 +500717010,10,7099.768770547249,10.0 +500719010,7,0.0,9.0 +500719010,8,0.0,9.0 +500719010,9,706.3113908060661,9.0 +500719010,10,0.0,9.0 +500723010,7,955.369005602193,10.0 +500723010,8,1040.0,10.0 +500723010,9,784.4765180552708,10.0 +500723010,10,8601.642933547628,10.0 +500732010,7,0.0,8.0 +500732010,8,2200.0,8.0 +500732010,9,1376.8363378112917,8.0 +500732010,10,917.5085795784137,8.0 +500733010,7,106.152111733577,inf +500733010,8,0.0,inf +500733010,9,0.0,inf +500733010,10,0.0,inf +500737020,7,1762.1250547773782,10.0 +500737020,8,2950.0,10.0 +500737020,9,3230.1974272864095,10.0 +500737020,10,2238.7631735311757,10.0 +500739010,7,5360.681642545639,9.0 +500739010,8,80.0,9.0 +500739010,9,3512.7219836088357,9.0 +500739010,10,3850.672658473622,9.0 +500741010,7,2929.7982838467256,10.0 +500741010,8,2690.0,10.0 +500741010,9,381.40815103527575,10.0 +500741010,10,2366.5895901824165,10.0 +500741020,7,1326.9013966697125,inf +500741020,8,3245.0,inf +500741020,9,974.7097193123714,inf +500741020,10,919.3290331093233,inf +500757020,7,5254.529530812062,9.0 +500757020,8,3965.0,9.0 +500757020,9,2721.653225906042,9.0 +500757020,10,4878.815462837597,9.0 +500760010,7,4299.160525209869,9.0 +500760010,8,990.0,9.0 +500760010,9,1996.5068646784805,9.0 +500760010,10,1110.426534071463,9.0 +500764010,7,1273.825340802924,10.0 +500764010,8,198.0,10.0 +500764010,9,3842.333965985,10.0 +500764010,10,3932.17962676463,10.0 +500771020,7,661.6269201730182,9.0 +500771020,8,720.0,9.0 +500771020,9,1186.6031365541912,9.0 +500771020,10,179.10105388249406,9.0 +500772010,7,254.7650681605848,9.0 +500772010,8,275.0,9.0 +500772010,9,3724.6154008506555,9.0 +500772010,10,1383.5446834912586,9.0 +500784010,7,106.152111733577,10.0 +500784010,8,0.0,10.0 +500784010,9,0.0,10.0 +500784010,10,0.0,10.0 +500788010,7,1655.9729430438013,10.0 +500788010,8,2190.0,10.0 +500788010,9,1318.447929504657,10.0 +500788010,10,5370.337916183175,10.0 +500794010,7,106.152111733577,9.0 +500794010,8,5910.0,9.0 +500794010,9,4520.392901158823,9.0 +500794010,10,447.75263470623514,9.0 +500799020,7,1174.0423557733616,9.0 +500799020,8,2110.0,9.0 +500799020,9,3814.0815103527575,9.0 +500799020,10,10012.494420002531,9.0 +500803010,7,46961.69423093447,9.0 +500803010,8,2040.0,9.0 +500803010,9,8551.076571358775,9.0 +500803010,10,3058.3619319280456,9.0 +500805020,7,1677.2033653905166,9.0 +500805020,8,240.0,9.0 +500805020,9,25803.909477448284,9.0 +500805020,10,14199.537541094498,9.0 +500832010,7,7972.023591191633,8.0 +500832010,8,1540.0,8.0 +500832010,9,8004.862429135416,8.0 +500832010,10,9557.381037275143,8.0 +500832020,7,6061.285579987247,10.0 +500832020,8,744.0,10.0 +500832020,9,794.8357517870932,10.0 +500832020,10,901.1244978002277,10.0 +500837010,7,4882.997139744542,9.0 +500837010,8,1900.0,9.0 +500837010,9,2354.3713026868872,9.0 +500837010,10,1911.4762074550285,9.0 +500858010,7,2599.665216355301,10.0 +500858010,8,0.0,10.0 +500858010,9,16097.307470730786,10.0 +500858010,10,1922.3989286404858,10.0 +500861010,7,827.0336502162728,10.0 +500861010,8,5000.0,10.0 +500861010,9,291.942041533174,10.0 +500861010,10,582.5451298910563,10.0 +500873020,7,53.0760558667885,10.0 +500873020,8,1010.0,10.0 +500873020,9,809.9037281242893,10.0 +500873020,10,4309.923734428362,10.0 +500882010,7,0.0,10.0 +500882010,8,165.0,10.0 +500882010,9,2260.1964505794117,10.0 +500882010,10,3223.818969884893,10.0 +500890010,7,0.0,8.0 +500890010,8,234.0,8.0 +500890010,9,0.0,8.0 +500890010,10,3194.895946746262,8.0 +500895020,7,594.4518257080313,9.0 +500895020,8,268.0,9.0 +500895020,9,376.69940842990195,9.0 +500895020,10,487.8815462837597,9.0 +500896020,7,0.0,9.0 +500896020,8,400.0,9.0 +500896020,9,1175.3021543012942,9.0 +500896020,10,953.9176501966048,9.0 +500898020,7,743.0647821350391,8.0 +500898020,8,240.0,8.0 +500898020,9,339.0294675869118,8.0 +500898020,10,2548.6349432733714,8.0 +500899020,7,6369.12670401462,10.0 +500899020,8,1670.0,10.0 +500899020,9,1657.4773970915687,10.0 +500899020,10,2820.8415986492814,10.0 +500904020,7,1583.7694401641625,10.0 +500904020,8,100.0,10.0 +500904020,9,94.17485210747549,10.0 +500904020,10,7880.446370829738,10.0 +500907010,7,0.0,inf +500907010,8,0.0,inf +500907010,9,0.0,inf +500907010,10,0.0,inf +500914020,7,1135.827595549274,inf +500914020,8,2480.0,inf +500914020,9,1619.8074562485785,inf +500914020,10,16502.683211574145,inf +500946010,7,0.0,8.0 +500946010,8,0.0,8.0 +500946010,9,753.3988168598039,8.0 +500946010,10,1365.3401481821631,8.0 +500952010,7,169.8433787737232,8.0 +500952010,8,560.0,8.0 +500952010,9,1732.817278777549,8.0 +500952010,10,3285.9186232917396,8.0 +500965010,7,0.0,10.0 +500965010,8,480.0,10.0 +500965010,9,67.80589351738236,10.0 +500965010,10,0.0,10.0 +500967020,7,0.0,8.0 +500967020,8,1140.0,8.0 +500967020,9,461.4567753266299,8.0 +500967020,10,714.5280108819987,8.0 +500983010,7,382.14760224087723,10.0 +500983010,8,240.0,10.0 +500983010,9,508.54420138036767,10.0 +500983010,10,1237.9084010184947,10.0 +500987010,7,0.0,8.0 +500987010,8,0.0,8.0 +500987010,9,0.0,8.0 +500987010,10,182.0453530909551,8.0 +500988010,7,1486.1295642700782,inf +500988010,8,600.0,inf +500988010,9,1412.6227816121323,inf +500988010,10,764.5904829820114,inf +501000010,7,4755.61460566425,10.0 +501000010,8,1270.0,10.0 +501000010,9,1130.0982252897059,10.0 +501000010,10,2999.9426525317754,10.0 +501008010,7,1401.2078748832164,8.0 +501008010,8,4820.0,8.0 +501008010,9,1563.3025449840932,8.0 +501008010,10,1201.4993304003037,8.0 +501018010,7,6262.974592281043,8.0 +501018010,8,9320.0,8.0 +501018010,9,4068.3536110429413,8.0 +501018010,10,3922.31308002662,8.0 +501019010,7,191.07380112043862,8.0 +501019010,8,3200.0,8.0 +501019010,9,113.00982252897059,8.0 +501019010,10,81.92040889092979,8.0 +501038010,7,1326.9013966697125,9.0 +501038010,8,1200.0,9.0 +501038010,9,2712.235740695294,9.0 +501038010,10,1884.1694044913852,9.0 +501041010,7,1624.1273095237282,8.0 +501041010,8,830.0,8.0 +501041010,9,7119.618819325147,8.0 +501041010,10,3276.816355637192,8.0 +501044010,7,0.0,8.0 +501044010,8,0.0,8.0 +501044010,9,0.0,8.0 +501044010,10,0.0,8.0 +501049010,7,318.456335200731,9.0 +501049010,8,270.0,9.0 +501049010,9,16288.48242050896,9.0 +501049010,10,223.91578430187477,9.0 +501067020,7,1772.7402659507359,8.0 +501067020,8,1690.0,8.0 +501067020,9,2636.895859009314,8.0 +501067020,10,888.3813230838609,8.0 +501073010,7,530.760558667885,10.0 +501073010,8,400.0,10.0 +501073010,9,0.0,10.0 +501073010,10,2585.0440138915624,10.0 +501083020,7,21.2304223467154,8.0 +501083020,8,128.0,8.0 +501083020,9,165.74773970915686,8.0 +501083020,10,338.6043567491765,8.0 +501093010,7,106.152111733577,inf +501093010,8,1150.0,inf +501093010,9,1083.010799235968,inf +501093010,10,592.5576243110588,inf +501094020,7,0.0,8.0 +501094020,8,2700.0,8.0 +501094020,9,447.3305475105086,8.0 +501094020,10,773.6927506365591,8.0 +501097020,7,1061.52111733577,8.0 +501097020,8,4720.0,8.0 +501097020,9,1469.1276928766176,8.0 +501097020,10,644.7637939769786,8.0 +501103010,7,1488.2526065047496,10.0 +501103010,8,1940.0,10.0 +501103010,9,1638.6424266700735,10.0 +501103010,10,1470.0162262094625,10.0 +501103020,7,743.0647821350391,8.0 +501103020,8,2700.0,8.0 +501103020,9,6121.365386985907,8.0 +501103020,10,864.7154271820367,8.0 +501107010,7,6623.891772175205,10.0 +501107010,8,3320.0,10.0 +501107010,9,4614.567753266299,10.0 +501107010,10,13380.3334521852,10.0 +501108020,7,1447.9148040459904,10.0 +501108020,8,2020.0,10.0 +501108020,9,913.4960654425123,10.0 +501108020,10,4068.7136415828463,10.0 +501113020,7,0.0,inf +501113020,8,225.0,inf +501113020,9,141.26227816121323,inf +501113020,10,11377.834568184693,inf +501115010,7,4148.4245265481895,10.0 +501115010,8,0.0,10.0 +501115010,9,0.0,10.0 +501115010,10,16384.08177818596,10.0 +501121010,7,1459.591536336684,9.0 +501121010,8,1060.0,9.0 +501121010,9,1572.7200301948408,9.0 +501121010,10,2202.748772400557,9.0 +501122010,7,106.152111733577,8.0 +501122010,8,4940.0,8.0 +501122010,9,1205.4381069756862,8.0 +501122010,10,2475.8168020369894,8.0 +501125010,7,4829.9210838777535,8.0 +501125010,8,5780.0,8.0 +501125010,9,12431.080478186765,8.0 +501125010,10,4687.667842092093,8.0 +501126010,7,631.6050648147832,8.0 +501126010,8,90.0,8.0 +501126010,9,0.0,8.0 +501126010,10,887.4710963184061,8.0 +501128010,7,4161.162779956218,9.0 +501128010,8,6500.0,9.0 +501128010,9,15124.481248460565,9.0 +501128010,10,35498.843852736245,9.0 +501131010,7,1284.4405519762818,10.0 +501131010,8,878.0,10.0 +501131010,9,1252.525533029424,10.0 +501131010,10,364.0907061819102,10.0 +501131020,7,721.8343597883236,10.0 +501131020,8,2050.0,10.0 +501131020,9,2373.2062731083824,10.0 +501131020,10,3540.782117619077,10.0 +501136010,7,16457.823403173777,9.0 +501136010,8,894.0,9.0 +501136010,9,841.9231778408309,9.0 +501136010,10,1091.3618917802758,9.0 +501141020,7,764.2952044817545,9.0 +501141020,8,4720.0,9.0 +501141020,9,2179.206077766983,9.0 +501141020,10,6116.723863856091,9.0 +501159010,7,2590.111526299279,inf +501159010,8,1780.0,inf +501159010,9,2759.3231667490318,inf +501159010,10,2002.498884000506,inf +501174010,7,5260.898657516076,9.0 +501174010,8,2084.0,9.0 +501174010,9,0.0,9.0 +501174010,10,0.0,9.0 +501177010,7,1583.7895070649688,10.0 +501177010,8,1535.0,10.0 +501177010,9,17144.531826165912,10.0 +501177010,10,436.9088474182922,10.0 +501180010,7,3359.7143363677123,9.0 +501180010,8,1260.0,9.0 +501180010,9,4445.0530194728435,9.0 +501180010,10,2912.7256494552817,9.0 +501181010,7,445.83886928102345,8.0 +501181010,8,720.0,8.0 +501181010,9,3156.2524694412054,8.0 +501181010,10,1011.9209544360914,8.0 +501184010,7,53.0760558667885,9.0 +501184010,8,25.0,9.0 +501184010,9,0.0,9.0 +501184010,10,330.4123158600835,9.0 +501189010,7,2229.194346405117,9.0 +501189010,8,1700.0,9.0 +501189010,9,1459.71020766587,9.0 +501189010,10,1708.6240540389933,9.0 +501203010,7,275.9954905073002,8.0 +501203010,8,5780.0,8.0 +501203010,9,1996.5068646784805,8.0 +501203010,10,3913.9750914555348,8.0 +501206020,7,2717.4940603795712,inf +501206020,8,1145.0,inf +501206020,9,1892.9145273602574,inf +501206020,10,2311.97598425513,inf +501210010,7,530.760558667885,10.0 +501210010,8,150.0,10.0 +501210010,9,470.87426053737744,10.0 +501210010,10,2912.7256494552817,10.0 +501212010,7,2547.650681605848,9.0 +501212010,8,4268.0,9.0 +501212010,9,5838.84083066348,9.0 +501212010,10,9223.704274948444,9.0 +501212020,7,2600.7267374726366,9.0 +501212020,8,3920.0,9.0 +501212020,9,6714.666955263003,9.0 +501212020,10,5283.481089533575,9.0 +501213020,7,1592.281676003655,9.0 +501213020,8,4500.0,9.0 +501213020,9,1657.4773970915687,9.0 +501213020,10,2443.0486384806172,9.0 +501214020,7,0.0,8.0 +501214020,8,0.0,8.0 +501214020,9,0.0,8.0 +501214020,10,0.0,8.0 +501218010,7,21.2304223467154,8.0 +501218010,8,0.0,8.0 +501218010,9,64.98064795415809,8.0 +501218010,10,0.0,8.0 +501219010,7,15.506880941555115,inf +501219010,8,0.0,inf +501219010,9,0.0,inf +501219010,10,0.0,inf +501220010,7,1061.52111733577,8.0 +501220010,8,3170.0,8.0 +501220010,9,1167.768166132696,8.0 +501220010,10,1201.4993304003037,8.0 +501225020,7,1061.52111733577,9.0 +501225020,8,2880.0,9.0 +501225020,9,7624.396026621216,9.0 +501225020,10,269.4271225746135,9.0 +501226020,7,4893.6123509179,9.0 +501226020,8,3240.0,9.0 +501226020,9,4784.082487059755,9.0 +501226020,10,1074.067583236635,9.0 +501231010,7,1167.6732290693471,8.0 +501231010,8,2150.0,8.0 +501231010,9,301.35952674392155,8.0 +501231010,10,31.857936790917144,8.0 +501238020,7,2653.802793339425,9.0 +501238020,8,1640.0,9.0 +501238020,9,2580.3909477448283,9.0 +501238020,10,3477.0662440372425,9.0 +501239010,7,615.6822480547467,8.0 +501239010,8,720.0,8.0 +501239010,9,1619.8074562485785,8.0 +501239010,10,1416.3128470476306,8.0 +501247010,7,1528.590408963509,9.0 +501247010,8,511.3990253689043,9.0 +501247010,9,1742.2347639882967,9.0 +501247010,10,0.0,9.0 +501249010,7,33013.30674914245,10.0 +501249010,8,1420.0,10.0 +501249010,9,11416.817320989254,10.0 +501249010,10,5625.201410510513,10.0 +501254020,7,14012.078748832164,9.0 +501254020,8,13350.0,9.0 +501254020,9,4332.043196943872,9.0 +501254020,10,3429.785181849761,9.0 +501260010,7,0.0,9.0 +501260010,8,50.0,9.0 +501260010,9,2825.2455632242645,9.0 +501260010,10,877.4586018984036,9.0 +501267010,7,836.4786404605868,10.0 +501267010,8,1680.0,10.0 +501267010,9,1629.224941459326,10.0 +501267010,10,1328.9310775639722,10.0 +501270010,7,626.2974592281043,inf +501270010,8,3625.0,inf +501270010,9,0.0,inf +501270010,10,0.0,inf +501276010,7,546.6833754279215,inf +501276010,8,1646.549892286245,inf +501276010,9,687.476420384571,inf +501276010,10,1343.2579041187055,inf +501281010,7,53.0760558667885,10.0 +501281010,8,1225.0,10.0 +501281010,9,4708.7426053737745,10.0 +501281010,10,2184.544237091461,10.0 +501282010,7,3566.7109542481876,inf +501282010,8,2480.0,inf +501282010,9,188.34970421495098,inf +501282010,10,5643.405945819608,inf +501283010,7,859.8321050419737,9.0 +501283010,8,7720.0,9.0 +501283010,9,2806.4105928027698,9.0 +501283010,10,2955.167389061152,9.0 +501284020,7,6757.643432959512,9.0 +501284020,8,1144.0,9.0 +501284020,9,3258.449882918652,9.0 +501284020,10,1491.861668580377,9.0 +501296010,7,1103.9819620292008,8.0 +501296010,8,600.0,8.0 +501296010,9,188.34970421495098,8.0 +501296010,10,819.204088909298,8.0 +501317010,7,2632.5723709927097,9.0 +501317010,8,870.0,9.0 +501317010,9,772.233787281299,9.0 +501317010,10,638.9791893492524,9.0 +501323020,7,2123.04223467154,inf +501323020,8,1000.0,inf +501323020,9,211.89341724181986,inf +501323020,10,182.0453530909551,inf +501328010,7,1210.134073762778,9.0 +501328010,8,7220.0,9.0 +501328010,9,734.5638464383088,9.0 +501328010,10,6608.828888264031,9.0 +501328020,7,231.41160357919787,10.0 +501328020,8,25120.0,10.0 +501328020,9,0.0,10.0 +501328020,10,2256.6732789194252,10.0 +501334020,7,3237.6394078740987,inf +501334020,8,2200.0,inf +501334020,9,828.7386985457844,inf +501334020,10,910.2267654547755,inf +501340020,7,0.0,8.0 +501340020,8,1160.0,8.0 +501340020,9,2486.2160956373527,8.0 +501340020,10,182.0453530909551,8.0 +501341010,7,8279.864715219006,10.0 +501341010,8,2338.0,10.0 +501341010,9,256.1555977323333,10.0 +501341010,10,8943.888197358623,10.0 +501350010,7,0.0,8.0 +501350010,8,500.0,8.0 +501350010,9,2636.895859009314,8.0 +501350010,10,1074.6063232949643,8.0 +501359020,7,3609.1717989416184,inf +501359020,8,2300.0,inf +501359020,9,14445.602017468744,inf +501359020,10,2753.435965500696,inf +501363010,7,636.912670401462,8.0 +501363010,8,201.4602221150229,8.0 +501363010,9,904.0785802317647,8.0 +501363010,10,327.68163556371917,8.0 +501376010,7,0.0,9.0 +501376010,8,0.0,9.0 +501376010,9,113.00982252897059,9.0 +501376010,10,0.0,9.0 +501377010,7,3035.9503955803025,9.0 +501377010,8,1300.0,9.0 +501377010,9,1318.447929504657,9.0 +501377010,10,2148.13516647327,9.0 +501386010,7,318.456335200731,9.0 +501386010,8,350.0,9.0 +501386010,9,2962.7408473011787,9.0 +501386010,10,2518.1608175878664,9.0 +501395010,7,237.77217443717842,8.0 +501395010,8,310.0,8.0 +501395010,9,1005.7874205078382,8.0 +501395010,10,2093.5215605459834,8.0 +501396010,7,530.760558667885,10.0 +501396010,8,1500.0,10.0 +501396010,9,9.417485210747548,10.0 +501396010,10,273.06802963643264,10.0 +501398010,7,1793.9706882974515,9.0 +501398010,8,1694.9778302946638,9.0 +501398010,9,2022.5410939235312,9.0 +501398010,10,179.10105388249406,9.0 +501398020,7,1061.52111733577,10.0 +501398020,8,4842.793800841897,10.0 +501398020,9,2358.119661076763,10.0 +501398020,10,9850.557963537172,10.0 +501400020,7,0.0,8.0 +501400020,8,810.0,8.0 +501400020,9,235.43713026868872,8.0 +501400020,10,0.0,8.0 +501401020,7,3609.1717989416184,10.0 +501401020,8,4200.0,10.0 +501401020,9,2900.5854449102453,10.0 +501401020,10,4396.395277146566,10.0 +501402010,7,53.0760558667885,9.0 +501402010,8,80.0,9.0 +501402010,9,1012.3796601553615,9.0 +501402010,10,728.1814123638204,9.0 +501410010,7,1241.979707282851,8.0 +501410010,8,1355.0,8.0 +501410010,9,2147.1866280504414,8.0 +501410010,10,1856.862601527742,8.0 +501413010,7,1592.281676003655,9.0 +501413010,8,8600.0,9.0 +501413010,9,8616.998967834008,9.0 +501413010,10,655.3632711274383,9.0 +501413020,7,318.456335200731,inf +501413020,8,50.0,inf +501413020,9,2260.1964505794117,inf +501413020,10,0.0,inf +501414020,7,5519.909810146004,10.0 +501414020,8,6000.0,10.0 +501414020,9,14597.1020766587,10.0 +501414020,10,32768.16355637192,10.0 +501415010,7,2972.2591285401563,inf +501415010,8,2060.0,inf +501415010,9,1035.9233731822303,inf +501415010,10,364.0907061819102,inf +501416010,7,350.3019687208041,10.0 +501416010,8,170.0,10.0 +501416010,9,1759.1862373676422,10.0 +501416010,10,1747.635389673169,10.0 +501417020,7,304.656560675366,9.0 +501417020,8,540.0,9.0 +501417020,9,880.5348672048958,9.0 +501417020,10,44.775263470623514,9.0 +501419020,7,51218.393911450905,9.0 +501419020,8,2650.0,9.0 +501419020,9,7533.988168598039,9.0 +501419020,10,12743.174716366857,9.0 +501421010,7,764.2952044817545,inf +501421010,8,2400.0,inf +501421010,9,452.03929011588235,inf +501421010,10,21.84544237091461,inf +501422010,7,17440.791957826703,10.0 +501422010,8,2275.0,10.0 +501422010,9,3277.284853340147,10.0 +501422010,10,4209.798790228337,10.0 +501431010,7,1273.825340802924,8.0 +501431010,8,2500.0,8.0 +501431010,9,18.834970421495097,8.0 +501431010,10,336.7839032182669,8.0 +501440010,7,527.5759953158777,8.0 +501440010,8,1120.0,8.0 +501440010,9,979.418461917745,8.0 +501440010,10,2257.362378327843,8.0 +501440020,7,578.9235551513909,inf +501440020,8,805.0,inf +501440020,9,1318.447929504657,inf +501440020,10,973.9426390366098,inf +501459010,7,106.152111733577,9.0 +501459010,8,67.0,9.0 +501459010,9,65.92239647523284,9.0 +501459010,10,1510.9764306549273,9.0 +501464010,7,6093.13121350732,8.0 +501464010,8,9260.0,8.0 +501464010,9,7439.813316490564,8.0 +501464010,10,1019.4539773093486,8.0 +501465020,7,0.0,inf +501465020,8,145.2838140252569,inf +501465020,9,84.75736689672794,inf +501465020,10,3276.816355637192,inf +501467010,7,1608.2044927636916,10.0 +501467010,8,2300.0,10.0 +501467010,9,565.0491126448529,10.0 +501467010,10,1197.8584233384845,10.0 +501467020,7,1276.733197521371,10.0 +501467020,8,4450.0,10.0 +501467020,9,400.24312145677084,10.0 +501467020,10,1371.7117355403466,10.0 +501486010,7,106.152111733577,8.0 +501486010,8,260.0,8.0 +501486010,9,5085.442013803677,8.0 +501486010,10,2164.5192482514562,8.0 +501494020,7,0.0,10.0 +501494020,8,351.0,10.0 +501494020,9,994.4864382549412,10.0 +501494020,10,1486.5387472247007,10.0 +501498020,7,1647.4807741051152,10.0 +501498020,8,1455.0,10.0 +501498020,9,2222.5265097364218,10.0 +501498020,10,0.0,10.0 +501504020,7,743.0647821350391,9.0 +501504020,8,17880.0,9.0 +501504020,9,4953.597220853211,9.0 +501504020,10,16405.656535636455,9.0 +501507010,7,1379.977452536501,9.0 +501507010,8,0.0,9.0 +501507010,9,8664.086393887745,9.0 +501507010,10,246.2639490884293,9.0 +501516010,7,0.0,8.0 +501516010,8,58.11352561010276,8.0 +501516010,9,188.34970421495098,8.0 +501516010,10,0.0,8.0 +501521010,7,0.0,9.0 +501521010,8,168.0,9.0 +501521010,9,3239.614912497157,9.0 +501521010,10,0.0,9.0 +501528010,7,785.5256268284699,10.0 +501528010,8,1680.0,10.0 +501528010,9,1261.9430182401716,10.0 +501528010,10,4405.497544801114,10.0 +501530010,7,1815.2011106441669,8.0 +501530010,8,2035.0,8.0 +501530010,9,970.0009767069976,8.0 +501530010,10,4369.088474182922,8.0 +501536010,7,5095.301363211696,8.0 +501536010,8,5540.0,8.0 +501536010,9,3578.644380084069,8.0 +501536010,10,18022.489956004556,8.0 +501540010,7,743.0647821350391,inf +501540010,8,450.0,inf +501540010,9,753.3988168598039,inf +501540010,10,254.86349432733715,inf +501543010,7,2101.8118123248246,9.0 +501543010,8,8480.0,9.0 +501543010,9,2768.7406519597794,9.0 +501543010,10,1656.6127131276914,9.0 +501554010,7,1613.5120983503705,8.0 +501554010,8,0.0,8.0 +501554010,9,2034.1768055214707,8.0 +501554010,10,3276.816355637192,8.0 +501555020,7,2133.6574458448977,inf +501555020,8,2925.047455708506,inf +501555020,9,9.417485210747548,inf +501555020,10,3713.725203055484,inf +501557010,7,0.0,9.0 +501557010,8,180.0,9.0 +501557010,9,474.64125462167647,9.0 +501557010,10,0.0,9.0 +501559020,7,0.0,inf +501559020,8,1600.0,inf +501559020,9,2316.701361843897,inf +501559020,10,500.6247210001265,inf +501569010,7,15073.599866167935,8.0 +501569010,8,42500.0,8.0 +501569010,9,941.7485210747549,8.0 +501569010,10,0.0,8.0 +501571010,7,2032.8129396979996,8.0 +501571010,8,3345.0,8.0 +501571010,9,4520.392901158823,8.0 +501571010,10,10746.063232949644,8.0 +501574010,7,302.5335184406945,8.0 +501574010,8,7600.0,8.0 +501574010,9,3936.5088180924754,8.0 +501574010,10,5820.784251181057,8.0 +501575010,7,11252.123843759162,8.0 +501575010,8,2700.0,8.0 +501575010,9,1083.010799235968,8.0 +501575010,10,3481.617377864516,8.0 +501579010,7,562.6061921879581,10.0 +501579010,8,268.0,10.0 +501579010,9,3077.634166872299,10.0 +501579010,10,3398.7867422081317,10.0 +501595020,7,917.1542453781053,10.0 +501595020,8,480.0,10.0 +501595020,9,0.0,10.0 +501595020,10,393.217962676463,10.0 +501596020,7,838.6016826952583,9.0 +501596020,8,390.0,9.0 +501596020,9,188.34970421495098,9.0 +501596020,10,182.0453530909551,9.0 +501599010,7,1740.8946324306628,10.0 +501599010,8,2630.0,10.0 +501599010,9,913.4960654425123,10.0 +501599010,10,919.3290331093233,10.0 +501605010,7,1783.3554771240938,8.0 +501605010,8,1600.0,8.0 +501605010,9,880.5348672048958,8.0 +501605010,10,5552.383269274131,8.0 +501617010,7,1141.135201135953,inf +501617010,8,520.0,inf +501617010,9,0.0,inf +501617010,10,1092.2721185457306,inf +501628010,7,3184.56335200731,8.0 +501628010,8,1820.0,8.0 +501628010,9,3917.67384767098,8.0 +501628010,10,3640.907061819102,8.0 +501629020,7,2972.2591285401563,10.0 +501629020,8,5040.0,10.0 +501629020,9,3371.4597054476226,10.0 +501629020,10,1547.3855012731183,10.0 +501630020,7,626.2974592281043,8.0 +501630020,8,85.0,8.0 +501630020,9,40.49518640621446,8.0 +501630020,10,393.217962676463,8.0 +501632020,7,2123.04223467154,9.0 +501632020,8,1225.0,9.0 +501632020,9,4708.7426053737745,9.0 +501632020,10,18.204535309095508,9.0 +501635010,7,3078.4112402737333,9.0 +501635010,8,1440.0,9.0 +501635010,9,0.0,9.0 +501635010,10,2149.2126465899287,9.0 +501643010,7,47.768450280109654,8.0 +501643010,8,2670.0,8.0 +501643010,9,1977.6718942569853,8.0 +501643010,10,291.27256494552813,8.0 +501647010,7,0.0,10.0 +501647010,8,75.0,10.0 +501647010,9,1412.6227816121323,10.0 +501647010,10,4642.156503819355,10.0 +501651010,7,1677.2033653905166,9.0 +501651010,8,4832.0,9.0 +501651010,9,4911.218537404847,9.0 +501651010,10,1791.0105388249406,9.0 +501653010,7,3173.9481408339525,10.0 +501653010,8,1580.0,10.0 +501653010,9,772.233787281299,10.0 +501653010,10,3513.4753146554335,10.0 +501665020,7,260.07267374726365,8.0 +501665020,8,1020.0,8.0 +501665020,9,1327.8654147154043,8.0 +501665020,10,209.35215605459837,8.0 +501666020,7,3078.4112402737333,8.0 +501666020,8,1500.0,8.0 +501666020,9,2542.7210069018383,8.0 +501666020,10,2293.771448946034,8.0 +501671020,7,435.2236581076657,10.0 +501671020,8,795.0,10.0 +501671020,9,576.35009489775,10.0 +501671020,10,3822.952414910057,10.0 +501684020,7,1889.5075888576707,inf +501684020,8,2640.0,inf +501684020,9,840.0396807986814,inf +501684020,10,1729.4308543640734,inf +501688010,7,95.53690056021931,10.0 +501688010,8,1000.0,10.0 +501688010,9,1167.768166132696,10.0 +501688010,10,1720.3285867095258,10.0 +501695010,7,6156.8224805474665,8.0 +501695010,8,11900.0,8.0 +501695010,9,6234.3752095148775,8.0 +501695010,10,5461.360592728653,8.0 +501710010,7,275.9954905073002,10.0 +501710010,8,480.0,10.0 +501710010,9,461.4567753266299,10.0 +501710010,10,1244.7523244833337,10.0 +501715010,7,5095.301363211696,8.0 +501715010,8,61200.0,8.0 +501715010,9,2915.653421247441,8.0 +501715010,10,3327.7890545026594,8.0 +501717020,7,743.0647821350391,8.0 +501717020,8,8000.0,8.0 +501717020,9,1977.6718942569853,8.0 +501717020,10,10746.063232949644,8.0 +501734010,7,0.0,9.0 +501734010,8,300.0,9.0 +501734010,9,94.17485210747549,9.0 +501734010,10,0.0,9.0 +501736010,7,12738.25340802924,9.0 +501736010,8,100.0,9.0 +501736010,9,0.0,9.0 +501736010,10,36.409070618191016,9.0 +501745010,7,318.456335200731,8.0 +501745010,8,757.0,8.0 +501745010,9,361.6314320927059,8.0 +501745010,10,762.9704895394246,8.0 +501746010,7,169.8433787737232,8.0 +501746010,8,0.0,8.0 +501746010,9,12807.779886616667,8.0 +501746010,10,3313.225426255383,8.0 +501747020,7,161.35120983503705,8.0 +501747020,8,698.0,8.0 +501747020,9,979.418461917745,8.0 +501747020,10,473.31791803648326,8.0 +501748010,7,0.0,10.0 +501748010,8,0.0,10.0 +501748010,9,904.0785802317647,10.0 +501748010,10,436.9088474182922,10.0 +501748020,7,31.8456335200731,9.0 +501748020,8,25.0,9.0 +501748020,9,23.543713026868872,9.0 +501748020,10,91.02267654547755,9.0 +501760010,7,2882.0298335666157,9.0 +501760010,8,880.0,9.0 +501760010,9,4746.412546216765,9.0 +501760010,10,6735.678064365338,9.0 +501767010,7,0.0,9.0 +501767010,8,640.0,9.0 +501767010,9,14597.1020766587,9.0 +501767010,10,113.77834568184694,9.0 +501768020,7,849.216893868616,9.0 +501768020,8,1520.0,9.0 +501768020,9,791.0687577027941,9.0 +501768020,10,3094.7710025462366,9.0 +501770010,7,265.3802793339425,8.0 +501770010,8,580.0,8.0 +501770010,9,264.8349773209288,8.0 +501770010,10,653.7188466711033,8.0 +501779010,7,0.0,8.0 +501779010,8,0.0,8.0 +501779010,9,687.476420384571,8.0 +501779010,10,0.0,8.0 +501780010,7,152.85904089635088,8.0 +501780010,8,100.0,8.0 +501780010,9,135.61178703476472,8.0 +501780010,10,573.123372423981,8.0 +501786020,7,169.8433787737232,9.0 +501786020,8,520.0,9.0 +501786020,9,1582.1375154055881,9.0 +501786020,10,0.0,9.0 +501790010,7,1103.9819620292008,9.0 +501790010,8,1080.0,9.0 +501790010,9,2731.0707111167894,9.0 +501790010,10,1492.7718953458318,9.0 +501803020,7,2802.415749766433,8.0 +501803020,8,59860.0,8.0 +501803020,9,2665.148314641556,8.0 +501803020,10,946.6358360729665,8.0 +501804010,7,0.0,10.0 +501804010,8,0.0,10.0 +501804010,9,0.0,10.0 +501804010,10,0.0,10.0 +501809010,7,1122.027821023909,8.0 +501809010,8,0.0,8.0 +501809010,9,0.0,8.0 +501809010,10,0.0,8.0 +501813010,7,10.33792062770341,10.0 +501813010,8,0.0,10.0 +501813010,9,1473.8364354819914,10.0 +501813010,10,6553.632711274384,10.0 +501828010,7,318.456335200731,9.0 +501828010,8,1646.549892286245,9.0 +501828010,9,1506.7976337196078,9.0 +501828010,10,2621.1439235703006,9.0 +501831010,7,0.0,9.0 +501831010,8,0.0,9.0 +501831010,9,0.0,9.0 +501831010,10,0.0,9.0 +501832010,7,1881.5015542420206,9.0 +501832010,8,60.0,9.0 +501832010,9,1921.1669829925,9.0 +501832010,10,1855.4869182226385,9.0 +501834010,7,0.0,9.0 +501834010,8,5000.0,9.0 +501834010,9,20530.117759429657,9.0 +501834010,10,22027.48772400557,9.0 +501842010,7,2186.733501711686,9.0 +501842010,8,1200.0,9.0 +501842010,9,470.87426053737744,9.0 +501842010,10,0.0,9.0 +501842020,7,33708.603080997374,10.0 +501842020,8,3960.0,10.0 +501842020,9,13598.848644319462,10.0 +501842020,10,10058.005758275269,10.0 +501845010,7,13481.31819016428,8.0 +501845010,8,6900.0,8.0 +501845010,9,9069.691004141396,8.0 +501845010,10,48606.10927528501,8.0 +501847010,7,286.61070168065794,10.0 +501847010,8,300.0,10.0 +501847010,9,0.0,10.0 +501847010,10,1737.2802226601923,10.0 +501850020,7,965.9842167755507,9.0 +501850020,8,2270.0,9.0 +501850020,9,19119.378474859674,9.0 +501850020,10,4065.593923132615,9.0 +501856010,7,1134.069892859064,9.0 +501856010,8,1760.0,9.0 +501856010,9,3898.8388772494854,9.0 +501856010,10,1601.9991072004048,9.0 +501863020,7,424.608446934308,8.0 +501863020,8,2060.0,8.0 +501863020,9,2156.6041132611886,8.0 +501863020,10,2275.566913636939,8.0 +501876010,7,2123.04223467154,inf +501876010,8,600.0,inf +501876010,9,1412.6227816121323,inf +501876010,10,182.0453530909551,inf +501879010,7,796.1408380018275,10.0 +501879010,8,4455.370296774545,10.0 +501879010,9,1431.4577520336275,10.0 +501879010,10,2757.9870993279696,10.0 +501881020,7,6369.12670401462,10.0 +501881020,8,1700.0,10.0 +501881020,9,819.3212133350368,10.0 +501881020,10,7176.22781884545,10.0 +501882010,7,8386.016826952584,8.0 +501882010,8,13460.0,8.0 +501882010,9,10342.282258442958,8.0 +501882010,10,8319.472636256647,8.0 +501889020,7,4033.780245875926,8.0 +501889020,8,12140.0,8.0 +501889020,9,7722.33787281299,8.0 +501889020,10,7394.682242554596,8.0 +501892010,7,3184.56335200731,9.0 +501892010,8,2325.0,9.0 +501892010,9,4520.392901158823,9.0 +501892010,10,728.1814123638204,9.0 +501893010,7,0.0,9.0 +501893010,8,0.0,9.0 +501893010,9,0.0,9.0 +501893010,10,12178.871664009595,9.0 +501893020,7,2016.890122937963,8.0 +501893020,8,390.0,8.0 +501893020,9,70.63113908060662,8.0 +501893020,10,147.75836945305758,8.0 +501903020,7,774.9104156551122,10.0 +501903020,8,1360.0,10.0 +501903020,9,1789.3221900420344,10.0 +501903020,10,2184.544237091461,10.0 +501912020,7,161351.20983503704,10.0 +501912020,8,21300.0,10.0 +501912020,9,18364.09616095772,10.0 +501912020,10,94923.55855772184,10.0 +501917010,7,1040.2906949890546,8.0 +501917010,8,6350.0,8.0 +501917010,9,5405.636510969093,8.0 +501917010,10,3882.1171546646174,8.0 +501931020,7,5148.377419078484,10.0 +501931020,8,9600.0,10.0 +501931020,9,5838.84083066348,10.0 +501931020,10,4241.656727019254,10.0 +501932020,7,1040.2906949890546,inf +501932020,8,880.0,inf +501932020,9,1196.0206217649388,inf +501932020,10,3586.2934558918155,inf +501933010,7,1539.2056201368666,8.0 +501933010,8,300.0,8.0 +501933010,9,0.0,8.0 +501933010,10,1554.6673153967565,8.0 +501939010,7,1751.5098436040205,9.0 +501939010,8,2300.0,9.0 +501939010,9,4060.819622874343,9.0 +501939010,10,582.5451298910563,9.0 +501942010,7,0.0,8.0 +501942010,8,92.0,8.0 +501942010,9,18.834970421495097,8.0 +501942010,10,0.0,8.0 +501947010,7,1061.52111733577,9.0 +501947010,8,985.0,9.0 +501947010,9,30427.89471592533,9.0 +501947010,10,7463.859476729159,9.0 +501948010,7,6050.67036881389,8.0 +501948010,8,5500.0,8.0 +501948010,9,1977.6718942569853,8.0 +501948010,10,7682.313900438305,8.0 +501951020,7,0.0,10.0 +501951020,8,150.0,10.0 +501951020,9,30606.826934929533,10.0 +501951020,10,18357.85802295564,10.0 +501954010,7,42.4608446934308,9.0 +501954010,8,2045.0,9.0 +501954010,9,1436.1664946390013,9.0 +501954010,10,2417.8642274136696,9.0 +501970010,7,10785.054552131423,8.0 +501970010,8,19050.0,8.0 +501970010,9,9040.785802317647,8.0 +501970010,10,14199.537541094498,8.0 +501975010,7,100.84450614689815,inf +501975010,8,0.0,inf +501975010,9,181.7574645674277,inf +501975010,10,364.0907061819102,inf +501977020,7,8386.016826952584,10.0 +501977020,8,4880.0,10.0 +501977020,9,6479.229824994314,10.0 +501977020,10,11559.87992127565,10.0 +501989010,7,530.760558667885,8.0 +501989010,8,2556.9951268445216,8.0 +501989010,9,480.693623219494,8.0 +501989010,10,2238.7631735311757,8.0 +501990010,7,1486.1295642700782,8.0 +501990010,8,1040.0,8.0 +501990010,9,583.884083066348,8.0 +501990010,10,336.7839032182669,8.0 +501991010,7,191.07380112043862,10.0 +501991010,8,180.0,10.0 +501991010,9,181.39382008282792,10.0 +501991010,10,637.1587358183428,10.0 +501993010,7,10.6152111733577,10.0 +501993010,8,775.0,10.0 +501993010,9,941.7485210747549,10.0 +501993010,10,1115.9380144475547,10.0 +501996010,7,3184.56335200731,8.0 +501996010,8,480.0,8.0 +501996010,9,1243.1080478186764,8.0 +501996010,10,1856.862601527742,8.0 +502000010,7,1486.1295642700782,8.0 +502000010,8,2020.0,8.0 +502000010,9,3116.245856236364,8.0 +502000010,10,1660.2536201895105,8.0 +502002010,7,0.0,8.0 +502002010,8,0.0,8.0 +502002010,9,0.0,8.0 +502002010,10,873.8176948365845,8.0 +502003010,7,3057.180817927018,8.0 +502003010,8,1200.0,8.0 +502003010,9,1789.3221900420344,8.0 +502003010,10,218.4544237091461,8.0 +502008010,7,281.30309609397904,inf +502008010,8,25.0,inf +502008010,9,0.0,inf +502008010,10,273.06802963643264,inf +502018010,7,2547.650681605848,9.0 +502018010,8,0.0,9.0 +502018010,9,391.76738476709806,9.0 +502018010,10,68.26700740910816,9.0 +502031010,7,2919.183072673368,8.0 +502031010,8,4050.0,8.0 +502031010,9,2335.536332265392,8.0 +502031010,10,2020.7034193096015,8.0 +502039010,7,10.6152111733577,9.0 +502039010,8,1680.0,9.0 +502039010,9,530.204417365087,9.0 +502039010,10,1572.871850705852,9.0 +502043010,7,152.85904089635088,10.0 +502043010,8,269.0,10.0 +502043010,9,612.1365386985907,10.0 +502043010,10,500.6247210001265,10.0 +502043020,7,817.3712603485429,inf +502043020,8,2914.0,inf +502043020,9,2900.5854449102453,inf +502043020,10,1310.7265422548767,inf +502044020,7,785.5256268284699,9.0 +502044020,8,1540.0,9.0 +502044020,9,583.884083066348,9.0 +502044020,10,1929.680742764124,9.0 +502049020,7,47.768450280109654,9.0 +502049020,8,300.0,9.0 +502049020,9,15821.375154055882,9.0 +502049020,10,2184.544237091461,9.0 +502053020,7,135.87470301897858,inf +502053020,8,100.0,inf +502053020,9,77.2233787281299,inf +502053020,10,300.37483260007593,inf +502054010,7,8704.473162153314,8.0 +502054010,8,16124.281287119431,8.0 +502054010,9,11621.176750062476,8.0 +502054010,10,19569.875457277674,8.0 +502060010,7,6416.89515429473,9.0 +502060010,8,1925.0,9.0 +502060010,9,847.5736689672794,9.0 +502060010,10,819.204088909298,9.0 +502065010,7,8725.70358450003,8.0 +502065010,8,1544.0,8.0 +502065010,9,3653.984261770049,8.0 +502065010,10,1875.0671368368376,8.0 +502072010,7,3046.56560675366,8.0 +502072010,8,6000.0,8.0 +502072010,9,3126.6050899681863,8.0 +502072010,10,2657.8621551279443,8.0 +502073010,7,2123.04223467154,8.0 +502073010,8,3300.0,8.0 +502073010,9,574.4665978556005,8.0 +502073010,10,1038.7861125184654,8.0 +502077010,7,509.5301363211696,inf +502077010,8,192.0,inf +502077010,9,414.3693492728922,inf +502077010,10,309.4771002546237,inf +502081020,7,3630.4022212883337,9.0 +502081020,8,3000.0,9.0 +502081020,9,1779.9047048312868,9.0 +502081020,10,7645.904829820114,9.0 +502086010,7,2736.601440491615,8.0 +502086010,8,12980.0,8.0 +502086010,9,19588.369238354902,8.0 +502086010,10,13016.242746003289,8.0 +502088020,7,1528.590408963509,10.0 +502088020,8,500.0,10.0 +502088020,9,461.4567753266299,10.0 +502088020,10,1419.9537541094498,10.0 +502094020,7,4415.927848116803,8.0 +502094020,8,4940.0,8.0 +502094020,9,2646.3133442200615,8.0 +502094020,10,4100.571578373763,8.0 +502102020,7,1167.6732290693471,10.0 +502102020,8,4600.0,10.0 +502102020,9,7194.958701011127,10.0 +502102020,10,25759.417462370147,10.0 +502104010,7,91.29081609087622,10.0 +502104010,8,588.0,10.0 +502104010,9,542.4471481390589,10.0 +502104010,10,1995.217069876868,10.0 +502113010,7,21.2304223467154,9.0 +502113010,8,100.0,9.0 +502113010,9,423.7868344836397,9.0 +502113010,10,0.0,9.0 +502117010,7,849.216893868616,9.0 +502117010,8,900.0,9.0 +502117010,9,37396.83377187852,9.0 +502117010,10,682.6700740910816,9.0 +502118010,7,16135.120983503704,9.0 +502118010,8,36236.0,9.0 +502118010,9,4708.7426053737745,9.0 +502118010,10,4232.554459364706,9.0 +502120010,7,1592.281676003655,10.0 +502120010,8,40.0,10.0 +502120010,9,296.6507841385478,10.0 +502120010,10,5731.23372423981,10.0 +502122010,7,2377.807302832125,9.0 +502122010,8,1340.0,9.0 +502122010,9,36125.473268427595,9.0 +502122010,10,8919.232483348203,9.0 +502146010,7,10.6152111733577,10.0 +502146010,8,0.0,10.0 +502146010,9,0.0,10.0 +502146010,10,74853.49445964956,10.0 +502182010,7,318.456335200731,9.0 +502182010,8,0.0,9.0 +502182010,9,3201.9449716541667,9.0 +502182010,10,68.26700740910816,9.0 +502182020,7,1061.52111733577,10.0 +502182020,8,25.0,10.0 +502182020,9,94.17485210747549,10.0 +502182020,10,7099.768770547249,10.0 +502183010,7,1857.6619553375976,10.0 +502183010,8,1325.0,10.0 +502183010,9,3766.9940842990195,10.0 +502183010,10,7190.791447092726,10.0 +502198010,7,1273.825340802924,8.0 +502198010,8,2687.0,8.0 +502198010,9,19010.2333691509,8.0 +502198010,10,10536.78503690448,8.0 +502198020,7,0.0,10.0 +502198020,8,2000.0,10.0 +502198020,9,1883.4970421495098,10.0 +502198020,10,1456.3628247276408,10.0 +502202010,7,3290.715463740887,10.0 +502202010,8,0.0,10.0 +502202010,9,0.0,10.0 +502202010,10,11686.343765832737,10.0 +502217020,7,923.52337208212,10.0 +502217020,8,240.0,10.0 +502217020,9,339.0294675869118,10.0 +502217020,10,2793.976440566907,10.0 +502224010,7,0.0,9.0 +502224010,8,720.0,9.0 +502224010,9,70.63113908060662,9.0 +502224010,10,0.0,9.0 +502225020,7,5371.296853718996,9.0 +502225020,8,5360.0,9.0 +502225020,9,4897.092309588726,9.0 +502225020,10,3420.8301291556363,9.0 +502227020,7,0.0,8.0 +502227020,8,472.0,8.0 +502227020,9,176.10697344097917,8.0 +502227020,10,229.37714489460342,8.0 +502229010,7,318.456335200731,10.0 +502229010,8,100.0,10.0 +502229010,9,606.4860475721422,10.0 +502229010,10,1522.3589580011994,10.0 +502233010,7,1897.9997577963568,inf +502233010,8,760.0,inf +502233010,9,0.0,inf +502233010,10,91.02267654547755,inf +502249020,7,3184.56335200731,8.0 +502249020,8,0.0,8.0 +502249020,9,248.6216095637353,8.0 +502249020,10,393.217962676463,8.0 +502263010,7,4989.149251478119,9.0 +502263010,8,1480.0,9.0 +502263010,9,10170.884027607353,9.0 +502263010,10,11377.834568184693,9.0 +502268020,7,249.45746257390596,10.0 +502268020,8,0.0,10.0 +502268020,9,659.2239647523285,10.0 +502268020,10,1365.3401481821631,10.0 +502271010,7,35200.04025085414,10.0 +502271010,8,1460.0,10.0 +502271010,9,960.58349149625,10.0 +502271010,10,2366.5895901824165,10.0 +502273020,7,0.0,10.0 +502273020,8,20.0,10.0 +502273020,9,18.834970421495097,10.0 +502273020,10,0.0,10.0 +502276020,7,10105.681037036531,8.0 +502276020,8,10270.0,8.0 +502276020,9,11771.856513434437,8.0 +502276020,10,7208.9959824018215,8.0 +502277010,7,371.53239106751954,9.0 +502277010,8,2420.0,9.0 +502277010,9,7920.105062238688,9.0 +502277010,10,2912.7256494552817,9.0 +502292010,7,132.69013966697125,inf +502292010,8,120.0,inf +502292010,9,2589.808432955576,inf +502292010,10,145.63628247276407,inf +502296010,7,0.0,8.0 +502296010,8,0.0,8.0 +502296010,9,4534.845502070698,8.0 +502296010,10,0.0,8.0 +502300020,7,891.6777385620469,10.0 +502300020,8,500.0,10.0 +502300020,9,94.17485210747549,10.0 +502300020,10,1450.7185364482018,10.0 +502314020,7,2789.677496358404,10.0 +502314020,8,5096.0,10.0 +502314020,9,4580.664806507608,10.0 +502314020,10,8301.268100947553,10.0 +502316010,7,6237.498085464985,9.0 +502316010,8,3590.0,9.0 +502316010,9,743.9813316490564,9.0 +502316010,10,575.2633157674181,9.0 +502328010,7,11039.819620292008,inf +502328010,8,3120.0,inf +502328010,9,2490.9248382427268,inf +502328010,10,29309.301847643772,inf +502328020,7,180.4585899470809,8.0 +502328020,8,5300.0,8.0 +502328020,9,3729.3241434560296,8.0 +502328020,10,5406.746986801367,8.0 +502334020,7,4691.923338624104,10.0 +502334020,8,2800.0,10.0 +502334020,9,9613.368903131099,10.0 +502334020,10,6462.610034728906,10.0 +502349010,7,1008.4450614689815,9.0 +502349010,8,1168.0,9.0 +502349010,9,1471.011189918767,9.0 +502349010,10,4133.652323607963,9.0 +502356010,7,3715.3239106751953,8.0 +502356010,8,1050.0,8.0 +502356010,9,974.7097193123714,8.0 +502356010,10,568.8917284092347,8.0 +502361010,7,0.0,10.0 +502361010,8,1430.0,10.0 +502361010,9,4463.887989894339,10.0 +502361010,10,1146.885724473017,10.0 +502366010,7,467.06929162773883,8.0 +502366010,8,1620.0,8.0 +502366010,9,464.28202088985415,8.0 +502366010,10,141.4898325671703,8.0 +502371010,7,21.2304223467154,8.0 +502371010,8,4650.0,8.0 +502371010,9,1761.0697344097916,8.0 +502371010,10,1228.8061333639469,8.0 +502373010,7,2176.1182905383284,8.0 +502373010,8,5100.0,8.0 +502373010,9,1789.3221900420344,8.0 +502373010,10,1329.8253250775183,8.0 +502387010,7,22928.85613445263,10.0 +502387010,8,10400.0,10.0 +502387010,9,2184.8565688934314,10.0 +502387010,10,6662.859923128956,10.0 +502387020,7,3481.7892648613256,8.0 +502387020,8,1462.0,8.0 +502387020,9,1685.7298527238113,8.0 +502387020,10,3713.725203055484,8.0 +502390010,7,0.0,10.0 +502390010,8,3264.0,10.0 +502390010,9,2743.313441890761,10.0 +502390010,10,3367.839032182669,10.0 +502396010,7,1103.9819620292008,10.0 +502396010,8,2340.0,10.0 +502396010,9,1497.3801485088602,10.0 +502396010,10,2834.446147626171,10.0 +502401010,7,6262.974592281043,10.0 +502401010,8,152000.0,10.0 +502401010,9,188.34970421495098,10.0 +502401010,10,4278.065797637445,10.0 +502409020,7,1448.976325163326,8.0 +502409020,8,2300.0,8.0 +502409020,9,602.7190534878431,8.0 +502409020,10,1880.5610657661875,8.0 +502413010,7,3503.019687208041,9.0 +502413010,8,6200.0,9.0 +502413010,9,17657.784770151655,9.0 +502413010,10,10746.063232949644,9.0 +502420020,7,1910.738011204386,10.0 +502420020,8,7000.0,10.0 +502420020,9,3296.1198237616422,10.0 +502420020,10,9402.805328830938,10.0 +502422010,7,5546.447838079399,9.0 +502422010,8,3430.0,9.0 +502422010,9,2862.915504067255,9.0 +502422010,10,3731.9297383645794,9.0 +502426010,7,6114.361635854036,9.0 +502426010,8,1317.239913828996,9.0 +502426010,9,6012.122558541236,9.0 +502426010,10,1774.9421926368123,9.0 +502432020,7,1008.4450614689815,10.0 +502432020,8,2900.0,10.0 +502432020,9,2166.021598471936,10.0 +502432020,10,546.1360592728653,10.0 +502435020,7,42.4608446934308,9.0 +502435020,8,100.0,9.0 +502435020,9,50854.42013803677,9.0 +502435020,10,21481.3516647327,9.0 +502449010,7,2275.901275567891,10.0 +502449010,8,270.0,10.0 +502449010,9,353.15569540303306,10.0 +502449010,10,15223.589580011994,10.0 +502450010,7,0.0,8.0 +502450010,8,2060.0,8.0 +502450010,9,2354.3713026868872,8.0 +502450010,10,1547.3855012731183,8.0 +502453010,7,42121.157935883355,8.0 +502453010,8,6410.0,8.0 +502453010,9,8249.717044614854,8.0 +502453010,10,14763.87813567646,8.0 +502458010,7,4405.312636943446,10.0 +502458010,8,1322.0,10.0 +502458010,9,828.7386985457844,10.0 +502458010,10,2757.9870993279696,10.0 +502461020,7,206.99661788047516,inf +502461020,8,630.0,inf +502461020,9,583.884083066348,inf +502461020,10,3203.9982144008095,inf +502471020,7,1103.9819620292008,8.0 +502471020,8,9830.87141570905,8.0 +502471020,9,753.3988168598039,8.0 +502471020,10,1647.7296957189453,8.0 +502472010,7,1114.5971732025585,9.0 +502472010,8,2740.0,9.0 +502472010,9,5443.306451812084,9.0 +502472010,10,4096.02044454649,9.0 +502475020,7,16559.729430438012,8.0 +502475020,8,980.0,8.0 +502475020,9,1280.7779886616668,8.0 +502475020,10,332.23276939099304,8.0 +502481010,7,2123.04223467154,10.0 +502481010,8,99.0,10.0 +502481010,9,113.00982252897059,10.0 +502481010,10,4737.222875191967,10.0 +502484010,7,0.0,10.0 +502484010,8,0.0,10.0 +502484010,9,6838.977760044871,10.0 +502484010,10,13432.579041187055,10.0 +502497010,7,318.456335200731,8.0 +502497010,8,2034.0,8.0 +502497010,9,2222.5265097364218,8.0 +502497010,10,1601.9991072004048,8.0 +502502020,7,1324.778354435041,9.0 +502502020,8,1348.0,9.0 +502502020,9,1054.7583436037255,9.0 +502502020,10,3251.330006204458,9.0 +502509020,7,1337.5166078430702,8.0 +502509020,8,13500.0,8.0 +502509020,9,8664.086393887745,8.0 +502509020,10,0.0,8.0 +502512020,7,12844.405519762817,8.0 +502512020,8,2560.0,8.0 +502512020,9,508.54420138036767,8.0 +502512020,10,527.9315239637698,8.0 +502514020,7,3184.56335200731,9.0 +502514020,8,11620.0,9.0 +502514020,9,53185.247727696784,9.0 +502514020,10,12743.174716366857,9.0 +502537010,7,265.3802793339425,8.0 +502537010,8,2180.0,8.0 +502537010,9,306.06826934929535,8.0 +502537010,10,7728.735465476499,8.0 +502540020,7,2759.954905073002,9.0 +502540020,8,240.0,9.0 +502540020,9,2495.6335808481003,9.0 +502540020,10,1747.635389673169,9.0 +502551020,7,2452.113781045629,8.0 +502551020,8,1100.0,8.0 +502551020,9,1489.8461603402623,8.0 +502551020,10,1865.9648691822897,8.0 +502556010,7,63.6912670401462,9.0 +502556010,8,0.0,9.0 +502556010,9,1017.0884027607353,9.0 +502556010,10,1893.9936448073747,9.0 +502557010,7,21.2304223467154,8.0 +502557010,8,2300.0,8.0 +502557010,9,1826.9921308850246,8.0 +502557010,10,455.1133827273878,8.0 +502569010,7,1082.7515396824854,10.0 +502569010,8,1450.0,10.0 +502569010,9,2279.031421000907,10.0 +502569010,10,2543.2349651314157,10.0 +502576020,7,1751.5098436040205,10.0 +502576020,8,4830.0,10.0 +502576020,9,4162.528463150416,10.0 +502576020,10,2330.180519564225,10.0 +502579010,7,1178.2884402427048,10.0 +502579010,8,2175.0,10.0 +502579010,9,1148.933195711201,10.0 +502579010,10,1297.073140773055,10.0 +502589020,7,5197.20739047593,9.0 +502589020,8,1370.0,9.0 +502589020,9,2051.128278900816,9.0 +502589020,10,523.3803901364959,9.0 +502600010,7,0.0,9.0 +502600010,8,60.0,9.0 +502600010,9,3616.314320927059,9.0 +502600010,10,427.8065797637445,9.0 +502602010,7,0.0,inf +502602010,8,0.0,inf +502602010,9,0.0,inf +502602010,10,0.0,inf +502605010,7,106.152111733577,10.0 +502605010,8,60.0,10.0 +502605010,9,1113.1467519103603,10.0 +502605010,10,4369.088474182922,10.0 +502606010,7,0.0,8.0 +502606010,8,240.0,8.0 +502606010,9,0.0,8.0 +502606010,10,283.99075082188995,8.0 +502622010,7,2685.648426859498,8.0 +502622010,8,916.0,8.0 +502622010,9,2068.0797522801618,8.0 +502622010,10,1328.9310775639722,8.0 +502622020,7,636.912670401462,inf +502622020,8,500.0,inf +502622020,9,285.3498018856507,inf +502622020,10,1274.3174716366857,inf +502628010,7,106.152111733577,inf +502628010,8,1000.0,inf +502628010,9,0.0,inf +502628010,10,273.06802963643264,inf +502655010,7,6501.816843681591,10.0 +502655010,8,917.0,10.0 +502655010,9,4445.0530194728435,10.0 +502655010,10,3091.130095484418,10.0 +502657020,7,2659.110398926104,8.0 +502657020,8,1560.0,8.0 +502657020,9,1506.7976337196078,8.0 +502657020,10,1251.5618025003164,8.0 +502672010,7,6751.274306255497,8.0 +502672010,8,3595.0,8.0 +502672010,9,2919.42041533174,8.0 +502672010,10,4835.728454827339,8.0 +502686010,7,3396.867575474464,inf +502686010,8,5500.0,inf +502686010,9,282.52455632242646,inf +502686010,10,746.3859476729159,inf +502690010,7,1337.5166078430702,10.0 +502690010,8,500.0,10.0 +502690010,9,1441.8169857654498,10.0 +502690010,10,8188.39998203116,10.0 +502698020,7,516.96078414252,inf +502698020,8,344.0,inf +502698020,9,226.01964505794118,inf +502698020,10,83.74086242183934,inf +502705010,7,827.0336502162728,inf +502705010,8,300.0,inf +502705010,9,941.7485210747549,inf +502705010,10,0.0,inf +502705020,7,2123.04223467154,9.0 +502705020,8,500.0,9.0 +502705020,9,1393.7878111906373,9.0 +502705020,10,1929.680742764124,9.0 +502706010,7,0.0,inf +502706010,8,1220.0,inf +502706010,9,4407.383078629853,inf +502706010,10,0.0,inf +502722010,7,1433.0535084032895,8.0 +502722010,8,250.0,8.0 +502722010,9,301.35952674392155,8.0 +502722010,10,91.02267654547755,8.0 +502724010,7,18364.315329908823,9.0 +502724010,8,640.0,9.0 +502724010,9,3653.984261770049,9.0 +502724010,10,1296.1629140076002,9.0 +502729010,7,0.0,8.0 +502729010,8,480.0,8.0 +502729010,9,1243.1080478186764,8.0 +502729010,10,1693.0217837458824,8.0 +502740020,7,2282.270402271906,inf +502740020,8,2500.0,inf +502740020,9,274.0488196327537,inf +502740020,10,0.0,inf +502744010,7,0.0,9.0 +502744010,8,0.0,9.0 +502744010,9,904.0785802317647,9.0 +502744010,10,0.0,9.0 +502745010,7,7218.343597883237,8.0 +502745010,8,0.0,8.0 +502745010,9,565.0491126448529,8.0 +502745010,10,3859.361485528248,8.0 +502746010,7,7669.490072750938,8.0 +502746010,8,5785.0,8.0 +502746010,9,16902.502456249702,8.0 +502746010,10,0.0,8.0 +502746020,7,15413.286623715381,9.0 +502746020,8,288.0,9.0 +502746020,9,452.03929011588235,9.0 +502746020,10,0.0,9.0 +502747020,7,4076.241090569357,10.0 +502747020,8,1260.0,10.0 +502747020,9,2335.536332265392,10.0 +502747020,10,3276.816355637192,10.0 +502748010,7,15583.130002489104,10.0 +502748010,8,5040.0,10.0 +502748010,9,12431.080478186765,10.0 +502748010,10,48059.97321601215,10.0 +502751010,7,1730.279421257305,10.0 +502751010,8,1615.0,10.0 +502751010,9,3060.6826934929536,10.0 +502751010,10,2876.3165788370907,10.0 +502752010,7,1910.738011204386,9.0 +502752010,8,1530.0,9.0 +502752010,9,7373.890920015331,9.0 +502752010,10,673.5678064365338,9.0 +502761010,7,4182.393202302934,8.0 +502761010,8,2632.0,8.0 +502761010,9,657.3404677101789,8.0 +502761010,10,782.7950182911069,8.0 diff --git a/tests/test_efficient_did_validation.py b/tests/test_efficient_did_validation.py new file mode 100644 index 00000000..78a234ec --- /dev/null +++ b/tests/test_efficient_did_validation.py @@ -0,0 +1,421 @@ +""" +Validation tests for EfficientDiD against Chen, Sant'Anna & Xie (2025). + +Path 1: HRS empirical replication (Table 6 of the paper) +Path 2: Compustat MC simulations (Tables 4 & 5 patterns) + +These tests validate the estimator against published results from +"Efficient Difference-in-Differences and Event Study Estimators." +""" + +from pathlib import Path + +import numpy as np +import pandas as pd +import pytest + +from diff_diff import CallawaySantAnna, EfficientDiD + +# ============================================================================= +# Data Loaders & Helpers +# ============================================================================= + +_HRS_FIXTURE = Path(__file__).parent / "data" / "hrs_edid_validation.csv" + +# Paper Table 6 reference values: (point_estimate, cluster_robust_se) +TABLE6_EDID = { + (8, 8): (3072, 806), + (8, 9): (1112, 637), + (8, 10): (1038, 817), + (9, 9): (3063, 690), + (9, 10): (90, 641), + (10, 10): (2908, 894), +} +TABLE6_ES = { + 0: (3024, 486), + 1: (692, 471), + 2: (1038, 816), +} +TABLE6_ES_AVG = (1585, 521) + +TABLE6_CS_SA = { + (8, 8): 2826, + (8, 9): 825, + (8, 10): 800, + (9, 9): 3031, + (9, 10): 107, + (10, 10): 3092, +} + + +def _load_hrs_data(): + """Load the committed HRS test fixture.""" + df = pd.read_csv(_HRS_FIXTURE) + # Ensure correct types + df["unit"] = df["unit"].astype(int) + df["time"] = df["time"].astype(int) + df["first_treat"] = df["first_treat"].astype(float) + return df + + +def _get_effect(effects_dict, g, t): + """Look up ATT(g,t) handling potential float/int key mismatch.""" + for key, val in effects_dict.items(): + if int(key[0]) == g and int(key[1]) == t: + return val + raise KeyError(f"ATT({g},{t}) not found in results") + + +def _assert_close(actual, expected, label, rtol=0.10, atol=200): + """Assert actual is close to expected with combined tolerance.""" + tol = max(rtol * abs(expected), atol) + diff = abs(actual - expected) + assert diff < tol, ( + f"{label}: expected {expected}, got {actual:.1f} " + f"(diff={diff:.1f}, tol={tol:.1f})" + ) + + +# ============================================================================= +# Compustat DGP (copied from test_efficient_did.py) +# ============================================================================= + + +def _make_compustat_dgp(n_units=400, n_periods=11, rho=0.0, seed=42): + """Simplified Compustat-style DGP from Section 5.2. + + Groups: G=5 (~1/3), G=8 (~1/3), G=inf (~1/3). + ATT(5,t) = 0.154*(t-4), ATT(8,t) = 0.093*(t-7). + """ + rng = np.random.default_rng(seed) + n_t = n_periods + + n_g5 = n_units // 3 + n_g8 = n_units // 3 + ft = np.full(n_units, np.inf) + ft[:n_g5] = 5 + ft[n_g5 : n_g5 + n_g8] = 8 + + units = np.repeat(np.arange(n_units), n_t) + times = np.tile(np.arange(1, n_t + 1), n_units) + ft_col = np.repeat(ft, n_t) + + alpha_t = rng.normal(0, 0.1, n_t) + eta_i = rng.normal(0, 0.5, n_units) + unit_fe = np.repeat(eta_i, n_t) + time_fe = np.tile(alpha_t, n_units) + + eps = np.zeros((n_units, n_t)) + eps[:, 0] = rng.normal(0, 0.3, n_units) + for t in range(1, n_t): + eps[:, t] = rho * eps[:, t - 1] + rng.normal(0, 0.3, n_units) + eps_flat = eps.flatten() + + tau = np.zeros(len(units)) + for i in range(n_units): + g = ft[i] + if np.isinf(g): + continue + for t_idx in range(n_t): + t = t_idx + 1 + if g == 5 and t >= 5: + tau[i * n_t + t_idx] = 0.154 * (t - 4) + elif g == 8 and t >= 8: + tau[i * n_t + t_idx] = 0.093 * (t - 7) + + y = unit_fe + time_fe + tau + eps_flat + + return pd.DataFrame( + {"unit": units, "time": times, "first_treat": ft_col, "y": y} + ) + + +def _compute_es_avg(result): + """Compute ES_avg (Eq 2.3): uniform average over post-treatment horizons.""" + if result.event_study_effects is None: + raise ValueError("No event study effects; use aggregate='all'") + es = { + int(e): d["effect"] + for e, d in result.event_study_effects.items() + if int(e) >= 0 + } + return np.mean(list(es.values())) + + +# Ground truth ES_avg for Compustat DGP (see plan for derivation) +_TRUE_ES_AVG_COMPUSTAT = np.mean( + [0.1235, 0.247, 0.3705, 0.494, 0.770, 0.924, 1.078] +) + + +def _true_overall_att_compustat(): + """Compute true overall_att using cohort-size weighting (our convention).""" + # Groups have equal size (1/3 each), so pi_5 = pi_8 + # Post-treatment (g,t) cells: + # G=5: t=5..11 -> 7 cells with effects 0.154*(1..7) + # G=8: t=8..11 -> 4 cells with effects 0.093*(1..4) + effects_g5 = [0.154 * k for k in range(1, 8)] # 7 cells + effects_g8 = [0.093 * k for k in range(1, 5)] # 4 cells + # Cohort-size-weighted: both groups have same pi, so weight by count + all_effects = effects_g5 + effects_g8 + return np.mean(all_effects) + + +def _run_mc_simulation(n_sims, rho, seed=1000, also_cs=False): + """Run MC simulation and return estimates.""" + edid_estimates = [] + edid_overall_att = [] + edid_overall_ci = [] + edid_overall_se = [] + cs_estimates_list = [] + + for i in range(n_sims): + data = _make_compustat_dgp(rho=rho, seed=seed + i) + + edid = EfficientDiD(pt_assumption="all") + res = edid.fit( + data, outcome="y", unit="unit", time="time", + first_treat="first_treat", aggregate="all", + ) + edid_estimates.append(_compute_es_avg(res)) + edid_overall_att.append(res.overall_att) + edid_overall_se.append(res.overall_se) + edid_overall_ci.append(res.overall_conf_int) + + if also_cs: + cs = CallawaySantAnna(control_group="never_treated") + cs_res = cs.fit( + data, outcome="y", unit="unit", time="time", + first_treat="first_treat", aggregate="event_study", + ) + cs_estimates_list.append(_compute_es_avg(cs_res)) + + return { + "edid_estimates": np.array(edid_estimates), + "edid_overall_att": np.array(edid_overall_att), + "edid_overall_se": np.array(edid_overall_se), + "edid_overall_ci": np.array(edid_overall_ci), + "cs_estimates": np.array(cs_estimates_list) if also_cs else None, + } + + +# ============================================================================= +# Path 1: HRS Empirical Replication (Table 6) +# ============================================================================= + + +@pytest.fixture(scope="module") +def hrs_data(): + """Load HRS validation fixture.""" + if not _HRS_FIXTURE.exists(): + pytest.skip(f"HRS fixture not found at {_HRS_FIXTURE}") + return _load_hrs_data() + + +@pytest.fixture(scope="module") +def edid_hrs_result(hrs_data): + """Fit EDiD on HRS data (shared across tests).""" + edid = EfficientDiD(pt_assumption="all") + return edid.fit( + hrs_data, outcome="outcome", unit="unit", time="time", + first_treat="first_treat", aggregate="all", + ) + + +class TestHRSReplication: + """Validate EDiD against Table 6 of Chen, Sant'Anna & Xie (2025).""" + + def test_sample_selection_yields_expected_counts(self, hrs_data): + n_units = hrs_data["unit"].nunique() + assert abs(n_units - 652) <= 10, f"Expected ~652 units, got {n_units}" + + groups = hrs_data.groupby("unit")["first_treat"].first() + + # Check 4 groups exist + finite_groups = sorted(g for g in groups.unique() if np.isfinite(g)) + assert finite_groups == [8, 9, 10], f"Expected groups [8,9,10], got {finite_groups}" + assert any(np.isinf(g) for g in groups.unique()), "Missing never-treated group" + + # Check approximate sizes + for g, expected in [(8, 252), (9, 176), (10, 163)]: + actual = (groups == g).sum() + assert abs(actual - expected) <= 15, ( + f"G={g}: expected ~{expected}, got {actual}" + ) + n_inf = groups.apply(np.isinf).sum() + assert abs(n_inf - 65) <= 10, f"G=inf: expected ~65, got {n_inf}" + + def test_group_time_effects_match_table6(self, edid_hrs_result): + for (g, t), (expected_effect, _) in TABLE6_EDID.items(): + info = _get_effect(edid_hrs_result.group_time_effects, g, t) + _assert_close(info["effect"], expected_effect, f"ATT({g},{t})") + + def test_event_study_effects_match_table6(self, edid_hrs_result): + for e, (expected_effect, _) in TABLE6_ES.items(): + # Find event study effect matching relative time e + found = False + for rel_time, info in edid_hrs_result.event_study_effects.items(): + if int(rel_time) == e: + _assert_close(info["effect"], expected_effect, f"ES({e})") + found = True + break + assert found, f"ES({e}) not found in event study effects" + + def test_es_avg_matches_table6(self, edid_hrs_result): + es_avg = _compute_es_avg(edid_hrs_result) + _assert_close(es_avg, TABLE6_ES_AVG[0], "ES_avg") + + def test_se_diagnostic_comparison(self, edid_hrs_result): + """Log and sanity-check analytical vs cluster-robust SEs.""" + for (g, t), (_, cluster_se) in TABLE6_EDID.items(): + info = _get_effect(edid_hrs_result.group_time_effects, g, t) + analytical_se = info["se"] + assert np.isfinite(analytical_se) and analytical_se > 0, ( + f"ATT({g},{t}): analytical SE should be finite positive, got {analytical_se}" + ) + ratio = analytical_se / cluster_se + assert 0.3 < ratio < 3.0, ( + f"ATT({g},{t}): SE ratio (analytical/cluster) = {ratio:.2f} " + f"outside (0.3, 3.0). Analytical={analytical_se:.1f}, " + f"cluster={cluster_se}" + ) + + def test_cs_cross_validation(self, hrs_data): + """Cross-validate data loading using CallawaySantAnna.""" + cs = CallawaySantAnna(control_group="never_treated") + cs_result = cs.fit( + hrs_data, outcome="outcome", unit="unit", time="time", + first_treat="first_treat", + ) + for (g, t), expected_effect in TABLE6_CS_SA.items(): + info = _get_effect(cs_result.group_time_effects, g, t) + _assert_close( + info["effect"], expected_effect, + f"CS ATT({g},{t})", rtol=0.15, atol=300, + ) + + def test_pretreatment_effects_near_zero(self, edid_hrs_result): + """Check pre-treatment effects are small (parallel trends plausibility).""" + pre_effects = [] + post_effects = [] + for (g, t), info in edid_hrs_result.group_time_effects.items(): + g_int, t_int = int(g), int(t) + if t_int < g_int: + pre_effects.append(abs(info["effect"])) + else: + post_effects.append(abs(info["effect"])) + + if not pre_effects: + pytest.skip("No pre-treatment effects to check") + + mean_post = np.mean(post_effects) + for i, pre_eff in enumerate(pre_effects): + assert pre_eff < 0.5 * mean_post, ( + f"Pre-treatment effect [{i}] = {pre_eff:.1f} is too large " + f"relative to mean post-treatment ({mean_post:.1f})" + ) + + +# ============================================================================= +# Path 2: Compustat MC Simulations (Tables 4 & 5 patterns) +# ============================================================================= + + +@pytest.mark.slow +class TestCompustatMCValidation: + """Validate MC properties against Tables 4 & 5 patterns.""" + + @pytest.mark.parametrize("rho", [0, 0.5, -0.5]) + def test_unbiasedness(self, ci_params, rho): + n_sims = ci_params.bootstrap(200, min_n=49) + mc = _run_mc_simulation(n_sims, rho=rho, seed=2000 + int(rho * 100)) + + mean_est = np.mean(mc["edid_estimates"]) + mcse = np.std(mc["edid_estimates"]) / np.sqrt(n_sims) + bias = abs(mean_est - _TRUE_ES_AVG_COMPUSTAT) + + assert bias < 3 * mcse + 0.05, ( + f"rho={rho}: bias={bias:.4f}, 3*MCSE={3*mcse:.4f}, " + f"mean={mean_est:.4f}, true={_TRUE_ES_AVG_COMPUSTAT:.4f}" + ) + + @pytest.mark.parametrize("rho", [0, -0.5]) + def test_edid_has_lower_rmse_than_cs(self, ci_params, rho): + n_sims = ci_params.bootstrap(150, min_n=49) + mc = _run_mc_simulation( + n_sims, rho=rho, seed=3000 + int(rho * 100), also_cs=True, + ) + + rmse_edid = np.sqrt( + np.mean((mc["edid_estimates"] - _TRUE_ES_AVG_COMPUSTAT) ** 2) + ) + rmse_cs = np.sqrt( + np.mean((mc["cs_estimates"] - _TRUE_ES_AVG_COMPUSTAT) ** 2) + ) + + # EDiD should not be meaningfully worse than CS + assert rmse_edid <= rmse_cs * 1.15, ( + f"rho={rho}: RMSE_edid={rmse_edid:.4f} > RMSE_cs={rmse_cs:.4f} * 1.15" + ) + + # For negative rho, efficiency gain should be clear + if rho == -0.5: + assert rmse_edid < rmse_cs, ( + f"rho={rho}: Expected RMSE_edid < RMSE_cs, " + f"got {rmse_edid:.4f} >= {rmse_cs:.4f}" + ) + + def test_efficiency_gain_increases_with_serial_correlation(self, ci_params): + n_sims = ci_params.bootstrap(150, min_n=49) + mc_zero = _run_mc_simulation(n_sims, rho=0, seed=4000, also_cs=True) + mc_neg = _run_mc_simulation(n_sims, rho=-0.5, seed=4500, also_cs=True) + + def rel_rmse(mc): + rmse_e = np.sqrt( + np.mean((mc["edid_estimates"] - _TRUE_ES_AVG_COMPUSTAT) ** 2) + ) + rmse_c = np.sqrt( + np.mean((mc["cs_estimates"] - _TRUE_ES_AVG_COMPUSTAT) ** 2) + ) + return rmse_c / rmse_e if rmse_e > 0 else 1.0 + + rel_zero = rel_rmse(mc_zero) + rel_neg = rel_rmse(mc_neg) + + assert rel_neg > rel_zero, ( + f"Expected larger efficiency gain at rho=-0.5 ({rel_neg:.2f}) " + f"than rho=0 ({rel_zero:.2f})" + ) + + def test_coverage_approximately_correct(self, ci_params): + n_sims = ci_params.bootstrap(200, min_n=49) + mc = _run_mc_simulation(n_sims, rho=0, seed=5000) + + true_overall = _true_overall_att_compustat() + covered = sum( + ci[0] <= true_overall <= ci[1] + for ci in mc["edid_overall_ci"] + ) + coverage = covered / n_sims + + if n_sims >= 200: + assert 0.88 <= coverage <= 0.99, ( + f"Coverage={coverage:.2f}, expected 0.88-0.99 (n_sims={n_sims})" + ) + else: + assert 0.80 <= coverage <= 1.00, ( + f"Coverage={coverage:.2f}, expected 0.80-1.00 (n_sims={n_sims})" + ) + + def test_analytical_se_calibration(self, ci_params): + n_sims = ci_params.bootstrap(200, min_n=49) + mc = _run_mc_simulation(n_sims, rho=0, seed=6000) + + mean_se = np.mean(mc["edid_overall_se"]) + mc_sd = np.std(mc["edid_overall_att"]) + + ratio = mean_se / mc_sd if mc_sd > 0 else float("inf") + assert 0.7 < ratio < 1.4, ( + f"SE calibration ratio={ratio:.2f} (mean_analytical={mean_se:.4f}, " + f"mc_sd={mc_sd:.4f}), expected 0.7-1.4" + ) From a4b388178e6f6d863213a6391dc4353da1e57ca6 Mon Sep 17 00:00:00 2001 From: igerber Date: Sat, 21 Mar 2026 10:25:18 -0400 Subject: [PATCH 2/5] Address AI review: tighten fixture guard, derive truth, add provenance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P2: Assert exact cohort counts (656/252/176/163/65) and wave support since the CSV fixture is deterministic — approximate tolerances could mask fixture drift. P3: Derive _TRUE_ES_AVG_COMPUSTAT programmatically from DGP parameters instead of hard-coding, so changes to the DGP definition propagate automatically. P3: Add tests/data/README.md documenting the HRS fixture source, sample selection steps, and expected counts for future audit/rebuild. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/data/README.md | 34 ++++++++++++++++++++ tests/test_efficient_did_validation.py | 44 +++++++++++++++++++------- 2 files changed, 66 insertions(+), 12 deletions(-) create mode 100644 tests/data/README.md diff --git a/tests/data/README.md b/tests/data/README.md new file mode 100644 index 00000000..96c3da78 --- /dev/null +++ b/tests/data/README.md @@ -0,0 +1,34 @@ +# Test Data Fixtures + +## hrs_edid_validation.csv + +**Source:** Dobkin, C., Finkelstein, A., Kluender, R., & Notowidigdo, M. J. (2018). +"The Economic Consequences of Hospital Admissions." *American Economic Review*, 108(2), 308-352. +Replication kit: https://www.openicpsr.org/openicpsr/project/116186/version/V1/view + +**Sample selection:** Follows Sun & Abraham (2021), as used by Chen, Sant'Anna & Xie (2025) +Section 6: + +1. Read `HRS_long.dta` from the Dobkin et al. replication kit +2. Keep waves 7-11, retain only individuals present in all 5 waves +3. Filter to ever-hospitalized individuals with `first_hosp >= 8` +4. Filter to ages 50-59 at hospitalization (`age_hosp`) +5. Drop wave 11 (no valid comparison group) +6. Recode `first_hosp == 11` as never-treated (`inf`) + +**Expected counts:** + +| Column | Values | +|--------|--------| +| Total individuals | 656 | +| Waves | 7, 8, 9, 10 | +| Rows | 2,624 | +| G=8 | 252 | +| G=9 | 176 | +| G=10 | 163 | +| G=inf | 65 | + +**Columns:** `unit` (hhidpn), `time` (wave), `outcome` (oop_spend, 2005 dollars), `first_treat` (first_hosp) + +**Regeneration:** Requires the Dobkin et al. replication kit (`.gitignore`d as `replication_data/`). +The extraction logic is documented in the plan file and was executed as a one-time preprocessing step. diff --git a/tests/test_efficient_did_validation.py b/tests/test_efficient_did_validation.py index 78a234ec..4c1143c1 100644 --- a/tests/test_efficient_did_validation.py +++ b/tests/test_efficient_did_validation.py @@ -142,10 +142,28 @@ def _compute_es_avg(result): return np.mean(list(es.values())) -# Ground truth ES_avg for Compustat DGP (see plan for derivation) -_TRUE_ES_AVG_COMPUSTAT = np.mean( - [0.1235, 0.247, 0.3705, 0.494, 0.770, 0.924, 1.078] -) +# Ground truth derived from DGP parameters (not hard-coded) +_ATT_COEFS = {5: 0.154, 8: 0.093} # ATT(g,t) = coef * (t - g + 1) for t >= g +_N_PERIODS = 11 + + +def _true_es_avg_from_dgp(): + """Derive ES_avg from DGP treatment effect parameters.""" + max_e = {g: _N_PERIODS - g for g in _ATT_COEFS} + all_e = range(0, max(max_e.values()) + 1) + es_values = [] + for e in all_e: + contributing = [ + coef * (e + 1) + for g, coef in _ATT_COEFS.items() + if e <= max_e[g] + ] + if contributing: + es_values.append(np.mean(contributing)) + return np.mean(es_values) + + +_TRUE_ES_AVG_COMPUSTAT = _true_es_avg_from_dgp() def _true_overall_att_compustat(): @@ -226,24 +244,26 @@ class TestHRSReplication: """Validate EDiD against Table 6 of Chen, Sant'Anna & Xie (2025).""" def test_sample_selection_yields_expected_counts(self, hrs_data): + # Fixture is deterministic — assert exact counts n_units = hrs_data["unit"].nunique() - assert abs(n_units - 652) <= 10, f"Expected ~652 units, got {n_units}" + assert n_units == 656, f"Expected 656 units, got {n_units}" groups = hrs_data.groupby("unit")["first_treat"].first() - # Check 4 groups exist finite_groups = sorted(g for g in groups.unique() if np.isfinite(g)) assert finite_groups == [8, 9, 10], f"Expected groups [8,9,10], got {finite_groups}" assert any(np.isinf(g) for g in groups.unique()), "Missing never-treated group" - # Check approximate sizes - for g, expected in [(8, 252), (9, 176), (10, 163)]: + expected_sizes = {8: 252, 9: 176, 10: 163} + for g, expected in expected_sizes.items(): actual = (groups == g).sum() - assert abs(actual - expected) <= 15, ( - f"G={g}: expected ~{expected}, got {actual}" - ) + assert actual == expected, f"G={g}: expected {expected}, got {actual}" n_inf = groups.apply(np.isinf).sum() - assert abs(n_inf - 65) <= 10, f"G=inf: expected ~65, got {n_inf}" + assert n_inf == 65, f"G=inf: expected 65, got {n_inf}" + + assert sorted(hrs_data["time"].unique()) == [7, 8, 9, 10], ( + f"Expected waves [7,8,9,10], got {sorted(hrs_data['time'].unique())}" + ) def test_group_time_effects_match_table6(self, edid_hrs_result): for (g, t), (expected_effect, _) in TABLE6_EDID.items(): From eec1fe838e7f156fadbec29b724d8464179f5d8b Mon Sep 17 00:00:00 2001 From: igerber Date: Sat, 21 Mar 2026 10:41:42 -0400 Subject: [PATCH 3/5] Address AI review: tighten tolerances, extract shared DGP P2: Replace loose max(10%*estimate, 200) tolerance with 0.1*SE (10% of one published standard error). Our actual diffs are all < 0.03 SE, so this catches real drift while absorbing minor sample differences. ATT(9,10)=90 now accepts [26, 154] instead of [-110, 290]. P3: Extract Compustat DGP into tests/edid_dgp.py as the single source of truth. Both test_efficient_did.py and test_efficient_did_validation.py import from it. Truth values (ES_avg, overall_att) are derived programmatically from the shared DGP parameters. Co-Authored-By: Claude Opus 4.6 (1M context) --- pyproject.toml | 1 + tests/edid_dgp.py | 87 +++++++++++++++++ tests/test_efficient_did.py | 63 +------------ tests/test_efficient_did_validation.py | 125 +++++-------------------- 4 files changed, 116 insertions(+), 160 deletions(-) create mode 100644 tests/edid_dgp.py diff --git a/pyproject.toml b/pyproject.toml index 710a1be3..376e8356 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,6 +89,7 @@ python-packages = ["diff_diff"] [tool.pytest.ini_options] testpaths = ["tests"] +pythonpath = ["tests"] python_files = "test_*.py" # Exclude slow tests by default; use `pytest -m ''` to run all tests addopts = "-v --tb=short -m 'not slow'" diff --git a/tests/edid_dgp.py b/tests/edid_dgp.py new file mode 100644 index 00000000..6fa6200c --- /dev/null +++ b/tests/edid_dgp.py @@ -0,0 +1,87 @@ +""" +Shared Compustat-style DGP for EfficientDiD tests. + +Used by both test_efficient_did.py and test_efficient_did_validation.py +to avoid duplication. Based on Section 5.2 of Chen, Sant'Anna & Xie (2025). +""" + +import numpy as np +import pandas as pd + +# DGP parameters — treatment effect coefficients +ATT_COEFS = {5: 0.154, 8: 0.093} +N_PERIODS = 11 + + +def make_compustat_dgp(n_units=400, n_periods=N_PERIODS, rho=0.0, seed=42): + """Simplified Compustat-style DGP from Section 5.2. + + Groups: G=5 (~1/3), G=8 (~1/3), G=inf (~1/3). + ATT(5,t) = 0.154*(t-4), ATT(8,t) = 0.093*(t-7). + """ + rng = np.random.default_rng(seed) + n_t = n_periods + + n_g5 = n_units // 3 + n_g8 = n_units // 3 + ft = np.full(n_units, np.inf) + ft[:n_g5] = 5 + ft[n_g5 : n_g5 + n_g8] = 8 + + units = np.repeat(np.arange(n_units), n_t) + times = np.tile(np.arange(1, n_t + 1), n_units) + ft_col = np.repeat(ft, n_t) + + alpha_t = rng.normal(0, 0.1, n_t) + eta_i = rng.normal(0, 0.5, n_units) + unit_fe = np.repeat(eta_i, n_t) + time_fe = np.tile(alpha_t, n_units) + + eps = np.zeros((n_units, n_t)) + eps[:, 0] = rng.normal(0, 0.3, n_units) + for t in range(1, n_t): + eps[:, t] = rho * eps[:, t - 1] + rng.normal(0, 0.3, n_units) + eps_flat = eps.flatten() + + tau = np.zeros(len(units)) + for i in range(n_units): + g = ft[i] + if np.isinf(g): + continue + for t_idx in range(n_t): + t = t_idx + 1 + if g == 5 and t >= 5: + tau[i * n_t + t_idx] = ATT_COEFS[5] * (t - 4) + elif g == 8 and t >= 8: + tau[i * n_t + t_idx] = ATT_COEFS[8] * (t - 7) + + y = unit_fe + time_fe + tau + eps_flat + + return pd.DataFrame( + {"unit": units, "time": times, "first_treat": ft_col, "y": y} + ) + + +def true_es_avg(): + """Derive ES_avg from DGP treatment effect parameters.""" + max_e = {g: N_PERIODS - g for g in ATT_COEFS} + all_e = range(0, max(max_e.values()) + 1) + es_values = [] + for e in all_e: + contributing = [ + coef * (e + 1) + for g, coef in ATT_COEFS.items() + if e <= max_e[g] + ] + if contributing: + es_values.append(np.mean(contributing)) + return np.mean(es_values) + + +def true_overall_att(): + """Compute true overall_att using cohort-size weighting (library convention).""" + effects = [] + for g, coef in ATT_COEFS.items(): + for t in range(g, N_PERIODS + 1): + effects.append(coef * (t - g + 1)) + return np.mean(effects) diff --git a/tests/test_efficient_did.py b/tests/test_efficient_did.py index efad78fc..3b727348 100644 --- a/tests/test_efficient_did.py +++ b/tests/test_efficient_did.py @@ -112,67 +112,12 @@ def _make_staggered_panel( ) -def _make_compustat_dgp( - n_units=400, - n_periods=11, - rho=0.0, - seed=42, -): - """Simplified Compustat-style DGP from Section 5.2. - - Groups: G=5 (~1/3), G=8 (~1/3), G=inf (~1/3). - ATT(5,t) = 0.154*(t-4), ATT(8,t) = 0.093*(t-7). - """ - rng = np.random.default_rng(seed) - n_t = n_periods - - # Assign groups - n_g5 = n_units // 3 - n_g8 = n_units // 3 - ft = np.full(n_units, np.inf) - ft[:n_g5] = 5 - ft[n_g5 : n_g5 + n_g8] = 8 - - units = np.repeat(np.arange(n_units), n_t) - times = np.tile(np.arange(1, n_t + 1), n_units) - ft_col = np.repeat(ft, n_t) - - # Unit and time FE - alpha_t = rng.normal(0, 0.1, n_t) - eta_i = rng.normal(0, 0.5, n_units) - unit_fe = np.repeat(eta_i, n_t) - time_fe = np.tile(alpha_t, n_units) - - # AR(1) errors - eps = np.zeros((n_units, n_t)) - eps[:, 0] = rng.normal(0, 0.3, n_units) - for t in range(1, n_t): - eps[:, t] = rho * eps[:, t - 1] + rng.normal(0, 0.3, n_units) - eps_flat = eps.flatten() +from edid_dgp import make_compustat_dgp - # Treatment effects - tau = np.zeros(len(units)) - for i in range(n_units): - g = ft[i] - if np.isinf(g): - continue - for t_idx in range(n_t): - t = t_idx + 1 - if g == 5 and t >= 5: - tau[i * n_t + t_idx] = 0.154 * (t - 4) - elif g == 8 and t >= 8: - tau[i * n_t + t_idx] = 0.093 * (t - 7) - - y = unit_fe + time_fe + tau + eps_flat - return pd.DataFrame( - { - "unit": units, - "time": times, - "first_treat": ft_col, - "y": y, - } - ) +def _make_compustat_dgp(n_units=400, n_periods=11, rho=0.0, seed=42): + """Delegate to shared DGP in edid_dgp.py.""" + return make_compustat_dgp(n_units=n_units, n_periods=n_periods, rho=rho, seed=seed) # ============================================================================= diff --git a/tests/test_efficient_did_validation.py b/tests/test_efficient_did_validation.py index 4c1143c1..62b56b75 100644 --- a/tests/test_efficient_did_validation.py +++ b/tests/test_efficient_did_validation.py @@ -15,6 +15,7 @@ import pytest from diff_diff import CallawaySantAnna, EfficientDiD +from edid_dgp import make_compustat_dgp, true_es_avg, true_overall_att # ============================================================================= # Data Loaders & Helpers @@ -66,9 +67,17 @@ def _get_effect(effects_dict, g, t): raise KeyError(f"ATT({g},{t}) not found in results") -def _assert_close(actual, expected, label, rtol=0.10, atol=200): - """Assert actual is close to expected with combined tolerance.""" - tol = max(rtol * abs(expected), atol) +def _assert_close(actual, expected, label, se=None, se_frac=0.1): + """Assert actual is close to expected, tolerance based on published SE. + + Default tolerance is 0.1 * SE (10% of one standard error). Our actual + diffs are all < 0.03 SE, so this catches real drift while absorbing the + 4-individual sample difference (656 vs paper's 652). + """ + if se is not None: + tol = se_frac * se + else: + tol = max(0.05 * abs(expected), 50) diff = abs(actual - expected) assert diff < tol, ( f"{label}: expected {expected}, got {actual:.1f} " @@ -76,60 +85,6 @@ def _assert_close(actual, expected, label, rtol=0.10, atol=200): ) -# ============================================================================= -# Compustat DGP (copied from test_efficient_did.py) -# ============================================================================= - - -def _make_compustat_dgp(n_units=400, n_periods=11, rho=0.0, seed=42): - """Simplified Compustat-style DGP from Section 5.2. - - Groups: G=5 (~1/3), G=8 (~1/3), G=inf (~1/3). - ATT(5,t) = 0.154*(t-4), ATT(8,t) = 0.093*(t-7). - """ - rng = np.random.default_rng(seed) - n_t = n_periods - - n_g5 = n_units // 3 - n_g8 = n_units // 3 - ft = np.full(n_units, np.inf) - ft[:n_g5] = 5 - ft[n_g5 : n_g5 + n_g8] = 8 - - units = np.repeat(np.arange(n_units), n_t) - times = np.tile(np.arange(1, n_t + 1), n_units) - ft_col = np.repeat(ft, n_t) - - alpha_t = rng.normal(0, 0.1, n_t) - eta_i = rng.normal(0, 0.5, n_units) - unit_fe = np.repeat(eta_i, n_t) - time_fe = np.tile(alpha_t, n_units) - - eps = np.zeros((n_units, n_t)) - eps[:, 0] = rng.normal(0, 0.3, n_units) - for t in range(1, n_t): - eps[:, t] = rho * eps[:, t - 1] + rng.normal(0, 0.3, n_units) - eps_flat = eps.flatten() - - tau = np.zeros(len(units)) - for i in range(n_units): - g = ft[i] - if np.isinf(g): - continue - for t_idx in range(n_t): - t = t_idx + 1 - if g == 5 and t >= 5: - tau[i * n_t + t_idx] = 0.154 * (t - 4) - elif g == 8 and t >= 8: - tau[i * n_t + t_idx] = 0.093 * (t - 7) - - y = unit_fe + time_fe + tau + eps_flat - - return pd.DataFrame( - {"unit": units, "time": times, "first_treat": ft_col, "y": y} - ) - - def _compute_es_avg(result): """Compute ES_avg (Eq 2.3): uniform average over post-treatment horizons.""" if result.event_study_effects is None: @@ -142,41 +97,7 @@ def _compute_es_avg(result): return np.mean(list(es.values())) -# Ground truth derived from DGP parameters (not hard-coded) -_ATT_COEFS = {5: 0.154, 8: 0.093} # ATT(g,t) = coef * (t - g + 1) for t >= g -_N_PERIODS = 11 - - -def _true_es_avg_from_dgp(): - """Derive ES_avg from DGP treatment effect parameters.""" - max_e = {g: _N_PERIODS - g for g in _ATT_COEFS} - all_e = range(0, max(max_e.values()) + 1) - es_values = [] - for e in all_e: - contributing = [ - coef * (e + 1) - for g, coef in _ATT_COEFS.items() - if e <= max_e[g] - ] - if contributing: - es_values.append(np.mean(contributing)) - return np.mean(es_values) - - -_TRUE_ES_AVG_COMPUSTAT = _true_es_avg_from_dgp() - - -def _true_overall_att_compustat(): - """Compute true overall_att using cohort-size weighting (our convention).""" - # Groups have equal size (1/3 each), so pi_5 = pi_8 - # Post-treatment (g,t) cells: - # G=5: t=5..11 -> 7 cells with effects 0.154*(1..7) - # G=8: t=8..11 -> 4 cells with effects 0.093*(1..4) - effects_g5 = [0.154 * k for k in range(1, 8)] # 7 cells - effects_g8 = [0.093 * k for k in range(1, 5)] # 4 cells - # Cohort-size-weighted: both groups have same pi, so weight by count - all_effects = effects_g5 + effects_g8 - return np.mean(all_effects) +_TRUE_ES_AVG_COMPUSTAT = true_es_avg() def _run_mc_simulation(n_sims, rho, seed=1000, also_cs=False): @@ -188,7 +109,7 @@ def _run_mc_simulation(n_sims, rho, seed=1000, also_cs=False): cs_estimates_list = [] for i in range(n_sims): - data = _make_compustat_dgp(rho=rho, seed=seed + i) + data = make_compustat_dgp(rho=rho, seed=seed + i) edid = EfficientDiD(pt_assumption="all") res = edid.fit( @@ -266,24 +187,23 @@ def test_sample_selection_yields_expected_counts(self, hrs_data): ) def test_group_time_effects_match_table6(self, edid_hrs_result): - for (g, t), (expected_effect, _) in TABLE6_EDID.items(): + for (g, t), (expected_effect, se) in TABLE6_EDID.items(): info = _get_effect(edid_hrs_result.group_time_effects, g, t) - _assert_close(info["effect"], expected_effect, f"ATT({g},{t})") + _assert_close(info["effect"], expected_effect, f"ATT({g},{t})", se=se) def test_event_study_effects_match_table6(self, edid_hrs_result): - for e, (expected_effect, _) in TABLE6_ES.items(): - # Find event study effect matching relative time e + for e, (expected_effect, se) in TABLE6_ES.items(): found = False for rel_time, info in edid_hrs_result.event_study_effects.items(): if int(rel_time) == e: - _assert_close(info["effect"], expected_effect, f"ES({e})") + _assert_close(info["effect"], expected_effect, f"ES({e})", se=se) found = True break assert found, f"ES({e}) not found in event study effects" def test_es_avg_matches_table6(self, edid_hrs_result): es_avg = _compute_es_avg(edid_hrs_result) - _assert_close(es_avg, TABLE6_ES_AVG[0], "ES_avg") + _assert_close(es_avg, TABLE6_ES_AVG[0], "ES_avg", se=TABLE6_ES_AVG[1]) def test_se_diagnostic_comparison(self, edid_hrs_result): """Log and sanity-check analytical vs cluster-robust SEs.""" @@ -307,11 +227,14 @@ def test_cs_cross_validation(self, hrs_data): hrs_data, outcome="outcome", unit="unit", time="time", first_treat="first_treat", ) + # CS-SA paper SEs from Table 6 + cs_ses = {(8,8): 1035, (8,9): 909, (8,10): 1008, + (9,9): 702, (9,10): 651, (10,10): 995} for (g, t), expected_effect in TABLE6_CS_SA.items(): info = _get_effect(cs_result.group_time_effects, g, t) _assert_close( info["effect"], expected_effect, - f"CS ATT({g},{t})", rtol=0.15, atol=300, + f"CS ATT({g},{t})", se=cs_ses[(g, t)], ) def test_pretreatment_effects_near_zero(self, edid_hrs_result): @@ -411,7 +334,7 @@ def test_coverage_approximately_correct(self, ci_params): n_sims = ci_params.bootstrap(200, min_n=49) mc = _run_mc_simulation(n_sims, rho=0, seed=5000) - true_overall = _true_overall_att_compustat() + true_overall = true_overall_att() covered = sum( ci[0] <= true_overall <= ci[1] for ci in mc["edid_overall_ci"] From 23402929c1504cddcc7ffc93d2d5b8a2b94671b6 Mon Sep 17 00:00:00 2001 From: igerber Date: Sat, 21 Mar 2026 11:03:10 -0400 Subject: [PATCH 4/5] Move shared DGP to tests/helpers/, remove global pythonpath P3: Move edid_dgp.py into tests/helpers/ and add the helpers directory to sys.path via conftest.py instead of the global pythonpath = ["tests"] setting. This avoids making every module under tests/ importable as a top-level module. Co-Authored-By: Claude Opus 4.6 (1M context) --- pyproject.toml | 1 - tests/conftest.py | 4 ++++ tests/{ => helpers}/edid_dgp.py | 0 3 files changed, 4 insertions(+), 1 deletion(-) rename tests/{ => helpers}/edid_dgp.py (100%) diff --git a/pyproject.toml b/pyproject.toml index 376e8356..710a1be3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -89,7 +89,6 @@ python-packages = ["diff_diff"] [tool.pytest.ini_options] testpaths = ["tests"] -pythonpath = ["tests"] python_files = "test_*.py" # Exclude slow tests by default; use `pytest -m ''` to run all tests addopts = "-v --tb=short -m 'not slow'" diff --git a/tests/conftest.py b/tests/conftest.py index 4d4ff412..6f377ceb 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,6 +8,10 @@ import math import os import subprocess +import sys + +# Make tests/helpers/ importable without adding all of tests/ to sys.path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), "helpers")) # Force non-interactive matplotlib backend before any test imports it. # Prevents plt.show() from blocking the test suite on a GUI window. diff --git a/tests/edid_dgp.py b/tests/helpers/edid_dgp.py similarity index 100% rename from tests/edid_dgp.py rename to tests/helpers/edid_dgp.py From 8c688557e81e70f30c4f19c7eebf4fe5e800467c Mon Sep 17 00:00:00 2001 From: igerber Date: Sat, 21 Mar 2026 11:43:27 -0400 Subject: [PATCH 5/5] Add inline regeneration script to HRS fixture README P3: Replace reference to non-committed plan file with the exact Python command sequence used to build hrs_edid_validation.csv. Co-Authored-By: Claude Opus 4.6 (1M context) --- tests/data/README.md | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/data/README.md b/tests/data/README.md index 96c3da78..1b361598 100644 --- a/tests/data/README.md +++ b/tests/data/README.md @@ -31,4 +31,25 @@ Section 6: **Columns:** `unit` (hhidpn), `time` (wave), `outcome` (oop_spend, 2005 dollars), `first_treat` (first_hosp) **Regeneration:** Requires the Dobkin et al. replication kit (`.gitignore`d as `replication_data/`). -The extraction logic is documented in the plan file and was executed as a one-time preprocessing step. + +```python +import pandas as pd, numpy as np +df = pd.read_stata("replication_data/116186-V1/Replication-Kit/HRS/Data/HRS_long.dta") +sub = df[df["wave"].isin([7, 8, 9, 10, 11])] +balanced = sub.groupby("hhidpn")["wave"].nunique() +sub = sub[sub["hhidpn"].isin(balanced[balanced == 5].index)] +sub = sub[sub["hhidpn"].isin(sub[sub["first_hosp"].notna()]["hhidpn"].unique())] +fh = sub.groupby("hhidpn")["first_hosp"].first() +sub = sub[sub["hhidpn"].isin(fh[fh >= 8].index)] +ages = sub.groupby("hhidpn")["age_hosp"].first() +sub = sub[sub["hhidpn"].isin(ages[(ages >= 50) & (ages <= 59)].index)] +sub = sub[sub["wave"] <= 10] +sub["first_treat"] = sub["first_hosp"].apply(lambda x: np.inf if x == 11 else int(x)) +out = sub[["hhidpn", "wave", "oop_spend", "first_treat"]].copy() +out.columns = ["unit", "time", "outcome", "first_treat"] +out["unit"] = out["unit"].astype(int) +out["time"] = out["time"].astype(int) +out.sort_values(["unit", "time"]).reset_index(drop=True).to_csv( + "tests/data/hrs_edid_validation.csv", index=False +) +```