process-improve 2.2.0__tar.gz → 2.2.2__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.
- {process_improve-2.2.0 → process_improve-2.2.2}/PKG-INFO +1 -1
- {process_improve-2.2.0 → process_improve-2.2.2}/pyproject.toml +30 -1
- {process_improve-2.2.0 → process_improve-2.2.2}/pyproject.toml.orig +29 -1
- process_improve-2.2.2/src/process_improve/_tool_registry.py +205 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/glm.py +4 -3
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_lm.py +2 -2
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/fit_linear_model.py +1 -4
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_uniform_sampling.py +3 -5
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/analysis.py +80 -17
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_mixture_constrained.py +3 -1
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_response_surface.py +1 -6
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_supersaturated.py +8 -10
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/next_step.py +161 -50
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/optimal.py +2 -7
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/random_effects.py +10 -2
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/monitoring/control_charts.py +61 -49
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/monitoring/metrics.py +7 -5
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_limits.py +13 -8
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_pls.py +9 -5
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_preprocessing.py +0 -97
- process_improve-2.2.2/src/process_improve/multivariate/_prm.py +399 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/_variance_components.py +54 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/ingest.py +19 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/tool_spec.py +6 -190
- process_improve-2.2.0/src/process_improve/multivariate/_prm.py +0 -390
- {process_improve-2.2.0 → process_improve-2.2.2}/README.md +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/_extras.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/_linalg.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/_random.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/_remote_data.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_batch_monitor.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_batch_pca.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_batch_plots.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_batch_pls.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_common.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_gaps.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/_online.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/alignment_helpers.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/control.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/data_input.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/datasets.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/features.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/plotting.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/preprocessing.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/batch/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/bivariate/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/bivariate/_elbow_peak.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/bivariate/methods.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/bivariate/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/chemistry/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/chemistry/preprocessing.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/config.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/batch/batch-fake-data.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/batch/details.txt +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/batch/dryer.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/batch/nylon.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/boilingpot.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/corrosion.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/golf.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/pollutant.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/NOTICE.md +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/anderson-whitcomb-2007.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/box-draper-2007.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/box-hunter-hunter-1978.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/davies-1956.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/derringer-suich-1980.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/efi-mooc-quizzes.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/fries-hunter-1980.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/goos-2025.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/goos-jones-2011.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/jones-nachtsheim-2011.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/jones-nachtsheim-2013.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/lenth-1989.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/montgomery-2013.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/nair-ffd-tutorial-2004.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/nist-ehandbook-ch5.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/nunez-ares-et-al-2023.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/nunez-ares-goos-2019.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/nunez-ares-goos-2020.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/pid-book.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/schmidt-launsby-2000.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/topics.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/reference_catalogue/ullmann-doe-2012.json +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/solar.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/experiments/test_doe1.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/monitoring/batch-yield-and-purity.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/monitoring/rubber-colour.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/C.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/Hotellings_T2_A3.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/Hotellings_T2_A6.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/LDPE.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/P.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/R.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/T.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/U.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/W.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/LDPE/Yhat_A6.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/cheddar-cheese.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/NOTICE +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/extraction1.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/extraction2.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/extraction3.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/ftir1.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/ftir2.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/dtu-pectin/ftir3.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/kamyr.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/solvents.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tablet-spectra.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/SOURCE +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group1.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group2.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group3.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group4.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group5.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/process_conditions.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/properties_Group1.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/properties_Group2.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/properties_Group3.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/properties_Group4.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/properties_Group5.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/datasets/multivariate/tpls-pyphi/quality_indicators.csv +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/_shared.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/aliasing.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/box_cox.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/curvature.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/diagnostics.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/lack_of_fit.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/lenth.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/mixture.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/model_selection.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/ols_extractors.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/prediction.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/split_plot.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/transforms.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_blocking.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_classical.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_desirability.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_expression_text.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_finite_fields.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_moment_aberration.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_orthogonal_arrays.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_region_geometry.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_region_quadrature.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_rules.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/analyze_experiment.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/analyze_omars.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/augment_design.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/compare_designs.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/create_factorial_design.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/doe_knowledge.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/evaluate_design.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/generate_design.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/optimize_responses.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/recommend_next_step.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/recommend_strategy.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/run_sheet.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/search_design_catalog.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/simulate_design_performance.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/trade_off_table.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_tools/visualize_doe.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/allocation.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/augment.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/benchmark.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/compare.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/crossed_arrays.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/datasets.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/design_catalog.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/design_measures.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_constrained.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_covariates.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_factorial.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_mixture.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_mixture_process.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_omars.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_omars_ilp.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_optimal.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_screening.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_space_filling.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_split_plot.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_three_level.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/designs_utils.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/evaluate.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/factor.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/gaussian_process.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/incomplete_blocks.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/api.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/data/concepts.yaml +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/data/decision_rules.yaml +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/data/design_types.yaml +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/data/diagnostics.yaml +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/engine.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/knowledge/models.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/layouts.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/least_squares_means.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/marginal_means.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/model_comparison.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/models.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/multistratum.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/omars.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/omars_trade_off.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/optimization.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/projections.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/pseudocomponents.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/reference_catalogue.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/region.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/run_order.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/run_sheet.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/separating.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/sequential.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/simulate.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/simulations.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/strategy/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/strategy/budget.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/strategy/domain_templates.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/strategy/engine.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/strategy/models.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/structures.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/surface_checks.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/three_level_components.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/trade_off.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/true_process.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/variance_dispersion.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/api.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/cube_plot.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/design_quality.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/diagnostics.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/effects.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/optimization_plots.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/registry.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/significance.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/square_plot.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/visualization/plots/surfaces.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/yates.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/interactions.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/mcp_server.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/monitoring/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/monitoring/evop.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/monitoring/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_adaptive.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_asca.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_base.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_categorical.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_common.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_cv_criteria.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_diagnostics.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_impute.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_mbpca.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_mbpls.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_nipals.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_null.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_opls.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_pca.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_pca_pls.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_plsda.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_procrustes.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_projection.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_resampling.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_robust.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/_tpls.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/methods.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/plots.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/multivariate/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/py.typed +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/recipes.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/_robust_regression.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/box_tidwell.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/methods.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/nonlinear.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/regression/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/analysis.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/designed.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/diagnostics.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/mam.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/panel.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/recipes.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/sensory/validation.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/batch.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/context.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/latent.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/model.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/recipes.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/simulation/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/tool_safety.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/classical.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/error_transmission.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/metrics.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/reference_distribution.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/serial_correlation.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/stated_values.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/univariate/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/adapters/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/adapters/base.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/adapters/echarts_adapter.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/adapters/plotly_adapter.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/charts/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/charts/boxplot.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/colors.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/raincloud.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/spec.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/themes.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/visualization/types.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/__init__.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/_expressions.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/project.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/recipe.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/tools.py +0 -0
- {process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/workbench/variant.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: process-improve
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis.
|
|
5
5
|
Keywords: Designed Experiments,Design of Experiments,DoE,Optimal Design,Response Surface,Latent Variables,PCA,PLS,Multivariate Data Analysis,Chemometrics,Process Monitoring,Batch data analysis
|
|
6
6
|
Author: Kevin Dunn
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "process-improve"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.2"
|
|
4
4
|
description = "Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -301,3 +301,32 @@ known-third-party = [
|
|
|
301
301
|
"pytest",
|
|
302
302
|
"pandas",
|
|
303
303
|
]
|
|
304
|
+
|
|
305
|
+
[tool.mutmut]
|
|
306
|
+
source_paths = ["src"]
|
|
307
|
+
only_mutate = [
|
|
308
|
+
"src/process_improve/multivariate/_limits.py",
|
|
309
|
+
"src/process_improve/monitoring/metrics.py",
|
|
310
|
+
"src/process_improve/monitoring/evop.py",
|
|
311
|
+
"src/process_improve/monitoring/control_charts.py",
|
|
312
|
+
]
|
|
313
|
+
pytest_add_cli_args = [
|
|
314
|
+
"-o",
|
|
315
|
+
"addopts=",
|
|
316
|
+
"-p",
|
|
317
|
+
"no:cacheprovider",
|
|
318
|
+
]
|
|
319
|
+
pytest_add_cli_args_test_selection = [
|
|
320
|
+
"tests/test_multivariate_limits.py",
|
|
321
|
+
"tests/test_multivariate.py",
|
|
322
|
+
"tests/test_audit_regressions_multivariate.py",
|
|
323
|
+
"tests/test_multiblock_validation.py",
|
|
324
|
+
"tests/test_multivariate_introspection.py",
|
|
325
|
+
"tests/test_monitoring.py",
|
|
326
|
+
"tests/test_monitoring_helpers.py",
|
|
327
|
+
"tests/test_audit_regressions_univariate_monitoring.py",
|
|
328
|
+
"tests/test_evop.py",
|
|
329
|
+
"tests/test_control_chart_cusum.py",
|
|
330
|
+
"tests/test_control_chart_ewma.py",
|
|
331
|
+
"tests/test_control_chart_hw_golden.py",
|
|
332
|
+
]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "process-improve"
|
|
3
|
-
version = "2.2.
|
|
3
|
+
version = "2.2.2"
|
|
4
4
|
description = 'Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis.'
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -449,3 +449,31 @@ docstring-quotes = "double"
|
|
|
449
449
|
|
|
450
450
|
[tool.ruff.lint.isort]
|
|
451
451
|
known-third-party=["pytest", "pandas"]
|
|
452
|
+
|
|
453
|
+
# Mutation testing: see "Mutation testing" in CONTRIBUTING.md. Modules join `only_mutate` one at a
|
|
454
|
+
# time, each with no survivor, starting with those whose numbers users act on; the tests listed
|
|
455
|
+
# are those that reach them.
|
|
456
|
+
[tool.mutmut]
|
|
457
|
+
source_paths = ["src"]
|
|
458
|
+
only_mutate = [
|
|
459
|
+
"src/process_improve/multivariate/_limits.py",
|
|
460
|
+
"src/process_improve/monitoring/metrics.py",
|
|
461
|
+
"src/process_improve/monitoring/evop.py",
|
|
462
|
+
"src/process_improve/monitoring/control_charts.py",
|
|
463
|
+
]
|
|
464
|
+
# The runner drops pytest.ini's addopts: no xdist workers and no coverage inside each mutant run.
|
|
465
|
+
pytest_add_cli_args = ["-o", "addopts=", "-p", "no:cacheprovider"]
|
|
466
|
+
pytest_add_cli_args_test_selection = [
|
|
467
|
+
"tests/test_multivariate_limits.py",
|
|
468
|
+
"tests/test_multivariate.py",
|
|
469
|
+
"tests/test_audit_regressions_multivariate.py",
|
|
470
|
+
"tests/test_multiblock_validation.py",
|
|
471
|
+
"tests/test_multivariate_introspection.py",
|
|
472
|
+
"tests/test_monitoring.py",
|
|
473
|
+
"tests/test_monitoring_helpers.py",
|
|
474
|
+
"tests/test_audit_regressions_univariate_monitoring.py",
|
|
475
|
+
"tests/test_evop.py",
|
|
476
|
+
"tests/test_control_chart_cusum.py",
|
|
477
|
+
"tests/test_control_chart_ewma.py",
|
|
478
|
+
"tests/test_control_chart_hw_golden.py",
|
|
479
|
+
]
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
"""(c) Kevin Dunn, 2010-2026. MIT License.
|
|
2
|
+
|
|
3
|
+
The ``@tool_spec`` decorator, the registry it fills, and ``clean``.
|
|
4
|
+
|
|
5
|
+
These are the parts of :mod:`process_improve.tool_spec` that every ``tools.py``
|
|
6
|
+
module imports. They live apart from tool discovery, which names every
|
|
7
|
+
``tools.py`` module, so that a tool module depends on this file alone and not,
|
|
8
|
+
through discovery, on every other tool module. ``tool_spec.py`` re-exports all
|
|
9
|
+
of it, and callers import it from there.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import math
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
import numpy as np
|
|
19
|
+
from pydantic import BaseModel
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Registry
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
#: Maps tool name -> decorated callable. Populated by ``@tool_spec``.
|
|
26
|
+
_TOOL_REGISTRY: dict[str, Callable[..., Any]] = {}
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# ---------------------------------------------------------------------------
|
|
30
|
+
# RNG metadata validation
|
|
31
|
+
# ---------------------------------------------------------------------------
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _validate_rng_metadata(name: str, rng: dict[str, Any]) -> None:
|
|
35
|
+
"""Reject ``rng`` payloads that don't match the published contract.
|
|
36
|
+
|
|
37
|
+
The contract is intentionally narrow so downstream consumers (the
|
|
38
|
+
factorial reproducible-export service) can introspect specs without
|
|
39
|
+
defensive type-checking. See ``CLAUDE.md`` for the full schema.
|
|
40
|
+
"""
|
|
41
|
+
if not isinstance(rng, dict):
|
|
42
|
+
raise TypeError(f"@tool_spec(name={name!r}): 'rng' must be a dict, got {type(rng).__name__}.")
|
|
43
|
+
if "uses_rng" not in rng or not isinstance(rng["uses_rng"], bool):
|
|
44
|
+
raise ValueError(f"@tool_spec(name={name!r}): 'rng' must have a boolean 'uses_rng' key.")
|
|
45
|
+
allowed_keys = {"uses_rng", "seed_param", "default_seed", "note"}
|
|
46
|
+
extra = set(rng) - allowed_keys
|
|
47
|
+
if extra:
|
|
48
|
+
raise ValueError(
|
|
49
|
+
f"@tool_spec(name={name!r}): unknown keys in 'rng': {sorted(extra)}. Allowed: {sorted(allowed_keys)}."
|
|
50
|
+
)
|
|
51
|
+
if not rng["uses_rng"]:
|
|
52
|
+
# Deterministic tools shouldn't carry a seed_param / default_seed.
|
|
53
|
+
if rng.get("seed_param") is not None or rng.get("default_seed") is not None:
|
|
54
|
+
raise ValueError(
|
|
55
|
+
f"@tool_spec(name={name!r}): 'seed_param' / 'default_seed' must be omitted when uses_rng is False."
|
|
56
|
+
)
|
|
57
|
+
return
|
|
58
|
+
seed_param = rng.get("seed_param")
|
|
59
|
+
if seed_param is not None and not isinstance(seed_param, str):
|
|
60
|
+
raise TypeError(
|
|
61
|
+
f"@tool_spec(name={name!r}): 'seed_param' must be a string or None, got {type(seed_param).__name__}."
|
|
62
|
+
)
|
|
63
|
+
default_seed = rng.get("default_seed")
|
|
64
|
+
if default_seed is not None and not isinstance(default_seed, int):
|
|
65
|
+
raise TypeError(
|
|
66
|
+
f"@tool_spec(name={name!r}): 'default_seed' must be an int or None, got {type(default_seed).__name__}."
|
|
67
|
+
)
|
|
68
|
+
if seed_param is None and default_seed is not None:
|
|
69
|
+
raise ValueError(f"@tool_spec(name={name!r}): 'default_seed' requires a 'seed_param' name.")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# ---------------------------------------------------------------------------
|
|
73
|
+
# Decorator
|
|
74
|
+
# ---------------------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def tool_spec( # noqa: PLR0913
|
|
78
|
+
name: str,
|
|
79
|
+
description: str,
|
|
80
|
+
*,
|
|
81
|
+
input_model: type[BaseModel],
|
|
82
|
+
examples: str = "",
|
|
83
|
+
category: str = "",
|
|
84
|
+
rng: dict[str, Any] | None = None,
|
|
85
|
+
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
|
|
86
|
+
"""Mark a function as an agent-callable tool.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
name:
|
|
91
|
+
Unique tool name exposed to the LLM (snake_case).
|
|
92
|
+
description:
|
|
93
|
+
Natural-language description of what the tool does and when to use it.
|
|
94
|
+
input_model:
|
|
95
|
+
A :class:`pydantic.BaseModel` subclass describing the tool's
|
|
96
|
+
input. The model is the single source of truth for both the
|
|
97
|
+
function's Python signature and the MCP JSON Schema (derived
|
|
98
|
+
via :meth:`BaseModel.model_json_schema`). Every input model
|
|
99
|
+
**must** set ``model_config = ConfigDict(extra="forbid")`` so
|
|
100
|
+
unknown keys are rejected (closes the SEC-15
|
|
101
|
+
kwarg-injection vector at the schema layer).
|
|
102
|
+
|
|
103
|
+
The decorated function then receives the parsed model as its
|
|
104
|
+
single positional argument::
|
|
105
|
+
|
|
106
|
+
class FooInput(BaseModel):
|
|
107
|
+
model_config = ConfigDict(extra="forbid")
|
|
108
|
+
values: list[float] = Field(..., min_length=2)
|
|
109
|
+
|
|
110
|
+
@tool_spec(name="foo", description="...", input_model=FooInput)
|
|
111
|
+
def foo(spec: FooInput) -> dict:
|
|
112
|
+
return {"n": len(spec.values)}
|
|
113
|
+
examples:
|
|
114
|
+
Optional natural-language -> tool-call mappings appended to
|
|
115
|
+
``description`` so the LLM sees worked examples.
|
|
116
|
+
category:
|
|
117
|
+
Optional category string (e.g. ``"univariate"``). Used for
|
|
118
|
+
filtering with :func:`get_tool_specs`.
|
|
119
|
+
rng:
|
|
120
|
+
Optional reproducibility metadata; see :func:`_validate_rng_metadata`
|
|
121
|
+
for the contract.
|
|
122
|
+
|
|
123
|
+
Returns
|
|
124
|
+
-------
|
|
125
|
+
Callable
|
|
126
|
+
The original function, with an attached ``_tool_spec`` dict
|
|
127
|
+
and ``_input_model`` attribute.
|
|
128
|
+
"""
|
|
129
|
+
if rng is not None:
|
|
130
|
+
_validate_rng_metadata(name, rng)
|
|
131
|
+
|
|
132
|
+
if not (isinstance(input_model, type) and issubclass(input_model, BaseModel)):
|
|
133
|
+
raise TypeError(
|
|
134
|
+
f"@tool_spec(name={name!r}): input_model must be a pydantic BaseModel subclass; got {input_model!r}."
|
|
135
|
+
)
|
|
136
|
+
extra_policy = input_model.model_config.get("extra")
|
|
137
|
+
if extra_policy != "forbid":
|
|
138
|
+
raise ValueError(
|
|
139
|
+
f"@tool_spec(name={name!r}): input_model {input_model.__name__} "
|
|
140
|
+
"must set model_config = ConfigDict(extra='forbid') so unknown "
|
|
141
|
+
"kwargs are rejected (ENG-04 / SEC-15 contract)."
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
|
|
145
|
+
"""Attach the assembled tool spec to ``func`` and return it unchanged."""
|
|
146
|
+
full_description = description
|
|
147
|
+
if examples:
|
|
148
|
+
full_description = f"{description}\n\nExamples\n--------\n{examples}"
|
|
149
|
+
|
|
150
|
+
spec: dict[str, Any] = {
|
|
151
|
+
"name": name,
|
|
152
|
+
"description": full_description,
|
|
153
|
+
"input_schema": input_model.model_json_schema(),
|
|
154
|
+
}
|
|
155
|
+
if category:
|
|
156
|
+
spec["category"] = category
|
|
157
|
+
if rng is not None:
|
|
158
|
+
spec["rng"] = dict(rng)
|
|
159
|
+
|
|
160
|
+
func._tool_spec = spec # type: ignore[attr-defined]
|
|
161
|
+
func._input_model = input_model # type: ignore[attr-defined]
|
|
162
|
+
_TOOL_REGISTRY[name] = func
|
|
163
|
+
return func
|
|
164
|
+
|
|
165
|
+
return decorator
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
# ---------------------------------------------------------------------------
|
|
169
|
+
# Serialisation helper
|
|
170
|
+
# ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def clean(value: Any) -> Any: # noqa: PLR0911, ANN401
|
|
174
|
+
"""Recursively convert numpy scalars / arrays to plain Python types.
|
|
175
|
+
|
|
176
|
+
All ``tools.py`` modules should call ``clean(result)`` before returning
|
|
177
|
+
so that every tool output is JSON-serialisable.
|
|
178
|
+
"""
|
|
179
|
+
if isinstance(value, dict):
|
|
180
|
+
# Keys need unwrapping too: json.dumps rejects numpy scalar keys (a
|
|
181
|
+
# dict keyed by np.int64 group labels from a pandas groupby is the
|
|
182
|
+
# common case), and previously they leaked through untouched. Only
|
|
183
|
+
# numpy scalars are unwrapped - other key types pass through so
|
|
184
|
+
# hashability is never at risk.
|
|
185
|
+
return {(k.item() if isinstance(k, np.generic) else k): clean(v) for k, v in value.items()}
|
|
186
|
+
if isinstance(value, (list, tuple, set, frozenset)):
|
|
187
|
+
return [clean(v) for v in value]
|
|
188
|
+
# np.bool_ subclasses neither np.integer nor Python bool, and json.dumps
|
|
189
|
+
# rejects it; it must be tested before the numeric branches.
|
|
190
|
+
if isinstance(value, np.bool_):
|
|
191
|
+
return bool(value)
|
|
192
|
+
if isinstance(value, np.integer):
|
|
193
|
+
return int(value)
|
|
194
|
+
if isinstance(value, np.floating):
|
|
195
|
+
v = float(value)
|
|
196
|
+
return None if math.isnan(v) or math.isinf(v) else v
|
|
197
|
+
if isinstance(value, float):
|
|
198
|
+
return None if math.isnan(value) or math.isinf(value) else value
|
|
199
|
+
if isinstance(value, np.ndarray):
|
|
200
|
+
return clean(value.tolist())
|
|
201
|
+
if isinstance(value, np.generic):
|
|
202
|
+
# Catch-all for the remaining numpy scalar types (datetime64,
|
|
203
|
+
# complex, str_, ...): unwrap to the closest Python equivalent.
|
|
204
|
+
return clean(value.item())
|
|
205
|
+
return value
|
{process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_analyses/glm.py
RENAMED
|
@@ -88,9 +88,10 @@ def _trials(df: pd.DataFrame, trials: str | float | Sequence[float] | None) -> n
|
|
|
88
88
|
if trials is None:
|
|
89
89
|
return None
|
|
90
90
|
if isinstance(trials, str):
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
found = df[trials].to_numpy(dtype=float) # a missing count already dropped its run
|
|
92
|
+
else:
|
|
93
|
+
found = np.broadcast_to(np.asarray(trials, dtype=float), (len(df),)).copy()
|
|
94
|
+
if np.any(found <= 0): # a column too (#1001): a zero reached statsmodels, which divided by it
|
|
94
95
|
raise ValueError("Every run's number of trials must be positive.")
|
|
95
96
|
return found
|
|
96
97
|
|
|
@@ -526,8 +526,8 @@ class Model(OLS):
|
|
|
526
526
|
|
|
527
527
|
return smry
|
|
528
528
|
|
|
529
|
-
def get_parameters(self, drop_intercept: bool = True) -> pd.
|
|
530
|
-
"""Get the parameter values; return them in a
|
|
529
|
+
def get_parameters(self, drop_intercept: bool = True) -> pd.Series:
|
|
530
|
+
"""Get the parameter values; return them in a pandas Series indexed by term."""
|
|
531
531
|
|
|
532
532
|
params = self._OLS.params.copy()
|
|
533
533
|
try:
|
|
@@ -98,10 +98,7 @@ def fit_linear_model(spec: FitLinearModelInput) -> dict[str, Any]:
|
|
|
98
98
|
model = lm(spec.formula, expt_data)
|
|
99
99
|
|
|
100
100
|
params = model.get_parameters(drop_intercept=True)
|
|
101
|
-
|
|
102
|
-
coefficients = [{"name": str(name), "estimate": float(value)} for name, value in params.items()]
|
|
103
|
-
else:
|
|
104
|
-
coefficients = params.to_dict(orient="records")
|
|
101
|
+
coefficients = [{"name": str(name), "estimate": float(value)} for name, value in params.items()]
|
|
105
102
|
|
|
106
103
|
r2 = float(model._OLS.rsquared)
|
|
107
104
|
|
{process_improve-2.2.0 → process_improve-2.2.2}/src/process_improve/experiments/_uniform_sampling.py
RENAMED
|
@@ -317,14 +317,12 @@ class UniformSampler:
|
|
|
317
317
|
t_lo = np.maximum(t_lo, np.where(rate < 0, limit, -np.inf).max(axis=1))
|
|
318
318
|
return np.minimum(t_lo, 0.0), np.maximum(t_hi, 0.0)
|
|
319
319
|
|
|
320
|
-
def _step(self, x: np.ndarray, rng: np.random.Generator, shape: np.ndarray
|
|
320
|
+
def _step(self, x: np.ndarray, rng: np.random.Generator, shape: np.ndarray) -> np.ndarray:
|
|
321
321
|
"""Move every chain once: a random direction, a uniform point on its chord, shrinking on a miss.
|
|
322
322
|
|
|
323
|
-
Directions are Gaussian with covariance ``shape @ shape.T`` (
|
|
323
|
+
Directions are Gaussian with covariance ``shape @ shape.T`` (see :meth:`_direction_shape`).
|
|
324
324
|
"""
|
|
325
|
-
d = rng.standard_normal(x.shape)
|
|
326
|
-
if shape is not None:
|
|
327
|
-
d = d @ shape.T
|
|
325
|
+
d = rng.standard_normal(x.shape) @ shape.T
|
|
328
326
|
if self.on_simplex:
|
|
329
327
|
d -= d.mean(axis=1, keepdims=True) # stay on the plane where the proportions sum to 1
|
|
330
328
|
d /= np.linalg.norm(d, axis=1, keepdims=True)
|
|
@@ -428,8 +428,13 @@ def _missing_cells_text(df: pd.DataFrame, lost: list[str]) -> str:
|
|
|
428
428
|
|
|
429
429
|
|
|
430
430
|
def _drop_incomplete_runs(df: pd.DataFrame, columns: list[str]) -> pd.DataFrame:
|
|
431
|
-
"""Drop runs with a missing response or factor setting, warning how many went."""
|
|
431
|
+
"""Drop runs with a missing response or factor setting, warning how many went; refuse when none is left."""
|
|
432
432
|
complete = df[columns].notna().all(axis=1)
|
|
433
|
+
if not complete.any():
|
|
434
|
+
raise ValueError(
|
|
435
|
+
f"No run has a value in every one of {', '.join(map(str, columns))}, so there is nothing to analyse: "
|
|
436
|
+
"each run is missing its response or a factor setting."
|
|
437
|
+
)
|
|
433
438
|
n_dropped = int((~complete).sum())
|
|
434
439
|
if n_dropped:
|
|
435
440
|
warnings.warn(
|
|
@@ -441,6 +446,33 @@ def _drop_incomplete_runs(df: pd.DataFrame, columns: list[str]) -> pd.DataFrame:
|
|
|
441
446
|
return df
|
|
442
447
|
|
|
443
448
|
|
|
449
|
+
def _stand_in(name: str, taken: pd.Index) -> str:
|
|
450
|
+
"""Return a name a formula can hold for the response: ``name_``, else ``name_1``, ``name_2``, ...
|
|
451
|
+
|
|
452
|
+
The stand-in never gains a second underscore, which the formula check refuses as dunder access (#1002).
|
|
453
|
+
"""
|
|
454
|
+
alias, k = f"{name}_", 0
|
|
455
|
+
while alias in taken:
|
|
456
|
+
k += 1
|
|
457
|
+
alias = f"{name}_{k}"
|
|
458
|
+
return alias
|
|
459
|
+
|
|
460
|
+
|
|
461
|
+
def _check_response_scale(response: pd.Series, name: str) -> None:
|
|
462
|
+
"""Refuse a response whose sums of squares cannot be held in double precision (#1005).
|
|
463
|
+
|
|
464
|
+
Every test, R-squared and p-value is unchanged when the response is divided by a constant,
|
|
465
|
+
so the remedy is a change of units; past this size ``n * max(y)**2`` overflows.
|
|
466
|
+
"""
|
|
467
|
+
largest = float(np.max(np.abs(response.to_numpy(dtype=float))))
|
|
468
|
+
if largest > np.sqrt(np.finfo(float).max / len(response)):
|
|
469
|
+
raise ValueError(
|
|
470
|
+
f"The response {name!r} is too large in its units to analyse: its sums of squares overflow, as its "
|
|
471
|
+
f"largest value is {largest:.3g}. Divide it by a power of 10 and analyse it again; the tests, "
|
|
472
|
+
"R-squared and p-values do not change."
|
|
473
|
+
)
|
|
474
|
+
|
|
475
|
+
|
|
444
476
|
def _top_level_terms(rhs: str) -> list[str]:
|
|
445
477
|
"""Split a formula's right-hand side at the ``+`` signs outside parentheses."""
|
|
446
478
|
terms, depth, start = [], 0, 0
|
|
@@ -1284,11 +1316,8 @@ def analyze_experiment( # noqa: PLR0913
|
|
|
1284
1316
|
# "yield" is the commonest response in chemistry, and a Python keyword, which a
|
|
1285
1317
|
# formula cannot name; a column named C, I or Q hides patsy's function of that
|
|
1286
1318
|
# name, so I(x1 ** 2) fails. Fit under a stand-in name and report the real one.
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
alias += "_"
|
|
1290
|
-
df = df.rename(columns={response_col: alias})
|
|
1291
|
-
response_col = alias
|
|
1319
|
+
response_col = _stand_in(response_col, df.columns)
|
|
1320
|
+
df = df.rename(columns={reported_response: response_col})
|
|
1292
1321
|
|
|
1293
1322
|
# Factor columns = everything except the response and the design-bookkeeping
|
|
1294
1323
|
# columns. A DesignResult carries "RunOrder" (and optionally "Block"); if a
|
|
@@ -1324,6 +1353,7 @@ def analyze_experiment( # noqa: PLR0913
|
|
|
1324
1353
|
*([trials_col] if trials_col else []),
|
|
1325
1354
|
]
|
|
1326
1355
|
df = _drop_incomplete_runs(df, used)
|
|
1356
|
+
_check_response_scale(df[response_col], reported_response)
|
|
1327
1357
|
coding = _resolve_coding(coding, df, factor_cols, model)
|
|
1328
1358
|
|
|
1329
1359
|
categorical = [c for c in factor_cols if not _is_numeric(df[c])]
|
|
@@ -1466,21 +1496,54 @@ def _design_rank(df: pd.DataFrame, rhs: str, factor_cols: list[str], model: str)
|
|
|
1466
1496
|
design's in floating point when the units are very unequal (pascals beside kelvin)
|
|
1467
1497
|
or a span is tiny next to its distance from zero. Coding each numeric factor to
|
|
1468
1498
|
-1/+1 removes both without changing which terms the runs can separate, as long as
|
|
1469
|
-
the coding re-expresses the model. A model that is
|
|
1470
|
-
columns once coded: ``A:B`` without ``B``,
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1499
|
+
the coding re-expresses the model (see :func:`_coding_re_expresses`). A model that is
|
|
1500
|
+
not hierarchical can span other columns once coded: ``A:B`` without ``A`` and ``B``,
|
|
1501
|
+
which coded varies where ``A * B`` is the same in every run, or a factor nested in
|
|
1502
|
+
another through the other's 0/1 indicators, ``I1:B + I2:B``, which coded are
|
|
1503
|
+
``(2*I1 - 1)*B`` and its negative. Its rank is then its own, of its columns as given
|
|
1504
|
+
scaled to unit length, which no choice of units changes. A mixture model's components
|
|
1505
|
+
are proportions and are not coded.
|
|
1475
1506
|
"""
|
|
1476
1507
|
coded = np.asarray(_coded_model_matrix(df, rhs, factor_cols, model), dtype=float)
|
|
1477
1508
|
rank = int(np.linalg.matrix_rank(coded))
|
|
1478
|
-
if model in SCHEFFE_MODELS:
|
|
1509
|
+
if model in SCHEFFE_MODELS or _coding_re_expresses(df, rhs, factor_cols, coded):
|
|
1479
1510
|
return rank
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1511
|
+
return int(np.linalg.matrix_rank(_unit_columns(np.asarray(dmatrix(rhs, df, return_type="dataframe"), dtype=float))))
|
|
1512
|
+
|
|
1513
|
+
|
|
1514
|
+
#: The golden ratio, whose multiples give each factor a different second coding (see :func:`_coding_re_expresses`).
|
|
1515
|
+
_GOLDEN_RATIO = (1 + 5**0.5) / 2
|
|
1516
|
+
|
|
1517
|
+
|
|
1518
|
+
def _coding_re_expresses(df: pd.DataFrame, rhs: str, factor_cols: list[str], coded: np.ndarray) -> bool:
|
|
1519
|
+
"""Whether coding the numeric factors re-expresses the model, rather than changing it.
|
|
1520
|
+
|
|
1521
|
+
A hierarchical model spans the same columns whatever each factor's origin and scale:
|
|
1522
|
+
``(A - a)*(B - b)`` lies in the span of 1, ``A``, ``B`` and ``A:B``. Another model's span
|
|
1523
|
+
moves with them, and the factors' own units are one more origin and scale. Comparing the
|
|
1524
|
+
coded columns with those as given cannot tell the two apart, since it is the columns as
|
|
1525
|
+
given that may have lost rank in floating point. So the model matrix ``coded`` is compared
|
|
1526
|
+
with a second coding instead, as well conditioned as the first: the i-th numeric factor's
|
|
1527
|
+
-1/+1 coding ``x`` becomes ``(1 + g) * (x + g)``, with ``g`` the fractional part of ``i``
|
|
1528
|
+
times the golden ratio. A span that moves keeps to this coding only if the runs line up
|
|
1529
|
+
with it by chance. When the coded columns already span every run, no coding can add to
|
|
1530
|
+
them, the comparison cannot tell, and the model is taken as changed.
|
|
1531
|
+
"""
|
|
1532
|
+
rank = int(np.linalg.matrix_rank(coded))
|
|
1533
|
+
if rank == len(coded):
|
|
1534
|
+
# shortcut: a saturated design is then ranked as given, which a span tiny next to its distance from zero can
|
|
1535
|
+
# lower; compare the codings on more points than the runs if such a design is met.
|
|
1536
|
+
return False
|
|
1537
|
+
second = df.copy()
|
|
1538
|
+
numeric = [col for col in factor_cols if _is_numeric(df[col])]
|
|
1539
|
+
for i, col in enumerate(numeric, start=1):
|
|
1540
|
+
g = i * _GOLDEN_RATIO % 1
|
|
1541
|
+
second[col] = (1 + g) * (_code_factor(df[col])[0] + g)
|
|
1542
|
+
moved = _unit_columns(
|
|
1543
|
+
np.asarray(dmatrix(_coded_formula(rhs, second, factor_cols), second, return_type="dataframe"), dtype=float)
|
|
1544
|
+
)
|
|
1545
|
+
both = np.hstack([_unit_columns(coded), moved])
|
|
1546
|
+
return int(np.linalg.matrix_rank(moved)) == rank == int(np.linalg.matrix_rank(both))
|
|
1484
1547
|
|
|
1485
1548
|
|
|
1486
1549
|
def _unit_columns(matrix: np.ndarray) -> np.ndarray:
|
|
@@ -245,7 +245,9 @@ def extreme_vertices(a_mat: np.ndarray, b_vec: np.ndarray) -> np.ndarray:
|
|
|
245
245
|
found = []
|
|
246
246
|
combos = itertools.combinations(range(m), q - 1)
|
|
247
247
|
while chunk := list(itertools.islice(combos, _VERTEX_CHUNK)):
|
|
248
|
-
|
|
248
|
+
# The row count is given, not -1: with one component each subset is empty, and numpy
|
|
249
|
+
# cannot infer a row count from rows of length 0 (#999).
|
|
250
|
+
subsets = np.array(chunk, dtype=int).reshape(len(chunk), q - 1)
|
|
249
251
|
systems = np.concatenate([a_red[subsets], np.full((len(subsets), 1, q), 1.0 / np.sqrt(q))], axis=1)
|
|
250
252
|
rhs = np.concatenate([b_red[subsets], np.full((len(subsets), 1), 1.0 / np.sqrt(q))], axis=1)
|
|
251
253
|
solvable = np.abs(np.linalg.det(systems)) > 1e-12 # every row has unit length, so this is a relative test
|
|
@@ -420,12 +420,7 @@ def _fractional_cube(
|
|
|
420
420
|
if not asked:
|
|
421
421
|
generators = [f"{factor_names[-1]}={''.join(factor_names[:-1])}"]
|
|
422
422
|
cube, frac_meta = dispatch_fractional_factorial(factors, resolution=resolution, generators=generators)
|
|
423
|
-
res = frac_meta.get("resolution")
|
|
424
|
-
if res is not None and res < 3:
|
|
425
|
-
raise ValueError(
|
|
426
|
-
f"The fractional cube has resolution {res}: it aliases main effects with each other, so no model of "
|
|
427
|
-
"them can be fitted. Supply other generators or use cube='full'."
|
|
428
|
-
)
|
|
423
|
+
res = frac_meta.get("resolution") # 3 or more: dispatch_fractional_factorial refuses generators that alias mains
|
|
429
424
|
aliased = _aliased_interactions(cube, factor_names)
|
|
430
425
|
if aliased and not asked:
|
|
431
426
|
raise ValueError(
|
|
@@ -109,18 +109,16 @@ def _drop_worst_columns(columns: np.ndarray, k: int) -> np.ndarray:
|
|
|
109
109
|
def _lin_half_fraction(h: np.ndarray, k: int) -> np.ndarray:
|
|
110
110
|
"""Best Lin half-fraction of ``h`` with ``k`` columns, over every choice of branching column."""
|
|
111
111
|
order = h.shape[0]
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
rows = h[:, branch] > 0
|
|
112
|
+
|
|
113
|
+
def branched(branch: int) -> np.ndarray:
|
|
115
114
|
others = [c for c in range(1, order) if c != branch]
|
|
116
|
-
|
|
115
|
+
return _drop_worst_columns(h[h[:, branch] > 0][:, others], k)
|
|
116
|
+
|
|
117
|
+
def key(design: np.ndarray) -> tuple[int, float, float]:
|
|
117
118
|
s = design.T @ design
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if best is None: # unreachable for order >= 4, which always offers a branching column
|
|
122
|
-
raise RuntimeError("No branching column was available.")
|
|
123
|
-
return best
|
|
119
|
+
return n_fully_aliased(design), e_s2(design), float(np.abs(s[np.triu_indices_from(s, k=1)]).max())
|
|
120
|
+
|
|
121
|
+
return min((branched(b) for b in range(1, order)), key=key) # the first branch of the best key, as before
|
|
124
122
|
|
|
125
123
|
|
|
126
124
|
def _smallest_unaliased(k: int) -> np.ndarray | None:
|