process-improve 1.3.2__tar.gz → 1.4.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.
- {process_improve-1.3.2 → process_improve-1.4.0}/PKG-INFO +1 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/preprocessing.py +1 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_utils.py +4 -2
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/mcp_server.py +11 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/monitoring/control_charts.py +1 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/multivariate/methods.py +13 -2
- process_improve-1.4.0/process_improve/tool_safety.py +368 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/tool_spec.py +32 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/univariate/metrics.py +1 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/pyproject.toml +1 -1
- {process_improve-1.3.2 → process_improve-1.4.0}/README.md +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/alignment_helpers.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/data_input.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/features.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/plotting.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/batch/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/bivariate/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/bivariate/methods.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/bivariate/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/batch/batch-fake-data.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/batch/details.txt +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/batch/dryer.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/batch/nylon.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/experiments/test_doe1.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/monitoring/batch-yield-and-purity.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/monitoring/rubber-colour.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/C.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/Hotellings_T2_A3.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/Hotellings_T2_A6.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/LDPE.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/P.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/R.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/T.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/U.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/W.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/Yhat_A6.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/kamyr.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tablet-spectra.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/SOURCE +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group1.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group2.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group3.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group4.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/formulas_Group5.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/process_conditions.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/properties_Group1.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/properties_Group2.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/properties_Group3.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/properties_Group4.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/properties_Group5.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/tpls-pyphi/quality_indicators.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/docs/outline.txt +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/analysis.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/augment.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/datasets.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_factorial.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_mixture.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_optimal.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_response_surface.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_screening.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/evaluate.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/factor.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/api.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/data/concepts.yaml +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/data/decision_rules.yaml +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/data/design_types.yaml +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/data/diagnostics.yaml +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/engine.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/models.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/models.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/optimal.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/optimization.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/simulations.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/budget.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/domain_templates.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/engine.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/models.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/structures.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/adapters/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/adapters/base.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/adapters/echarts_adapter.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/adapters/plotly_adapter.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/api.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/colors.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/cube_plot.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/design_quality.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/diagnostics.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/effects.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/optimization_plots.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/registry.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/significance.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/plots/surfaces.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/spec.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/types.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/boilingpot.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/distillate-flow.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/oil-company-doe.csv +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/trade-off-table.html +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/trade-off-table.pdf +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/media/trade-off-table.png +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/monitoring/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/monitoring/metrics.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/monitoring/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/multivariate/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/multivariate/plots.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/multivariate/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/Example notebook.ipynb +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/Tablets.xlsx +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/alignment-and-pca-example.ipynb +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/batch-optimization.ipynb +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/batch_llm.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/batch_llm_multivariate.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/batch_music.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/demo-multiplots.ipynb +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/experiments/case-studies.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/least-squares-modelling/Misguided-reliance-on-R2-alone.ipynb +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/multivariate/pca_example.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/regression/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/regression/methods.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/regression/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/univariate/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/univariate/tools.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/visualization/__init__.py +0 -0
- {process_improve-1.3.2 → process_improve-1.4.0}/process_improve/visualization/plots.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: process-improve
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.4.0
|
|
4
4
|
Summary: Designed Experiments; Latent Variables (PCA, PLS, multivariate methods with missing data); Process Monitoring; Batch data analysis.
|
|
5
5
|
Keywords: Designed Experiments,Latent Variables,PCA,PLS,Multivariate Data Analysis,Batch data analysis
|
|
6
6
|
Author: Kevin Dunn
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_utils.py
RENAMED
|
@@ -185,8 +185,10 @@ def build_design_result( # noqa: PLR0913
|
|
|
185
185
|
Number of full replicates.
|
|
186
186
|
blocks : int or None
|
|
187
187
|
Number of blocks (None = no blocking).
|
|
188
|
-
random_seed : int
|
|
189
|
-
Seed for reproducible randomization.
|
|
188
|
+
random_seed : int or None
|
|
189
|
+
Seed for reproducible randomization. When ``None`` the original run
|
|
190
|
+
order of *coded_matrix* is preserved (used for designs whose run order
|
|
191
|
+
is part of the solution, e.g. split-plot optimal designs).
|
|
190
192
|
generators : list[str] or None
|
|
191
193
|
Generator strings (fractional factorials).
|
|
192
194
|
defining_relation : list[str] or None
|
|
@@ -32,14 +32,22 @@ from __future__ import annotations
|
|
|
32
32
|
|
|
33
33
|
import json
|
|
34
34
|
import logging
|
|
35
|
+
import os
|
|
35
36
|
from typing import Any
|
|
36
37
|
|
|
37
38
|
from mcp.server.fastmcp import FastMCP
|
|
38
39
|
|
|
40
|
+
from process_improve.tool_safety import ToolSafetyError, safe_execute_tool_call
|
|
39
41
|
from process_improve.tool_spec import discover_tools, execute_tool_call, get_tool_specs
|
|
40
42
|
|
|
41
43
|
logger = logging.getLogger(__name__)
|
|
42
44
|
|
|
45
|
+
# Opt-in safety. The default (stdio on the user's own machine) keeps the
|
|
46
|
+
# fast in-process path so local Claude Desktop / Cursor integrations don't
|
|
47
|
+
# pay subprocess overhead. Set ``PROCESS_IMPROVE_MCP_SAFE_MODE=1`` when the
|
|
48
|
+
# server is fronted by HTTP or otherwise reachable from untrusted clients.
|
|
49
|
+
_SAFE_MODE = os.environ.get("PROCESS_IMPROVE_MCP_SAFE_MODE", "0").lower() in {"1", "true", "yes"}
|
|
50
|
+
|
|
43
51
|
mcp = FastMCP(
|
|
44
52
|
"process-improve",
|
|
45
53
|
instructions=(
|
|
@@ -75,10 +83,12 @@ def _create_mcp_tool(
|
|
|
75
83
|
# Define an async handler that calls through to our tool registry
|
|
76
84
|
async def handler(**kwargs: Any) -> str: # noqa: ANN401
|
|
77
85
|
try:
|
|
78
|
-
result = execute_tool_call(tool_name, kwargs)
|
|
86
|
+
result = safe_execute_tool_call(tool_name, kwargs) if _SAFE_MODE else execute_tool_call(tool_name, kwargs)
|
|
79
87
|
if isinstance(result, dict):
|
|
80
88
|
return json.dumps(result, indent=2, default=str)
|
|
81
89
|
return str(result)
|
|
90
|
+
except ToolSafetyError as exc:
|
|
91
|
+
return json.dumps(exc.to_dict())
|
|
82
92
|
except Exception as exc: # noqa: BLE001
|
|
83
93
|
return json.dumps({"error": str(exc)})
|
|
84
94
|
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/monitoring/control_charts.py
RENAMED
|
@@ -57,7 +57,7 @@ class ControlChart:
|
|
|
57
57
|
self.style = style.strip()
|
|
58
58
|
self.variant = variant.strip().lower()
|
|
59
59
|
|
|
60
|
-
# Will be calculated by the self.
|
|
60
|
+
# Will be calculated by the self.calculate_limits() function
|
|
61
61
|
self.target = None
|
|
62
62
|
self._given_target = None
|
|
63
63
|
self._given_s = None
|
|
@@ -1840,13 +1840,24 @@ def ellipse_coordinates( # noqa: PLR0913
|
|
|
1840
1840
|
Parameters
|
|
1841
1841
|
----------
|
|
1842
1842
|
score_horiz : int
|
|
1843
|
-
|
|
1843
|
+
1-based index of the score to plot on the horizontal axis. Must satisfy
|
|
1844
|
+
``1 <= score_horiz <= n_components``.
|
|
1844
1845
|
score_vert : int
|
|
1845
|
-
|
|
1846
|
+
1-based index of the score to plot on the vertical axis. Must satisfy
|
|
1847
|
+
``1 <= score_vert <= n_components``.
|
|
1846
1848
|
conf_level : float
|
|
1847
1849
|
The `conf_level` confidence value: e.g. 0.95 is for the 95% confidence limit.
|
|
1848
1850
|
n_points : int, optional
|
|
1849
1851
|
Number of points to use in the ellipse; by default 100.
|
|
1852
|
+
n_components : int
|
|
1853
|
+
Number of components `A` in the fitted model. Required to look up the
|
|
1854
|
+
Hotelling's T^2 limit and to bound `score_horiz`/`score_vert`.
|
|
1855
|
+
scaling_factor_for_scores : pd.Series
|
|
1856
|
+
Per-component standard deviations of the scores (``model.scaling_factor_for_scores_``).
|
|
1857
|
+
Used to scale the ellipse axes.
|
|
1858
|
+
n_rows : int
|
|
1859
|
+
Number of rows `N` in the data used to fit the model. Required to compute the
|
|
1860
|
+
Hotelling's T^2 limit; must be strictly positive.
|
|
1850
1861
|
|
|
1851
1862
|
Returns
|
|
1852
1863
|
-------
|
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
"""(c) Kevin Dunn, 2010-2026. MIT License.
|
|
2
|
+
|
|
3
|
+
Safe execution wrapper for process-improve tool calls.
|
|
4
|
+
|
|
5
|
+
Adds the four guard rails needed to expose the tool registry over an
|
|
6
|
+
untrusted transport (public MCP server, hosted REST API, etc.):
|
|
7
|
+
|
|
8
|
+
1. Input-size validation (reject oversize arrays/strings before work).
|
|
9
|
+
2. Wall-clock timeout via subprocess isolation.
|
|
10
|
+
3. Memory cap per subprocess (POSIX; best-effort on Windows).
|
|
11
|
+
4. Structured error types so callers can distinguish failure modes.
|
|
12
|
+
|
|
13
|
+
The in-process :func:`process_improve.tool_spec.execute_tool_call` is
|
|
14
|
+
left untouched for callers that trust their input (notebooks, tests,
|
|
15
|
+
the stdio MCP server running on the user's own machine). Hosted
|
|
16
|
+
callers should use :func:`safe_execute_tool_call` instead.
|
|
17
|
+
|
|
18
|
+
Environment variables (all optional):
|
|
19
|
+
|
|
20
|
+
- ``PROCESS_IMPROVE_TOOL_TIMEOUT`` -- seconds, default 10
|
|
21
|
+
- ``PROCESS_IMPROVE_MAX_CELLS`` -- max numeric leaves in input, default 1_000_000
|
|
22
|
+
- ``PROCESS_IMPROVE_MAX_STRING`` -- max chars in any single string, default 100_000
|
|
23
|
+
- ``PROCESS_IMPROVE_MAX_DEPTH`` -- max nested dict/list depth, default 10
|
|
24
|
+
- ``PROCESS_IMPROVE_MAX_MEMORY_MB`` -- per-subprocess RSS cap, default 1024
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import contextlib
|
|
30
|
+
import multiprocessing
|
|
31
|
+
import os
|
|
32
|
+
import sys
|
|
33
|
+
from concurrent.futures import ProcessPoolExecutor
|
|
34
|
+
from concurrent.futures import TimeoutError as FuturesTimeoutError
|
|
35
|
+
from concurrent.futures.process import BrokenProcessPool
|
|
36
|
+
from typing import Any
|
|
37
|
+
|
|
38
|
+
# Prefer ``fork`` on Linux: the worker inherits the parent's imported
|
|
39
|
+
# numpy/registry/etc., which makes startup and tool-dispatch much cheaper
|
|
40
|
+
# than re-importing on every spawn. macOS is excluded because Apple's
|
|
41
|
+
# Accelerate framework (used by numpy) is not fork-safe and Python 3.13
|
|
42
|
+
# emits a DeprecationWarning when a multi-threaded parent forks; Windows
|
|
43
|
+
# does not support fork at all. On those platforms we fall back to the
|
|
44
|
+
# platform default (spawn).
|
|
45
|
+
_DEFAULT_MP_CONTEXT: multiprocessing.context.BaseContext | None = None
|
|
46
|
+
if sys.platform.startswith("linux"):
|
|
47
|
+
try:
|
|
48
|
+
_DEFAULT_MP_CONTEXT = multiprocessing.get_context("fork")
|
|
49
|
+
except ValueError:
|
|
50
|
+
_DEFAULT_MP_CONTEXT = None
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Defaults (read once at import time; tests can override via env before import)
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
DEFAULT_TIMEOUT_S: float = float(os.environ.get("PROCESS_IMPROVE_TOOL_TIMEOUT", "10"))
|
|
57
|
+
DEFAULT_MAX_CELLS: int = int(os.environ.get("PROCESS_IMPROVE_MAX_CELLS", "1000000"))
|
|
58
|
+
DEFAULT_MAX_STRING: int = int(os.environ.get("PROCESS_IMPROVE_MAX_STRING", "100000"))
|
|
59
|
+
DEFAULT_MAX_DEPTH: int = int(os.environ.get("PROCESS_IMPROVE_MAX_DEPTH", "10"))
|
|
60
|
+
DEFAULT_MEMORY_MB: int = int(os.environ.get("PROCESS_IMPROVE_MAX_MEMORY_MB", "1024"))
|
|
61
|
+
|
|
62
|
+
# Keys whose numeric value scales the cost of the underlying algorithm.
|
|
63
|
+
# A malicious caller can otherwise request a huge SVD or a long ESD loop
|
|
64
|
+
# with a tiny input array.
|
|
65
|
+
_SCALAR_CAPS: dict[str, float] = {
|
|
66
|
+
"n_components": 50,
|
|
67
|
+
"max_outliers_to_detect": 20,
|
|
68
|
+
"n_iter": 10_000,
|
|
69
|
+
"max_iter": 10_000,
|
|
70
|
+
"n_boot": 1_000,
|
|
71
|
+
"n_permutations": 1_000,
|
|
72
|
+
"budget": 10_000,
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
# Structured errors
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class ToolSafetyError(Exception):
|
|
82
|
+
"""Base class for safety-related tool-execution failures."""
|
|
83
|
+
|
|
84
|
+
code: str = "tool_safety_error"
|
|
85
|
+
|
|
86
|
+
def __init__(self, message: str, *, details: dict[str, Any] | None = None) -> None:
|
|
87
|
+
super().__init__(message)
|
|
88
|
+
self.details = details or {}
|
|
89
|
+
|
|
90
|
+
def to_dict(self) -> dict[str, Any]:
|
|
91
|
+
"""Return a JSON-serialisable representation of this error."""
|
|
92
|
+
return {"error": self.code, "message": str(self), "details": self.details}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
class ToolInputTooLargeError(ToolSafetyError):
|
|
96
|
+
"""Input exceeded an allowed size limit (cells, string length, depth)."""
|
|
97
|
+
|
|
98
|
+
code = "input_too_large"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ToolInputInvalidError(ToolSafetyError):
|
|
102
|
+
"""Input failed structural validation (unexpected types, bad shape)."""
|
|
103
|
+
|
|
104
|
+
code = "input_invalid"
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ToolTimeoutError(ToolSafetyError):
|
|
108
|
+
"""Tool call exceeded the wall-clock timeout."""
|
|
109
|
+
|
|
110
|
+
code = "timeout"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class ToolMemoryExceededError(ToolSafetyError):
|
|
114
|
+
"""Subprocess was killed, most likely by the memory limit."""
|
|
115
|
+
|
|
116
|
+
code = "memory_exceeded"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
# ---------------------------------------------------------------------------
|
|
120
|
+
# Input validation
|
|
121
|
+
# ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _count_numeric_leaves(value: Any, depth: int, max_depth: int) -> int: # noqa: ANN401
|
|
125
|
+
if depth > max_depth:
|
|
126
|
+
raise ToolInputTooLargeError(
|
|
127
|
+
f"Input nesting depth exceeds limit of {max_depth}",
|
|
128
|
+
details={"limit": max_depth},
|
|
129
|
+
)
|
|
130
|
+
if isinstance(value, (list, tuple)):
|
|
131
|
+
return sum(_count_numeric_leaves(v, depth + 1, max_depth) for v in value)
|
|
132
|
+
if isinstance(value, dict):
|
|
133
|
+
return sum(_count_numeric_leaves(v, depth + 1, max_depth) for v in value.values())
|
|
134
|
+
if isinstance(value, (int, float, bool)):
|
|
135
|
+
return 1
|
|
136
|
+
# Strings, None, and anything else do not count as numeric cells.
|
|
137
|
+
return 0
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _check_strings(value: Any, limit: int, depth: int, max_depth: int) -> None: # noqa: ANN401
|
|
141
|
+
if depth > max_depth:
|
|
142
|
+
# Depth check is already handled by _count_numeric_leaves; keep this
|
|
143
|
+
# function simple so it can be reused independently.
|
|
144
|
+
raise ToolInputTooLargeError(
|
|
145
|
+
f"Input nesting depth exceeds limit of {max_depth}",
|
|
146
|
+
details={"limit": max_depth},
|
|
147
|
+
)
|
|
148
|
+
if isinstance(value, str):
|
|
149
|
+
if len(value) > limit:
|
|
150
|
+
raise ToolInputTooLargeError(
|
|
151
|
+
f"String length {len(value)} exceeds limit of {limit}",
|
|
152
|
+
details={"limit": limit, "observed": len(value)},
|
|
153
|
+
)
|
|
154
|
+
return
|
|
155
|
+
if isinstance(value, (list, tuple)):
|
|
156
|
+
for v in value:
|
|
157
|
+
_check_strings(v, limit, depth + 1, max_depth)
|
|
158
|
+
elif isinstance(value, dict):
|
|
159
|
+
for v in value.values():
|
|
160
|
+
_check_strings(v, limit, depth + 1, max_depth)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def validate_input(
|
|
164
|
+
tool_input: dict[str, Any],
|
|
165
|
+
*,
|
|
166
|
+
max_cells: int = DEFAULT_MAX_CELLS,
|
|
167
|
+
max_string: int = DEFAULT_MAX_STRING,
|
|
168
|
+
max_depth: int = DEFAULT_MAX_DEPTH,
|
|
169
|
+
scalar_caps: dict[str, float] | None = None,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Raise :class:`ToolInputTooLargeError` if *tool_input* breaks any limit.
|
|
172
|
+
|
|
173
|
+
Parameters
|
|
174
|
+
----------
|
|
175
|
+
tool_input:
|
|
176
|
+
The ``input`` dict that would be passed as keyword arguments to
|
|
177
|
+
the tool function.
|
|
178
|
+
max_cells:
|
|
179
|
+
Maximum number of numeric leaves anywhere in the payload.
|
|
180
|
+
max_string:
|
|
181
|
+
Maximum length of any single string value.
|
|
182
|
+
max_depth:
|
|
183
|
+
Maximum nesting depth for dicts/lists.
|
|
184
|
+
scalar_caps:
|
|
185
|
+
Override the default per-key numeric caps (see :data:`_SCALAR_CAPS`).
|
|
186
|
+
"""
|
|
187
|
+
if not isinstance(tool_input, dict):
|
|
188
|
+
raise ToolInputInvalidError(
|
|
189
|
+
f"Tool input must be a dict, got {type(tool_input).__name__}",
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
caps = {**_SCALAR_CAPS, **(scalar_caps or {})}
|
|
193
|
+
for key, limit in caps.items():
|
|
194
|
+
if key in tool_input:
|
|
195
|
+
observed = tool_input[key]
|
|
196
|
+
if isinstance(observed, (int, float)) and not isinstance(observed, bool) and observed > limit:
|
|
197
|
+
raise ToolInputTooLargeError(
|
|
198
|
+
f"Parameter {key!r}={observed} exceeds limit of {limit}",
|
|
199
|
+
details={"key": key, "limit": limit, "observed": observed},
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
_check_strings(tool_input, max_string, 0, max_depth)
|
|
203
|
+
|
|
204
|
+
cells = _count_numeric_leaves(tool_input, 0, max_depth)
|
|
205
|
+
if cells > max_cells:
|
|
206
|
+
raise ToolInputTooLargeError(
|
|
207
|
+
f"Input contains {cells} numeric cells; limit is {max_cells}",
|
|
208
|
+
details={"limit": max_cells, "observed": cells},
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
# ---------------------------------------------------------------------------
|
|
213
|
+
# Subprocess worker
|
|
214
|
+
# ---------------------------------------------------------------------------
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _apply_memory_limit(memory_mb: int) -> None:
|
|
218
|
+
"""Apply an address-space limit to the current process (POSIX)."""
|
|
219
|
+
try:
|
|
220
|
+
import resource # noqa: PLC0415 POSIX-only
|
|
221
|
+
except ImportError:
|
|
222
|
+
return # Windows: no-op
|
|
223
|
+
limit_bytes = memory_mb * 1024 * 1024
|
|
224
|
+
# Some sandboxes disallow raising the hard limit; ignore silently.
|
|
225
|
+
with contextlib.suppress(ValueError, OSError):
|
|
226
|
+
resource.setrlimit(resource.RLIMIT_AS, (limit_bytes, limit_bytes))
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
def _pool_initializer(memory_mb: int) -> None:
|
|
230
|
+
"""Run inside each worker process before it accepts tasks.
|
|
231
|
+
|
|
232
|
+
Imports run *before* the memory cap is applied so that large
|
|
233
|
+
data files loaded at import time (e.g. pyDOE3's orthogonal-array
|
|
234
|
+
tables) do not count against the per-call budget.
|
|
235
|
+
"""
|
|
236
|
+
# Warm the registry so the first real call doesn't pay discovery cost.
|
|
237
|
+
from process_improve.tool_spec import discover_tools # noqa: PLC0415
|
|
238
|
+
|
|
239
|
+
discover_tools()
|
|
240
|
+
_apply_memory_limit(memory_mb)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _worker_run(tool_name: str, tool_input: dict[str, Any]) -> Any: # noqa: ANN401
|
|
244
|
+
"""Target function executed inside a worker process."""
|
|
245
|
+
from process_improve.tool_spec import execute_tool_call # noqa: PLC0415
|
|
246
|
+
|
|
247
|
+
return execute_tool_call(tool_name, tool_input)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
# ---------------------------------------------------------------------------
|
|
251
|
+
# Pool management
|
|
252
|
+
# ---------------------------------------------------------------------------
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
_pool: ProcessPoolExecutor | None = None
|
|
256
|
+
_pool_memory_mb: int | None = None
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def get_pool(memory_mb: int = DEFAULT_MEMORY_MB, max_workers: int = 1) -> ProcessPoolExecutor:
|
|
260
|
+
"""Return a lazily-initialised module-level :class:`ProcessPoolExecutor`.
|
|
261
|
+
|
|
262
|
+
The pool is recreated if ``memory_mb`` changes (e.g. tests override it).
|
|
263
|
+
"""
|
|
264
|
+
global _pool, _pool_memory_mb # noqa: PLW0603
|
|
265
|
+
if _pool is None or _pool_memory_mb != memory_mb:
|
|
266
|
+
shutdown_pool()
|
|
267
|
+
kwargs: dict[str, Any] = {
|
|
268
|
+
"max_workers": max_workers,
|
|
269
|
+
"initializer": _pool_initializer,
|
|
270
|
+
"initargs": (memory_mb,),
|
|
271
|
+
}
|
|
272
|
+
if _DEFAULT_MP_CONTEXT is not None:
|
|
273
|
+
kwargs["mp_context"] = _DEFAULT_MP_CONTEXT
|
|
274
|
+
_pool = ProcessPoolExecutor(**kwargs)
|
|
275
|
+
_pool_memory_mb = memory_mb
|
|
276
|
+
return _pool
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def shutdown_pool() -> None:
|
|
280
|
+
"""Shut down the module-level pool, if any. Safe to call repeatedly."""
|
|
281
|
+
global _pool, _pool_memory_mb # noqa: PLW0603
|
|
282
|
+
if _pool is not None:
|
|
283
|
+
_pool.shutdown(wait=False, cancel_futures=True)
|
|
284
|
+
_pool = None
|
|
285
|
+
_pool_memory_mb = None
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
# ---------------------------------------------------------------------------
|
|
289
|
+
# Public entry point
|
|
290
|
+
# ---------------------------------------------------------------------------
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def safe_execute_tool_call( # noqa: PLR0913
|
|
294
|
+
tool_name: str,
|
|
295
|
+
tool_input: dict[str, Any],
|
|
296
|
+
*,
|
|
297
|
+
timeout: float = DEFAULT_TIMEOUT_S,
|
|
298
|
+
max_cells: int = DEFAULT_MAX_CELLS,
|
|
299
|
+
max_string: int = DEFAULT_MAX_STRING,
|
|
300
|
+
max_depth: int = DEFAULT_MAX_DEPTH,
|
|
301
|
+
memory_mb: int = DEFAULT_MEMORY_MB,
|
|
302
|
+
executor: ProcessPoolExecutor | None = None,
|
|
303
|
+
) -> Any: # noqa: ANN401
|
|
304
|
+
"""Execute a tool call with input validation, timeout, and memory cap.
|
|
305
|
+
|
|
306
|
+
Parameters
|
|
307
|
+
----------
|
|
308
|
+
tool_name, tool_input:
|
|
309
|
+
Same meaning as :func:`process_improve.tool_spec.execute_tool_call`.
|
|
310
|
+
timeout:
|
|
311
|
+
Wall-clock seconds. On overrun, the current subprocess is terminated
|
|
312
|
+
and a fresh pool is started; :class:`ToolTimeoutError` is raised.
|
|
313
|
+
max_cells, max_string, max_depth:
|
|
314
|
+
Input-size limits. See :func:`validate_input`.
|
|
315
|
+
memory_mb:
|
|
316
|
+
RSS cap applied to the worker subprocess via ``RLIMIT_AS`` (POSIX).
|
|
317
|
+
On overrun the subprocess dies and :class:`ToolMemoryExceededError`
|
|
318
|
+
is raised.
|
|
319
|
+
executor:
|
|
320
|
+
Optional caller-provided pool. When *None* (default) a module-level
|
|
321
|
+
singleton is used.
|
|
322
|
+
|
|
323
|
+
Raises
|
|
324
|
+
------
|
|
325
|
+
ToolInputInvalidError, ToolInputTooLargeError:
|
|
326
|
+
Synchronous rejection before any subprocess work.
|
|
327
|
+
ToolTimeoutError:
|
|
328
|
+
Wall-clock overrun.
|
|
329
|
+
ToolMemoryExceededError:
|
|
330
|
+
Worker subprocess died unexpectedly (likely OOM).
|
|
331
|
+
ValueError:
|
|
332
|
+
Unknown tool name (propagated from ``execute_tool_call``).
|
|
333
|
+
"""
|
|
334
|
+
validate_input(
|
|
335
|
+
tool_input,
|
|
336
|
+
max_cells=max_cells,
|
|
337
|
+
max_string=max_string,
|
|
338
|
+
max_depth=max_depth,
|
|
339
|
+
)
|
|
340
|
+
|
|
341
|
+
pool = executor if executor is not None else get_pool(memory_mb=memory_mb)
|
|
342
|
+
future = pool.submit(_worker_run, tool_name, tool_input)
|
|
343
|
+
|
|
344
|
+
try:
|
|
345
|
+
return future.result(timeout=timeout)
|
|
346
|
+
except FuturesTimeoutError as exc:
|
|
347
|
+
# Kill the whole pool so the runaway worker cannot hold the CPU.
|
|
348
|
+
if executor is None:
|
|
349
|
+
shutdown_pool()
|
|
350
|
+
raise ToolTimeoutError(
|
|
351
|
+
f"Tool {tool_name!r} exceeded {timeout}s timeout",
|
|
352
|
+
details={"tool_name": tool_name, "timeout": timeout},
|
|
353
|
+
) from exc
|
|
354
|
+
except BrokenProcessPool as exc:
|
|
355
|
+
if executor is None:
|
|
356
|
+
shutdown_pool()
|
|
357
|
+
raise ToolMemoryExceededError(
|
|
358
|
+
f"Tool {tool_name!r} worker died (likely exceeded memory limit of {memory_mb} MB)",
|
|
359
|
+
details={"tool_name": tool_name, "memory_mb": memory_mb},
|
|
360
|
+
) from exc
|
|
361
|
+
except MemoryError as exc:
|
|
362
|
+
# RLIMIT_AS caused an allocator to fail inside the worker; the worker
|
|
363
|
+
# stays alive, but the tool could not complete. Surface as a
|
|
364
|
+
# structured error so hosted callers can distinguish this from bugs.
|
|
365
|
+
raise ToolMemoryExceededError(
|
|
366
|
+
f"Tool {tool_name!r} exceeded memory limit of {memory_mb} MB",
|
|
367
|
+
details={"tool_name": tool_name, "memory_mb": memory_mb},
|
|
368
|
+
) from exc
|
|
@@ -252,3 +252,35 @@ def execute_tool_call(tool_name: str, tool_input: dict[str, Any]) -> Any: # noq
|
|
|
252
252
|
available = sorted(_TOOL_REGISTRY)
|
|
253
253
|
raise ValueError(f"Unknown tool {tool_name!r}. Available tools: {available}")
|
|
254
254
|
return _TOOL_REGISTRY[tool_name](**tool_input)
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# ---------------------------------------------------------------------------
|
|
258
|
+
# Safety wrapper re-exports
|
|
259
|
+
# ---------------------------------------------------------------------------
|
|
260
|
+
# Callers that expose the registry over an untrusted transport should use
|
|
261
|
+
# ``safe_execute_tool_call`` from ``process_improve.tool_safety`` instead of
|
|
262
|
+
# ``execute_tool_call``. The names are re-exported here for discoverability.
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
from process_improve.tool_safety import ( # noqa: E402
|
|
266
|
+
ToolInputInvalidError,
|
|
267
|
+
ToolInputTooLargeError,
|
|
268
|
+
ToolMemoryExceededError,
|
|
269
|
+
ToolSafetyError,
|
|
270
|
+
ToolTimeoutError,
|
|
271
|
+
safe_execute_tool_call,
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
__all__ = [
|
|
275
|
+
"ToolInputInvalidError",
|
|
276
|
+
"ToolInputTooLargeError",
|
|
277
|
+
"ToolMemoryExceededError",
|
|
278
|
+
"ToolSafetyError",
|
|
279
|
+
"ToolTimeoutError",
|
|
280
|
+
"clean",
|
|
281
|
+
"discover_tools",
|
|
282
|
+
"execute_tool_call",
|
|
283
|
+
"get_tool_specs",
|
|
284
|
+
"safe_execute_tool_call",
|
|
285
|
+
"tool_spec",
|
|
286
|
+
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/batch/batch-fake-data.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/experiments/test_doe1.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/C.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/LDPE.csv
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/P.csv
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/R.csv
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/T.csv
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/U.csv
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/LDPE/W.csv
RENAMED
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/datasets/multivariate/kamyr.csv
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_factorial.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_mixture.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_optimal.py
RENAMED
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/designs_screening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/__init__.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/api.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/engine.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/knowledge/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/__init__.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/budget.py
RENAMED
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/engine.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/strategy/models.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/api.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/colors.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/spec.py
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/experiments/visualization/types.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/Tablets.xlsx
RENAMED
|
File without changes
|
{process_improve-1.3.2 → process_improve-1.4.0}/process_improve/notebooks_examples/batch/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|