finite-selection 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) 2025 goji+
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,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: finite-selection
3
+ Version: 0.1.0
4
+ Summary: Finite Selection Model for randomized, balanced allocation of units to treatment groups
5
+ Keywords: experimental design,randomization,covariate balance,finite selection model,causal inference,randomized controlled trials
6
+ Author: Gaurav Sood
7
+ Author-email: Gaurav Sood <gsood07@gmail.com>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Science/Research
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Topic :: Scientific/Engineering :: Mathematics
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: numpy>=2.0
20
+ Requires-Dist: pandas>=2.2
21
+ Requires-Dist: scipy>=1.11
22
+ Requires-Dist: pyarrow>=15 ; extra == 'data'
23
+ Requires-Dist: matplotlib>=3.8 ; extra == 'plot'
24
+ Requires-Python: >=3.12
25
+ Project-URL: Homepage, https://github.com/finite-sample/finite-selection
26
+ Project-URL: Documentation, https://finite-sample.github.io/finite-selection/
27
+ Project-URL: Repository, https://github.com/finite-sample/finite-selection
28
+ Project-URL: Issues, https://github.com/finite-sample/finite-selection/issues
29
+ Project-URL: Changelog, https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md
30
+ Provides-Extra: data
31
+ Provides-Extra: plot
32
+ Description-Content-Type: text/markdown
33
+
34
+ # finite-selection
35
+
36
+ [![PyPI](https://img.shields.io/pypi/v/finite-selection)](https://pypi.org/project/finite-selection/)
37
+ [![CI](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml/badge.svg)](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml)
38
+ [![Docs](https://github.com/finite-sample/finite-selection/actions/workflows/docs.yml/badge.svg)](https://finite-sample.github.io/finite-selection/)
39
+
40
+ <!-- SPHINX-START -->
41
+
42
+ finite-selection assigns units to treatment groups at random while keeping the
43
+ groups alike on their covariates. It implements the Finite Selection Model
44
+ (FSM) that Carl Morris built for the RAND Health Insurance Experiment, in
45
+ Python, with allocation results checked against the R package
46
+ [FSM](https://cran.r-project.org/package=FSM). It works with NumPy arrays and
47
+ pandas data frames and includes balance diagnostics and randomization tests.
48
+ The contribution is a tested Python implementation, documented corrections,
49
+ and reproducible examples; the method is due to the authors cited below.
50
+
51
+ ## How it works
52
+
53
+ The groups take turns choosing units, like captains picking teams. A random
54
+ draw fixes the order of turns, under a rule that never lets one group get far
55
+ ahead of its share. On its turn a group takes the remaining unit that most
56
+ improves its own design: by default, the unit that most increases the
57
+ determinant of its X'X matrix (D-optimality). Every group chases the same goal,
58
+ so the groups come out balanced. The turn order is random, so
59
+ randomization-based inference still applies.
60
+
61
+ ## Installation
62
+
63
+ Requires Python 3.12 or newer.
64
+
65
+ ```bash
66
+ pip install finite-selection
67
+ pip install "finite-selection[data,plot]" # example data and love plots
68
+ ```
69
+
70
+ ## Example
71
+
72
+ This splits the 445 men of the National Supported Work data into groups of
73
+ 222 and 223, once with the FSM and once by complete randomization. The table
74
+ reports TASMD for the first group: the distance between its covariate means and
75
+ the full-sample means, in standard deviations.
76
+
77
+ ```python
78
+ import numpy as np
79
+ import finite_selection as fs
80
+
81
+ x = fs.lalonde()
82
+ rng = np.random.default_rng(2026)
83
+
84
+ order = fs.som([222, 223], method="scomars", rng=rng) # who chooses when
85
+ fsm_z = fs.fsm(x, order, rng=rng).assignment # who goes where
86
+ crd_z = fs.crd([222, 223], rng=rng) # complete randomization
87
+
88
+ print(fs.tasmd_rand(x, {"CRD": crd_z, "FSM": fsm_z}).round(3))
89
+ ```
90
+
91
+ ```text
92
+ CRD FSM
93
+ Age 0.066 0.002
94
+ Education 0.004 0.004
95
+ Black 0.023 0.011
96
+ Hispanic 0.055 0.007
97
+ Married 0.043 0.007
98
+ Nodegree 0.018 0.004
99
+ Re74 0.016 0.006
100
+ Re75 0.006 0.002
101
+ ```
102
+
103
+ The FSM group sits within 0.011 standard deviations of the full sample on
104
+ every covariate. The randomized group is off by up to 0.066, on age. That is
105
+ one draw of each. Over 200 draws, the average TASMD per covariate is 0.034 to
106
+ 0.041 under complete randomization and 0.004 to 0.008 under the FSM.
107
+ `tasmd_rand` reports these averages when given a matrix of assignments.
108
+
109
+ The package also allocates units that arrive in batches (`fsm_batch`), offers
110
+ ten other selection functions, and covers the analysis side: Fisher
111
+ randomization tests (`perm_test`), effective sample sizes for comparing designs
112
+ (`ess_rand`, `ess_model`), squares and interactions of the covariates
113
+ (`make_sq_inter`), and love plots (`love_plot`). The
114
+ [user guide](https://finite-sample.github.io/finite-selection/guide.html) runs a full experiment with them.
115
+
116
+ ## What it assumes
117
+
118
+ The FSM needs every unit and its covariates before assignment starts, so it
119
+ suits experiments that enroll a known list, not ones that recruit as they go.
120
+ It balances the columns you give it. Balance on squares or interactions
121
+ requires passing them in, through `make_sq_inter` for example. Against outcome
122
+ components it cannot see, it can increase variance relative to complete
123
+ randomization. Covariate
124
+ balance alone does not guarantee more precise estimates for every outcome.
125
+ The [JRSS-A discussion](https://doi.org/10.1093/jrsssa/qnag030) examines this
126
+ robustness concern. Run time grows with the square of the sample: about 0.1 seconds for 445
127
+ units and 7 seconds for 5,000.
128
+
129
+ ## Agreement with R
130
+
131
+ The script `tests/fixtures/make_r_fixtures.R` runs R's exported functions on a
132
+ grid of cases and saves their inputs and outputs. The test suite checks the
133
+ Python functions against those records:
134
+
135
+ - Given the same turn order, `fsm` reproduces R's allocation and selection
136
+ sequence in all 67 cases, which span the 11 selection functions, two to four
137
+ groups, and the options (intercept, scaling, ridge size, `Q_initial`,
138
+ collinear data). `fsm_batch` does the same in 3 cases.
139
+ - Random draws (`som`, `crd`) match R in distribution over 10,000 draws. R and
140
+ numpy use different random number generators, so individual draws differ.
141
+ - In several places R 1.0.0 departs from its own documentation, and Python
142
+ follows the documentation. For example, R's `ess_rand` reads only the first N
143
+ assignments, and its `perm_test` ignores a nonzero null effect. Fixes are
144
+ proposed upstream, and [Behaviour and parity with R](https://finite-sample.github.io/finite-selection/behavior.html) lists
145
+ each departure with its test.
146
+
147
+ `perm_test` imputes the two-group sharp null for every supported contrast,
148
+ including when `tau=0`. Sampled reference assignments use the Monte Carlo
149
+ correction `(b + 1) / (B + 1)`; `exact=True` is for a complete, equally weighted
150
+ reference distribution. Rank tests and tests with more than two groups support
151
+ only the sharp no-effect null.
152
+
153
+ ## Credits
154
+
155
+ Carl N. Morris introduced the FSM (1979, *Journal of Econometrics* 11, 43-61).
156
+ Ambarish Chattopadhyay, Carl N. Morris and José R. Zubizarreta recast it in the
157
+ potential-outcomes framework and wrote the R package FSM, described in
158
+ "Randomized and balanced allocation of units into treatment groups using the
159
+ finite selection model for R" (arXiv:2105.02393) and "Balanced and robust
160
+ randomized treatment assignments: the finite selection model for the Health
161
+ Insurance Experiment and beyond" (*JRSS-A* 189(4), 2026; arXiv:2205.09736).
162
+ This package is an independent implementation checked against theirs. The
163
+ bundled data is Dehejia and Wahba's subset of the National Supported Work
164
+ demonstration (LaLonde 1986), from
165
+ [NBER](https://users.nber.org/~rdehejia/nswdata.html).
166
+
167
+ Cite the papers when you use the method, and this package (`CITATION.cff`) when
168
+ you use the software.
@@ -0,0 +1,135 @@
1
+ # finite-selection
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/finite-selection)](https://pypi.org/project/finite-selection/)
4
+ [![CI](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml/badge.svg)](https://github.com/finite-sample/finite-selection/actions/workflows/ci.yml)
5
+ [![Docs](https://github.com/finite-sample/finite-selection/actions/workflows/docs.yml/badge.svg)](https://finite-sample.github.io/finite-selection/)
6
+
7
+ <!-- SPHINX-START -->
8
+
9
+ finite-selection assigns units to treatment groups at random while keeping the
10
+ groups alike on their covariates. It implements the Finite Selection Model
11
+ (FSM) that Carl Morris built for the RAND Health Insurance Experiment, in
12
+ Python, with allocation results checked against the R package
13
+ [FSM](https://cran.r-project.org/package=FSM). It works with NumPy arrays and
14
+ pandas data frames and includes balance diagnostics and randomization tests.
15
+ The contribution is a tested Python implementation, documented corrections,
16
+ and reproducible examples; the method is due to the authors cited below.
17
+
18
+ ## How it works
19
+
20
+ The groups take turns choosing units, like captains picking teams. A random
21
+ draw fixes the order of turns, under a rule that never lets one group get far
22
+ ahead of its share. On its turn a group takes the remaining unit that most
23
+ improves its own design: by default, the unit that most increases the
24
+ determinant of its X'X matrix (D-optimality). Every group chases the same goal,
25
+ so the groups come out balanced. The turn order is random, so
26
+ randomization-based inference still applies.
27
+
28
+ ## Installation
29
+
30
+ Requires Python 3.12 or newer.
31
+
32
+ ```bash
33
+ pip install finite-selection
34
+ pip install "finite-selection[data,plot]" # example data and love plots
35
+ ```
36
+
37
+ ## Example
38
+
39
+ This splits the 445 men of the National Supported Work data into groups of
40
+ 222 and 223, once with the FSM and once by complete randomization. The table
41
+ reports TASMD for the first group: the distance between its covariate means and
42
+ the full-sample means, in standard deviations.
43
+
44
+ ```python
45
+ import numpy as np
46
+ import finite_selection as fs
47
+
48
+ x = fs.lalonde()
49
+ rng = np.random.default_rng(2026)
50
+
51
+ order = fs.som([222, 223], method="scomars", rng=rng) # who chooses when
52
+ fsm_z = fs.fsm(x, order, rng=rng).assignment # who goes where
53
+ crd_z = fs.crd([222, 223], rng=rng) # complete randomization
54
+
55
+ print(fs.tasmd_rand(x, {"CRD": crd_z, "FSM": fsm_z}).round(3))
56
+ ```
57
+
58
+ ```text
59
+ CRD FSM
60
+ Age 0.066 0.002
61
+ Education 0.004 0.004
62
+ Black 0.023 0.011
63
+ Hispanic 0.055 0.007
64
+ Married 0.043 0.007
65
+ Nodegree 0.018 0.004
66
+ Re74 0.016 0.006
67
+ Re75 0.006 0.002
68
+ ```
69
+
70
+ The FSM group sits within 0.011 standard deviations of the full sample on
71
+ every covariate. The randomized group is off by up to 0.066, on age. That is
72
+ one draw of each. Over 200 draws, the average TASMD per covariate is 0.034 to
73
+ 0.041 under complete randomization and 0.004 to 0.008 under the FSM.
74
+ `tasmd_rand` reports these averages when given a matrix of assignments.
75
+
76
+ The package also allocates units that arrive in batches (`fsm_batch`), offers
77
+ ten other selection functions, and covers the analysis side: Fisher
78
+ randomization tests (`perm_test`), effective sample sizes for comparing designs
79
+ (`ess_rand`, `ess_model`), squares and interactions of the covariates
80
+ (`make_sq_inter`), and love plots (`love_plot`). The
81
+ [user guide](https://finite-sample.github.io/finite-selection/guide.html) runs a full experiment with them.
82
+
83
+ ## What it assumes
84
+
85
+ The FSM needs every unit and its covariates before assignment starts, so it
86
+ suits experiments that enroll a known list, not ones that recruit as they go.
87
+ It balances the columns you give it. Balance on squares or interactions
88
+ requires passing them in, through `make_sq_inter` for example. Against outcome
89
+ components it cannot see, it can increase variance relative to complete
90
+ randomization. Covariate
91
+ balance alone does not guarantee more precise estimates for every outcome.
92
+ The [JRSS-A discussion](https://doi.org/10.1093/jrsssa/qnag030) examines this
93
+ robustness concern. Run time grows with the square of the sample: about 0.1 seconds for 445
94
+ units and 7 seconds for 5,000.
95
+
96
+ ## Agreement with R
97
+
98
+ The script `tests/fixtures/make_r_fixtures.R` runs R's exported functions on a
99
+ grid of cases and saves their inputs and outputs. The test suite checks the
100
+ Python functions against those records:
101
+
102
+ - Given the same turn order, `fsm` reproduces R's allocation and selection
103
+ sequence in all 67 cases, which span the 11 selection functions, two to four
104
+ groups, and the options (intercept, scaling, ridge size, `Q_initial`,
105
+ collinear data). `fsm_batch` does the same in 3 cases.
106
+ - Random draws (`som`, `crd`) match R in distribution over 10,000 draws. R and
107
+ numpy use different random number generators, so individual draws differ.
108
+ - In several places R 1.0.0 departs from its own documentation, and Python
109
+ follows the documentation. For example, R's `ess_rand` reads only the first N
110
+ assignments, and its `perm_test` ignores a nonzero null effect. Fixes are
111
+ proposed upstream, and [Behaviour and parity with R](https://finite-sample.github.io/finite-selection/behavior.html) lists
112
+ each departure with its test.
113
+
114
+ `perm_test` imputes the two-group sharp null for every supported contrast,
115
+ including when `tau=0`. Sampled reference assignments use the Monte Carlo
116
+ correction `(b + 1) / (B + 1)`; `exact=True` is for a complete, equally weighted
117
+ reference distribution. Rank tests and tests with more than two groups support
118
+ only the sharp no-effect null.
119
+
120
+ ## Credits
121
+
122
+ Carl N. Morris introduced the FSM (1979, *Journal of Econometrics* 11, 43-61).
123
+ Ambarish Chattopadhyay, Carl N. Morris and José R. Zubizarreta recast it in the
124
+ potential-outcomes framework and wrote the R package FSM, described in
125
+ "Randomized and balanced allocation of units into treatment groups using the
126
+ finite selection model for R" (arXiv:2105.02393) and "Balanced and robust
127
+ randomized treatment assignments: the finite selection model for the Health
128
+ Insurance Experiment and beyond" (*JRSS-A* 189(4), 2026; arXiv:2205.09736).
129
+ This package is an independent implementation checked against theirs. The
130
+ bundled data is Dehejia and Wahba's subset of the National Supported Work
131
+ demonstration (LaLonde 1986), from
132
+ [NBER](https://users.nber.org/~rdehejia/nswdata.html).
133
+
134
+ Cite the papers when you use the method, and this package (`CITATION.cff`) when
135
+ you use the software.
@@ -0,0 +1,170 @@
1
+ [project]
2
+ name = "finite-selection"
3
+ description = "Finite Selection Model for randomized, balanced allocation of units to treatment groups"
4
+ readme = "README.md"
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ requires-python = ">=3.12"
8
+ version = "0.1.0"
9
+ keywords = [
10
+ "experimental design",
11
+ "randomization",
12
+ "covariate balance",
13
+ "finite selection model",
14
+ "causal inference",
15
+ "randomized controlled trials",
16
+ ]
17
+ classifiers = [
18
+ "Development Status :: 4 - Beta",
19
+ "Intended Audience :: Science/Research",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.12",
23
+ "Programming Language :: Python :: 3.13",
24
+ "Programming Language :: Python :: 3.14",
25
+ "Topic :: Scientific/Engineering :: Mathematics",
26
+ "Typing :: Typed",
27
+ ]
28
+ dependencies = [
29
+ "numpy>=2.0",
30
+ "pandas>=2.2",
31
+ "scipy>=1.11",
32
+ ]
33
+
34
+ [[project.authors]]
35
+ name = "Gaurav Sood"
36
+ email = "gsood07@gmail.com"
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/finite-sample/finite-selection"
40
+ Documentation = "https://finite-sample.github.io/finite-selection/"
41
+ Repository = "https://github.com/finite-sample/finite-selection"
42
+ Issues = "https://github.com/finite-sample/finite-selection/issues"
43
+ Changelog = "https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md"
44
+
45
+ [project.optional-dependencies]
46
+ plot = ["matplotlib>=3.8"]
47
+ data = ["pyarrow>=15"]
48
+
49
+ [build-system]
50
+ requires = ["uv_build>=0.12.5,<0.13"]
51
+ build-backend = "uv_build"
52
+
53
+ [tool.uv.build-backend]
54
+ module-name = "finite_selection"
55
+
56
+ [tool.ruff]
57
+ line-length = 88
58
+ target-version = "py312"
59
+
60
+ [tool.ruff.lint]
61
+ external = ["DOC"]
62
+ select = [
63
+ "E",
64
+ "W",
65
+ "F",
66
+ "I",
67
+ "B",
68
+ "C4",
69
+ "UP",
70
+ "N",
71
+ "D",
72
+ "S",
73
+ "SIM",
74
+ "T20",
75
+ "PT",
76
+ "RUF",
77
+ "PTH",
78
+ "RET",
79
+ "PIE",
80
+ "FURB",
81
+ "PERF",
82
+ "DTZ",
83
+ "LOG",
84
+ "G",
85
+ "TC",
86
+ "FLY",
87
+ "RSE",
88
+ "SLOT",
89
+ "FA",
90
+ "A",
91
+ "EXE",
92
+ "ICN",
93
+ "PGH",
94
+ "PLE",
95
+ "ARG",
96
+ "SLF",
97
+ ]
98
+ ignore = [
99
+ "D203",
100
+ "D213",
101
+ "W191",
102
+ "D206",
103
+ "D300",
104
+ ]
105
+
106
+ [tool.ruff.lint.pydocstyle]
107
+ convention = "google"
108
+
109
+ [tool.ruff.lint.per-file-ignores]
110
+ "tests/**" = [
111
+ "S101",
112
+ "D",
113
+ "ARG",
114
+ "SLF",
115
+ ]
116
+ "docs/**" = ["D"]
117
+
118
+ [tool.pyright]
119
+ include = ["src"]
120
+ typeCheckingMode = "standard"
121
+
122
+ [tool.pydoclint]
123
+ style = "google"
124
+ arg-type-hints-in-docstring = false
125
+ check-return-types = false
126
+ check-yield-types = false
127
+ check-class-attributes = false
128
+ allow-init-docstring = true
129
+ exclude = '\.venv|tests|docs'
130
+
131
+ [tool.pytest.ini_options]
132
+ minversion = "8"
133
+ testpaths = ["tests"]
134
+ log_level = "INFO"
135
+ xfail_strict = true
136
+ filterwarnings = ["error"]
137
+ addopts = [
138
+ "-ra",
139
+ "--strict-config",
140
+ "--strict-markers",
141
+ ]
142
+
143
+ [tool.coverage.run]
144
+ source = ["src"]
145
+
146
+ [tool.preen]
147
+
148
+ [tool.codespell]
149
+ ignore-words-list = "som"
150
+
151
+ [dependency-groups]
152
+ dev = [
153
+ "ruff>=0.14",
154
+ "pyright>=1.1.390",
155
+ "pre-commit>=4",
156
+ { include-group = "test" },
157
+ ]
158
+ test = [
159
+ "matplotlib>=3.8",
160
+ "pyarrow>=15",
161
+ "pytest>=8",
162
+ "pytest-cov>=6",
163
+ ]
164
+ docs = [
165
+ "sphinx>=8",
166
+ "py-canon @ git+https://github.com/gojiplus/py-canon@v1",
167
+ "furo",
168
+ "myst-parser",
169
+ "sphinx-copybutton",
170
+ ]
@@ -0,0 +1,130 @@
1
+ [project]
2
+ name = "finite-selection"
3
+ description = "Finite Selection Model for randomized, balanced allocation of units to treatment groups"
4
+ readme = "README.md"
5
+ license = "MIT"
6
+ license-files = ["LICENSE"]
7
+ authors = [{ name = "Gaurav Sood", email = "gsood07@gmail.com" }]
8
+ requires-python = ">=3.12"
9
+ version = "0.1.0"
10
+ keywords = [
11
+ "experimental design",
12
+ "randomization",
13
+ "covariate balance",
14
+ "finite selection model",
15
+ "causal inference",
16
+ "randomized controlled trials",
17
+ ]
18
+ classifiers = [
19
+ "Development Status :: 4 - Beta",
20
+ "Intended Audience :: Science/Research",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.12",
24
+ "Programming Language :: Python :: 3.13",
25
+ "Programming Language :: Python :: 3.14",
26
+ "Topic :: Scientific/Engineering :: Mathematics",
27
+ "Typing :: Typed",
28
+ ]
29
+ dependencies = [
30
+ "numpy>=2.0",
31
+ "pandas>=2.2",
32
+ "scipy>=1.11",
33
+ ]
34
+
35
+ [project.urls]
36
+ Homepage = "https://github.com/finite-sample/finite-selection"
37
+ Documentation = "https://finite-sample.github.io/finite-selection/"
38
+ Repository = "https://github.com/finite-sample/finite-selection"
39
+ Issues = "https://github.com/finite-sample/finite-selection/issues"
40
+ Changelog = "https://github.com/finite-sample/finite-selection/blob/main/CHANGELOG.md"
41
+
42
+ [project.optional-dependencies]
43
+ plot = [
44
+ "matplotlib>=3.8",
45
+ ]
46
+ data = [
47
+ "pyarrow>=15",
48
+ ]
49
+
50
+ [build-system]
51
+ requires = ["uv_build>=0.12.5,<0.13"]
52
+ build-backend = "uv_build"
53
+
54
+ [tool.uv.build-backend]
55
+ module-name = "finite_selection"
56
+
57
+ [dependency-groups]
58
+ dev = [
59
+ "ruff>=0.14",
60
+ "pyright>=1.1.390",
61
+ "pre-commit>=4",
62
+ { include-group = "test" },
63
+ ]
64
+ test = [
65
+ "matplotlib>=3.8",
66
+ "pyarrow>=15",
67
+ "pytest>=8",
68
+ "pytest-cov>=6",
69
+ ]
70
+ docs = [
71
+ "sphinx>=8",
72
+ "py-canon @ git+https://github.com/gojiplus/py-canon@v1",
73
+ "furo",
74
+ "myst-parser",
75
+ "sphinx-copybutton",
76
+ ]
77
+
78
+ [tool.ruff]
79
+ line-length = 88
80
+ target-version = "py312"
81
+
82
+ [tool.ruff.lint]
83
+ external = ["DOC"]
84
+ select = [
85
+ "E", "W", "F", "I", "B", "C4", "UP", "N", "D", "S", "SIM", "T20", "PT", "RUF",
86
+ "PTH", "RET", "PIE", "FURB", "PERF", "DTZ", "LOG", "G", "TC", "FLY",
87
+ "RSE", "SLOT", "FA", "A", "EXE", "ICN", "PGH", "PLE", "ARG", "SLF",
88
+ ]
89
+ # D203/D213: the google convention this standard picks. W191/D206/D300:
90
+ # ruff's own docs list these as always incompatible with `ruff format`,
91
+ # which the standard also runs.
92
+ ignore = ["D203", "D213", "W191", "D206", "D300"]
93
+
94
+ [tool.ruff.lint.pydocstyle]
95
+ convention = "google"
96
+
97
+ [tool.ruff.lint.per-file-ignores]
98
+ # Unused fixture arguments and private-member access are how tests are written.
99
+ "tests/**" = ["S101", "D", "ARG", "SLF"]
100
+ "docs/**" = ["D"]
101
+
102
+ [tool.pyright]
103
+ include = ["src"]
104
+ typeCheckingMode = "standard"
105
+
106
+ [tool.pydoclint]
107
+ style = "google"
108
+ arg-type-hints-in-docstring = false
109
+ check-return-types = false
110
+ check-yield-types = false
111
+ check-class-attributes = false
112
+ allow-init-docstring = true
113
+ exclude = '\.venv|tests|docs'
114
+
115
+ [tool.pytest.ini_options]
116
+ minversion = "8"
117
+ testpaths = ["tests"]
118
+ log_level = "INFO"
119
+ xfail_strict = true
120
+ filterwarnings = ["error"]
121
+ addopts = ["-ra", "--strict-config", "--strict-markers"]
122
+
123
+ [tool.coverage.run]
124
+ source = ["src"]
125
+
126
+ [tool.preen]
127
+
128
+ [tool.codespell]
129
+ # som is the selection order matrix function, named as in the R package.
130
+ ignore-words-list = "som"
@@ -0,0 +1,45 @@
1
+ """Finite Selection Model: randomized, balanced allocation of units to groups."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ from .core import FSMResult, fsm, fsm_batch
6
+ from .datasets import lalonde
7
+ from .features import make_sq_inter
8
+ from .inference import (
9
+ PermTestResult,
10
+ TasmdSummary,
11
+ crd,
12
+ ess_model,
13
+ ess_rand,
14
+ perm_test,
15
+ tasmd,
16
+ tasmd_rand,
17
+ )
18
+ from .plot import asmd, love_plot
19
+ from .som import SelectionOrder, scomars_probs, som
20
+
21
+ try:
22
+ __version__ = version("finite-selection")
23
+ except PackageNotFoundError: # pragma: no cover - not installed
24
+ __version__ = "0.0.0"
25
+
26
+ __all__ = [
27
+ "FSMResult",
28
+ "PermTestResult",
29
+ "SelectionOrder",
30
+ "TasmdSummary",
31
+ "asmd",
32
+ "crd",
33
+ "ess_model",
34
+ "ess_rand",
35
+ "fsm",
36
+ "fsm_batch",
37
+ "lalonde",
38
+ "love_plot",
39
+ "make_sq_inter",
40
+ "perm_test",
41
+ "scomars_probs",
42
+ "som",
43
+ "tasmd",
44
+ "tasmd_rand",
45
+ ]