tf-inference 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gaurav Sood
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,301 @@
1
+ Metadata-Version: 2.4
2
+ Name: tf-inference
3
+ Version: 0.1.0
4
+ Summary: Numerically constructed tF critical values for single-instrument IV inference
5
+ Keywords: instrumental variables,weak instruments,econometrics,inference,tF
6
+ Author: Gaurav Sood
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
13
+ Requires-Dist: numpy>=1.26
14
+ Requires-Dist: scipy>=1.12
15
+ Requires-Dist: pyarrow>=18
16
+ Requires-Python: >=3.12
17
+ Project-URL: Homepage, https://github.com/finite-sample/tf-inference
18
+ Project-URL: Repository, https://github.com/finite-sample/tf-inference
19
+ Project-URL: Issues, https://github.com/finite-sample/tf-inference/issues
20
+ Project-URL: Documentation, https://github.com/finite-sample/tf-inference#readme
21
+ Description-Content-Type: text/markdown
22
+
23
+ # tf-inference
24
+
25
+ ![PyPI](https://img.shields.io/pypi/v/tf-inference.svg)
26
+ [![CI](https://github.com/finite-sample/tf-inference/actions/workflows/ci.yml/badge.svg)](https://github.com/finite-sample/tf-inference/actions/workflows/ci.yml)
27
+ ![Python](https://img.shields.io/pypi/pyversions/tf-inference.svg)
28
+
29
+ tf-inference computes tF critical values and confidence intervals for
30
+ instrumental-variable (IV) models with one endogenous regressor and one
31
+ excluded instrument. It provides generated tables for common confidence
32
+ levels and numerical calibration for other levels.
33
+
34
+ The tF method and its theoretical results are due to David S. Lee,
35
+ Justin McCrary, Marcelo J. Moreira and Jack Porter, authors of [Valid
36
+ t-Ratio Inference for IV (2022)](https://doi.org/10.1257/aer.20211063).
37
+ This package provides an independent Python implementation of their
38
+ Appendix B.3 construction and reusable numerical tables. Critical values
39
+ depend on the first-stage F statistic and a two-sided significance
40
+ level. The code constructs the curve from its boundary expansion and
41
+ recurrence; the published rounded tables serve as test references.
42
+
43
+ This is an initial numerical implementation. Its calibration uses
44
+ deterministic integration, a finite nuisance-parameter grid and local
45
+ searches. These checks are documented and reproducible; they are not a
46
+ proof of a uniform size bound. The inferential framework is asymptotic
47
+ under the single-instrument IV model, not a finite-sample coverage
48
+ guarantee or a remedy for invalid instruments.
49
+
50
+ ## Installation
51
+
52
+ Install with Python 3.12 or later:
53
+
54
+ python -m pip install tf-inference
55
+
56
+ NumPy, SciPy and PyArrow are required at runtime. No Stata, external data
57
+ download, API key or network access is needed to evaluate or generate
58
+ critical values.
59
+
60
+ ## Use the generated tables
61
+
62
+ ``` python
63
+ from tf_inference import critical_value, confidence_interval
64
+
65
+ critical_value([3.8, 3.9, 10, 1000], alpha=0.05)
66
+ # Approximately [inf, 30.93, 3.43035, 1.95996]
67
+
68
+ confidence_interval(coefficient=1, se=0.4, f_stat=10, alpha=0.05)
69
+ # Approximately [-0.37214, 2.37214]
70
+ ```
71
+
72
+ `alpha` is the significance level: 0.05 means 95% confidence. The return
73
+ value of `critical_value` is the threshold for **absolute t**, not t
74
+ squared or a standard-error multiplier. Divide it by the normal
75
+ two-sided critical value to obtain the corresponding standard-error
76
+ multiplier for that alpha.
77
+
78
+ Inputs broadcast as NumPy arrays. Confidence intervals put lower and
79
+ upper bounds on the final axis. Complex inputs, nonfinite or negative F statistics,
80
+ nonfinite coefficients, and nonpositive standard errors are rejected.
81
+
82
+ The 95% boundary is about 3.84145882. F at or below the boundary returns
83
+ an infinite critical value; F strictly above it has a finite critical
84
+ value. There is no artificial cutoff at F=4. The boundary is computed
85
+ separately for each alpha as `scipy.special.ndtri(alpha / 2)**2`. Very
86
+ close to the boundary, rounding in the input F itself can materially
87
+ affect the result.
88
+
89
+ Bundled tables cover alpha values 0.0001, 0.0005, 0.001, 0.002, 0.005,
90
+ 0.01, 0.02, 0.025, 0.03, 0.04, 0.05, 0.06, 0.075, 0.1, 0.125, 0.15, 0.2
91
+ and 0.25. Each contains at least 16,385 rows, concentrated near the
92
+ boundary. List the installed levels with `available_alphas()`. Tables
93
+ are never interpolated across alpha values.
94
+
95
+ The Python convenience functions and CLI default to `method="table"`. A
96
+ missing level raises an error; numerical calibration requires an
97
+ explicit `method="compute"` or a direct call to `calibrate`. The `auto`
98
+ method is not supported.
99
+
100
+ ## Calculate an unconventional level
101
+
102
+ ``` python
103
+ from tf_inference import calibrate
104
+
105
+ calibration = calibrate(alpha=0.037)
106
+ calibration.critical_value([4.5, 10, 100])
107
+ calibration.confidence_interval(1, 0.4, 10)
108
+ print(calibration.diagnostics)
109
+ ```
110
+
111
+ The bundled Parquet dataset is read and validated once; interpolators are
112
+ cached per alpha and shared by `load_table`,
113
+ `critical_value` and `confidence_interval`. Repeated lookup does not
114
+ read files, verify checksums again or rebuild the interpolator. Explicit
115
+ `method="compute"` calls use a separate cache of up to 32 calibrations.
116
+ Direct `calibrate` calls always compute afresh. Tables loaded from a
117
+ custom directory are read and checksum-verified on each call so changes
118
+ are detected.
119
+
120
+ For large inputs, pass a NumPy array in one call. For repeated work at
121
+ one level, retain `load_table(alpha)` or the result of
122
+ `calibrate(alpha)` and call its methods directly.
123
+
124
+ The numerical alpha domain is \[0.0001, 0.25\]. It covers confidence
125
+ levels from 75% to 99.99%. This is an explicit implementation range, not
126
+ a theoretical limit of tF. Calculations outside it are rejected rather
127
+ than extrapolated.
128
+
129
+ `calibrate` accepts `epsilon`, `seeds`, `size_tolerance`,
130
+ `strength_limit`, `strengths` and `correlations`. Smaller initialization
131
+ epsilon and more seeds allow convergence checks. These settings are not
132
+ claims of certified error. Failed recurrence, integration or
133
+ optimization raises `ConvergenceError`. Inspect the returned diagnostics
134
+ when doing new calibrations, and validate beyond the search settings
135
+ before relying on an unconventional level for research.
136
+
137
+ ## Generate constants for other software
138
+
139
+ The command-line interface exposes the same calculation:
140
+
141
+ tf-inference critical 3.9 10 100 --alpha 0.05
142
+ tf-inference critical 10 --alpha 0.037 --method compute
143
+ tf-inference generate --alpha 0.05 0.01 0.037 --output tables
144
+
145
+ The generator writes one `calibrations.parquet` dataset and a
146
+ `calibrations.json` manifest. Adding or replacing one alpha preserves the other
147
+ levels in that directory. The Parquet schema has three nonnullable float64
148
+ columns: `alpha`, `f_stat` and `regularized_squared`. Calibration settings,
149
+ plateaus and diagnostics are embedded as JSON in the Arrow schema metadata.
150
+ The schema-versioned manifest records the dataset's SHA-256 checksum.
151
+ Loading validates the checksum, schema, finite values, ordered grids,
152
+ boundary and plateau invariants, and agreement with the metadata.
153
+
154
+ `export_table(calibration, directory, points=16385)` and
155
+ `load_table(alpha, directory=directory)` provide the same operations in Python.
156
+ For a portable gzip CSV, add `--csv` to the generation command or pass
157
+ `include_csv=True` to `export_table`. CSV files are optional exports, not
158
+ packaged runtime data.
159
+
160
+ For accurate boundary evaluation, interpolate the regularized quantity
161
+ `Z(F) = (F - boundary) * critical(F)**2` using a monotone cubic interpolator.
162
+ It is the Parquet `regularized_squared` column (and the optional CSV's
163
+ `branch_regularized_squared` column). Then compute
164
+ `sqrt(Z(F) / (F - boundary))`. Cap F at the metadata's `plateau_f` before
165
+ evaluation and return infinity when F is at or below the boundary. The raw
166
+ branch extends to the Property (C) endpoint; at large F use the selected
167
+ plateau. The CSV's first critical value is infinite and must not be
168
+ interpolated as an ordinary finite row.
169
+
170
+ The export measures relative interpolation differences at every cell
171
+ midpoint against the computed curve, and rejects tables exceeding 1e-6
172
+ there. This is a measured check, not an interval-arithmetic error bound.
173
+ The shipped validation also compares randomly chosen F values against a
174
+ separately refined curve.
175
+
176
+ ## How the calculation works
177
+
178
+ 1. Compute the boundary q and initialize the squared critical value
179
+ near it using the expansion in Appendix B.3, step 1.
180
+ 2. Apply the inverse map in step 2 to extend the decreasing curve. The
181
+ code interpolates Z(F), whose finite boundary limit is q cubed,
182
+ rather than interpolating a divergent critical value.
183
+ 3. Locate the tangency that limits the decreasing segment under
184
+ Property (C). Its admissible plateau is also constrained to be at
185
+ least the normal two-sided critical value.
186
+ 4. Integrate null rejection probabilities in the Gaussian weak-IV
187
+ experiment. Search the nuisance parameters and move the plateau
188
+ earlier if it over-rejects beyond the requested numerical tolerance.
189
+
190
+ The size search can change the plateau. For example, alpha=0.037
191
+ requires an adjustment to the first candidate. For alpha=0.01 the
192
+ plateau is about 2.72549, above the normal 99% critical value of about
193
+ 2.57583. Replacing the 95% normal quantile with another quantile does
194
+ not implement general tF.
195
+
196
+ The default size search covers strength f0 from 0 to 80 and absolute
197
+ correlation rho from 0 to 1. Here E\[F\] = 1 + f0 squared; f0 is not F.
198
+ It includes singular rho=1 calculations, correlations approaching one,
199
+ and local searches between grid points. The strong-instrument limit is
200
+ checked separately by the normal critical-value constraint. The
201
+ unbounded nuisance domain is not exhaustively certified. The recorded
202
+ integration error does not include curve approximation or missed extrema
203
+ in the parameter search.
204
+
205
+ ## Performance
206
+
207
+ Table lookup avoids numerical calibration. For large inputs, evaluate an array
208
+ in one call. `make benchmark` records separate timings for warm scalar and
209
+ array lookup, loading the complete Parquet dataset with empty package caches,
210
+ and fresh calibration. Imports and operating-system file-cache effects are
211
+ excluded. Results and environment details are in `benchmarks/results.json`;
212
+ `benchmarks/baseline.json` preserves the earlier implementation's measurements.
213
+ These are local observations, not CI timing assertions. Tests enforce that
214
+ default calls never calibrate and warm calls avoid file access and interpolator
215
+ construction.
216
+
217
+ ## Validation and development
218
+
219
+ Install development dependencies and run the checks:
220
+
221
+ uv sync --all-groups
222
+ make ci
223
+
224
+ Tests cover the published rounded-table values and plateau landmarks,
225
+ initialization and grid refinement, the defining two-intersection
226
+ equations, monotonicity and the exact boundary, near-singular numerical
227
+ integration, independent Gaussian Monte Carlo calculations,
228
+ unconventional-alpha plateau adjustment, interval broadcasting, table
229
+ roundtrips and corrupted files, Parquet schema violations, complex inputs and
230
+ large-strength numerical stability. `make ci` runs Ruff, Pyright, pydoclint,
231
+ tests with a 90% coverage floor (including branch measurement), documentation
232
+ and distribution checks.
233
+ `preen check --strict` checks adoption of the shared py-canon standard.
234
+
235
+ `validation/validate.py` evaluates bundled tables against finer
236
+ recurrence calculations and held-out nuisance-parameter grids extending
237
+ to f0=160. `validation/results.json` records all cases and the
238
+ environment. Reproduce it:
239
+
240
+ uv run python validation/validate.py --output validation/results.json
241
+
242
+ Rebuild the bundled constants from scratch:
243
+
244
+ make tables
245
+
246
+ `make ci-docker` uses the standard `python:3.12` image. Documentation
247
+ includes this README directly; it is not maintained as a second copy.
248
+
249
+ ## Scope and integration
250
+
251
+ This package takes summary quantities. It does not fit an IV model or
252
+ verify that an instrument is valid. For use with an estimator, require
253
+ one endogenous regressor and one excluded instrument, and use the
254
+ appropriate first-stage squared t statistic and compatible covariance
255
+ estimates. It supplies the numerical calibration; estimator-specific
256
+ eligibility checks belong in the calling package.
257
+
258
+ This implements the 2022 tF construction. VtF is a different procedure
259
+ using additional information and is outside the present implementation.
260
+ No generic p-value API is provided: numerical nesting across arbitrary
261
+ alpha levels would need separate validation before inverting the family
262
+ of tests.
263
+
264
+ ## Citation and sources
265
+
266
+ Please cite the paper when using this package for research:
267
+
268
+ Lee, David S., Justin McCrary, Marcelo J. Moreira, and Jack Porter.
269
+ 2022. [Valid t-Ratio Inference for
270
+ IV](https://doi.org/10.1257/aer.20211063). *American Economic Review*
271
+ 112 (10): 3260-3290.
272
+
273
+ ``` bibtex
274
+ @article{lee2022valid,
275
+ author = {Lee, David S. and McCrary, Justin and Moreira, Marcelo J. and Porter, Jack},
276
+ title = {Valid {t}-Ratio Inference for {IV}},
277
+ journal = {American Economic Review},
278
+ year = {2022},
279
+ volume = {112},
280
+ number = {10},
281
+ pages = {3260--3290},
282
+ doi = {10.1257/aer.20211063}
283
+ }
284
+ ```
285
+
286
+ The authors provide the construction and supporting materials:
287
+
288
+ - [Author manuscript with Appendix
289
+ B.3](https://eml.berkeley.edu/~jmccrary/LMMP_2_15_22.pdf), February
290
+ 16, 2022.
291
+ - [Published supplemental
292
+ appendix](https://www.aeaweb.org/articles/materials/17480).
293
+ - [Data and code for the paper](https://doi.org/10.3886/E164502V1), the
294
+ authors' replication package.
295
+ - [Authors' supplementary
296
+ material](https://irs.princeton.edu/davidlee-supplementarytF) and
297
+ [Stata implementation](https://www.princeton.edu/~davidlee/wp/tf.ado).
298
+
299
+ AI assistance was used in this package's development and validation. The
300
+ numerical limitations and executed checks are recorded above and in the
301
+ repository's validation results.
@@ -0,0 +1,279 @@
1
+ # tf-inference
2
+
3
+ ![PyPI](https://img.shields.io/pypi/v/tf-inference.svg)
4
+ [![CI](https://github.com/finite-sample/tf-inference/actions/workflows/ci.yml/badge.svg)](https://github.com/finite-sample/tf-inference/actions/workflows/ci.yml)
5
+ ![Python](https://img.shields.io/pypi/pyversions/tf-inference.svg)
6
+
7
+ tf-inference computes tF critical values and confidence intervals for
8
+ instrumental-variable (IV) models with one endogenous regressor and one
9
+ excluded instrument. It provides generated tables for common confidence
10
+ levels and numerical calibration for other levels.
11
+
12
+ The tF method and its theoretical results are due to David S. Lee,
13
+ Justin McCrary, Marcelo J. Moreira and Jack Porter, authors of [Valid
14
+ t-Ratio Inference for IV (2022)](https://doi.org/10.1257/aer.20211063).
15
+ This package provides an independent Python implementation of their
16
+ Appendix B.3 construction and reusable numerical tables. Critical values
17
+ depend on the first-stage F statistic and a two-sided significance
18
+ level. The code constructs the curve from its boundary expansion and
19
+ recurrence; the published rounded tables serve as test references.
20
+
21
+ This is an initial numerical implementation. Its calibration uses
22
+ deterministic integration, a finite nuisance-parameter grid and local
23
+ searches. These checks are documented and reproducible; they are not a
24
+ proof of a uniform size bound. The inferential framework is asymptotic
25
+ under the single-instrument IV model, not a finite-sample coverage
26
+ guarantee or a remedy for invalid instruments.
27
+
28
+ ## Installation
29
+
30
+ Install with Python 3.12 or later:
31
+
32
+ python -m pip install tf-inference
33
+
34
+ NumPy, SciPy and PyArrow are required at runtime. No Stata, external data
35
+ download, API key or network access is needed to evaluate or generate
36
+ critical values.
37
+
38
+ ## Use the generated tables
39
+
40
+ ``` python
41
+ from tf_inference import critical_value, confidence_interval
42
+
43
+ critical_value([3.8, 3.9, 10, 1000], alpha=0.05)
44
+ # Approximately [inf, 30.93, 3.43035, 1.95996]
45
+
46
+ confidence_interval(coefficient=1, se=0.4, f_stat=10, alpha=0.05)
47
+ # Approximately [-0.37214, 2.37214]
48
+ ```
49
+
50
+ `alpha` is the significance level: 0.05 means 95% confidence. The return
51
+ value of `critical_value` is the threshold for **absolute t**, not t
52
+ squared or a standard-error multiplier. Divide it by the normal
53
+ two-sided critical value to obtain the corresponding standard-error
54
+ multiplier for that alpha.
55
+
56
+ Inputs broadcast as NumPy arrays. Confidence intervals put lower and
57
+ upper bounds on the final axis. Complex inputs, nonfinite or negative F statistics,
58
+ nonfinite coefficients, and nonpositive standard errors are rejected.
59
+
60
+ The 95% boundary is about 3.84145882. F at or below the boundary returns
61
+ an infinite critical value; F strictly above it has a finite critical
62
+ value. There is no artificial cutoff at F=4. The boundary is computed
63
+ separately for each alpha as `scipy.special.ndtri(alpha / 2)**2`. Very
64
+ close to the boundary, rounding in the input F itself can materially
65
+ affect the result.
66
+
67
+ Bundled tables cover alpha values 0.0001, 0.0005, 0.001, 0.002, 0.005,
68
+ 0.01, 0.02, 0.025, 0.03, 0.04, 0.05, 0.06, 0.075, 0.1, 0.125, 0.15, 0.2
69
+ and 0.25. Each contains at least 16,385 rows, concentrated near the
70
+ boundary. List the installed levels with `available_alphas()`. Tables
71
+ are never interpolated across alpha values.
72
+
73
+ The Python convenience functions and CLI default to `method="table"`. A
74
+ missing level raises an error; numerical calibration requires an
75
+ explicit `method="compute"` or a direct call to `calibrate`. The `auto`
76
+ method is not supported.
77
+
78
+ ## Calculate an unconventional level
79
+
80
+ ``` python
81
+ from tf_inference import calibrate
82
+
83
+ calibration = calibrate(alpha=0.037)
84
+ calibration.critical_value([4.5, 10, 100])
85
+ calibration.confidence_interval(1, 0.4, 10)
86
+ print(calibration.diagnostics)
87
+ ```
88
+
89
+ The bundled Parquet dataset is read and validated once; interpolators are
90
+ cached per alpha and shared by `load_table`,
91
+ `critical_value` and `confidence_interval`. Repeated lookup does not
92
+ read files, verify checksums again or rebuild the interpolator. Explicit
93
+ `method="compute"` calls use a separate cache of up to 32 calibrations.
94
+ Direct `calibrate` calls always compute afresh. Tables loaded from a
95
+ custom directory are read and checksum-verified on each call so changes
96
+ are detected.
97
+
98
+ For large inputs, pass a NumPy array in one call. For repeated work at
99
+ one level, retain `load_table(alpha)` or the result of
100
+ `calibrate(alpha)` and call its methods directly.
101
+
102
+ The numerical alpha domain is \[0.0001, 0.25\]. It covers confidence
103
+ levels from 75% to 99.99%. This is an explicit implementation range, not
104
+ a theoretical limit of tF. Calculations outside it are rejected rather
105
+ than extrapolated.
106
+
107
+ `calibrate` accepts `epsilon`, `seeds`, `size_tolerance`,
108
+ `strength_limit`, `strengths` and `correlations`. Smaller initialization
109
+ epsilon and more seeds allow convergence checks. These settings are not
110
+ claims of certified error. Failed recurrence, integration or
111
+ optimization raises `ConvergenceError`. Inspect the returned diagnostics
112
+ when doing new calibrations, and validate beyond the search settings
113
+ before relying on an unconventional level for research.
114
+
115
+ ## Generate constants for other software
116
+
117
+ The command-line interface exposes the same calculation:
118
+
119
+ tf-inference critical 3.9 10 100 --alpha 0.05
120
+ tf-inference critical 10 --alpha 0.037 --method compute
121
+ tf-inference generate --alpha 0.05 0.01 0.037 --output tables
122
+
123
+ The generator writes one `calibrations.parquet` dataset and a
124
+ `calibrations.json` manifest. Adding or replacing one alpha preserves the other
125
+ levels in that directory. The Parquet schema has three nonnullable float64
126
+ columns: `alpha`, `f_stat` and `regularized_squared`. Calibration settings,
127
+ plateaus and diagnostics are embedded as JSON in the Arrow schema metadata.
128
+ The schema-versioned manifest records the dataset's SHA-256 checksum.
129
+ Loading validates the checksum, schema, finite values, ordered grids,
130
+ boundary and plateau invariants, and agreement with the metadata.
131
+
132
+ `export_table(calibration, directory, points=16385)` and
133
+ `load_table(alpha, directory=directory)` provide the same operations in Python.
134
+ For a portable gzip CSV, add `--csv` to the generation command or pass
135
+ `include_csv=True` to `export_table`. CSV files are optional exports, not
136
+ packaged runtime data.
137
+
138
+ For accurate boundary evaluation, interpolate the regularized quantity
139
+ `Z(F) = (F - boundary) * critical(F)**2` using a monotone cubic interpolator.
140
+ It is the Parquet `regularized_squared` column (and the optional CSV's
141
+ `branch_regularized_squared` column). Then compute
142
+ `sqrt(Z(F) / (F - boundary))`. Cap F at the metadata's `plateau_f` before
143
+ evaluation and return infinity when F is at or below the boundary. The raw
144
+ branch extends to the Property (C) endpoint; at large F use the selected
145
+ plateau. The CSV's first critical value is infinite and must not be
146
+ interpolated as an ordinary finite row.
147
+
148
+ The export measures relative interpolation differences at every cell
149
+ midpoint against the computed curve, and rejects tables exceeding 1e-6
150
+ there. This is a measured check, not an interval-arithmetic error bound.
151
+ The shipped validation also compares randomly chosen F values against a
152
+ separately refined curve.
153
+
154
+ ## How the calculation works
155
+
156
+ 1. Compute the boundary q and initialize the squared critical value
157
+ near it using the expansion in Appendix B.3, step 1.
158
+ 2. Apply the inverse map in step 2 to extend the decreasing curve. The
159
+ code interpolates Z(F), whose finite boundary limit is q cubed,
160
+ rather than interpolating a divergent critical value.
161
+ 3. Locate the tangency that limits the decreasing segment under
162
+ Property (C). Its admissible plateau is also constrained to be at
163
+ least the normal two-sided critical value.
164
+ 4. Integrate null rejection probabilities in the Gaussian weak-IV
165
+ experiment. Search the nuisance parameters and move the plateau
166
+ earlier if it over-rejects beyond the requested numerical tolerance.
167
+
168
+ The size search can change the plateau. For example, alpha=0.037
169
+ requires an adjustment to the first candidate. For alpha=0.01 the
170
+ plateau is about 2.72549, above the normal 99% critical value of about
171
+ 2.57583. Replacing the 95% normal quantile with another quantile does
172
+ not implement general tF.
173
+
174
+ The default size search covers strength f0 from 0 to 80 and absolute
175
+ correlation rho from 0 to 1. Here E\[F\] = 1 + f0 squared; f0 is not F.
176
+ It includes singular rho=1 calculations, correlations approaching one,
177
+ and local searches between grid points. The strong-instrument limit is
178
+ checked separately by the normal critical-value constraint. The
179
+ unbounded nuisance domain is not exhaustively certified. The recorded
180
+ integration error does not include curve approximation or missed extrema
181
+ in the parameter search.
182
+
183
+ ## Performance
184
+
185
+ Table lookup avoids numerical calibration. For large inputs, evaluate an array
186
+ in one call. `make benchmark` records separate timings for warm scalar and
187
+ array lookup, loading the complete Parquet dataset with empty package caches,
188
+ and fresh calibration. Imports and operating-system file-cache effects are
189
+ excluded. Results and environment details are in `benchmarks/results.json`;
190
+ `benchmarks/baseline.json` preserves the earlier implementation's measurements.
191
+ These are local observations, not CI timing assertions. Tests enforce that
192
+ default calls never calibrate and warm calls avoid file access and interpolator
193
+ construction.
194
+
195
+ ## Validation and development
196
+
197
+ Install development dependencies and run the checks:
198
+
199
+ uv sync --all-groups
200
+ make ci
201
+
202
+ Tests cover the published rounded-table values and plateau landmarks,
203
+ initialization and grid refinement, the defining two-intersection
204
+ equations, monotonicity and the exact boundary, near-singular numerical
205
+ integration, independent Gaussian Monte Carlo calculations,
206
+ unconventional-alpha plateau adjustment, interval broadcasting, table
207
+ roundtrips and corrupted files, Parquet schema violations, complex inputs and
208
+ large-strength numerical stability. `make ci` runs Ruff, Pyright, pydoclint,
209
+ tests with a 90% coverage floor (including branch measurement), documentation
210
+ and distribution checks.
211
+ `preen check --strict` checks adoption of the shared py-canon standard.
212
+
213
+ `validation/validate.py` evaluates bundled tables against finer
214
+ recurrence calculations and held-out nuisance-parameter grids extending
215
+ to f0=160. `validation/results.json` records all cases and the
216
+ environment. Reproduce it:
217
+
218
+ uv run python validation/validate.py --output validation/results.json
219
+
220
+ Rebuild the bundled constants from scratch:
221
+
222
+ make tables
223
+
224
+ `make ci-docker` uses the standard `python:3.12` image. Documentation
225
+ includes this README directly; it is not maintained as a second copy.
226
+
227
+ ## Scope and integration
228
+
229
+ This package takes summary quantities. It does not fit an IV model or
230
+ verify that an instrument is valid. For use with an estimator, require
231
+ one endogenous regressor and one excluded instrument, and use the
232
+ appropriate first-stage squared t statistic and compatible covariance
233
+ estimates. It supplies the numerical calibration; estimator-specific
234
+ eligibility checks belong in the calling package.
235
+
236
+ This implements the 2022 tF construction. VtF is a different procedure
237
+ using additional information and is outside the present implementation.
238
+ No generic p-value API is provided: numerical nesting across arbitrary
239
+ alpha levels would need separate validation before inverting the family
240
+ of tests.
241
+
242
+ ## Citation and sources
243
+
244
+ Please cite the paper when using this package for research:
245
+
246
+ Lee, David S., Justin McCrary, Marcelo J. Moreira, and Jack Porter.
247
+ 2022. [Valid t-Ratio Inference for
248
+ IV](https://doi.org/10.1257/aer.20211063). *American Economic Review*
249
+ 112 (10): 3260-3290.
250
+
251
+ ``` bibtex
252
+ @article{lee2022valid,
253
+ author = {Lee, David S. and McCrary, Justin and Moreira, Marcelo J. and Porter, Jack},
254
+ title = {Valid {t}-Ratio Inference for {IV}},
255
+ journal = {American Economic Review},
256
+ year = {2022},
257
+ volume = {112},
258
+ number = {10},
259
+ pages = {3260--3290},
260
+ doi = {10.1257/aer.20211063}
261
+ }
262
+ ```
263
+
264
+ The authors provide the construction and supporting materials:
265
+
266
+ - [Author manuscript with Appendix
267
+ B.3](https://eml.berkeley.edu/~jmccrary/LMMP_2_15_22.pdf), February
268
+ 16, 2022.
269
+ - [Published supplemental
270
+ appendix](https://www.aeaweb.org/articles/materials/17480).
271
+ - [Data and code for the paper](https://doi.org/10.3886/E164502V1), the
272
+ authors' replication package.
273
+ - [Authors' supplementary
274
+ material](https://irs.princeton.edu/davidlee-supplementarytF) and
275
+ [Stata implementation](https://www.princeton.edu/~davidlee/wp/tf.ado).
276
+
277
+ AI assistance was used in this package's development and validation. The
278
+ numerical limitations and executed checks are recorded above and in the
279
+ repository's validation results.