diff --git a/README.md b/README.md
index f17f8d4..a568e92 100644
--- a/README.md
+++ b/README.md
@@ -16,9 +16,12 @@ To install Dial from source, git clone this repository and run the following fro
`pip install .`
-Alternatively, both intersect-sdk and Dial may be installed with the following:
+By default, **only scikit-learn is available as a backend**. We also support GPax and Sable as backends. To install these:
-`pip install -e .`
+- for GPax: `pip install ".[gpax]"`
+- for Sable: `pip install ".[sable]"`
+
+Use commas to add multiple backends: `pip install ".[gpax,sable]"`
## Installing (developers)
diff --git a/pyproject.toml b/pyproject.toml
index b36ae29..42f3188 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -20,12 +20,9 @@ classifiers = ["Programming Language :: Python :: 3"]
dependencies = [
"intersect_sdk>=0.9.3,<0.10.0",
"numpy",
- "scikit-learn>=1.4.0,<2.0.0", # TODO consider making an optional dependency group
+ "scikit-learn>=1.4.0,<2.0.0", # TODO consider making an optional dependency group
"scipy>=1.12.0,<2.0.0",
- "gpax>=0.1.8", # TODO consider making an optional dependency group
- "numpyro<0.20.1", # depend on older numpyro for gpax (numpyro.contrib.module: random_haiku_module)
- "pymongo>=4.12.1", # TODO - this is only needed for dial_service, dial_dataclass can use a simple fixture for ObjectID representation which allows it to skip this dependency
- "sable @ git+https://code.ornl.gov/sable/sable.git", # TODO this references the internal repo, transition to public version
+ "pymongo>=4.12.1", # TODO - this is only needed for dial_service, dial_dataclass can use a simple fixture for ObjectID representation which allows it to skip this dependency
]
[project.urls]
@@ -36,6 +33,11 @@ Issues = "https://github.com/INTERSECT-DIAL/dial/issues"
[project.optional-dependencies]
docs = ["sphinx>=5.3.0", "furo>=2023.3.27"]
+gpax = [
+ "gpax>=0.1.8",
+ "numpyro<0.20.1", # depend on older numpyro for gpax (numpyro.contrib.module: random_haiku_module)
+]
+sable = ["sable @ git+https://code.ornl.gov/sable/sable.git"]
[dependency-groups]
dev = [
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/benchmarks/__init__.py b/tests/benchmarks/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/benchmarks/test_strainmap.py b/tests/benchmarks/test_strainmap.py
index e91fa3e..3dd9725 100644
--- a/tests/benchmarks/test_strainmap.py
+++ b/tests/benchmarks/test_strainmap.py
@@ -1,846 +1,890 @@
-"""
-Benchmark which is meant to test core DIAL functionality (without the INTERSECT or MONGO pieces) for the Strain-Mapping benchmark problem.
-"""
-
-import logging
-import sys
-from dataclasses import dataclass
-from pathlib import Path
-
-import numpy as np
-import pandas as pd
-import pytest
-from scipy.interpolate import LinearNDInterpolator
-
-# from pytest_benchmark.fixture import BenchmarkFixture
-from dial_dataclass import (
- DialInputPredictions,
- DialInputSingleOtherStrategy,
- Normal,
-)
-from dial_service import (
- core as dial_core,
-)
-from dial_service.serverside_data import (
- ServersideInputBase,
- ServersideInputPrediction,
- ServersideInputSingle,
-)
-from dial_service.service_specific_dataclasses import DialWorkflowCreationParamsService
-
-logger = logging.getLogger(__name__)
-
-MOCK_WORKFLOW_ID = '6984e6a6ef6e6290dabced91'
-"""fake ObjectID for testing purposes, we do not actually interact with a DB in these tests."""
-
-
-###############
-low_f_data_name = (
- Path(__file__).parents[1] / 'fixtures' / 'adaptive_strain_manufacturing_low_fidelity.csv'
-)
-high_f_data_name = (
- Path(__file__).parents[1] / 'fixtures' / 'adaptive_strain_manufacturing_high_fidelity.csv'
-)
-
-
-def read_and_prepare_data():
- # normalization helper
- def normalize_data(in_data):
- m_data = (in_data.max() + in_data.min()) * 0.5
- d_data = (in_data.max() - in_data.min()) * 0.5
- return (in_data - m_data) / d_data
-
- # define constants and read data
- # wall_st_index = 0
- # wall_st_end = 676
- x_col_index = 0 # z follow next
- e_col_index = 2 # e11, e22 and e33
- nrows = 26 # Rows in sim strain map of the wall
- ncols = 26 # Cols in sim strain map of the wall
- data = pd.read_csv(low_f_data_name)
-
- Y, Z, E11, E22, E33, R11, R22, R33 = np.array(
- [
- data.values[:, x_col_index],
- data.values[:, x_col_index + 1],
- data.values[:, e_col_index],
- data.values[:, e_col_index + 1],
- data.values[:, e_col_index + 2],
- data.values[:, e_col_index + 3],
- data.values[:, e_col_index + 4],
- data.values[:, e_col_index + 5],
- ]
- )
-
- # Convert data
- x1 = Y.astype(np.float32).reshape(nrows, ncols)
- x2 = Z.astype(np.float32).reshape(nrows, ncols)
-
- # Sim_e11 = np.array(E11).astype(np.float32).reshape(nrows, ncols)
- # Real_e11 = np.array(R11).astype(np.float32).reshape(nrows, ncols)
-
- # Sim_e22 = np.array(E22).astype(np.float32).reshape(nrows, ncols)
- # Real_e22 = np.array(R22).astype(np.float32).reshape(nrows, ncols)
-
- # Sim_e33 = np.array(E33).astype(np.float32).reshape(nrows, ncols)
- Real_e33 = np.array(R33).astype(np.float32).reshape(nrows, ncols)
-
- # Normalize data
- x1_norm = normalize_data(x1)
- x2_norm = normalize_data(x2)
-
- # Sim_e11_norm = normalize_data(Sim_e11)
- # Real_e11_norm = normalize_data(Real_e11)
-
- # Sim_e22_norm = normalize_data(Sim_e22)
- # Real_e22_norm = normalize_data(Real_e22)
-
- # Sim_e33_norm = normalize_data(Sim_e33)
- Real_e33_norm = normalize_data(Real_e33)
-
- # read high fidelity data
- # data = pd.read_csv(high_f_data_name)
-
- # Y, Z, E11, E22, E33, R11, R22, R33 = np.array(
- # [
- # data.values[:, x_col_index],
- # data.values[:, x_col_index + 1],
- # data.values[:, e_col_index],
- # data.values[:, e_col_index + 1],
- # data.values[:, e_col_index + 2],
- # data.values[:, e_col_index + 3],
- # data.values[:, e_col_index + 4],
- # data.values[:, e_col_index + 5],
- # ]
- # )
-
- # Sim_hi_e11 = np.array(E11).astype(np.float32).reshape(nrows, ncols)
- # Sim_hi_e22 = np.array(E22).astype(np.float32).reshape(nrows, ncols)
- # Sim_hi_e33 = np.array(E33).astype(np.float32).reshape(nrows, ncols)
-
- # Transpose the high-fidelity simulation data
- # TODO, figure out why this is transposed
- # Sim_hi_e11 = Sim_hi_e11.T
- # Sim_hi_e22 = Sim_hi_e22.T
- # Sim_hi_e33 = Sim_hi_e33.T
-
- # Normalize data
- # Sim_hi_e11_norm = normalize_data(Sim_hi_e11)
- # Sim_hi_e22_norm = normalize_data(Sim_hi_e22)
- # Sim_hi_e33_norm = normalize_data(Sim_hi_e33)
-
- # return data that will be used for the benchmark
- return nrows, (x1_norm, x2_norm), Real_e33_norm
-
-
-###############
-
-## Select data for ground truth
-
-ngrid, x_grids, y_grid = read_and_prepare_data()
-
-# default inputs
-INITIAL_BOUNDS = [[-1.0, 1.0], [-1.0, 1.0]]
-NUM_DIMS = len(INITIAL_BOUNDS)
-
-MESHGRID_SIZE = ngrid
-INITIAL_MESHGRIDS = x_grids
-INITIAL_POINTS_TO_PREDICT = np.hstack([mg.reshape(-1, 1) for mg in INITIAL_MESHGRIDS])
-
-INITIAL_PREDICTIONS = y_grid.reshape(-1, 1)
-
-###############
-
-NOISE_LEVEL = 1.0e-2
-
-truth_interp = LinearNDInterpolator(INITIAL_POINTS_TO_PREDICT, INITIAL_PREDICTIONS)
-
-
-@dataclass
-class StrainMap:
- """Strain Map function."""
-
- noise_level: float
-
- truth_interp: LinearNDInterpolator
- """Strain interpolator that is used as 'ground_truth'"""
-
- def strain_map(self, x) -> float:
- """
- Represents a measured strain as a function of two simulation parameters.
- """
- x = np.asarray(x).reshape((-1, 2))
- x1, x2 = x[:, 0], x[:, 1]
-
- y_true = truth_interp(np.asarray(x1), np.asarray(x2))
-
- # print("Evaluated truth model", np.hstack((x, y_true)))
-
- y_noise = y_true + self.noise_level * np.random.normal(size=y_true.shape)
- return y_noise
-
-
-# build a strain map from the selected truth values
-truth_strain_map = StrainMap(truth_interp=truth_interp, noise_level=NOISE_LEVEL)
-
-###############
-
-# test parameters
-INITIAL_NUM_POINTS = 25
-MAX_ITERATIONS = 150 # only allow a maximum of this many iterations in tests
-
-INITIAL_DATASET_X = np.random.uniform(-1.0, 1.0, size=(INITIAL_NUM_POINTS, NUM_DIMS)).tolist()
-
-TARGET_ERROR = 0.11
-
-
-def run_simulation(
- dataset_x: list[list[float]], dataset_y: list[float], strategy: str, strategy_args: object
-) -> tuple[np.ndarray, np.ndarray]:
- # important "Hyper-parameters"
- length_scale = 0.4
- prior_std = 1.0
-
- # Assume that there is some small noise in the measurements to stabilize the fit
- statistics_y = Normal(loc='y', scale=NOISE_LEVEL)
-
- # modify a local copy of strategy_args
- strategy_args = strategy_args.copy()
- backend = strategy_args.pop('backend', 'sklearn')
-
- if backend == 'sable':
- # train model with new data
- kernel = 'rbf'
- kernel_args = {
- 'sigma_range': [5e-2, 1.0],
- 'gamma': 0.5,
- }
- backend_args = {
- 'prior_std': prior_std,
- }
-
- else:
- # train model with new data
- kernel = 'matern'
- kernel_args = {
- 'length_scale': length_scale,
- 'constant_value': prior_std**2,
- }
- backend_args = {}
-
- client_state = DialWorkflowCreationParamsService(
- dataset_x=dataset_x,
- dataset_y=dataset_y,
- statistics_y=statistics_y,
- bounds=INITIAL_BOUNDS,
- kernel=kernel,
- kernel_args=kernel_args,
- y_is_good=False,
- backend=backend,
- backend_args=backend_args,
- seed=-1,
- dim_x=2,
- )
-
- data = ServersideInputBase(client_state)
- model = dial_core.train_model(data)
-
- # use get_surrogate_values to predict mean and standard deviation on the inital points grid
- data = ServersideInputPrediction(
- client_state,
- DialInputPredictions(
- workflow_id=MOCK_WORKFLOW_ID,
- points_to_predict=INITIAL_POINTS_TO_PREDICT,
- ),
- )
- surrogate_mean, surrogate_std, _ = dial_core.get_surrogate_values(data, model)
- mean_grid = np.array(surrogate_mean).reshape((-1, 1))
-
- # subtract the true values and save mean absolute error and standard deviation
- err_grid = np.abs(mean_grid - INITIAL_PREDICTIONS).reshape((MESHGRID_SIZE,) * NUM_DIMS)
- std_grid = np.array(surrogate_std).reshape((MESHGRID_SIZE,) * NUM_DIMS)
-
- # get_next_point
- data = ServersideInputSingle(
- client_state,
- DialInputSingleOtherStrategy(
- workflow_id=MOCK_WORKFLOW_ID,
- bounds=INITIAL_BOUNDS,
- y_is_good=False,
- seed=-1,
- strategy=strategy,
- strategy_args=strategy_args,
- discrete_measurements=True,
- discrete_measurement_grid_size=[MESHGRID_SIZE, MESHGRID_SIZE],
- ),
- )
- next_point = dial_core.get_next_point(data, model)
-
- dataset_x.append(next_point)
-
- # compute at next point
- next_point_y = truth_strain_map.strain_map(next_point).reshape(-1).tolist()
- dataset_y.append(next_point_y[0])
-
- return err_grid, std_grid
-
-
-def graph(err_grid, dataset_x, strategy):
- try:
- import matplotlib as mpl
- import matplotlib.pyplot as plt
-
- mpl.use('Agg') # Use non-interactive backend
- except ImportError:
- logger.error( # noqa: TRY400
- 'Error: matplotlib is required for generating plots. Install it with: pip install matplotlib'
- )
- return
-
- plt.clf()
- data = np.array(err_grid)
- plt.contourf(
- INITIAL_MESHGRIDS[0],
- INITIAL_MESHGRIDS[1],
- data,
- levels=np.logspace(-2, 0, 10),
- norm='log',
- extend='both',
- )
- cbar = plt.colorbar()
- cbar.set_ticks(np.logspace(-2, 0, 7))
- cbar.set_label('Overall error')
- plt.xlabel('Simulation Parameter #1')
- plt.ylabel('Simulation Parameter #2')
- # add black dots for data points and a red marker for the recommendation:
- X_train = np.array(dataset_x)
- plt.scatter(X_train[:, 0], X_train[:, 1], color='black', marker='o')
- plt.scatter(1.0, 1.0, s=300, color='None', edgecolors='black', marker='o')
-
- plt.savefig(f'graph_{strategy}.png')
-
-
-def accuracy_benchmark(
- strategy: str, strategy_args: object, max_iterations=MAX_ITERATIONS
-) -> tuple[int, float]:
- """
- returns:
- - number of iterations taken to reach an acceptably accurate target
- - target value achieved
- """
-
- iterations = 0
-
- initial_dataset_x = np.random.uniform(-1.0, 1.0, size=(INITIAL_NUM_POINTS, NUM_DIMS)).tolist()
-
- dataset_x = initial_dataset_x
- dataset_y = truth_strain_map.strain_map(dataset_x).reshape(-1).tolist()
-
- # run simulations until we reach an acceptable target range
- while iterations < max_iterations:
- try:
- err_grid, std_grid = run_simulation(dataset_x, dataset_y, strategy, strategy_args)
- except Exception as e:
- logger.exception('Error during simulation')
- raise AssertionError from e
-
- # guess has no meaning here, take the last acquired datapoint
- guess = dataset_x[-1]
-
- # compute the RMSE and MAD on the grid and the average
- # rmse = np.sqrt(err_grid**2 + std_grid**2)
- mad = np.abs(err_grid)
- # total_rmse = np.sqrt(np.mean(rmse**2))
- total_mad = np.sqrt(np.mean(mad**2))
-
- # pick the MAD over the RMSE as an error criterion, it only measures the mean deviation:
- # it is less sensitive to wrong std and hyperparameter calibration, but does not measure how well
- # the "error bars" (std_grid) quantify the actual ty
- error = total_mad
- print(iterations, error)
-
- graph(mad, dataset_x, f'{strategy}_{strategy_args.get("backend", "sklearn")}')
-
- if error <= TARGET_ERROR:
- break
- iterations += 1
-
- return iterations, error, guess
-
-
-TEST_PARAMS = (
- ('strategy', 'strategy_args', 'max_iterations'),
- [
- ('uncertainty', {}, 2),
- ('uncertainty', {'backend': 'sable'}, 2),
- ('random', {}, 2),
- # use low number of iterations for unit test
- ],
-)
-
-
-@pytest.mark.parametrize(*TEST_PARAMS)
-def test_benchmark_strainmap_accuracy(
- # benchmark: BenchmarkFixture,
- strategy: str,
- strategy_args: dict,
- max_iterations: int,
-) -> None:
- # NUM_RUNS = 20
- # for _ in range(NUM_RUNS):
- # iterations, target = benchmark(
- # partial(accuracy_benchmark, strategy, strategy_args)
- # )
- iterations, target, guess = accuracy_benchmark(strategy, strategy_args, max_iterations)
- print(
- 'Iterations for',
- strategy,
- ': ',
- iterations,
- ' best guess:',
- guess,
- ' with target value:',
- target,
- )
- print(
- 'Maximum early terminus value',
- TARGET_ERROR,
- ' with ',
- max_iterations,
- ' maximum iterations.',
- )
- print(
- 'Accuracy benchmark for strategy:',
- strategy,
- 'reached' if iterations <= max_iterations else 'not reached',
- )
-
-
-if __name__ == '__main__':
- """Generate HTML benchmark report with plots comparing different strategies."""
- import argparse
- import datetime
- import json
- from pathlib import Path
-
- logger = logging.getLogger(f'{__name__}_runner')
-
- try:
- import matplotlib as mpl
- import matplotlib.pyplot as plt
-
- mpl.use('Agg') # Use non-interactive backend
- except ImportError:
- logger.error( # noqa: TRY400
- 'Error: matplotlib is required for generating plots. Install it with: pip install matplotlib'
- )
- sys.exit(1)
-
- def positive_int_type(arg):
- try:
- val = int(arg)
- except ValueError as e:
- msg = 'Must be an integer'
- raise argparse.ArgumentTypeError(msg) from e
- if val < 1:
- msg = 'Argument must be a positive number'
- raise argparse.ArgumentTypeError(msg)
- return val
-
- parser = argparse.ArgumentParser(description='Generate the Strainmap HTML benchmark pages.')
- parser.add_argument(
- '--num-runs',
- '-n',
- type=positive_int_type,
- default=3,
- help='Number of runs for each strategy.',
- )
- args = parser.parse_args()
-
- strategies = TEST_PARAMS[1]
-
- # Run multiple iterations for statistical analysis
- NUM_RUNS = args.num_runs
- logger.info('Running benchmarks with %d iterations per strategy...', NUM_RUNS)
-
- results = {}
- for strategy, strategy_args, _ in strategies:
- strategy_name = f'{strategy}' + (f' {json.dumps(strategy_args)}' if strategy_args else '')
- logger.info('\nBenchmarking: %s', strategy_name)
-
- iterations_list = []
- targets_list = []
- guesses_list = []
-
- for run in range(NUM_RUNS):
- iterations, target, guess = accuracy_benchmark(strategy, strategy_args)
- iterations_list.append(iterations)
- targets_list.append(target)
- guesses_list.append(guess)
- logger.info(
- ' Run %d/%d: iterations=%d, target=%.4f', run + 1, NUM_RUNS, iterations, target
- )
-
- results[strategy_name] = {
- 'strategy': strategy,
- 'strategy_args': strategy_args,
- 'iterations': iterations_list,
- 'targets': targets_list,
- 'guesses': guesses_list,
- 'avg_iterations': np.mean(iterations_list),
- 'std_iterations': np.std(iterations_list),
- 'avg_target': np.mean(targets_list),
- 'std_target': np.std(targets_list),
- 'success_rate': sum(1 for t in targets_list if t <= TARGET_ERROR) / NUM_RUNS * 100,
- }
-
- # Generate plots
- output_dir = Path('reports/benchmarks')
- output_dir.mkdir(parents=True, exist_ok=True)
-
- fig, axes = plt.subplots(2, 2, figsize=(14, 10))
- fig.suptitle('Strainmap Optimization Benchmark Comparison', fontsize=16, fontweight='bold')
-
- # Plot 1: Average iterations to convergence
- ax1 = axes[0, 0]
- strategy_names = list(results.keys())
- avg_iterations = [results[s]['avg_iterations'] for s in strategy_names]
- std_iterations = [results[s]['std_iterations'] for s in strategy_names]
- bars1 = ax1.bar(
- range(len(strategy_names)), avg_iterations, yerr=std_iterations, capsize=5, alpha=0.7
- )
- ax1.set_xlabel('Strategy')
- ax1.set_ylabel('Average Iterations')
- ax1.set_title('Iterations to Convergence (Lower is Better)')
- ax1.set_xticks(range(len(strategy_names)))
- ax1.set_xticklabels(
- [s.replace(' ', '\n') for s in strategy_names], rotation=0, ha='center', fontsize=8
- )
- ax1.grid(axis='y', alpha=0.3)
-
- # Add value labels on bars
- for _i, (bar, val, std) in enumerate(zip(bars1, avg_iterations, std_iterations, strict=False)):
- height = bar.get_height()
- ax1.text(
- bar.get_x() + bar.get_width() / 2.0,
- height,
- f'{val:.1f}±{std:.1f}',
- ha='center',
- va='bottom',
- fontsize=9,
- )
-
- # Plot 2: Average target value achieved
- ax2 = axes[0, 1]
- avg_targets = [results[s]['avg_target'] for s in strategy_names]
- std_targets = [results[s]['std_target'] for s in strategy_names]
- bars2 = ax2.bar(
- range(len(strategy_names)),
- avg_targets,
- yerr=std_targets,
- capsize=5,
- alpha=0.7,
- color='orange',
- )
- ax2.set_xlabel('Strategy')
- ax2.set_ylabel('Average Target Value')
- ax2.set_title('Final Target Value (Lower is Better)')
- ax2.set_xticks(range(len(strategy_names)))
- ax2.set_xticklabels(
- [s.replace(' ', '\n') for s in strategy_names], rotation=0, ha='center', fontsize=8
- )
- ax2.axhline(
- y=TARGET_ERROR, color='r', linestyle='--', label=f'Target Threshold ({TARGET_ERROR})'
- )
- ax2.legend()
- ax2.grid(axis='y', alpha=0.3)
-
- # Add value labels on bars
- for _i, (bar, val, std) in enumerate(zip(bars2, avg_targets, std_targets, strict=False)):
- height = bar.get_height()
- ax2.text(
- bar.get_x() + bar.get_width() / 2.0,
- height,
- f'{val:.2f}±{std:.2f}',
- ha='center',
- va='bottom',
- fontsize=9,
- )
-
- # Plot 3: Success rate
- ax3 = axes[1, 0]
- success_rates = [results[s]['success_rate'] for s in strategy_names]
- bars3 = ax3.bar(range(len(strategy_names)), success_rates, alpha=0.7, color='green')
- ax3.set_xlabel('Strategy')
- ax3.set_ylabel('Success Rate (%)')
- ax3.set_title(f'Success Rate (Target ≤ {TARGET_ERROR})')
- ax3.set_xticks(range(len(strategy_names)))
- ax3.set_xticklabels(
- [s.replace(' ', '\n') for s in strategy_names], rotation=0, ha='center', fontsize=8
- )
- ax3.set_ylim([0, 105])
- ax3.grid(axis='y', alpha=0.3)
-
- # Add value labels on bars
- for bar, val in zip(bars3, success_rates, strict=False):
- height = bar.get_height()
- ax3.text(
- bar.get_x() + bar.get_width() / 2.0,
- height,
- f'{val:.1f}%',
- ha='center',
- va='bottom',
- fontsize=9,
- )
-
- # Plot 4: Box plot of iterations distribution
- ax4 = axes[1, 1]
- iterations_data = [results[s]['iterations'] for s in strategy_names]
- bp = ax4.boxplot(iterations_data, patch_artist=True)
- for patch in bp['boxes']:
- patch.set_facecolor('lightblue')
- ax4.set_xlabel('Strategy')
- ax4.set_ylabel('Iterations')
- ax4.set_title('Iterations Distribution')
- ax4.set_xticklabels([s.replace(' ', '\n') for s in strategy_names], fontsize=8)
- ax4.grid(axis='y', alpha=0.3)
-
- plt.tight_layout()
- plot_path = output_dir / 'strainmap_benchmark.png'
- plt.savefig(plot_path, dpi=150, bbox_inches='tight')
- logger.info('✓ Plot saved to %s', plot_path)
- plt.close()
-
- # Generate HTML report
- html_content = f"""
-
-
-
-
- Strainmap Optimization Benchmark Report
-
-
-
- 📊 Strainmap Optimization Benchmark Report
-
-
-
-
-
🎯 Test Objective
-
This benchmark evaluates different acquisition strategies for Bayesian optimization on a strain mapping experiment dataset.
- The goal is to minimize the total surrogate error (over all inputs) within {MAX_ITERATIONS} iterations, starting from {INITIAL_NUM_POINTS} initial points.
-
-
- 📈 Benchmark Results
-
-
-
Performance Comparison
-

-
-
- 📋 Detailed Statistics
-
-
-
-
- | Strategy |
- Strategy Args |
- Avg Iterations |
- Std Iterations |
- Avg Target Value |
- Std Target Value |
- Success Rate |
-
-
-
-"""
-
- # Find best performers
- best_iterations_idx = min(range(len(strategy_names)), key=lambda i: avg_iterations[i])
- best_target_idx = min(range(len(strategy_names)), key=lambda i: avg_targets[i])
- best_success_idx = max(range(len(strategy_names)), key=lambda i: success_rates[i])
-
- for i, strategy_name in enumerate(strategy_names):
- result = results[strategy_name]
- row_class = ''
- if i in (best_iterations_idx, best_target_idx, best_success_idx):
- row_class = ' class="best"'
-
- args_str = json.dumps(result['strategy_args']) if result['strategy_args'] else 'None'
-
- html_content += f"""
- {result['strategy']} |
- {args_str} |
- {result['avg_iterations']:.2f} |
- {result['std_iterations']:.2f} |
- {result['avg_target']:.4f} |
- {result['std_target']:.4f} |
- {result['success_rate']:.1f}% |
-
-"""
-
- html_content += """
-
-
- 🏆 Key Findings
-
-"""
-
- # Add findings
- best_strategy = strategy_names[best_iterations_idx]
- html_content += f"""
Fastest Convergence: {best_strategy} with {avg_iterations[best_iterations_idx]:.2f} ± {std_iterations[best_iterations_idx]:.2f} iterations on average
-"""
-
- best_accuracy_strategy = strategy_names[best_target_idx]
- html_content += f"""
Best Accuracy: {best_accuracy_strategy} with average target value {avg_targets[best_target_idx]:.4f} ± {std_targets[best_target_idx]:.4f}
-"""
-
- best_reliability_strategy = strategy_names[best_success_idx]
- html_content += f"""
Most Reliable: {best_reliability_strategy} with {success_rates[best_success_idx]:.1f}% success rate
-"""
-
- html_content += """
-
- 📊 Raw Data
-
- Click to expand raw results JSON
-
-"""
-
- # Prepare JSON-serializable results
- json_results = {}
- for strategy_name, result in results.items():
- json_results[strategy_name] = {
- 'strategy': result['strategy'],
- 'strategy_args': result['strategy_args'],
- 'iterations': result['iterations'],
- 'targets': result['targets'],
- 'guesses': [[float(x) for x in guess] for guess in result['guesses']],
- 'statistics': {
- 'avg_iterations': float(result['avg_iterations']),
- 'std_iterations': float(result['std_iterations']),
- 'avg_target': float(result['avg_target']),
- 'std_target': float(result['std_target']),
- 'success_rate': float(result['success_rate']),
- },
- }
-
- html_content += json.dumps(json_results, indent=2)
- html_content += """
-
-
-
-
-
-
-"""
-
- # Save HTML report
- html_path = output_dir / 'strainmap_benchmark.html'
- html_path.write_text(html_content)
- logger.info('✓ HTML report saved to %s', html_path)
-
- # Save JSON data
- json_path = output_dir / 'strainmap_benchmark.json'
- json_path.write_text(json.dumps(json_results, indent=2))
- logger.info('✓ JSON data saved to %s', json_path)
-
- logger.info('\n%s', '=' * 60)
- logger.info('📊 Benchmark Summary')
- logger.info('%s', '=' * 60)
- for strategy_name in strategy_names:
- result = results[strategy_name]
- logger.info('\n%s:', strategy_name)
- logger.info(
- ' Avg Iterations: %.2f ± %.2f', result['avg_iterations'], result['std_iterations']
- )
- logger.info(' Avg Target: %.4f ± %.4f', result['avg_target'], result['std_target'])
- logger.info(' Success Rate: %.1f%%', result['success_rate'])
-
- logger.info('\n%s', '=' * 60)
- logger.info('✓ Open %s in your browser to view the full report', html_path)
- logger.info('%s', '=' * 60)
- # assert iterations <= MAX_ITERATIONS
+"""
+Benchmark which is meant to test core DIAL functionality (without the INTERSECT or MONGO pieces) for the Strain-Mapping benchmark problem.
+"""
+
+import logging
+import sys
+from dataclasses import dataclass
+from pathlib import Path
+
+import numpy as np
+import pandas as pd
+import pytest
+from scipy.interpolate import LinearNDInterpolator
+
+# from pytest_benchmark.fixture import BenchmarkFixture
+from dial_dataclass import (
+ DialInputPredictions,
+ DialInputSingleOtherStrategy,
+ Normal,
+)
+from dial_service import (
+ core as dial_core,
+)
+from dial_service.serverside_data import (
+ ServersideInputBase,
+ ServersideInputPrediction,
+ ServersideInputSingle,
+)
+from dial_service.service_specific_dataclasses import (
+ DialWorkflowCreationParamsService,
+)
+
+from ..helpers import generate_pytest_parameters
+
+logger = logging.getLogger(__name__)
+
+MOCK_WORKFLOW_ID = '6984e6a6ef6e6290dabced91'
+"""fake ObjectID for testing purposes, we do not actually interact with a DB in these tests."""
+
+
+###############
+low_f_data_name = (
+ Path(__file__).parents[1] / 'fixtures' / 'adaptive_strain_manufacturing_low_fidelity.csv'
+)
+high_f_data_name = (
+ Path(__file__).parents[1] / 'fixtures' / 'adaptive_strain_manufacturing_high_fidelity.csv'
+)
+
+
+def read_and_prepare_data():
+ # normalization helper
+ def normalize_data(in_data):
+ m_data = (in_data.max() + in_data.min()) * 0.5
+ d_data = (in_data.max() - in_data.min()) * 0.5
+ return (in_data - m_data) / d_data
+
+ # define constants and read data
+ # wall_st_index = 0
+ # wall_st_end = 676
+ x_col_index = 0 # z follow next
+ e_col_index = 2 # e11, e22 and e33
+ nrows = 26 # Rows in sim strain map of the wall
+ ncols = 26 # Cols in sim strain map of the wall
+ data = pd.read_csv(low_f_data_name)
+
+ Y, Z, E11, E22, E33, R11, R22, R33 = np.array(
+ [
+ data.values[:, x_col_index],
+ data.values[:, x_col_index + 1],
+ data.values[:, e_col_index],
+ data.values[:, e_col_index + 1],
+ data.values[:, e_col_index + 2],
+ data.values[:, e_col_index + 3],
+ data.values[:, e_col_index + 4],
+ data.values[:, e_col_index + 5],
+ ]
+ )
+
+ # Convert data
+ x1 = Y.astype(np.float32).reshape(nrows, ncols)
+ x2 = Z.astype(np.float32).reshape(nrows, ncols)
+
+ # Sim_e11 = np.array(E11).astype(np.float32).reshape(nrows, ncols)
+ # Real_e11 = np.array(R11).astype(np.float32).reshape(nrows, ncols)
+
+ # Sim_e22 = np.array(E22).astype(np.float32).reshape(nrows, ncols)
+ # Real_e22 = np.array(R22).astype(np.float32).reshape(nrows, ncols)
+
+ # Sim_e33 = np.array(E33).astype(np.float32).reshape(nrows, ncols)
+ Real_e33 = np.array(R33).astype(np.float32).reshape(nrows, ncols)
+
+ # Normalize data
+ x1_norm = normalize_data(x1)
+ x2_norm = normalize_data(x2)
+
+ # Sim_e11_norm = normalize_data(Sim_e11)
+ # Real_e11_norm = normalize_data(Real_e11)
+
+ # Sim_e22_norm = normalize_data(Sim_e22)
+ # Real_e22_norm = normalize_data(Real_e22)
+
+ # Sim_e33_norm = normalize_data(Sim_e33)
+ Real_e33_norm = normalize_data(Real_e33)
+
+ # read high fidelity data
+ # data = pd.read_csv(high_f_data_name)
+
+ # Y, Z, E11, E22, E33, R11, R22, R33 = np.array(
+ # [
+ # data.values[:, x_col_index],
+ # data.values[:, x_col_index + 1],
+ # data.values[:, e_col_index],
+ # data.values[:, e_col_index + 1],
+ # data.values[:, e_col_index + 2],
+ # data.values[:, e_col_index + 3],
+ # data.values[:, e_col_index + 4],
+ # data.values[:, e_col_index + 5],
+ # ]
+ # )
+
+ # Sim_hi_e11 = np.array(E11).astype(np.float32).reshape(nrows, ncols)
+ # Sim_hi_e22 = np.array(E22).astype(np.float32).reshape(nrows, ncols)
+ # Sim_hi_e33 = np.array(E33).astype(np.float32).reshape(nrows, ncols)
+
+ # Transpose the high-fidelity simulation data
+ # TODO, figure out why this is transposed
+ # Sim_hi_e11 = Sim_hi_e11.T
+ # Sim_hi_e22 = Sim_hi_e22.T
+ # Sim_hi_e33 = Sim_hi_e33.T
+
+ # Normalize data
+ # Sim_hi_e11_norm = normalize_data(Sim_hi_e11)
+ # Sim_hi_e22_norm = normalize_data(Sim_hi_e22)
+ # Sim_hi_e33_norm = normalize_data(Sim_hi_e33)
+
+ # return data that will be used for the benchmark
+ return nrows, (x1_norm, x2_norm), Real_e33_norm
+
+
+###############
+
+## Select data for ground truth
+
+ngrid, x_grids, y_grid = read_and_prepare_data()
+
+# default inputs
+INITIAL_BOUNDS = [[-1.0, 1.0], [-1.0, 1.0]]
+NUM_DIMS = len(INITIAL_BOUNDS)
+
+MESHGRID_SIZE = ngrid
+INITIAL_MESHGRIDS = x_grids
+INITIAL_POINTS_TO_PREDICT = np.hstack([mg.reshape(-1, 1) for mg in INITIAL_MESHGRIDS])
+
+INITIAL_PREDICTIONS = y_grid.reshape(-1, 1)
+
+###############
+
+NOISE_LEVEL = 1.0e-2
+
+truth_interp = LinearNDInterpolator(INITIAL_POINTS_TO_PREDICT, INITIAL_PREDICTIONS)
+
+
+@dataclass
+class StrainMap:
+ """Strain Map function."""
+
+ noise_level: float
+
+ truth_interp: LinearNDInterpolator
+ """Strain interpolator that is used as 'ground_truth'"""
+
+ def strain_map(self, x) -> float:
+ """
+ Represents a measured strain as a function of two simulation parameters.
+ """
+ x = np.asarray(x).reshape((-1, 2))
+ x1, x2 = x[:, 0], x[:, 1]
+
+ y_true = truth_interp(np.asarray(x1), np.asarray(x2))
+
+ # print("Evaluated truth model", np.hstack((x, y_true)))
+
+ y_noise = y_true + self.noise_level * np.random.normal(size=y_true.shape)
+ return y_noise
+
+
+# build a strain map from the selected truth values
+truth_strain_map = StrainMap(truth_interp=truth_interp, noise_level=NOISE_LEVEL)
+
+###############
+
+# test parameters
+INITIAL_NUM_POINTS = 25
+MAX_ITERATIONS = 150 # only allow a maximum of this many iterations in tests
+
+INITIAL_DATASET_X = np.random.uniform(-1.0, 1.0, size=(INITIAL_NUM_POINTS, NUM_DIMS)).tolist()
+
+TARGET_ERROR = 0.11
+
+
+def run_simulation(
+ dataset_x: list[list[float]],
+ dataset_y: list[float],
+ strategy: str,
+ strategy_args: object,
+) -> tuple[np.ndarray, np.ndarray]:
+ # important "Hyper-parameters"
+ length_scale = 0.4
+ prior_std = 1.0
+
+ # Assume that there is some small noise in the measurements to stabilize the fit
+ statistics_y = Normal(loc='y', scale=NOISE_LEVEL)
+
+ # modify a local copy of strategy_args
+ strategy_args = strategy_args.copy()
+ backend = strategy_args.pop('backend', 'sklearn')
+
+ if backend == 'sable':
+ # train model with new data
+ kernel = 'rbf'
+ kernel_args = {
+ 'sigma_range': [5e-2, 1.0],
+ 'gamma': 0.5,
+ }
+ backend_args = {
+ 'prior_std': prior_std,
+ }
+
+ else:
+ # train model with new data
+ kernel = 'matern'
+ kernel_args = {
+ 'length_scale': length_scale,
+ 'constant_value': prior_std**2,
+ }
+ backend_args = {}
+
+ client_state = DialWorkflowCreationParamsService(
+ dataset_x=dataset_x,
+ dataset_y=dataset_y,
+ statistics_y=statistics_y,
+ bounds=INITIAL_BOUNDS,
+ kernel=kernel,
+ kernel_args=kernel_args,
+ y_is_good=False,
+ backend=backend,
+ backend_args=backend_args,
+ seed=-1,
+ dim_x=2,
+ )
+
+ data = ServersideInputBase(client_state)
+ model = dial_core.train_model(data)
+
+ # use get_surrogate_values to predict mean and standard deviation on the inital points grid
+ data = ServersideInputPrediction(
+ client_state,
+ DialInputPredictions(
+ workflow_id=MOCK_WORKFLOW_ID,
+ points_to_predict=INITIAL_POINTS_TO_PREDICT,
+ ),
+ )
+ surrogate_mean, surrogate_std, _ = dial_core.get_surrogate_values(data, model)
+ mean_grid = np.array(surrogate_mean).reshape((-1, 1))
+
+ # subtract the true values and save mean absolute error and standard deviation
+ err_grid = np.abs(mean_grid - INITIAL_PREDICTIONS).reshape((MESHGRID_SIZE,) * NUM_DIMS)
+ std_grid = np.array(surrogate_std).reshape((MESHGRID_SIZE,) * NUM_DIMS)
+
+ # get_next_point
+ data = ServersideInputSingle(
+ client_state,
+ DialInputSingleOtherStrategy(
+ workflow_id=MOCK_WORKFLOW_ID,
+ bounds=INITIAL_BOUNDS,
+ y_is_good=False,
+ seed=-1,
+ strategy=strategy,
+ strategy_args=strategy_args,
+ discrete_measurements=True,
+ discrete_measurement_grid_size=[MESHGRID_SIZE, MESHGRID_SIZE],
+ ),
+ )
+ next_point = dial_core.get_next_point(data, model)
+
+ dataset_x.append(next_point)
+
+ # compute at next point
+ next_point_y = truth_strain_map.strain_map(next_point).reshape(-1).tolist()
+ dataset_y.append(next_point_y[0])
+
+ return err_grid, std_grid
+
+
+def graph(err_grid, dataset_x, strategy):
+ try:
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+
+ mpl.use('Agg') # Use non-interactive backend
+ except ImportError:
+ logger.error( # noqa: TRY400
+ 'Error: matplotlib is required for generating plots. Install it with: pip install matplotlib'
+ )
+ return
+
+ plt.clf()
+ data = np.array(err_grid)
+ plt.contourf(
+ INITIAL_MESHGRIDS[0],
+ INITIAL_MESHGRIDS[1],
+ data,
+ levels=np.logspace(-2, 0, 10),
+ norm='log',
+ extend='both',
+ )
+ cbar = plt.colorbar()
+ cbar.set_ticks(np.logspace(-2, 0, 7))
+ cbar.set_label('Overall error')
+ plt.xlabel('Simulation Parameter #1')
+ plt.ylabel('Simulation Parameter #2')
+ # add black dots for data points and a red marker for the recommendation:
+ X_train = np.array(dataset_x)
+ plt.scatter(X_train[:, 0], X_train[:, 1], color='black', marker='o')
+ plt.scatter(1.0, 1.0, s=300, color='None', edgecolors='black', marker='o')
+
+ plt.savefig(f'graph_{strategy}.png')
+
+
+def accuracy_benchmark(
+ strategy: str, strategy_args: object, max_iterations=MAX_ITERATIONS
+) -> tuple[int, float, float]:
+ """
+ returns:
+ - number of iterations taken to reach an acceptably accurate target
+ - target value achieved
+ """
+
+ iterations = 0
+
+ initial_dataset_x = np.random.uniform(-1.0, 1.0, size=(INITIAL_NUM_POINTS, NUM_DIMS)).tolist()
+
+ dataset_x = initial_dataset_x
+ dataset_y = truth_strain_map.strain_map(dataset_x).reshape(-1).tolist()
+
+ # run simulations until we reach an acceptable target range
+ while iterations < max_iterations:
+ try:
+ err_grid, std_grid = run_simulation(dataset_x, dataset_y, strategy, strategy_args)
+ except Exception as e:
+ logger.exception('Error during simulation')
+ raise AssertionError from e
+
+ # guess has no meaning here, take the last acquired datapoint
+ guess = dataset_x[-1]
+
+ # compute the RMSE and MAD on the grid and the average
+ # rmse = np.sqrt(err_grid**2 + std_grid**2)
+ mad = np.abs(err_grid)
+ # total_rmse = np.sqrt(np.mean(rmse**2))
+ total_mad = np.sqrt(np.mean(mad**2))
+
+ # pick the MAD over the RMSE as an error criterion, it only measures the mean deviation:
+ # it is less sensitive to wrong std and hyperparameter calibration, but does not measure how well
+ # the "error bars" (std_grid) quantify the actual ty
+ error = total_mad
+ print(iterations, error)
+
+ graph(
+ mad,
+ dataset_x,
+ f'{strategy}_{strategy_args.get("backend", "sklearn")}',
+ )
+
+ if error <= TARGET_ERROR:
+ break
+ iterations += 1
+
+ return iterations, error, guess
+
+
+TEST_PARAMS = (
+ ('backend', 'strategy', 'strategy_args', 'max_iterations'),
+ [
+ ('sklearn', 'uncertainty', {}, 2),
+ ('sable', 'uncertainty', {}, 2),
+ ('sklearn', 'random', {}, 2),
+ # use low number of iterations for unit test
+ ],
+)
+
+
+@pytest.mark.parametrize(*generate_pytest_parameters(TEST_PARAMS, 0))
+def test_benchmark_strainmap_accuracy(
+ # benchmark: BenchmarkFixture,
+ backend: str,
+ strategy: str,
+ strategy_args: dict,
+ max_iterations: int,
+) -> None:
+ # NUM_RUNS = 20
+ # for _ in range(NUM_RUNS):
+ # iterations, target = benchmark(
+ # partial(accuracy_benchmark, strategy, strategy_args)
+ # )
+ iterations, target, guess = accuracy_benchmark(
+ strategy, {'backend': backend, **strategy_args}, max_iterations
+ )
+ print(
+ 'Iterations for',
+ strategy,
+ ': ',
+ iterations,
+ ' best guess:',
+ guess,
+ ' with target value:',
+ target,
+ )
+ print(
+ 'Maximum early terminus value',
+ TARGET_ERROR,
+ ' with ',
+ max_iterations,
+ ' maximum iterations.',
+ )
+ print(
+ 'Accuracy benchmark for strategy:',
+ strategy,
+ 'reached' if iterations <= max_iterations else 'not reached',
+ )
+
+
+if __name__ == '__main__':
+ """Generate HTML benchmark report with plots comparing different strategies."""
+ import argparse
+ import datetime
+ import json
+ from pathlib import Path
+
+ logger = logging.getLogger(f'{__name__}_runner')
+
+ try:
+ import matplotlib as mpl
+ import matplotlib.pyplot as plt
+
+ mpl.use('Agg') # Use non-interactive backend
+ except ImportError:
+ logger.error( # noqa: TRY400
+ 'Error: matplotlib is required for generating plots. Install it with: pip install matplotlib'
+ )
+ sys.exit(1)
+
+ def positive_int_type(arg):
+ try:
+ val = int(arg)
+ except ValueError as e:
+ msg = 'Must be an integer'
+ raise argparse.ArgumentTypeError(msg) from e
+ if val < 1:
+ msg = 'Argument must be a positive number'
+ raise argparse.ArgumentTypeError(msg)
+ return val
+
+ parser = argparse.ArgumentParser(description='Generate the Strainmap HTML benchmark pages.')
+ parser.add_argument(
+ '--num-runs',
+ '-n',
+ type=positive_int_type,
+ default=3,
+ help='Number of runs for each strategy.',
+ )
+ args = parser.parse_args()
+
+ strategies = TEST_PARAMS[1]
+
+ # Run multiple iterations for statistical analysis
+ NUM_RUNS = args.num_runs
+ logger.info('Running benchmarks with %d iterations per strategy...', NUM_RUNS)
+
+ results = {}
+ for strategy, strategy_args, _ in strategies:
+ strategy_name = f'{strategy}' + (f' {json.dumps(strategy_args)}' if strategy_args else '')
+ logger.info('\nBenchmarking: %s', strategy_name)
+
+ iterations_list = []
+ targets_list = []
+ guesses_list = []
+
+ for run in range(NUM_RUNS):
+ iterations, target, guess = accuracy_benchmark(strategy, strategy_args)
+ iterations_list.append(iterations)
+ targets_list.append(target)
+ guesses_list.append(guess)
+ logger.info(
+ ' Run %d/%d: iterations=%d, target=%.4f',
+ run + 1,
+ NUM_RUNS,
+ iterations,
+ target,
+ )
+
+ results[strategy_name] = {
+ 'strategy': strategy,
+ 'strategy_args': strategy_args,
+ 'iterations': iterations_list,
+ 'targets': targets_list,
+ 'guesses': guesses_list,
+ 'avg_iterations': np.mean(iterations_list),
+ 'std_iterations': np.std(iterations_list),
+ 'avg_target': np.mean(targets_list),
+ 'std_target': np.std(targets_list),
+ 'success_rate': sum(1 for t in targets_list if t <= TARGET_ERROR) / NUM_RUNS * 100,
+ }
+
+ # Generate plots
+ output_dir = Path('reports/benchmarks')
+ output_dir.mkdir(parents=True, exist_ok=True)
+
+ fig, axes = plt.subplots(2, 2, figsize=(14, 10))
+ fig.suptitle(
+ 'Strainmap Optimization Benchmark Comparison',
+ fontsize=16,
+ fontweight='bold',
+ )
+
+ # Plot 1: Average iterations to convergence
+ ax1 = axes[0, 0]
+ strategy_names = list(results.keys())
+ avg_iterations = [results[s]['avg_iterations'] for s in strategy_names]
+ std_iterations = [results[s]['std_iterations'] for s in strategy_names]
+ bars1 = ax1.bar(
+ range(len(strategy_names)),
+ avg_iterations,
+ yerr=std_iterations,
+ capsize=5,
+ alpha=0.7,
+ )
+ ax1.set_xlabel('Strategy')
+ ax1.set_ylabel('Average Iterations')
+ ax1.set_title('Iterations to Convergence (Lower is Better)')
+ ax1.set_xticks(range(len(strategy_names)))
+ ax1.set_xticklabels(
+ [s.replace(' ', '\n') for s in strategy_names],
+ rotation=0,
+ ha='center',
+ fontsize=8,
+ )
+ ax1.grid(axis='y', alpha=0.3)
+
+ # Add value labels on bars
+ for _i, (bar, val, std) in enumerate(zip(bars1, avg_iterations, std_iterations, strict=False)):
+ height = bar.get_height()
+ ax1.text(
+ bar.get_x() + bar.get_width() / 2.0,
+ height,
+ f'{val:.1f}±{std:.1f}',
+ ha='center',
+ va='bottom',
+ fontsize=9,
+ )
+
+ # Plot 2: Average target value achieved
+ ax2 = axes[0, 1]
+ avg_targets = [results[s]['avg_target'] for s in strategy_names]
+ std_targets = [results[s]['std_target'] for s in strategy_names]
+ bars2 = ax2.bar(
+ range(len(strategy_names)),
+ avg_targets,
+ yerr=std_targets,
+ capsize=5,
+ alpha=0.7,
+ color='orange',
+ )
+ ax2.set_xlabel('Strategy')
+ ax2.set_ylabel('Average Target Value')
+ ax2.set_title('Final Target Value (Lower is Better)')
+ ax2.set_xticks(range(len(strategy_names)))
+ ax2.set_xticklabels(
+ [s.replace(' ', '\n') for s in strategy_names],
+ rotation=0,
+ ha='center',
+ fontsize=8,
+ )
+ ax2.axhline(
+ y=TARGET_ERROR,
+ color='r',
+ linestyle='--',
+ label=f'Target Threshold ({TARGET_ERROR})',
+ )
+ ax2.legend()
+ ax2.grid(axis='y', alpha=0.3)
+
+ # Add value labels on bars
+ for _i, (bar, val, std) in enumerate(zip(bars2, avg_targets, std_targets, strict=False)):
+ height = bar.get_height()
+ ax2.text(
+ bar.get_x() + bar.get_width() / 2.0,
+ height,
+ f'{val:.2f}±{std:.2f}',
+ ha='center',
+ va='bottom',
+ fontsize=9,
+ )
+
+ # Plot 3: Success rate
+ ax3 = axes[1, 0]
+ success_rates = [results[s]['success_rate'] for s in strategy_names]
+ bars3 = ax3.bar(range(len(strategy_names)), success_rates, alpha=0.7, color='green')
+ ax3.set_xlabel('Strategy')
+ ax3.set_ylabel('Success Rate (%)')
+ ax3.set_title(f'Success Rate (Target ≤ {TARGET_ERROR})')
+ ax3.set_xticks(range(len(strategy_names)))
+ ax3.set_xticklabels(
+ [s.replace(' ', '\n') for s in strategy_names],
+ rotation=0,
+ ha='center',
+ fontsize=8,
+ )
+ ax3.set_ylim([0, 105])
+ ax3.grid(axis='y', alpha=0.3)
+
+ # Add value labels on bars
+ for bar, val in zip(bars3, success_rates, strict=False):
+ height = bar.get_height()
+ ax3.text(
+ bar.get_x() + bar.get_width() / 2.0,
+ height,
+ f'{val:.1f}%',
+ ha='center',
+ va='bottom',
+ fontsize=9,
+ )
+
+ # Plot 4: Box plot of iterations distribution
+ ax4 = axes[1, 1]
+ iterations_data = [results[s]['iterations'] for s in strategy_names]
+ bp = ax4.boxplot(iterations_data, patch_artist=True)
+ for patch in bp['boxes']:
+ patch.set_facecolor('lightblue')
+ ax4.set_xlabel('Strategy')
+ ax4.set_ylabel('Iterations')
+ ax4.set_title('Iterations Distribution')
+ ax4.set_xticklabels([s.replace(' ', '\n') for s in strategy_names], fontsize=8)
+ ax4.grid(axis='y', alpha=0.3)
+
+ plt.tight_layout()
+ plot_path = output_dir / 'strainmap_benchmark.png'
+ plt.savefig(plot_path, dpi=150, bbox_inches='tight')
+ logger.info('✓ Plot saved to %s', plot_path)
+ plt.close()
+
+ # Generate HTML report
+ html_content = f"""
+
+
+
+
+ Strainmap Optimization Benchmark Report
+
+
+
+ 📊 Strainmap Optimization Benchmark Report
+
+
+
+
+
🎯 Test Objective
+
This benchmark evaluates different acquisition strategies for Bayesian optimization on a strain mapping experiment dataset.
+ The goal is to minimize the total surrogate error (over all inputs) within {MAX_ITERATIONS} iterations, starting from {INITIAL_NUM_POINTS} initial points.
+
+
+ 📈 Benchmark Results
+
+
+
Performance Comparison
+

+
+
+ 📋 Detailed Statistics
+
+
+
+
+ | Strategy |
+ Strategy Args |
+ Avg Iterations |
+ Std Iterations |
+ Avg Target Value |
+ Std Target Value |
+ Success Rate |
+
+
+
+"""
+
+ # Find best performers
+ best_iterations_idx = min(range(len(strategy_names)), key=lambda i: avg_iterations[i])
+ best_target_idx = min(range(len(strategy_names)), key=lambda i: avg_targets[i])
+ best_success_idx = max(range(len(strategy_names)), key=lambda i: success_rates[i])
+
+ for i, strategy_name in enumerate(strategy_names):
+ result = results[strategy_name]
+ row_class = ''
+ if i in (best_iterations_idx, best_target_idx, best_success_idx):
+ row_class = ' class="best"'
+
+ args_str = json.dumps(result['strategy_args']) if result['strategy_args'] else 'None'
+
+ html_content += f"""
+ {result['strategy']} |
+ {args_str} |
+ {result['avg_iterations']:.2f} |
+ {result['std_iterations']:.2f} |
+ {result['avg_target']:.4f} |
+ {result['std_target']:.4f} |
+ {result['success_rate']:.1f}% |
+
+"""
+
+ html_content += """
+
+
+ 🏆 Key Findings
+
+"""
+
+ # Add findings
+ best_strategy = strategy_names[best_iterations_idx]
+ html_content += f"""
Fastest Convergence: {best_strategy} with {avg_iterations[best_iterations_idx]:.2f} ± {std_iterations[best_iterations_idx]:.2f} iterations on average
+"""
+
+ best_accuracy_strategy = strategy_names[best_target_idx]
+ html_content += f"""
Best Accuracy: {best_accuracy_strategy} with average target value {avg_targets[best_target_idx]:.4f} ± {std_targets[best_target_idx]:.4f}
+"""
+
+ best_reliability_strategy = strategy_names[best_success_idx]
+ html_content += f"""
Most Reliable: {best_reliability_strategy} with {success_rates[best_success_idx]:.1f}% success rate
+"""
+
+ html_content += """
+
+ 📊 Raw Data
+
+ Click to expand raw results JSON
+
+"""
+
+ # Prepare JSON-serializable results
+ json_results = {}
+ for strategy_name, result in results.items():
+ json_results[strategy_name] = {
+ 'strategy': result['strategy'],
+ 'strategy_args': result['strategy_args'],
+ 'iterations': result['iterations'],
+ 'targets': result['targets'],
+ 'guesses': [[float(x) for x in guess] for guess in result['guesses']],
+ 'statistics': {
+ 'avg_iterations': float(result['avg_iterations']),
+ 'std_iterations': float(result['std_iterations']),
+ 'avg_target': float(result['avg_target']),
+ 'std_target': float(result['std_target']),
+ 'success_rate': float(result['success_rate']),
+ },
+ }
+
+ html_content += json.dumps(json_results, indent=2)
+ html_content += """
+
+
+
+
+
+
+"""
+
+ # Save HTML report
+ html_path = output_dir / 'strainmap_benchmark.html'
+ html_path.write_text(html_content)
+ logger.info('✓ HTML report saved to %s', html_path)
+
+ # Save JSON data
+ json_path = output_dir / 'strainmap_benchmark.json'
+ json_path.write_text(json.dumps(json_results, indent=2))
+ logger.info('✓ JSON data saved to %s', json_path)
+
+ logger.info('\n%s', '=' * 60)
+ logger.info('📊 Benchmark Summary')
+ logger.info('%s', '=' * 60)
+ for strategy_name in strategy_names:
+ result = results[strategy_name]
+ logger.info('\n%s:', strategy_name)
+ logger.info(
+ ' Avg Iterations: %.2f ± %.2f',
+ result['avg_iterations'],
+ result['std_iterations'],
+ )
+ logger.info(
+ ' Avg Target: %.4f ± %.4f',
+ result['avg_target'],
+ result['std_target'],
+ )
+ logger.info(' Success Rate: %.1f%%', result['success_rate'])
+
+ logger.info('\n%s', '=' * 60)
+ logger.info('✓ Open %s in your browser to view the full report', html_path)
+ logger.info('%s', '=' * 60)
+ # assert iterations <= MAX_ITERATIONS
diff --git a/tests/helpers.py b/tests/helpers.py
new file mode 100644
index 0000000..930ea72
--- /dev/null
+++ b/tests/helpers.py
@@ -0,0 +1,30 @@
+from copy import deepcopy
+
+import pytest
+
+from dial_service.service_specific_dataclasses import AVAILABLE_DIAL_BACKENDS
+
+
+def generate_pytest_parameters(
+ old_params: tuple[tuple[str], tuple[list[object]]], backend_idx: int
+) -> tuple[tuple[str], tuple[list[object]]]:
+ """
+ Generates test safeguards from generic parameters.
+
+ This should only really be used if you simultaneously want to use generic parameters in contexts other than Pytest.
+
+ Params:
+ - old_params = your normal pytest.mark.parametrize parameters (don't use pytest.param)
+ - backend_idx = the index of the "backend" parameter in your args list"""
+ new_params = deepcopy(old_params)
+ for i, test in enumerate(old_params[1]):
+ backend_name = test[backend_idx]
+ if backend_name != 'sklearn':
+ new_params[1][i] = pytest.param(
+ *test,
+ marks=pytest.mark.skipif(
+ backend_name not in AVAILABLE_DIAL_BACKENDS,
+ reason=f'{backend_name} not installed',
+ ),
+ )
+ return new_params
diff --git a/tests/unit/__init__.py b/tests/unit/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/tests/unit/test_internals.py b/tests/unit/test_internals.py
index 1b6f9c1..7d32e16 100644
--- a/tests/unit/test_internals.py
+++ b/tests/unit/test_internals.py
@@ -18,6 +18,7 @@
ServersideInputSingle,
)
from dial_service.service_specific_dataclasses import (
+ AVAILABLE_DIAL_BACKENDS,
DialWorkflowCreationParamsService,
)
@@ -332,7 +333,13 @@ def prediction_1D_heteroscedastic(backend):
('backend', 'approx'),
[
('sklearn', 1.842309),
- # ('gpax', 2.0),
+ # pytest.param(
+ # 'gpax', 2.0,
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_EI_1D(backend, approx):
@@ -349,7 +356,13 @@ def test_EI_1D(backend, approx):
('backend', 'val'),
[
('sklearn', 1.0),
- # ('gpax', 2.0),
+ # pytest.param(
+ # 'gpax', 2.0,
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_EI_1D_discrete(backend, val):
@@ -370,7 +383,13 @@ def test_EI_1D_discrete(backend, val):
('backend', 'approx'),
[
('sklearn', [1.705352, -1.682829]),
- # ('gpax', [2.0, 2.0]),
+ # pytest.param(
+ # 'gpax', [2.0, 2,0],
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_EI_2D(backend, approx):
@@ -387,7 +406,12 @@ def test_EI_2D(backend, approx):
('backend', 'approx'),
[
('sklearn', [2.000000, -1.143727, -1.859496]),
- # ('gpax', [2.0, 2.0, -2.0], # WAS: [2.0, 2.0, 2.0]
+ # pytest.param(
+ # 'gpax', [2.0, 2,0, 2.0,], # WAS: [2.0,2.0,2,0]
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
# ),
],
)
@@ -405,7 +429,13 @@ def test_EI_3D(backend, approx):
('backend', 'approx'),
[
('sklearn', [1.5]),
- # ('gpax',),
+ # pytest.param(
+ # 'gpax' [2.0],
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_uncertainty(backend, approx):
@@ -419,7 +449,13 @@ def test_uncertainty(backend, approx):
('backend', 'approx'),
[
('sklearn', [1.790396262]),
- # ('gpax', [2.0]),
+ # pytest.param(
+ # 'gpax' [2.0],
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_preprocessing_standardize(backend, approx):
@@ -435,7 +471,13 @@ def test_preprocessing_standardize(backend, approx):
('backend', 'val'),
[
('sklearn', [1.0]),
- # ('gpax', [2.0]),
+ # pytest.param(
+ # 'gpax' [2.0],
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_preprocessing_standardize_discrete(backend, val):
@@ -459,7 +501,13 @@ def test_preprocessing_standardize_discrete(backend, val):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_random(backend):
@@ -475,7 +523,13 @@ def test_random(backend):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_hypercube_single_point(backend):
@@ -505,7 +559,13 @@ def test_hypercube_single_point(backend):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_random_discrete(backend):
@@ -530,7 +590,13 @@ def test_random_discrete(backend):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_hypercube_single_point_discrete(backend):
@@ -566,7 +632,13 @@ def test_hypercube_single_point_discrete(backend):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_hypercube_single_point_discrete_2D(backend):
@@ -601,7 +673,13 @@ def test_hypercube_single_point_discrete_2D(backend):
('backend'),
[
('sklearn'),
- ('gpax'),
+ pytest.param(
+ 'gpax',
+ marks=pytest.mark.skipif(
+ 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ reason='gpax not installed',
+ ),
+ ),
],
)
def test_random_points(backend):
@@ -616,7 +694,13 @@ def test_random_points(backend):
('backend'),
[
('sklearn'),
- # ('gpax'),
+ # pytest.param(
+ # 'gpax',
+ # marks=pytest.mark.skipif(
+ # 'gpax' not in AVAILABLE_DIAL_BACKENDS,
+ # reason='gpax not installed',
+ # ),
+ # ),
],
)
def test_hypercube_multiple_points(backend):
@@ -644,7 +728,7 @@ def test_hypercube_multiple_points(backend):
],
[2.11126987e01, 2.96625069e01, 2.11126987e01],
),
- # (
+ # pytest.param(
# 'gpax',
# [
# 76.99987768175089,
@@ -654,6 +738,7 @@ def test_hypercube_multiple_points(backend):
# 82.26569221517353,
# ],
# [3335.7290084812175, 3327.202331393974, 3335.7290084812175],
+ # marks=pytest.mark.skipif('gpax' not in AVAILABLE_DIAL_BACKENDS, reason='gpax not installed')
# ),
],
)
@@ -673,10 +758,14 @@ def test_surrogate(backend, expected_means, expected_stddevs):
[-1.0, -0.65, 0.0, 0.65, 1.0],
[1e-2, 0.42, 0.59, 0.42, 1e-5],
),
- (
+ pytest.param(
'sable',
[-1.0, -0.56, 0.0, 0.56, 1.0],
[1e-2, 0.29, 0.34, 0.29, 1e-5],
+ marks=pytest.mark.skipif(
+ 'sable' not in AVAILABLE_DIAL_BACKENDS,
+ reason='sable not installed',
+ ),
),
],
)
diff --git a/uv.lock b/uv.lock
index 9a8f535..89d216d 100644
--- a/uv.lock
+++ b/uv.lock
@@ -374,7 +374,7 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/66/54/eb9bfc647b19f2009dd5c7f5ec51c4e6ca831725f1aea7a993034f483147/contourpy-1.3.2.tar.gz", hash = "sha256:b6945942715a034c671b7fc54f9588126b0b8bf23db2696e3ca8328f3ff0ab54", size = 13466130, upload-time = "2025-04-15T17:47:53.79Z" }
wheels = [
@@ -450,7 +450,7 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/58/01/1253e6698a07380cd31a736d248a3f2a50a7c88779a1813da27503cadc2a/contourpy-1.3.3.tar.gz", hash = "sha256:083e12155b210502d0bca491432bb04d56dc3432f95a979b429f2848c3dbe880", size = 13466174, upload-time = "2025-07-26T12:03:12.549Z" }
wheels = [
@@ -650,7 +650,7 @@ name = "cuda-bindings"
version = "13.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "cuda-pathfinder", marker = "python_full_version < '3.15'" },
+ { name = "cuda-pathfinder" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/a9/21/8464d133752951c154feafb3b65c297e7d80f301183d220bec4c830f1441/cuda_bindings-13.3.1-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:120fcc53d57903df529c3486962c56528cba5b7d6c57c99537320ed9922c8b86", size = 6073403, upload-time = "2026-05-29T23:11:36.22Z" },
@@ -685,43 +685,43 @@ wheels = [
[package.optional-dependencies]
cublas = [
- { name = "nvidia-cublas", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-cuda-nvrtc", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cudart = [
- { name = "nvidia-cuda-runtime", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cuda-runtime", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cufft = [
- { name = "nvidia-cufft", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cufft", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cufile = [
- { name = "nvidia-cufile", marker = "(platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cufile", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cupti = [
- { name = "nvidia-cuda-cupti", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cuda-cupti", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
curand = [
- { name = "nvidia-curand", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-curand", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cusolver = [
- { name = "nvidia-cublas", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-cusolver", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-cusparse", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-cusolver", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cusparse = [
- { name = "nvidia-cusparse", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
+ { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvjitlink = [
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvrtc = [
- { name = "nvidia-cuda-nvrtc", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvtx = [
- { name = "nvidia-nvtx", marker = "(python_full_version < '3.15' and platform_machine == 'AMD64' and sys_platform == 'win32') or (platform_machine == 'aarch64' and sys_platform == 'linux') or (platform_machine == 'x86_64' and sys_platform == 'linux')" },
+ { name = "nvidia-nvtx", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
[[package]]
@@ -738,14 +738,10 @@ name = "dial"
version = "0.1.6"
source = { editable = "." }
dependencies = [
- { name = "gpax", version = "0.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "gpax", version = "0.1.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" },
{ name = "intersect-sdk" },
{ name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
- { name = "numpyro" },
{ name = "pymongo" },
- { name = "sable" },
{ name = "scikit-learn", version = "1.7.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
{ name = "scikit-learn", version = "1.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
{ name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
@@ -759,6 +755,14 @@ docs = [
{ name = "sphinx", version = "9.0.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
{ name = "sphinx", version = "9.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
]
+gpax = [
+ { name = "gpax", version = "0.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
+ { name = "gpax", version = "0.1.9", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.13'" },
+ { name = "numpyro" },
+]
+sable = [
+ { name = "sable" },
+]
[package.dev-dependencies]
dev = [
@@ -775,17 +779,17 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "furo", marker = "extra == 'docs'", specifier = ">=2023.3.27" },
- { name = "gpax", specifier = ">=0.1.8" },
+ { name = "gpax", marker = "extra == 'gpax'", specifier = ">=0.1.8" },
{ name = "intersect-sdk", specifier = ">=0.9.3,<0.10.0" },
{ name = "numpy" },
- { name = "numpyro", specifier = "<0.20.1" },
+ { name = "numpyro", marker = "extra == 'gpax'", specifier = "<0.20.1" },
{ name = "pymongo", specifier = ">=4.12.1" },
- { name = "sable", git = "https://code.ornl.gov/sable/sable.git" },
+ { name = "sable", marker = "extra == 'sable'", git = "https://code.ornl.gov/sable/sable.git" },
{ name = "scikit-learn", specifier = ">=1.4.0,<2.0.0" },
{ name = "scipy", specifier = ">=1.12.0,<2.0.0" },
{ name = "sphinx", marker = "extra == 'docs'", specifier = ">=5.3.0" },
]
-provides-extras = ["docs"]
+provides-extras = ["docs", "gpax", "sable"]
[package.metadata.requires-dev]
dev = [
@@ -877,13 +881,13 @@ wheels = [
[package.optional-dependencies]
epath = [
- { name = "fsspec", marker = "python_full_version < '3.11'" },
- { name = "importlib-resources", marker = "python_full_version < '3.11'" },
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
- { name = "zipp", marker = "python_full_version < '3.11'" },
+ { name = "fsspec" },
+ { name = "importlib-resources" },
+ { name = "typing-extensions" },
+ { name = "zipp" },
]
epy = [
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
]
[[package]]
@@ -901,12 +905,12 @@ wheels = [
[package.optional-dependencies]
epath = [
- { name = "fsspec", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "zipp", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "fsspec" },
+ { name = "typing-extensions" },
+ { name = "zipp" },
]
epy = [
- { name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "typing-extensions" },
]
[[package]]
@@ -914,7 +918,7 @@ name = "exceptiongroup"
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
@@ -938,15 +942,15 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "msgpack", marker = "python_full_version < '3.11'" },
- { name = "optax", marker = "python_full_version < '3.11'" },
- { name = "orbax-checkpoint", marker = "python_full_version < '3.11'" },
- { name = "pyyaml", marker = "python_full_version < '3.11'" },
- { name = "rich", marker = "python_full_version < '3.11'" },
- { name = "tensorstore", version = "0.1.78", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "treescope", marker = "python_full_version < '3.11'" },
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" } },
+ { name = "msgpack" },
+ { name = "optax" },
+ { name = "orbax-checkpoint" },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "tensorstore", version = "0.1.78", source = { registry = "https://pypi.org/simple" } },
+ { name = "treescope" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e6/76/4ea55a60a47e98fcff591238ee26ed4624cb4fdc4893aa3ebf78d0d021f4/flax-0.10.7.tar.gz", hash = "sha256:2930d6671e23076f6db3b96afacf45c5060898f5c189ecab6dda7e05d26c2085", size = 5136099, upload-time = "2025-07-02T06:10:07.819Z" }
wheels = [
@@ -962,16 +966,16 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "msgpack", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "optax", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "orbax-checkpoint", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "pyyaml", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "rich", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "tensorstore", version = "0.1.82", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "treescope", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" } },
+ { name = "msgpack" },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "optax" },
+ { name = "orbax-checkpoint" },
+ { name = "pyyaml" },
+ { name = "rich" },
+ { name = "tensorstore", version = "0.1.82", source = { registry = "https://pypi.org/simple" } },
+ { name = "treescope" },
+ { name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8b/02/2d4fbc31dcf5fb02e2b8ce733f8eecaffc7f24e905df2da39539809b195b/flax-0.12.0.tar.gz", hash = "sha256:cb3d4a2028666640c1a2e5b267dadfbd42ef14c6db41896fb4c765a7f05ebe74", size = 5038989, upload-time = "2025-09-25T23:59:00.919Z" }
wheels = [
@@ -1083,10 +1087,10 @@ resolution-markers = [
"python_full_version == '3.13.*'",
]
dependencies = [
- { name = "dm-haiku", marker = "python_full_version >= '3.13'" },
- { name = "jax", version = "0.5.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "matplotlib", marker = "python_full_version >= '3.13'" },
- { name = "numpyro", marker = "python_full_version >= '3.13'" },
+ { name = "dm-haiku" },
+ { name = "jax", version = "0.5.3", source = { registry = "https://pypi.org/simple" } },
+ { name = "matplotlib" },
+ { name = "numpyro" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9e/25/74b8c1c77bad231a92674be105a5fd9152fe3a9eb77efa27d342d77fce20/gpax-0.1.8.tar.gz", hash = "sha256:7bc7b89bd58db2d31f9c6007515d3883810e064c69d5b8895543647422a368aa", size = 73263, upload-time = "2024-03-20T06:39:56.206Z" }
wheels = [
@@ -1103,16 +1107,16 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "dm-haiku", marker = "python_full_version < '3.13'" },
- { name = "flax", version = "0.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "dm-haiku" },
+ { name = "flax", version = "0.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "flax", version = "0.12.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jaxlib", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "jaxopt", marker = "python_full_version < '3.13'" },
- { name = "matplotlib", marker = "python_full_version < '3.13'" },
- { name = "numpyro", marker = "python_full_version < '3.13'" },
+ { name = "jaxopt" },
+ { name = "matplotlib" },
+ { name = "numpyro" },
]
sdist = { url = "https://files.pythonhosted.org/packages/9e/b8/b45ecc6fe6c6d8363f1c66fd07b3a14dc1c1d09c1d0b18d5202a74fb4e91/gpax-0.1.9.tar.gz", hash = "sha256:d86d2738ae3f83a5c5fdb65f6bc421a27d49c46198a9677464f1879a95fcfcca", size = 61256, upload-time = "2025-07-04T06:11:06.435Z" }
wheels = [
@@ -1233,11 +1237,11 @@ resolution-markers = [
"python_full_version == '3.13.*'",
]
dependencies = [
- { name = "jaxlib", version = "0.5.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "ml-dtypes", version = "0.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "opt-einsum", marker = "python_full_version >= '3.13'" },
- { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
+ { name = "jaxlib", version = "0.5.3", source = { registry = "https://pypi.org/simple" } },
+ { name = "ml-dtypes", version = "0.4.1", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "opt-einsum" },
+ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/13/e5/dabb73ab10330e9535aba14fc668b04a46fcd8e78f06567c4f4f1adce340/jax-0.5.3.tar.gz", hash = "sha256:f17fcb0fd61dc289394af6ce4de2dada2312f2689bb0d73642c6f026a95fbb2c", size = 2072748, upload-time = "2025-03-19T18:23:40.901Z" }
wheels = [
@@ -1252,11 +1256,11 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "opt-einsum", marker = "python_full_version < '3.11'" },
- { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" } },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
+ { name = "opt-einsum" },
+ { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/cf/1e/267f59c8fb7f143c3f778c76cb7ef1389db3fd7e4540f04b9f42ca90764d/jax-0.6.2.tar.gz", hash = "sha256:a437d29038cbc8300334119692744704ca7941490867b9665406b7f90665cd96", size = 2334091, upload-time = "2025-06-17T23:10:27.186Z" }
wheels = [
@@ -1272,11 +1276,11 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "jaxlib", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "opt-einsum", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "jaxlib", version = "0.7.1", source = { registry = "https://pypi.org/simple" } },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "opt-einsum" },
+ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/bc/e8/b393ee314d3b042bd66b986d38e52f4e6046590399d916381265c20467d3/jax-0.7.1.tar.gz", hash = "sha256:118f56338c503361d2791f069d24339d8d44a8db442ed851d2e591222fb7a56d", size = 2428411, upload-time = "2025-08-20T15:55:46.098Z" }
wheels = [
@@ -1295,9 +1299,9 @@ resolution-markers = [
"python_full_version == '3.13.*'",
]
dependencies = [
- { name = "ml-dtypes", version = "0.4.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
- { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
+ { name = "ml-dtypes", version = "0.4.1", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/2e/12/b1da8468ad843b30976b0e87c6b344ee621fb75ef8bbd39156a303f59059/jaxlib-0.5.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:48ff5c89fb8a0fe04d475e9ddc074b4879a91d7ab68a51cec5cd1e87f81e6c47", size = 63694868, upload-time = "2025-03-19T18:23:52.193Z" },
@@ -1327,9 +1331,9 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
+ { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/15/c5/41598634c99cbebba46e6777286fb76abc449d33d50aeae5d36128ca8803/jaxlib-0.6.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:da4601b2b5dc8c23d6afb293eacfb9aec4e1d1871cb2f29c5a151d103e73b0f8", size = 54298019, upload-time = "2025-06-17T23:10:36.916Z" },
@@ -1361,9 +1365,9 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/af/5058d545e95f99a54289648f5430cc3c23263dd70a1391e7491f24ed328d/jaxlib-0.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f32c3e4c167b7327c342e82d3df84079714ea0b43718be871d039999670b3c9", size = 57686934, upload-time = "2025-08-20T15:55:58.989Z" },
@@ -1395,13 +1399,13 @@ name = "jaxopt"
version = "0.8.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jaxlib", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/3a/da/ff7d7fbd13b8ed5e8458e80308d075fc649062b9f8676d3fc56f2dc99a82/jaxopt-0.8.5.tar.gz", hash = "sha256:2790bd68ef132b216c083a8bc7a2704eceb35a92c0fc0a1e652e79dfb1e9e9ab", size = 121709, upload-time = "2025-04-14T17:59:01.618Z" }
@@ -1715,7 +1719,7 @@ name = "markdown-it-py"
version = "4.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "mdurl", marker = "python_full_version < '3.13'" },
+ { name = "mdurl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" }
wheels = [
@@ -1919,7 +1923,7 @@ resolution-markers = [
"python_full_version == '3.13.*'",
]
dependencies = [
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.13'" },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/fd/15/76f86faa0902836cc133939732f7611ace68cf54148487a99c539c272dc8/ml_dtypes-0.4.1.tar.gz", hash = "sha256:fad5f2de464fd09127e49b7fd1252b9006fb43d2edc1ff112d390c324af5ca7a", size = 692594, upload-time = "2024-09-13T19:07:11.624Z" }
wheels = [
@@ -1947,7 +1951,7 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/4a/c27b42ed9b1c7d13d9ba8b6905dece787d6259152f2309338aed29b2447b/ml_dtypes-0.5.4.tar.gz", hash = "sha256:8ab06a50fb9bf9666dd0fe5dfb4676fa2b0ac0f31ecff72a6c3af8e22c063453", size = 692314, upload-time = "2025-11-17T22:32:31.031Z" }
@@ -2361,7 +2365,7 @@ name = "nvidia-cublas"
version = "13.1.1.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "nvidia-cuda-nvrtc", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
+ { name = "nvidia-cuda-nvrtc" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" },
@@ -2400,7 +2404,7 @@ name = "nvidia-cudnn-cu13"
version = "9.20.0.48"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "nvidia-cublas", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
+ { name = "nvidia-cublas" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/56/c5/83384d846b2fd17c44bd499b36c75a45ed4f095fbbb2252294e89cea5c5c/nvidia_cudnn_cu13-9.20.0.48-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:e31454ae00094b0c55319d9d15b6fa2fc50a9e1c0f5c8c80fb75258234e731e1", size = 444574296, upload-time = "2026-03-09T19:28:27.751Z" },
@@ -2412,7 +2416,7 @@ name = "nvidia-cufft"
version = "12.0.0.61"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
+ { name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" },
@@ -2442,9 +2446,9 @@ name = "nvidia-cusolver"
version = "12.0.4.66"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "nvidia-cublas", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
- { name = "nvidia-cusparse", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
+ { name = "nvidia-cublas" },
+ { name = "nvidia-cusparse" },
+ { name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" },
@@ -2456,7 +2460,7 @@ name = "nvidia-cusparse"
version = "12.6.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "nvidia-nvjitlink", marker = "(python_full_version < '3.15' and sys_platform == 'emscripten') or (python_full_version < '3.15' and sys_platform == 'win32') or (sys_platform != 'emscripten' and sys_platform != 'win32')" },
+ { name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" },
@@ -2522,12 +2526,12 @@ name = "optax"
version = "0.2.8"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "absl-py", marker = "python_full_version < '3.13'" },
- { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "absl-py" },
+ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "jaxlib", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jaxlib", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/f9/e3d11ae6f298ee941a0690e353a323d158ba5dedc436e75621c310845c5c/optax-0.2.8.tar.gz", hash = "sha256:5b225b35066fc3eebaa4d798f1b4173b4d57d1a480610908981f8343b50af0b0", size = 301193, upload-time = "2026-03-20T23:30:05.465Z" }
@@ -2540,25 +2544,25 @@ name = "orbax-checkpoint"
version = "0.11.36"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "absl-py", marker = "python_full_version < '3.13'" },
- { name = "aiofiles", marker = "python_full_version < '3.13'" },
- { name = "etils", version = "1.13.0", source = { registry = "https://pypi.org/simple" }, extra = ["epath", "epy"], marker = "python_full_version < '3.11'" },
+ { name = "absl-py" },
+ { name = "aiofiles" },
+ { name = "etils", version = "1.13.0", source = { registry = "https://pypi.org/simple" }, extra = ["epath", "epy"], marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "etils", version = "1.14.0", source = { registry = "https://pypi.org/simple" }, extra = ["epath", "epy"], marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "humanize", marker = "python_full_version < '3.13'" },
- { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "humanize" },
+ { name = "jax", version = "0.6.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "jax", version = "0.7.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "msgpack", marker = "python_full_version < '3.13'" },
- { name = "nest-asyncio", marker = "python_full_version < '3.13' and sys_platform == 'win32'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "msgpack" },
+ { name = "nest-asyncio", marker = "sys_platform == 'win32'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "protobuf", marker = "python_full_version < '3.13'" },
- { name = "psutil", marker = "python_full_version < '3.13'" },
- { name = "pyyaml", marker = "python_full_version < '3.13'" },
- { name = "simplejson", marker = "python_full_version < '3.13'" },
- { name = "tensorstore", version = "0.1.78", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "protobuf" },
+ { name = "psutil" },
+ { name = "pyyaml" },
+ { name = "simplejson" },
+ { name = "tensorstore", version = "0.1.78", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "tensorstore", version = "0.1.82", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "typing-extensions", marker = "python_full_version < '3.13'" },
- { name = "uvloop", marker = "python_full_version < '3.13' and sys_platform != 'win32'" },
+ { name = "typing-extensions" },
+ { name = "uvloop", marker = "sys_platform != 'win32'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/a9/95/2eb9afead8b1aaa5a5184ced09f57c7c0ee473ea283be8e36f22ea92680f/orbax_checkpoint-0.11.36.tar.gz", hash = "sha256:60ed7084a9b79385fb5b9e4b05d98c2db6f5892d05ee8d82df680cfac1622312", size = 585461, upload-time = "2026-04-14T17:03:47.475Z" }
wheels = [
@@ -3312,8 +3316,8 @@ name = "rich"
version = "15.0.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "markdown-it-py", marker = "python_full_version < '3.13'" },
- { name = "pygments", marker = "python_full_version < '3.13'" },
+ { name = "markdown-it-py" },
+ { name = "pygments" },
]
sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" }
wheels = [
@@ -3494,10 +3498,10 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "joblib", marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "threadpoolctl", marker = "python_full_version < '3.11'" },
+ { name = "joblib" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
+ { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" } },
+ { name = "threadpoolctl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" }
wheels = [
@@ -3547,10 +3551,10 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "joblib", marker = "python_full_version >= '3.11'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
- { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
- { name = "threadpoolctl", marker = "python_full_version >= '3.11'" },
+ { name = "joblib" },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "scipy", version = "1.17.1", source = { registry = "https://pypi.org/simple" } },
+ { name = "threadpoolctl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" }
wheels = [
@@ -3600,7 +3604,7 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" }
wheels = [
@@ -3665,7 +3669,7 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
wheels = [
@@ -3850,23 +3854,23 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "alabaster", marker = "python_full_version < '3.11'" },
- { name = "babel", marker = "python_full_version < '3.11'" },
- { name = "colorama", marker = "python_full_version < '3.11' and sys_platform == 'win32'" },
- { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "imagesize", marker = "python_full_version < '3.11'" },
- { name = "jinja2", marker = "python_full_version < '3.11'" },
- { name = "packaging", marker = "python_full_version < '3.11'" },
- { name = "pygments", marker = "python_full_version < '3.11'" },
- { name = "requests", marker = "python_full_version < '3.11'" },
- { name = "snowballstemmer", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-applehelp", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-devhelp", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-htmlhelp", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-jsmath", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-qthelp", marker = "python_full_version < '3.11'" },
- { name = "sphinxcontrib-serializinghtml", marker = "python_full_version < '3.11'" },
- { name = "tomli", marker = "python_full_version < '3.11'" },
+ { name = "alabaster" },
+ { name = "babel" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "docutils", version = "0.21.2", source = { registry = "https://pypi.org/simple" } },
+ { name = "imagesize" },
+ { name = "jinja2" },
+ { name = "packaging" },
+ { name = "pygments" },
+ { name = "requests" },
+ { name = "snowballstemmer" },
+ { name = "sphinxcontrib-applehelp" },
+ { name = "sphinxcontrib-devhelp" },
+ { name = "sphinxcontrib-htmlhelp" },
+ { name = "sphinxcontrib-jsmath" },
+ { name = "sphinxcontrib-qthelp" },
+ { name = "sphinxcontrib-serializinghtml" },
+ { name = "tomli" },
]
sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/be0b61178fe2cdcb67e2a92fc9ebb488e3c51c4f74a36a7824c0adf23425/sphinx-8.1.3.tar.gz", hash = "sha256:43c1911eecb0d3e161ad78611bc905d1ad0e523e4ddc202a58a821773dc4c927", size = 8184611, upload-time = "2024-10-13T20:27:13.93Z" }
wheels = [
@@ -3881,23 +3885,23 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "alabaster", marker = "python_full_version == '3.11.*'" },
- { name = "babel", marker = "python_full_version == '3.11.*'" },
- { name = "colorama", marker = "python_full_version == '3.11.*' and sys_platform == 'win32'" },
- { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" },
- { name = "imagesize", marker = "python_full_version == '3.11.*'" },
- { name = "jinja2", marker = "python_full_version == '3.11.*'" },
- { name = "packaging", marker = "python_full_version == '3.11.*'" },
- { name = "pygments", marker = "python_full_version == '3.11.*'" },
- { name = "requests", marker = "python_full_version == '3.11.*'" },
- { name = "roman-numerals", marker = "python_full_version == '3.11.*'" },
- { name = "snowballstemmer", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-applehelp", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-devhelp", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-htmlhelp", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-jsmath", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-qthelp", marker = "python_full_version == '3.11.*'" },
- { name = "sphinxcontrib-serializinghtml", marker = "python_full_version == '3.11.*'" },
+ { name = "alabaster" },
+ { name = "babel" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "imagesize" },
+ { name = "jinja2" },
+ { name = "packaging" },
+ { name = "pygments" },
+ { name = "requests" },
+ { name = "roman-numerals" },
+ { name = "snowballstemmer" },
+ { name = "sphinxcontrib-applehelp" },
+ { name = "sphinxcontrib-devhelp" },
+ { name = "sphinxcontrib-htmlhelp" },
+ { name = "sphinxcontrib-jsmath" },
+ { name = "sphinxcontrib-qthelp" },
+ { name = "sphinxcontrib-serializinghtml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/42/50/a8c6ccc36d5eacdfd7913ddccd15a9cee03ecafc5ee2bc40e1f168d85022/sphinx-9.0.4.tar.gz", hash = "sha256:594ef59d042972abbc581d8baa577404abe4e6c3b04ef61bd7fc2acbd51f3fa3", size = 8710502, upload-time = "2025-12-04T07:45:27.343Z" }
wheels = [
@@ -3917,23 +3921,23 @@ resolution-markers = [
"python_full_version == '3.12.*'",
]
dependencies = [
- { name = "alabaster", marker = "python_full_version >= '3.12'" },
- { name = "babel", marker = "python_full_version >= '3.12'" },
- { name = "colorama", marker = "python_full_version >= '3.12' and sys_platform == 'win32'" },
- { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" },
- { name = "imagesize", marker = "python_full_version >= '3.12'" },
- { name = "jinja2", marker = "python_full_version >= '3.12'" },
- { name = "packaging", marker = "python_full_version >= '3.12'" },
- { name = "pygments", marker = "python_full_version >= '3.12'" },
- { name = "requests", marker = "python_full_version >= '3.12'" },
- { name = "roman-numerals", marker = "python_full_version >= '3.12'" },
- { name = "snowballstemmer", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-applehelp", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-devhelp", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-htmlhelp", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-jsmath", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-qthelp", marker = "python_full_version >= '3.12'" },
- { name = "sphinxcontrib-serializinghtml", marker = "python_full_version >= '3.12'" },
+ { name = "alabaster" },
+ { name = "babel" },
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+ { name = "docutils", version = "0.22.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "imagesize" },
+ { name = "jinja2" },
+ { name = "packaging" },
+ { name = "pygments" },
+ { name = "requests" },
+ { name = "roman-numerals" },
+ { name = "snowballstemmer" },
+ { name = "sphinxcontrib-applehelp" },
+ { name = "sphinxcontrib-devhelp" },
+ { name = "sphinxcontrib-htmlhelp" },
+ { name = "sphinxcontrib-jsmath" },
+ { name = "sphinxcontrib-qthelp" },
+ { name = "sphinxcontrib-serializinghtml" },
]
sdist = { url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz", hash = "sha256:7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb", size = 8718324, upload-time = "2025-12-31T15:09:27.646Z" }
wheels = [
@@ -4084,8 +4088,8 @@ resolution-markers = [
"python_full_version < '3.11'",
]
dependencies = [
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/9f/ee/05eb424437f4db63331c90e4605025eedc0f71da3faff97161d5d7b405af/tensorstore-0.1.78.tar.gz", hash = "sha256:e26074ffe462394cf54197eb76d6569b500f347573cd74da3f4dd5f510a4ad7c", size = 6913502, upload-time = "2025-10-06T17:44:29.649Z" }
wheels = [
@@ -4120,8 +4124,8 @@ resolution-markers = [
"python_full_version == '3.11.*'",
]
dependencies = [
- { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
- { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
+ { name = "ml-dtypes", version = "0.5.4", source = { registry = "https://pypi.org/simple" } },
+ { name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" } },
]
sdist = { url = "https://files.pythonhosted.org/packages/cd/9b/43aedb544937f214dd7c665a7edf1b8b74f2f55d53ebd351c0ce69acf81a/tensorstore-0.1.82.tar.gz", hash = "sha256:ccfceffb7611fc61330f6da24b8b0abd9251d480ac8a5bac5a1729f9ed0c3a9f", size = 7160364, upload-time = "2026-03-13T00:22:16.888Z" }
wheels = [
@@ -4279,7 +4283,7 @@ name = "treescope"
version = "0.1.10"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" },
+ { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11' or python_full_version >= '3.13'" },
{ name = "numpy", version = "2.4.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f0/2a/d13d3c38862632742d2fe2f7ae307c431db06538fd05ca03020d207b5dcc/treescope-0.1.10.tar.gz", hash = "sha256:20f74656f34ab2d8716715013e8163a0da79bdc2554c16d5023172c50d27ea95", size = 138870, upload-time = "2025-08-08T05:43:48.048Z" }