discopt-doe 0.2.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.
- discopt_doe-0.2.0/PKG-INFO +203 -0
- discopt_doe-0.2.0/README.md +177 -0
- discopt_doe-0.2.0/pyproject.toml +97 -0
- discopt_doe-0.2.0/setup.cfg +4 -0
- discopt_doe-0.2.0/src/discopt/doe/__init__.py +282 -0
- discopt_doe-0.2.0/src/discopt/doe/acquisition.py +221 -0
- discopt_doe-0.2.0/src/discopt/doe/anova.py +399 -0
- discopt_doe-0.2.0/src/discopt/doe/cli.py +2220 -0
- discopt_doe-0.2.0/src/discopt/doe/design.py +1168 -0
- discopt_doe-0.2.0/src/discopt/doe/discrimination.py +840 -0
- discopt_doe-0.2.0/src/discopt/doe/discrimination_sequential.py +243 -0
- discopt_doe-0.2.0/src/discopt/doe/estimability.py +394 -0
- discopt_doe-0.2.0/src/discopt/doe/exploration.py +225 -0
- discopt_doe-0.2.0/src/discopt/doe/fim.py +953 -0
- discopt_doe-0.2.0/src/discopt/doe/fractional.py +363 -0
- discopt_doe-0.2.0/src/discopt/doe/gui/__init__.py +6 -0
- discopt_doe-0.2.0/src/discopt/doe/gui/app.py +2342 -0
- discopt_doe-0.2.0/src/discopt/doe/gui/discopt-logo.png +0 -0
- discopt_doe-0.2.0/src/discopt/doe/gui/launcher.py +142 -0
- discopt_doe-0.2.0/src/discopt/doe/install.py +71 -0
- discopt_doe-0.2.0/src/discopt/doe/latin.py +405 -0
- discopt_doe-0.2.0/src/discopt/doe/model_based.py +549 -0
- discopt_doe-0.2.0/src/discopt/doe/optimize.py +366 -0
- discopt_doe-0.2.0/src/discopt/doe/profile.py +426 -0
- discopt_doe-0.2.0/src/discopt/doe/screening.py +352 -0
- discopt_doe-0.2.0/src/discopt/doe/selection.py +391 -0
- discopt_doe-0.2.0/src/discopt/doe/sequential.py +225 -0
- discopt_doe-0.2.0/src/discopt/doe/skill/SKILL.md +169 -0
- discopt_doe-0.2.0/src/discopt/doe/skill/agents/doe-expert.md +83 -0
- discopt_doe-0.2.0/src/discopt/doe/skill/agents/estimability-expert.md +125 -0
- discopt_doe-0.2.0/src/discopt/doe/skill/agents/identifiability-expert.md +111 -0
- discopt_doe-0.2.0/src/discopt/doe/skill/agents/model-discrimination-expert.md +138 -0
- discopt_doe-0.2.0/src/discopt/doe/surrogate.py +299 -0
- discopt_doe-0.2.0/src/discopt/doe/templates.py +623 -0
- discopt_doe-0.2.0/src/discopt/doe/workbook.py +794 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/PKG-INFO +203 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/SOURCES.txt +60 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/dependency_links.txt +1 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/entry_points.txt +5 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/requires.txt +14 -0
- discopt_doe-0.2.0/src/discopt_doe.egg-info/top_level.txt +1 -0
- discopt_doe-0.2.0/tests/test_batch_doe.py +436 -0
- discopt_doe-0.2.0/tests/test_discrimination_criteria.py +447 -0
- discopt_doe-0.2.0/tests/test_discrimination_examples.py +288 -0
- discopt_doe-0.2.0/tests/test_discrimination_sequential.py +287 -0
- discopt_doe-0.2.0/tests/test_doe.py +377 -0
- discopt_doe-0.2.0/tests/test_doe_cli.py +873 -0
- discopt_doe-0.2.0/tests/test_doe_fractional.py +237 -0
- discopt_doe-0.2.0/tests/test_doe_gui.py +257 -0
- discopt_doe-0.2.0/tests/test_doe_latin.py +489 -0
- discopt_doe-0.2.0/tests/test_doe_model_based.py +427 -0
- discopt_doe-0.2.0/tests/test_doe_optimize.py +431 -0
- discopt_doe-0.2.0/tests/test_estimability.py +199 -0
- discopt_doe-0.2.0/tests/test_fim.py +535 -0
- discopt_doe-0.2.0/tests/test_identifiability.py +249 -0
- discopt_doe-0.2.0/tests/test_identifiability_edge_cases.py +327 -0
- discopt_doe-0.2.0/tests/test_install.py +49 -0
- discopt_doe-0.2.0/tests/test_langmuir_batch_reactor.py +260 -0
- discopt_doe-0.2.0/tests/test_model_selection.py +298 -0
- discopt_doe-0.2.0/tests/test_plugin.py +53 -0
- discopt_doe-0.2.0/tests/test_profile.py +232 -0
- discopt_doe-0.2.0/tests/test_sequential_doe.py +227 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: discopt-doe
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Design-of-experiments plugin for the discopt modeling language
|
|
5
|
+
Author-email: John Kitchin <jkitchin@andrew.cmu.edu>
|
|
6
|
+
License: EPL-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/jkitchin/discopt-doe
|
|
8
|
+
Project-URL: Documentation, https://jkitchin.github.io/discopt-doe/
|
|
9
|
+
Project-URL: Repository, https://github.com/jkitchin/discopt-doe
|
|
10
|
+
Project-URL: Issues, https://github.com/jkitchin/discopt-doe/issues
|
|
11
|
+
Project-URL: Changelog, https://github.com/jkitchin/discopt-doe/blob/main/CHANGELOG.md
|
|
12
|
+
Requires-Python: >=3.10
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
Requires-Dist: discopt>=0.6
|
|
15
|
+
Requires-Dist: jax>=0.4
|
|
16
|
+
Requires-Dist: numpy>=1.24
|
|
17
|
+
Requires-Dist: scipy>=1.10
|
|
18
|
+
Requires-Dist: openpyxl>=3.1
|
|
19
|
+
Provides-Extra: gui
|
|
20
|
+
Requires-Dist: streamlit>=1.49; extra == "gui"
|
|
21
|
+
Requires-Dist: pandas>=2.0; extra == "gui"
|
|
22
|
+
Requires-Dist: matplotlib>=3.5; extra == "gui"
|
|
23
|
+
Requires-Dist: scikit-learn>=1.0; extra == "gui"
|
|
24
|
+
Provides-Extra: ml
|
|
25
|
+
Requires-Dist: scikit-learn>=1.0; extra == "ml"
|
|
26
|
+
|
|
27
|
+
# discopt-doe
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
[](https://github.com/jkitchin/discopt-doe/actions/workflows/ci.yml)
|
|
32
|
+
|
|
33
|
+
Design-of-experiments plugin for the [discopt](https://github.com/jkitchin/discopt)
|
|
34
|
+
modeling language. Installs as the `discopt.doe` namespace package — code written
|
|
35
|
+
against `from discopt.doe import ...` works unchanged.
|
|
36
|
+
|
|
37
|
+
Three complementary entry points:
|
|
38
|
+
|
|
39
|
+
1. **"What is the best operating condition?"** — active-learning optimization:
|
|
40
|
+
fit a surrogate to completed experiments, recommend the next batch via an
|
|
41
|
+
acquisition function (EI, UCB, steepest ascent), track everything in an
|
|
42
|
+
Excel workbook.
|
|
43
|
+
2. **"Does this factor matter?"** — classical designs: 2-level full/fractional
|
|
44
|
+
factorials, mixture designs, Latin/Graeco-Latin squares, main-effect
|
|
45
|
+
estimates, ANOVA.
|
|
46
|
+
3. **"How precisely can I estimate the model parameters?"** — model-based DoE:
|
|
47
|
+
exact D/A/E-optimal design from the Fisher Information Matrix (JAX
|
|
48
|
+
autodiff), identifiability/estimability diagnostics, profile likelihood,
|
|
49
|
+
model discrimination, sequential estimate–design loops.
|
|
50
|
+
|
|
51
|
+
Parameter estimation (`discopt.estimate`) lives in the base package; both
|
|
52
|
+
share the same `Experiment` interface.
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
Its `discopt>=0.6` dependency is on PyPI, so both a from-source install and a
|
|
57
|
+
direct git install resolve without any extra steps.
|
|
58
|
+
|
|
59
|
+
> **Not yet on PyPI:** `discopt-doe` itself has not been published yet, so the
|
|
60
|
+
> plain `pip install discopt-doe` form below works only once the first release
|
|
61
|
+
> is cut. Until then, install from source or git.
|
|
62
|
+
|
|
63
|
+
Recommended (uv):
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
git clone https://github.com/jkitchin/discopt-doe
|
|
67
|
+
cd discopt-doe
|
|
68
|
+
uv sync --all-extras # core + gui + ml + dev
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
With pip, straight from git:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install "git+https://github.com/jkitchin/discopt-doe" # core
|
|
75
|
+
pip install "git+https://github.com/jkitchin/discopt-doe#egg=discopt-doe[gui]" # + GUI
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Once `discopt-doe` is published, the usual form applies:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pip install discopt-doe # core
|
|
82
|
+
pip install "discopt-doe[gui]" # + Streamlit workbook GUI
|
|
83
|
+
pip install "discopt-doe[ml]" # + scikit-learn surrogates
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Requires `discopt>=0.6` (the first release with the public
|
|
87
|
+
`discopt.parametric` API and the CLI plugin hook).
|
|
88
|
+
|
|
89
|
+
## Quick start
|
|
90
|
+
|
|
91
|
+
FIM-based optimal design:
|
|
92
|
+
|
|
93
|
+
```python
|
|
94
|
+
from discopt.doe import compute_fim, optimal_experiment, DesignCriterion
|
|
95
|
+
|
|
96
|
+
fim = compute_fim(experiment, param_values={"k": 2.0}, design_values={"T": 350.0})
|
|
97
|
+
design = optimal_experiment(
|
|
98
|
+
experiment,
|
|
99
|
+
param_values={"k": 2.0},
|
|
100
|
+
design_bounds={"T": (300, 400)},
|
|
101
|
+
criterion=DesignCriterion.D_OPTIMAL,
|
|
102
|
+
)
|
|
103
|
+
print(design.summary())
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Active-learning round against a workbook:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
from discopt.doe import optimize_round, OptimizationCriterion
|
|
110
|
+
|
|
111
|
+
result = optimize_round(
|
|
112
|
+
workbook="opt.xlsx",
|
|
113
|
+
criterion=OptimizationCriterion.MAXIMIZE,
|
|
114
|
+
surrogate="gp",
|
|
115
|
+
acquisition="expected_improvement",
|
|
116
|
+
batch_size=4,
|
|
117
|
+
)
|
|
118
|
+
print(result.next_designs)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Identifiability diagnostics before you spend beam time:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from discopt.doe import diagnose_identifiability, estimability_rank
|
|
125
|
+
|
|
126
|
+
diag = diagnose_identifiability(experiment, param_values)
|
|
127
|
+
est = estimability_rank(experiment, param_values)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Command line
|
|
131
|
+
|
|
132
|
+
Installing this package adds the `doe` subcommand to the base discopt CLI
|
|
133
|
+
(via the `"discopt.cli"` entry-point group):
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
discopt doe templates # list workbook templates
|
|
137
|
+
discopt doe new linear -o run.xlsx --input T:300:400 --n 8
|
|
138
|
+
discopt doe status run.xlsx
|
|
139
|
+
discopt doe fit run.xlsx # fit parameters to completed rows
|
|
140
|
+
discopt doe anova run.xlsx # ANOVA F-table (latin/factorial designs)
|
|
141
|
+
discopt doe extend run.xlsx --n 4 # design the next batch
|
|
142
|
+
discopt doe optimize run.xlsx # one active-learning round (optimize template)
|
|
143
|
+
discopt doe gui run.xlsx # Streamlit GUI (needs [gui] extra)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## GUI
|
|
147
|
+
|
|
148
|
+
`discopt doe gui [workbook.xlsx]` launches a Streamlit app over a campaign
|
|
149
|
+
workbook (install the `[gui]` extra, which also pulls scikit-learn for the
|
|
150
|
+
active-learning round). It wraps the same `do_*` functions as the CLI:
|
|
151
|
+
|
|
152
|
+
- **Create** a new campaign from a template, browsing to an output folder.
|
|
153
|
+
- **Edit responses** in-app or in Excel, then Save; the **Rename** panel can
|
|
154
|
+
rename factors/response — note this clears the fit artifacts, so re-run Fit.
|
|
155
|
+
- **Fit / Extend / Optimize / ANOVA** panels drive the corresponding verb, and
|
|
156
|
+
a **History** panel shows the workbook's audit log.
|
|
157
|
+
|
|
158
|
+
Flags: `--port N`, `--no-browser`. The `DISCOPT_DOE_WORKBOOK` environment
|
|
159
|
+
variable pre-selects a workbook. Keep charts in a separate file — the CLI/GUI
|
|
160
|
+
rewrite the workbook and openpyxl does not preserve embedded charts (a `.bak`
|
|
161
|
+
is written before the first save).
|
|
162
|
+
|
|
163
|
+
## Development
|
|
164
|
+
|
|
165
|
+
The project is uv-managed:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
uv sync --all-extras # create .venv with everything
|
|
169
|
+
uv run pytest # fast test set (slow tests excluded by default)
|
|
170
|
+
uv run pytest -m '' # everything
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
To develop against a local discopt checkout instead of the PyPI release, add
|
|
174
|
+
a `[tool.uv.sources]` override pointing `discopt` at your editable clone:
|
|
175
|
+
|
|
176
|
+
```toml
|
|
177
|
+
[tool.uv.sources]
|
|
178
|
+
discopt = { path = "../../projects/discopt", editable = true }
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Docs are a Jupyter Book:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
uv run jupyter-book build docs/
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Claude Code skill
|
|
188
|
+
|
|
189
|
+
The package bundles a `/discopt-doe` skill and four expert agents (DoE,
|
|
190
|
+
estimability, identifiability, model discrimination) for Claude Code:
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
discopt-doe-install-skill # install to ~/.claude
|
|
194
|
+
discopt-doe-install-skill --project # install to ./.claude (versioned)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Literature
|
|
198
|
+
|
|
199
|
+
The methods implemented here are referenced throughout the docs; the full
|
|
200
|
+
bibliography is in [docs/references.bib](docs/references.bib) (Atkinson &
|
|
201
|
+
Donev optimal design, Franceschini & Macchietto MBDoE, Yao estimability,
|
|
202
|
+
Raue profile likelihood, Hunter–Reiner/Buzzi-Ferraris discrimination, and
|
|
203
|
+
more).
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# discopt-doe
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
[](https://github.com/jkitchin/discopt-doe/actions/workflows/ci.yml)
|
|
6
|
+
|
|
7
|
+
Design-of-experiments plugin for the [discopt](https://github.com/jkitchin/discopt)
|
|
8
|
+
modeling language. Installs as the `discopt.doe` namespace package — code written
|
|
9
|
+
against `from discopt.doe import ...` works unchanged.
|
|
10
|
+
|
|
11
|
+
Three complementary entry points:
|
|
12
|
+
|
|
13
|
+
1. **"What is the best operating condition?"** — active-learning optimization:
|
|
14
|
+
fit a surrogate to completed experiments, recommend the next batch via an
|
|
15
|
+
acquisition function (EI, UCB, steepest ascent), track everything in an
|
|
16
|
+
Excel workbook.
|
|
17
|
+
2. **"Does this factor matter?"** — classical designs: 2-level full/fractional
|
|
18
|
+
factorials, mixture designs, Latin/Graeco-Latin squares, main-effect
|
|
19
|
+
estimates, ANOVA.
|
|
20
|
+
3. **"How precisely can I estimate the model parameters?"** — model-based DoE:
|
|
21
|
+
exact D/A/E-optimal design from the Fisher Information Matrix (JAX
|
|
22
|
+
autodiff), identifiability/estimability diagnostics, profile likelihood,
|
|
23
|
+
model discrimination, sequential estimate–design loops.
|
|
24
|
+
|
|
25
|
+
Parameter estimation (`discopt.estimate`) lives in the base package; both
|
|
26
|
+
share the same `Experiment` interface.
|
|
27
|
+
|
|
28
|
+
## Install
|
|
29
|
+
|
|
30
|
+
Its `discopt>=0.6` dependency is on PyPI, so both a from-source install and a
|
|
31
|
+
direct git install resolve without any extra steps.
|
|
32
|
+
|
|
33
|
+
> **Not yet on PyPI:** `discopt-doe` itself has not been published yet, so the
|
|
34
|
+
> plain `pip install discopt-doe` form below works only once the first release
|
|
35
|
+
> is cut. Until then, install from source or git.
|
|
36
|
+
|
|
37
|
+
Recommended (uv):
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/jkitchin/discopt-doe
|
|
41
|
+
cd discopt-doe
|
|
42
|
+
uv sync --all-extras # core + gui + ml + dev
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
With pip, straight from git:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install "git+https://github.com/jkitchin/discopt-doe" # core
|
|
49
|
+
pip install "git+https://github.com/jkitchin/discopt-doe#egg=discopt-doe[gui]" # + GUI
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Once `discopt-doe` is published, the usual form applies:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install discopt-doe # core
|
|
56
|
+
pip install "discopt-doe[gui]" # + Streamlit workbook GUI
|
|
57
|
+
pip install "discopt-doe[ml]" # + scikit-learn surrogates
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Requires `discopt>=0.6` (the first release with the public
|
|
61
|
+
`discopt.parametric` API and the CLI plugin hook).
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
FIM-based optimal design:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
from discopt.doe import compute_fim, optimal_experiment, DesignCriterion
|
|
69
|
+
|
|
70
|
+
fim = compute_fim(experiment, param_values={"k": 2.0}, design_values={"T": 350.0})
|
|
71
|
+
design = optimal_experiment(
|
|
72
|
+
experiment,
|
|
73
|
+
param_values={"k": 2.0},
|
|
74
|
+
design_bounds={"T": (300, 400)},
|
|
75
|
+
criterion=DesignCriterion.D_OPTIMAL,
|
|
76
|
+
)
|
|
77
|
+
print(design.summary())
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Active-learning round against a workbook:
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
from discopt.doe import optimize_round, OptimizationCriterion
|
|
84
|
+
|
|
85
|
+
result = optimize_round(
|
|
86
|
+
workbook="opt.xlsx",
|
|
87
|
+
criterion=OptimizationCriterion.MAXIMIZE,
|
|
88
|
+
surrogate="gp",
|
|
89
|
+
acquisition="expected_improvement",
|
|
90
|
+
batch_size=4,
|
|
91
|
+
)
|
|
92
|
+
print(result.next_designs)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Identifiability diagnostics before you spend beam time:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from discopt.doe import diagnose_identifiability, estimability_rank
|
|
99
|
+
|
|
100
|
+
diag = diagnose_identifiability(experiment, param_values)
|
|
101
|
+
est = estimability_rank(experiment, param_values)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Command line
|
|
105
|
+
|
|
106
|
+
Installing this package adds the `doe` subcommand to the base discopt CLI
|
|
107
|
+
(via the `"discopt.cli"` entry-point group):
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
discopt doe templates # list workbook templates
|
|
111
|
+
discopt doe new linear -o run.xlsx --input T:300:400 --n 8
|
|
112
|
+
discopt doe status run.xlsx
|
|
113
|
+
discopt doe fit run.xlsx # fit parameters to completed rows
|
|
114
|
+
discopt doe anova run.xlsx # ANOVA F-table (latin/factorial designs)
|
|
115
|
+
discopt doe extend run.xlsx --n 4 # design the next batch
|
|
116
|
+
discopt doe optimize run.xlsx # one active-learning round (optimize template)
|
|
117
|
+
discopt doe gui run.xlsx # Streamlit GUI (needs [gui] extra)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## GUI
|
|
121
|
+
|
|
122
|
+
`discopt doe gui [workbook.xlsx]` launches a Streamlit app over a campaign
|
|
123
|
+
workbook (install the `[gui]` extra, which also pulls scikit-learn for the
|
|
124
|
+
active-learning round). It wraps the same `do_*` functions as the CLI:
|
|
125
|
+
|
|
126
|
+
- **Create** a new campaign from a template, browsing to an output folder.
|
|
127
|
+
- **Edit responses** in-app or in Excel, then Save; the **Rename** panel can
|
|
128
|
+
rename factors/response — note this clears the fit artifacts, so re-run Fit.
|
|
129
|
+
- **Fit / Extend / Optimize / ANOVA** panels drive the corresponding verb, and
|
|
130
|
+
a **History** panel shows the workbook's audit log.
|
|
131
|
+
|
|
132
|
+
Flags: `--port N`, `--no-browser`. The `DISCOPT_DOE_WORKBOOK` environment
|
|
133
|
+
variable pre-selects a workbook. Keep charts in a separate file — the CLI/GUI
|
|
134
|
+
rewrite the workbook and openpyxl does not preserve embedded charts (a `.bak`
|
|
135
|
+
is written before the first save).
|
|
136
|
+
|
|
137
|
+
## Development
|
|
138
|
+
|
|
139
|
+
The project is uv-managed:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
uv sync --all-extras # create .venv with everything
|
|
143
|
+
uv run pytest # fast test set (slow tests excluded by default)
|
|
144
|
+
uv run pytest -m '' # everything
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
To develop against a local discopt checkout instead of the PyPI release, add
|
|
148
|
+
a `[tool.uv.sources]` override pointing `discopt` at your editable clone:
|
|
149
|
+
|
|
150
|
+
```toml
|
|
151
|
+
[tool.uv.sources]
|
|
152
|
+
discopt = { path = "../../projects/discopt", editable = true }
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Docs are a Jupyter Book:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
uv run jupyter-book build docs/
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Claude Code skill
|
|
162
|
+
|
|
163
|
+
The package bundles a `/discopt-doe` skill and four expert agents (DoE,
|
|
164
|
+
estimability, identifiability, model discrimination) for Claude Code:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
discopt-doe-install-skill # install to ~/.claude
|
|
168
|
+
discopt-doe-install-skill --project # install to ./.claude (versioned)
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Literature
|
|
172
|
+
|
|
173
|
+
The methods implemented here are referenced throughout the docs; the full
|
|
174
|
+
bibliography is in [docs/references.bib](docs/references.bib) (Atkinson &
|
|
175
|
+
Donev optimal design, Franceschini & Macchietto MBDoE, Yao estimability,
|
|
176
|
+
Raue profile likelihood, Hunter–Reiner/Buzzi-Ferraris discrimination, and
|
|
177
|
+
more).
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "discopt-doe"
|
|
7
|
+
version = "0.2.0"
|
|
8
|
+
description = "Design-of-experiments plugin for the discopt modeling language"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "EPL-2.0" }
|
|
12
|
+
authors = [{ name = "John Kitchin", email = "jkitchin@andrew.cmu.edu" }]
|
|
13
|
+
dependencies = [
|
|
14
|
+
# Public parametric-compile API + the "discopt.cli" plugin hook land in 0.6.
|
|
15
|
+
"discopt>=0.6",
|
|
16
|
+
"jax>=0.4", # fim.py / model_based.py use jax directly
|
|
17
|
+
"numpy>=1.24",
|
|
18
|
+
"scipy>=1.10",
|
|
19
|
+
"openpyxl>=3.1", # workbook.py and the `discopt doe` CLI verbs
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
[project.urls]
|
|
23
|
+
Homepage = "https://github.com/jkitchin/discopt-doe"
|
|
24
|
+
Documentation = "https://jkitchin.github.io/discopt-doe/"
|
|
25
|
+
Repository = "https://github.com/jkitchin/discopt-doe"
|
|
26
|
+
Issues = "https://github.com/jkitchin/discopt-doe/issues"
|
|
27
|
+
Changelog = "https://github.com/jkitchin/discopt-doe/blob/main/CHANGELOG.md"
|
|
28
|
+
|
|
29
|
+
[project.optional-dependencies]
|
|
30
|
+
# The GUI needs matplotlib (history / surrogate diagnostic plots) and
|
|
31
|
+
# scikit-learn (its optimize round fits a GP surrogate), so the gui extra
|
|
32
|
+
# pulls in the ml extra's dependency too.
|
|
33
|
+
# streamlit >= 1.49: the app uses st.logo (added 1.35) and the width="stretch"
|
|
34
|
+
# element API (string width literals, ~1.49); older versions crash at startup.
|
|
35
|
+
gui = ["streamlit>=1.49", "pandas>=2.0", "matplotlib>=3.5", "scikit-learn>=1.0"]
|
|
36
|
+
ml = ["scikit-learn>=1.0"] # surrogate.py sklearn estimators
|
|
37
|
+
|
|
38
|
+
[project.scripts]
|
|
39
|
+
discopt-doe-install-skill = "discopt.doe.install:main"
|
|
40
|
+
|
|
41
|
+
# The base discopt CLI discovers plugin subcommands through this group (see
|
|
42
|
+
# the protocol in discopt/cli.py): the entry-point name is the subcommand and
|
|
43
|
+
# the value is a module exposing add_subparser(subparsers) and run(args).
|
|
44
|
+
# This is what keeps `discopt doe ...` working after the extraction.
|
|
45
|
+
[project.entry-points."discopt.cli"]
|
|
46
|
+
doe = "discopt.doe.cli"
|
|
47
|
+
|
|
48
|
+
[dependency-groups]
|
|
49
|
+
dev = [
|
|
50
|
+
"pytest>=8",
|
|
51
|
+
"pytest-timeout",
|
|
52
|
+
# tutorial notebooks and exploration.plot_* use matplotlib
|
|
53
|
+
"matplotlib>=3.5",
|
|
54
|
+
# notebook build scripts (scripts/build_*_notebook.py)
|
|
55
|
+
"nbformat>=5",
|
|
56
|
+
"nbclient>=0.10",
|
|
57
|
+
"ipykernel>=6",
|
|
58
|
+
# docs build
|
|
59
|
+
"jupyter-book<2",
|
|
60
|
+
"sphinxcontrib-bibtex",
|
|
61
|
+
# lint/format hooks (see .pre-commit-config.yaml)
|
|
62
|
+
"pre-commit>=3",
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
# discopt.doe is a PEP 420 namespace subpackage: it merges into the ``discopt``
|
|
66
|
+
# namespace at import time (discopt's __init__ extends its __path__ via
|
|
67
|
+
# pkgutil.extend_path). We deliberately package only ``discopt.doe`` — never
|
|
68
|
+
# ``discopt`` — so this distribution never shadows the base package.
|
|
69
|
+
[tool.setuptools.packages.find]
|
|
70
|
+
where = ["src"]
|
|
71
|
+
include = ["discopt.doe*"]
|
|
72
|
+
namespaces = true
|
|
73
|
+
|
|
74
|
+
[tool.setuptools.package-data]
|
|
75
|
+
"discopt.doe" = ["gui/discopt-logo.png", "skill/SKILL.md", "skill/agents/*.md"]
|
|
76
|
+
|
|
77
|
+
[tool.pytest.ini_options]
|
|
78
|
+
testpaths = ["tests"]
|
|
79
|
+
timeout = 300
|
|
80
|
+
addopts = "-m 'not slow'"
|
|
81
|
+
markers = [
|
|
82
|
+
"smoke: one solve per code path on a tiny instance; fast",
|
|
83
|
+
"slow: long-running tests (excluded by default; run with -m '')",
|
|
84
|
+
"integration: end-to-end multi-component workflows",
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
[tool.ruff]
|
|
88
|
+
line-length = 100
|
|
89
|
+
target-version = "py310"
|
|
90
|
+
# The docs notebooks are demonstrative (and several are generated by
|
|
91
|
+
# scripts/build_*_notebook.py); their idiomatic style (`plt.show();`,
|
|
92
|
+
# mid-cell imports) should not gate commits, so keep them out of lint/format.
|
|
93
|
+
extend-exclude = ["docs/notebooks"]
|
|
94
|
+
|
|
95
|
+
[tool.ruff.lint.per-file-ignores]
|
|
96
|
+
# The discopt version guard must run before the API re-exports.
|
|
97
|
+
"src/discopt/doe/__init__.py" = ["E402"]
|